1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* DokuWiki Plugin extension (Helper Component) |
4
|
|
|
* |
5
|
|
|
* @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html |
6
|
|
|
* @author Michael Hamann <[email protected]> |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Class helper_plugin_extension_list takes care of creating a HTML list of extensions |
11
|
|
|
*/ |
12
|
|
|
class helper_plugin_extension_list extends DokuWiki_Plugin |
13
|
|
|
{ |
14
|
|
|
protected $form = ''; |
15
|
|
|
/** @var helper_plugin_extension_gui */ |
16
|
|
|
protected $gui; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Constructor |
20
|
|
|
* |
21
|
|
|
* loads additional helpers |
22
|
|
|
*/ |
23
|
|
|
public function __construct() |
24
|
|
|
{ |
25
|
|
|
$this->gui = plugin_load('helper', 'extension_gui'); |
|
|
|
|
26
|
|
|
} |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* Initialize the extension table form |
30
|
|
|
*/ |
31
|
|
|
public function startForm() |
32
|
|
|
{ |
33
|
|
|
$this->form .= '<ul class="extensionList">'; |
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Build single row of extension table |
38
|
|
|
* |
39
|
|
|
* @param helper_plugin_extension_extension $extension The extension that shall be added |
40
|
|
|
* @param bool $showinfo Show the info area |
41
|
|
|
*/ |
42
|
|
|
public function addRow(helper_plugin_extension_extension $extension, $showinfo = false) |
43
|
|
|
{ |
44
|
|
|
$this->startRow($extension); |
45
|
|
|
$this->populateColumn('legend', $this->makeLegend($extension, $showinfo)); |
46
|
|
|
$this->populateColumn('actions', $this->makeActions($extension)); |
47
|
|
|
$this->endRow(); |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Adds a header to the form |
52
|
|
|
* |
53
|
|
|
* @param string $id The id of the header |
54
|
|
|
* @param string $header The content of the header |
55
|
|
|
* @param int $level The level of the header |
56
|
|
|
*/ |
57
|
|
|
public function addHeader($id, $header, $level = 2) |
58
|
|
|
{ |
59
|
|
|
$this->form .='<h'.$level.' id="'.$id.'">'.hsc($header).'</h'.$level.'>'.DOKU_LF; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Adds a paragraph to the form |
64
|
|
|
* |
65
|
|
|
* @param string $data The content |
66
|
|
|
*/ |
67
|
|
|
public function addParagraph($data) |
68
|
|
|
{ |
69
|
|
|
$this->form .= '<p>'.hsc($data).'</p>'.DOKU_LF; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Add hidden fields to the form with the given data |
74
|
|
|
* |
75
|
|
|
* @param array $data key-value list of fields and their values to add |
76
|
|
|
*/ |
77
|
|
|
public function addHidden(array $data) |
78
|
|
|
{ |
79
|
|
|
$this->form .= '<div class="no">'; |
80
|
|
|
foreach ($data as $key => $value) { |
81
|
|
|
$this->form .= '<input type="hidden" name="'.hsc($key).'" value="'.hsc($value).'" />'; |
82
|
|
|
} |
83
|
|
|
$this->form .= '</div>'.DOKU_LF; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Add closing tags |
88
|
|
|
*/ |
89
|
|
|
public function endForm() |
90
|
|
|
{ |
91
|
|
|
$this->form .= '</ul>'; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Show message when no results are found |
96
|
|
|
*/ |
97
|
|
|
public function nothingFound() |
98
|
|
|
{ |
99
|
|
|
global $lang; |
100
|
|
|
$this->form .= '<li class="notfound">'.$lang['nothingfound'].'</li>'; |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
/** |
104
|
|
|
* Print the form |
105
|
|
|
* |
106
|
|
|
* @param bool $returnonly whether to return html or print |
107
|
|
|
*/ |
108
|
|
|
public function render($returnonly = false) |
109
|
|
|
{ |
110
|
|
|
if ($returnonly) return $this->form; |
111
|
|
|
echo $this->form; |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* Start the HTML for the row for the extension |
116
|
|
|
* |
117
|
|
|
* @param helper_plugin_extension_extension $extension The extension |
118
|
|
|
*/ |
119
|
|
|
private function startRow(helper_plugin_extension_extension $extension) |
120
|
|
|
{ |
121
|
|
|
$this->form .= '<li id="extensionplugin__'.hsc($extension->getID()). |
122
|
|
|
'" class="'.$this->makeClass($extension).'">'; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Add a column with the given class and content |
127
|
|
|
* @param string $class The class name |
128
|
|
|
* @param string $html The content |
129
|
|
|
*/ |
130
|
|
|
private function populateColumn($class, $html) |
131
|
|
|
{ |
132
|
|
|
$this->form .= '<div class="'.$class.' col">'.$html.'</div>'.DOKU_LF; |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* End the row |
137
|
|
|
*/ |
138
|
|
|
private function endRow() |
139
|
|
|
{ |
140
|
|
|
$this->form .= '</li>'.DOKU_LF; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* Generate the link to the plugin homepage |
145
|
|
|
* |
146
|
|
|
* @param helper_plugin_extension_extension $extension The extension |
147
|
|
|
* @return string The HTML code |
148
|
|
|
*/ |
149
|
|
|
public function makeHomepageLink(helper_plugin_extension_extension $extension) |
150
|
|
|
{ |
151
|
|
|
global $conf; |
152
|
|
|
$url = $extension->getURL(); |
153
|
|
|
if (strtolower(parse_url($url, PHP_URL_HOST)) == 'www.dokuwiki.org') { |
154
|
|
|
$linktype = 'interwiki'; |
155
|
|
|
} else { |
156
|
|
|
$linktype = 'extern'; |
157
|
|
|
} |
158
|
|
|
$param = array( |
159
|
|
|
'href' => $url, |
160
|
|
|
'title' => $url, |
161
|
|
|
'class' => ($linktype == 'extern') ? 'urlextern' : 'interwiki iw_doku', |
162
|
|
|
'target' => $conf['target'][$linktype], |
163
|
|
|
'rel' => ($linktype == 'extern') ? 'noopener' : '', |
164
|
|
|
); |
165
|
|
|
if ($linktype == 'extern' && $conf['relnofollow']) { |
166
|
|
|
$param['rel'] = implode(' ', [$param['rel'], 'ugc nofollow']); |
167
|
|
|
} |
168
|
|
|
$html = ' <a '. buildAttributes($param, true).'>'. |
169
|
|
|
$this->getLang('homepage_link').'</a>'; |
170
|
|
|
return $html; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* Generate the class name for the row of the extension |
175
|
|
|
* |
176
|
|
|
* @param helper_plugin_extension_extension $extension The extension object |
177
|
|
|
* @return string The class name |
178
|
|
|
*/ |
179
|
|
|
public function makeClass(helper_plugin_extension_extension $extension) |
180
|
|
|
{ |
181
|
|
|
$class = ($extension->isTemplate()) ? 'template' : 'plugin'; |
182
|
|
|
if ($extension->isInstalled()) { |
183
|
|
|
$class.=' installed'; |
184
|
|
|
$class.= ($extension->isEnabled()) ? ' enabled':' disabled'; |
185
|
|
|
if ($extension->updateAvailable()) $class .= ' updatable'; |
186
|
|
|
} |
187
|
|
|
if (!$extension->canModify()) $class.= ' notselect'; |
188
|
|
|
if ($extension->isProtected()) $class.= ' protected'; |
189
|
|
|
//if($this->showinfo) $class.= ' showinfo'; |
190
|
|
|
return $class; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* Generate a link to the author of the extension |
195
|
|
|
* |
196
|
|
|
* @param helper_plugin_extension_extension $extension The extension object |
197
|
|
|
* @return string The HTML code of the link |
198
|
|
|
*/ |
199
|
|
|
public function makeAuthor(helper_plugin_extension_extension $extension) |
200
|
|
|
{ |
201
|
|
|
if ($extension->getAuthor()) { |
202
|
|
|
$mailid = $extension->getEmailID(); |
203
|
|
|
if ($mailid) { |
204
|
|
|
$url = $this->gui->tabURL('search', array('q' => 'authorid:'.$mailid)); |
205
|
|
|
$html = '<a href="'.$url.'" class="author" title="'.$this->getLang('author_hint').'" >'. |
206
|
|
|
'<img src="//www.gravatar.com/avatar/'.$mailid. |
207
|
|
|
'?s=20&d=mm" width="20" height="20" alt="" /> '. |
208
|
|
|
hsc($extension->getAuthor()).'</a>'; |
|
|
|
|
209
|
|
|
} else { |
210
|
|
|
$html = '<span class="author">'.hsc($extension->getAuthor()).'</span>'; |
|
|
|
|
211
|
|
|
} |
212
|
|
|
$html = '<bdi>'.$html.'</bdi>'; |
213
|
|
|
} else { |
214
|
|
|
$html = '<em class="author">'.$this->getLang('unknown_author').'</em>'.DOKU_LF; |
215
|
|
|
} |
216
|
|
|
return $html; |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* Get the link and image tag for the screenshot/thumbnail |
221
|
|
|
* |
222
|
|
|
* @param helper_plugin_extension_extension $extension The extension object |
223
|
|
|
* @return string The HTML code |
224
|
|
|
*/ |
225
|
|
|
public function makeScreenshot(helper_plugin_extension_extension $extension) |
226
|
|
|
{ |
227
|
|
|
$screen = $extension->getScreenshotURL(); |
228
|
|
|
$thumb = $extension->getThumbnailURL(); |
229
|
|
|
|
230
|
|
|
if ($screen) { |
231
|
|
|
// use protocol independent URLs for images coming from us #595 |
232
|
|
|
$screen = str_replace('http://www.dokuwiki.org', '//www.dokuwiki.org', $screen); |
233
|
|
|
$thumb = str_replace('http://www.dokuwiki.org', '//www.dokuwiki.org', $thumb); |
234
|
|
|
|
235
|
|
|
$title = sprintf($this->getLang('screenshot'), hsc($extension->getDisplayName())); |
236
|
|
|
$img = '<a href="'.hsc($screen).'" target="_blank" class="extension_screenshot">'. |
237
|
|
|
'<img alt="'.$title.'" width="120" height="70" src="'.hsc($thumb).'" />'. |
238
|
|
|
'</a>'; |
239
|
|
|
} elseif ($extension->isTemplate()) { |
240
|
|
|
$img = '<img alt="" width="120" height="70" src="'.DOKU_BASE. |
241
|
|
|
'lib/plugins/extension/images/template.png" />'; |
242
|
|
|
} else { |
243
|
|
|
$img = '<img alt="" width="120" height="70" src="'.DOKU_BASE. |
244
|
|
|
'lib/plugins/extension/images/plugin.png" />'; |
245
|
|
|
} |
246
|
|
|
$html = '<div class="screenshot" >'.$img.'<span></span></div>'.DOKU_LF; |
247
|
|
|
return $html; |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
/** |
251
|
|
|
* Extension main description |
252
|
|
|
* |
253
|
|
|
* @param helper_plugin_extension_extension $extension The extension object |
254
|
|
|
* @param bool $showinfo Show the info section |
255
|
|
|
* @return string The HTML code |
256
|
|
|
*/ |
257
|
|
|
public function makeLegend(helper_plugin_extension_extension $extension, $showinfo = false) |
258
|
|
|
{ |
259
|
|
|
$html = '<div>'; |
260
|
|
|
$html .= '<h2>'; |
261
|
|
|
$html .= sprintf( |
262
|
|
|
$this->getLang('extensionby'), |
263
|
|
|
'<bdi>'.hsc($extension->getDisplayName()).'</bdi>', |
264
|
|
|
$this->makeAuthor($extension) |
265
|
|
|
); |
266
|
|
|
$html .= '</h2>'.DOKU_LF; |
267
|
|
|
|
268
|
|
|
$html .= $this->makeScreenshot($extension); |
269
|
|
|
|
270
|
|
|
$popularity = $extension->getPopularity(); |
271
|
|
|
if ($popularity !== false && !$extension->isBundled()) { |
272
|
|
|
$popularityText = sprintf($this->getLang('popularity'), round($popularity*100, 2)); |
273
|
|
|
$html .= '<div class="popularity" title="'.$popularityText.'">'. |
274
|
|
|
'<div style="width: '.($popularity * 100).'%;">'. |
275
|
|
|
'<span class="a11y">'.$popularityText.'</span>'. |
276
|
|
|
'</div></div>'.DOKU_LF; |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
if ($extension->getDescription()) { |
280
|
|
|
$html .= '<p><bdi>'; |
281
|
|
|
$html .= hsc($extension->getDescription()).' '; |
282
|
|
|
$html .= '</bdi></p>'.DOKU_LF; |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
$html .= $this->makeLinkbar($extension); |
286
|
|
|
|
287
|
|
|
if ($showinfo) { |
288
|
|
|
$url = $this->gui->tabURL(''); |
289
|
|
|
$class = 'close'; |
290
|
|
|
} else { |
291
|
|
|
$url = $this->gui->tabURL('', array('info' => $extension->getID())); |
292
|
|
|
$class = ''; |
293
|
|
|
} |
294
|
|
|
$html .= ' <a href="'.$url.'#extensionplugin__'.$extension->getID(). |
295
|
|
|
'" class="info '.$class.'" title="'.$this->getLang('btn_info'). |
296
|
|
|
'" data-extid="'.$extension->getID().'">'.$this->getLang('btn_info').'</a>'; |
297
|
|
|
|
298
|
|
|
if ($showinfo) { |
299
|
|
|
$html .= $this->makeInfo($extension); |
300
|
|
|
} |
301
|
|
|
$html .= $this->makeNoticeArea($extension); |
302
|
|
|
$html .= '</div>'.DOKU_LF; |
303
|
|
|
return $html; |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
/** |
307
|
|
|
* Generate the link bar HTML code |
308
|
|
|
* |
309
|
|
|
* @param helper_plugin_extension_extension $extension The extension instance |
310
|
|
|
* @return string The HTML code |
311
|
|
|
*/ |
312
|
|
|
public function makeLinkbar(helper_plugin_extension_extension $extension) |
313
|
|
|
{ |
314
|
|
|
global $conf; |
315
|
|
|
$html = '<div class="linkbar">'; |
316
|
|
|
$html .= $this->makeHomepageLink($extension); |
317
|
|
|
|
318
|
|
|
$bugtrackerURL = $extension->getBugtrackerURL(); |
319
|
|
|
if ($bugtrackerURL) { |
320
|
|
|
if (strtolower(parse_url($bugtrackerURL, PHP_URL_HOST)) == 'www.dokuwiki.org') { |
321
|
|
|
$linktype = 'interwiki'; |
322
|
|
|
} else { |
323
|
|
|
$linktype = 'extern'; |
324
|
|
|
} |
325
|
|
|
$param = array( |
326
|
|
|
'href' => $bugtrackerURL, |
327
|
|
|
'title' => $bugtrackerURL, |
328
|
|
|
'class' => 'bugs', |
329
|
|
|
'target' => $conf['target'][$linktype], |
330
|
|
|
'rel' => ($linktype == 'extern') ? 'noopener' : '', |
331
|
|
|
); |
332
|
|
|
if ($conf['relnofollow']) { |
333
|
|
|
$param['rel'] = implode(' ', [$param['rel'], 'ugc nofollow']); |
334
|
|
|
} |
335
|
|
|
$html .= ' <a '.buildAttributes($param, true).'>'. |
336
|
|
|
$this->getLang('bugs_features').'</a>'; |
337
|
|
|
} |
338
|
|
|
if ($extension->getTags()) { |
339
|
|
|
$first = true; |
340
|
|
|
$html .= ' <span class="tags">'.$this->getLang('tags').' '; |
341
|
|
|
foreach ($extension->getTags() as $tag) { |
342
|
|
|
if (!$first) { |
343
|
|
|
$html .= ', '; |
344
|
|
|
} else { |
345
|
|
|
$first = false; |
346
|
|
|
} |
347
|
|
|
$url = $this->gui->tabURL('search', ['q' => 'tag:'.$tag]); |
348
|
|
|
$html .= '<bdi><a href="'.$url.'">'.hsc($tag).'</a></bdi>'; |
349
|
|
|
} |
350
|
|
|
$html .= '</span>'; |
351
|
|
|
} |
352
|
|
|
$html .= '</div>'.DOKU_LF; |
353
|
|
|
return $html; |
354
|
|
|
} |
355
|
|
|
|
356
|
|
|
/** |
357
|
|
|
* Notice area |
358
|
|
|
* |
359
|
|
|
* @param helper_plugin_extension_extension $extension The extension |
360
|
|
|
* @return string The HTML code |
361
|
|
|
*/ |
362
|
|
|
public function makeNoticeArea(helper_plugin_extension_extension $extension) |
363
|
|
|
{ |
364
|
|
|
$html = ''; |
365
|
|
|
$missing_dependencies = $extension->getMissingDependencies(); |
366
|
|
|
if (!empty($missing_dependencies)) { |
367
|
|
|
$html .= '<div class="msg error">' . |
368
|
|
|
sprintf( |
369
|
|
|
$this->getLang('missing_dependency'), |
370
|
|
|
'<bdi>' . implode(', ', $missing_dependencies) . '</bdi>' |
371
|
|
|
) . |
372
|
|
|
'</div>'; |
373
|
|
|
} |
374
|
|
|
if ($extension->isInWrongFolder()) { |
375
|
|
|
$html .= '<div class="msg error">' . |
376
|
|
|
sprintf( |
377
|
|
|
$this->getLang('wrong_folder'), |
378
|
|
|
'<bdi>' . hsc($extension->getInstallName()) . '</bdi>', |
379
|
|
|
'<bdi>' . hsc($extension->getBase()) . '</bdi>' |
380
|
|
|
) . |
381
|
|
|
'</div>'; |
382
|
|
|
} |
383
|
|
|
if (($securityissue = $extension->getSecurityIssue()) !== false) { |
384
|
|
|
$html .= '<div class="msg error">'. |
385
|
|
|
sprintf($this->getLang('security_issue'), '<bdi>'.hsc($securityissue).'</bdi>'). |
386
|
|
|
'</div>'; |
387
|
|
|
} |
388
|
|
|
if (($securitywarning = $extension->getSecurityWarning()) !== false) { |
389
|
|
|
$html .= '<div class="msg notify">'. |
390
|
|
|
sprintf($this->getLang('security_warning'), '<bdi>'.hsc($securitywarning).'</bdi>'). |
391
|
|
|
'</div>'; |
392
|
|
|
} |
393
|
|
|
if ($extension->updateAvailable()) { |
394
|
|
|
$html .= '<div class="msg notify">'. |
395
|
|
|
sprintf($this->getLang('update_available'), hsc($extension->getLastUpdate())). |
|
|
|
|
396
|
|
|
'</div>'; |
397
|
|
|
} |
398
|
|
|
if ($extension->hasDownloadURLChanged()) { |
399
|
|
|
$html .= '<div class="msg notify">' . |
400
|
|
|
sprintf( |
401
|
|
|
$this->getLang('url_change'), |
402
|
|
|
'<bdi>' . hsc($extension->getDownloadURL()) . '</bdi>', |
|
|
|
|
403
|
|
|
'<bdi>' . hsc($extension->getLastDownloadURL()) . '</bdi>' |
|
|
|
|
404
|
|
|
) . |
405
|
|
|
'</div>'; |
406
|
|
|
} |
407
|
|
|
return $html.DOKU_LF; |
408
|
|
|
} |
409
|
|
|
|
410
|
|
|
/** |
411
|
|
|
* Create a link from the given URL |
412
|
|
|
* |
413
|
|
|
* Shortens the URL for display |
414
|
|
|
* |
415
|
|
|
* @param string $url |
416
|
|
|
* @return string HTML link |
417
|
|
|
*/ |
418
|
|
|
public function shortlink($url) |
419
|
|
|
{ |
420
|
|
|
$link = parse_url($url); |
421
|
|
|
|
422
|
|
|
$base = $link['host']; |
423
|
|
|
if (!empty($link['port'])) $base .= $base.':'.$link['port']; |
424
|
|
|
$long = $link['path']; |
425
|
|
|
if (!empty($link['query'])) $long .= $link['query']; |
426
|
|
|
|
427
|
|
|
$name = shorten($base, $long, 55); |
428
|
|
|
|
429
|
|
|
$html = '<a href="'.hsc($url).'" class="urlextern">'.hsc($name).'</a>'; |
430
|
|
|
return $html; |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
/** |
434
|
|
|
* Plugin/template details |
435
|
|
|
* |
436
|
|
|
* @param helper_plugin_extension_extension $extension The extension |
437
|
|
|
* @return string The HTML code |
438
|
|
|
*/ |
439
|
|
|
public function makeInfo(helper_plugin_extension_extension $extension) |
440
|
|
|
{ |
441
|
|
|
$default = $this->getLang('unknown'); |
442
|
|
|
$html = '<dl class="details">'; |
443
|
|
|
|
444
|
|
|
$html .= '<dt>'.$this->getLang('status').'</dt>'; |
445
|
|
|
$html .= '<dd>'.$this->makeStatus($extension).'</dd>'; |
446
|
|
|
|
447
|
|
|
if ($extension->getDonationURL()) { |
448
|
|
|
$html .= '<dt>'.$this->getLang('donate').'</dt>'; |
449
|
|
|
$html .= '<dd>'; |
450
|
|
|
$html .= '<a href="'.$extension->getDonationURL().'" class="donate">'. |
451
|
|
|
$this->getLang('donate_action').'</a>'; |
452
|
|
|
$html .= '</dd>'; |
453
|
|
|
} |
454
|
|
|
|
455
|
|
|
if (!$extension->isBundled()) { |
456
|
|
|
$html .= '<dt>'.$this->getLang('downloadurl').'</dt>'; |
457
|
|
|
$html .= '<dd><bdi>'; |
458
|
|
|
$html .= ($extension->getDownloadURL() |
459
|
|
|
? $this->shortlink($extension->getDownloadURL()) |
460
|
|
|
: $default); |
461
|
|
|
$html .= '</bdi></dd>'; |
462
|
|
|
|
463
|
|
|
$html .= '<dt>'.$this->getLang('repository').'</dt>'; |
464
|
|
|
$html .= '<dd><bdi>'; |
465
|
|
|
$html .= ($extension->getSourcerepoURL() |
466
|
|
|
? $this->shortlink($extension->getSourcerepoURL()) |
467
|
|
|
: $default); |
468
|
|
|
$html .= '</bdi></dd>'; |
469
|
|
|
} |
470
|
|
|
|
471
|
|
|
if ($extension->isInstalled()) { |
472
|
|
|
if ($extension->getInstalledVersion()) { |
473
|
|
|
$html .= '<dt>'.$this->getLang('installed_version').'</dt>'; |
474
|
|
|
$html .= '<dd>'; |
475
|
|
|
$html .= hsc($extension->getInstalledVersion()); |
|
|
|
|
476
|
|
|
$html .= '</dd>'; |
477
|
|
|
} |
478
|
|
|
if (!$extension->isBundled()) { |
479
|
|
|
$html .= '<dt>'.$this->getLang('install_date').'</dt>'; |
480
|
|
|
$html .= '<dd>'; |
481
|
|
|
$html .= ($extension->getUpdateDate() |
482
|
|
|
? hsc($extension->getUpdateDate()) |
|
|
|
|
483
|
|
|
: $this->getLang('unknown')); |
484
|
|
|
$html .= '</dd>'; |
485
|
|
|
} |
486
|
|
|
} |
487
|
|
|
if (!$extension->isInstalled() || $extension->updateAvailable()) { |
488
|
|
|
$html .= '<dt>'.$this->getLang('available_version').'</dt>'; |
489
|
|
|
$html .= '<dd>'; |
490
|
|
|
$html .= ($extension->getLastUpdate() |
491
|
|
|
? hsc($extension->getLastUpdate()) |
|
|
|
|
492
|
|
|
: $this->getLang('unknown')); |
493
|
|
|
$html .= '</dd>'; |
494
|
|
|
} |
495
|
|
|
|
496
|
|
|
$html .= '<dt>'.$this->getLang('provides').'</dt>'; |
497
|
|
|
$html .= '<dd><bdi>'; |
498
|
|
|
$html .= ($extension->getTypes() |
499
|
|
|
? hsc(implode(', ', $extension->getTypes())) |
500
|
|
|
: $default); |
501
|
|
|
$html .= '</bdi></dd>'; |
502
|
|
|
|
503
|
|
|
if (!$extension->isBundled() && $extension->getCompatibleVersions()) { |
504
|
|
|
$html .= '<dt>'.$this->getLang('compatible').'</dt>'; |
505
|
|
|
$html .= '<dd>'; |
506
|
|
|
foreach ($extension->getCompatibleVersions() as $date => $version) { |
507
|
|
|
$html .= '<bdi>'.$version['label'].' ('.$date.')</bdi>, '; |
508
|
|
|
} |
509
|
|
|
$html = rtrim($html, ', '); |
510
|
|
|
$html .= '</dd>'; |
511
|
|
|
} |
512
|
|
|
if ($extension->getDependencies()) { |
513
|
|
|
$html .= '<dt>'.$this->getLang('depends').'</dt>'; |
514
|
|
|
$html .= '<dd>'; |
515
|
|
|
$html .= $this->makeLinkList($extension->getDependencies()); |
516
|
|
|
$html .= '</dd>'; |
517
|
|
|
} |
518
|
|
|
|
519
|
|
|
if ($extension->getSimilarExtensions()) { |
520
|
|
|
$html .= '<dt>'.$this->getLang('similar').'</dt>'; |
521
|
|
|
$html .= '<dd>'; |
522
|
|
|
$html .= $this->makeLinkList($extension->getSimilarExtensions()); |
523
|
|
|
$html .= '</dd>'; |
524
|
|
|
} |
525
|
|
|
|
526
|
|
|
if ($extension->getConflicts()) { |
527
|
|
|
$html .= '<dt>'.$this->getLang('conflicts').'</dt>'; |
528
|
|
|
$html .= '<dd>'; |
529
|
|
|
$html .= $this->makeLinkList($extension->getConflicts()); |
530
|
|
|
$html .= '</dd>'; |
531
|
|
|
} |
532
|
|
|
$html .= '</dl>'.DOKU_LF; |
533
|
|
|
return $html; |
534
|
|
|
} |
535
|
|
|
|
536
|
|
|
/** |
537
|
|
|
* Generate a list of links for extensions |
538
|
|
|
* |
539
|
|
|
* @param array $ext The extensions |
540
|
|
|
* @return string The HTML code |
541
|
|
|
*/ |
542
|
|
|
public function makeLinkList($ext) |
543
|
|
|
{ |
544
|
|
|
$html = ''; |
545
|
|
|
foreach ($ext as $link) { |
546
|
|
|
$html .= '<bdi><a href="'. |
547
|
|
|
$this->gui->tabURL('search', array('q'=>'ext:'.$link)).'">'. |
548
|
|
|
hsc($link).'</a></bdi>, '; |
549
|
|
|
} |
550
|
|
|
return rtrim($html, ', '); |
551
|
|
|
} |
552
|
|
|
|
553
|
|
|
/** |
554
|
|
|
* Display the action buttons if they are possible |
555
|
|
|
* |
556
|
|
|
* @param helper_plugin_extension_extension $extension The extension |
557
|
|
|
* @return string The HTML code |
558
|
|
|
*/ |
559
|
|
|
public function makeActions(helper_plugin_extension_extension $extension) |
560
|
|
|
{ |
561
|
|
|
global $conf; |
562
|
|
|
$html = ''; |
563
|
|
|
$errors = ''; |
564
|
|
|
|
565
|
|
|
if ($extension->isInstalled()) { |
566
|
|
|
if (($canmod = $extension->canModify()) === true) { |
567
|
|
|
if (!$extension->isProtected()) { |
568
|
|
|
$html .= $this->makeAction('uninstall', $extension); |
569
|
|
|
} |
570
|
|
|
if ($extension->getDownloadURL()) { |
571
|
|
|
if ($extension->updateAvailable()) { |
572
|
|
|
$html .= $this->makeAction('update', $extension); |
573
|
|
|
} else { |
574
|
|
|
$html .= $this->makeAction('reinstall', $extension); |
575
|
|
|
} |
576
|
|
|
} |
577
|
|
|
} else { |
578
|
|
|
$errors .= '<p class="permerror">'.$this->getLang($canmod).'</p>'; |
579
|
|
|
} |
580
|
|
|
|
581
|
|
|
if (!$extension->isProtected() && !$extension->isTemplate()) { // no enable/disable for templates |
582
|
|
|
if ($extension->isEnabled()) { |
583
|
|
|
$html .= $this->makeAction('disable', $extension); |
584
|
|
|
} else { |
585
|
|
|
$html .= $this->makeAction('enable', $extension); |
586
|
|
|
} |
587
|
|
|
} |
588
|
|
|
|
589
|
|
|
if ($extension->isGitControlled()) { |
590
|
|
|
$errors .= '<p class="permerror">'.$this->getLang('git').'</p>'; |
591
|
|
|
} |
592
|
|
|
|
593
|
|
|
if ($extension->isEnabled() && |
594
|
|
|
in_array('Auth', $extension->getTypes()) && |
595
|
|
|
$conf['authtype'] != $extension->getID() |
596
|
|
|
) { |
597
|
|
|
$errors .= '<p class="permerror">'.$this->getLang('auth').'</p>'; |
598
|
|
|
} |
599
|
|
|
} else { |
600
|
|
|
if (($canmod = $extension->canModify()) === true) { |
601
|
|
|
if ($extension->getDownloadURL()) { |
602
|
|
|
$html .= $this->makeAction('install', $extension); |
603
|
|
|
} |
604
|
|
|
} else { |
605
|
|
|
$errors .= '<div class="permerror">'.$this->getLang($canmod).'</div>'; |
606
|
|
|
} |
607
|
|
|
} |
608
|
|
|
|
609
|
|
|
if (!$extension->isInstalled() && $extension->getDownloadURL()) { |
610
|
|
|
$html .= ' <span class="version">'.$this->getLang('available_version').' '; |
611
|
|
|
$html .= ($extension->getLastUpdate() |
612
|
|
|
? hsc($extension->getLastUpdate()) |
|
|
|
|
613
|
|
|
: $this->getLang('unknown')).'</span>'; |
614
|
|
|
} |
615
|
|
|
|
616
|
|
|
return $html.' '.$errors.DOKU_LF; |
617
|
|
|
} |
618
|
|
|
|
619
|
|
|
/** |
620
|
|
|
* Display an action button for an extension |
621
|
|
|
* |
622
|
|
|
* @param string $action The action |
623
|
|
|
* @param helper_plugin_extension_extension $extension The extension |
624
|
|
|
* @return string The HTML code |
625
|
|
|
*/ |
626
|
|
|
public function makeAction($action, $extension) |
627
|
|
|
{ |
628
|
|
|
$title = ''; |
629
|
|
|
|
630
|
|
|
switch ($action) { |
631
|
|
|
case 'install': |
632
|
|
|
case 'reinstall': |
633
|
|
|
$title = 'title="'.hsc($extension->getDownloadURL()).'"'; |
|
|
|
|
634
|
|
|
break; |
635
|
|
|
} |
636
|
|
|
|
637
|
|
|
$classes = 'button '.$action; |
638
|
|
|
$name = 'fn['.$action.']['.hsc($extension->getID()).']'; |
639
|
|
|
|
640
|
|
|
$html = '<button class="'.$classes.'" name="'.$name.'" type="submit" '.$title.'>'. |
641
|
|
|
$this->getLang('btn_'.$action).'</button> '; |
642
|
|
|
return $html; |
643
|
|
|
} |
644
|
|
|
|
645
|
|
|
/** |
646
|
|
|
* Plugin/template status |
647
|
|
|
* |
648
|
|
|
* @param helper_plugin_extension_extension $extension The extension |
649
|
|
|
* @return string The description of all relevant statusses |
650
|
|
|
*/ |
651
|
|
|
public function makeStatus(helper_plugin_extension_extension $extension) |
652
|
|
|
{ |
653
|
|
|
$status = array(); |
654
|
|
|
|
655
|
|
|
if ($extension->isInstalled()) { |
656
|
|
|
$status[] = $this->getLang('status_installed'); |
657
|
|
|
if ($extension->isProtected()) { |
658
|
|
|
$status[] = $this->getLang('status_protected'); |
659
|
|
|
} else { |
660
|
|
|
$status[] = $extension->isEnabled() |
661
|
|
|
? $this->getLang('status_enabled') |
662
|
|
|
: $this->getLang('status_disabled'); |
663
|
|
|
} |
664
|
|
|
} else { |
665
|
|
|
$status[] = $this->getLang('status_not_installed'); |
666
|
|
|
} |
667
|
|
|
if (!$extension->canModify()) $status[] = $this->getLang('status_unmodifiable'); |
668
|
|
|
if ($extension->isBundled()) $status[] = $this->getLang('status_bundled'); |
669
|
|
|
$status[] = $extension->isTemplate() |
670
|
|
|
? $this->getLang('status_template') |
671
|
|
|
: $this->getLang('status_plugin'); |
672
|
|
|
return implode(', ', $status); |
673
|
|
|
} |
674
|
|
|
} |
675
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.