diff options
author | ArthurHoaro <arthur@hoa.ro> | 2020-10-13 12:05:08 +0200 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2020-10-13 12:05:08 +0200 |
commit | b6f678a5a1d15acf284ebcec16c905e976671ce1 (patch) | |
tree | 33c7da831482ed79c44896ef19c73c72ada84f2e /plugins | |
parent | b14687036b9b800681197f51fdc47e62f0c88e2e (diff) | |
parent | 1c1520b6b98ab20201bfe15577782a52320339df (diff) | |
download | Shaarli-b6f678a5a1d15acf284ebcec16c905e976671ce1.tar.gz Shaarli-b6f678a5a1d15acf284ebcec16c905e976671ce1.tar.zst Shaarli-b6f678a5a1d15acf284ebcec16c905e976671ce1.zip |
Merge branch 'v0.12' into latest
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/addlink_toolbar/addlink_toolbar.php | 6 | ||||
-rw-r--r-- | plugins/archiveorg/archiveorg.html | 2 | ||||
-rw-r--r-- | plugins/archiveorg/archiveorg.php | 7 | ||||
-rw-r--r-- | plugins/default_colors/default_colors.php | 56 | ||||
-rw-r--r-- | plugins/demo_plugin/demo_plugin.php | 33 | ||||
-rw-r--r-- | plugins/isso/isso.php | 6 | ||||
-rw-r--r-- | plugins/isso/isso_button.html | 5 | ||||
-rw-r--r-- | plugins/markdown/README.md | 102 | ||||
-rw-r--r-- | plugins/markdown/help.html | 5 | ||||
-rw-r--r-- | plugins/markdown/markdown.css | 173 | ||||
-rw-r--r-- | plugins/markdown/markdown.meta | 4 | ||||
-rw-r--r-- | plugins/markdown/markdown.php | 365 | ||||
-rw-r--r-- | plugins/playvideos/README.md | 9 | ||||
-rw-r--r-- | plugins/playvideos/playvideos.php | 6 | ||||
-rw-r--r-- | plugins/pubsubhubbub/pubsubhubbub.php | 8 | ||||
-rw-r--r-- | plugins/qrcode/qrcode.php | 9 | ||||
-rw-r--r-- | plugins/qrcode/shaarli-qrcode.js | 15 | ||||
-rw-r--r-- | plugins/wallabag/README.md | 2 | ||||
-rw-r--r-- | plugins/wallabag/wallabag.php | 4 |
19 files changed, 85 insertions, 732 deletions
diff --git a/plugins/addlink_toolbar/addlink_toolbar.php b/plugins/addlink_toolbar/addlink_toolbar.php index 8bf4ed46..ab6ed6de 100644 --- a/plugins/addlink_toolbar/addlink_toolbar.php +++ b/plugins/addlink_toolbar/addlink_toolbar.php | |||
@@ -5,7 +5,7 @@ | |||
5 | * Adds the addlink input on the linklist page. | 5 | * Adds the addlink input on the linklist page. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | use Shaarli\Router; | 8 | use Shaarli\Render\TemplatePage; |
9 | 9 | ||
10 | /** | 10 | /** |
11 | * When linklist is displayed, add play videos to header's toolbar. | 11 | * When linklist is displayed, add play videos to header's toolbar. |
@@ -16,11 +16,11 @@ use Shaarli\Router; | |||
16 | */ | 16 | */ |
17 | function hook_addlink_toolbar_render_header($data) | 17 | function hook_addlink_toolbar_render_header($data) |
18 | { | 18 | { |
19 | if ($data['_PAGE_'] == Router::$PAGE_LINKLIST && $data['_LOGGEDIN_'] === true) { | 19 | if ($data['_PAGE_'] == TemplatePage::LINKLIST && $data['_LOGGEDIN_'] === true) { |
20 | $form = array( | 20 | $form = array( |
21 | 'attr' => array( | 21 | 'attr' => array( |
22 | 'method' => 'GET', | 22 | 'method' => 'GET', |
23 | 'action' => '', | 23 | 'action' => $data['_BASE_PATH_'] . '/admin/shaare', |
24 | 'name' => 'addform', | 24 | 'name' => 'addform', |
25 | 'class' => 'addform', | 25 | 'class' => 'addform', |
26 | ), | 26 | ), |
diff --git a/plugins/archiveorg/archiveorg.html b/plugins/archiveorg/archiveorg.html index ad501f47..e37d887e 100644 --- a/plugins/archiveorg/archiveorg.html +++ b/plugins/archiveorg/archiveorg.html | |||
@@ -1,5 +1,5 @@ | |||
1 | <span> | 1 | <span> |
2 | <a href="https://web.archive.org/web/%s"> | 2 | <a href="https://web.archive.org/web/%s"> |
3 | <img class="linklist-plugin-icon" src="plugins/archiveorg/internetarchive.png" title="%s" alt="archive.org" /> | 3 | <img class="linklist-plugin-icon" src="%s/archiveorg/internetarchive.png" title="%s" alt="archive.org" /> |
4 | </a> | 4 | </a> |
5 | </span> | 5 | </span> |
diff --git a/plugins/archiveorg/archiveorg.php b/plugins/archiveorg/archiveorg.php index 0ee1c73c..922b5966 100644 --- a/plugins/archiveorg/archiveorg.php +++ b/plugins/archiveorg/archiveorg.php | |||
@@ -17,12 +17,15 @@ use Shaarli\Plugin\PluginManager; | |||
17 | function hook_archiveorg_render_linklist($data) | 17 | function hook_archiveorg_render_linklist($data) |
18 | { | 18 | { |
19 | $archive_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/archiveorg/archiveorg.html'); | 19 | $archive_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/archiveorg/archiveorg.html'); |
20 | $path = ($data['_BASE_PATH_'] ?? '') . '/' . PluginManager::$PLUGINS_PATH; | ||
20 | 21 | ||
21 | foreach ($data['links'] as &$value) { | 22 | foreach ($data['links'] as &$value) { |
22 | if ($value['private'] && preg_match('/^\?[a-zA-Z0-9-_@]{6}($|&|#)/', $value['real_url'])) { | 23 | $isNote = startsWith($value['real_url'], '/shaare/'); |
24 | if ($value['private'] && $isNote) { | ||
23 | continue; | 25 | continue; |
24 | } | 26 | } |
25 | $archive = sprintf($archive_html, $value['url'], t('View on archive.org')); | 27 | $url = $isNote ? rtrim(index_url($_SERVER), '/') . $value['real_url'] : $value['real_url']; |
28 | $archive = sprintf($archive_html, $url, $path, t('View on archive.org')); | ||
26 | $value['link_plugin'][] = $archive; | 29 | $value['link_plugin'][] = $archive; |
27 | } | 30 | } |
28 | 31 | ||
diff --git a/plugins/default_colors/default_colors.php b/plugins/default_colors/default_colors.php index 1928cc9f..e1fd5cfb 100644 --- a/plugins/default_colors/default_colors.php +++ b/plugins/default_colors/default_colors.php | |||
@@ -15,6 +15,8 @@ const DEFAULT_COLORS_PLACEHOLDERS = [ | |||
15 | 'DEFAULT_COLORS_DARK_MAIN', | 15 | 'DEFAULT_COLORS_DARK_MAIN', |
16 | ]; | 16 | ]; |
17 | 17 | ||
18 | const DEFAULT_COLORS_CSS_FILE = '/default_colors/default_colors.css'; | ||
19 | |||
18 | /** | 20 | /** |
19 | * Display an error if the plugin is active a no color is configured. | 21 | * Display an error if the plugin is active a no color is configured. |
20 | * | 22 | * |
@@ -24,58 +26,62 @@ const DEFAULT_COLORS_PLACEHOLDERS = [ | |||
24 | */ | 26 | */ |
25 | function default_colors_init($conf) | 27 | function default_colors_init($conf) |
26 | { | 28 | { |
27 | $params = ''; | 29 | $params = []; |
28 | foreach (DEFAULT_COLORS_PLACEHOLDERS as $placeholder) { | 30 | foreach (DEFAULT_COLORS_PLACEHOLDERS as $placeholder) { |
29 | $params .= trim($conf->get('plugins.'. $placeholder, '')); | 31 | $value = trim($conf->get('plugins.'. $placeholder, '')); |
32 | if (strlen($value) > 0) { | ||
33 | $params[$placeholder] = $value; | ||
34 | } | ||
30 | } | 35 | } |
31 | 36 | ||
32 | if (empty($params)) { | 37 | if (empty($params)) { |
33 | $error = t('Default colors plugin error: '. | 38 | $error = t('Default colors plugin error: '. |
34 | 'This plugin is active and no custom color is configured.'); | 39 | 'This plugin is active and no custom color is configured.'); |
35 | return array($error); | 40 | return [$error]; |
41 | } | ||
42 | |||
43 | // Colors are defined but the custom CSS file does not exist -> generate it | ||
44 | if (!file_exists(PluginManager::$PLUGINS_PATH . DEFAULT_COLORS_CSS_FILE)) { | ||
45 | default_colors_generate_css_file($params); | ||
36 | } | 46 | } |
37 | } | 47 | } |
38 | 48 | ||
39 | /** | 49 | /** |
40 | * When plugin parameters are saved, we regenerate the custom CSS file with provided settings. | 50 | * When linklist is displayed, include default_colors CSS file. |
41 | * | 51 | * |
42 | * @param array $data $_POST array | 52 | * @param array $data - header data. |
43 | * | 53 | * |
44 | * @return array Updated $_POST array | 54 | * @return mixed - header data with default_colors CSS file added. |
45 | */ | 55 | */ |
46 | function hook_default_colors_save_plugin_parameters($data) | 56 | function hook_default_colors_render_includes($data) |
47 | { | 57 | { |
48 | $file = PluginManager::$PLUGINS_PATH . '/default_colors/default_colors.css'; | 58 | $file = PluginManager::$PLUGINS_PATH . '/default_colors/default_colors.css'; |
49 | $template = file_get_contents(PluginManager::$PLUGINS_PATH . '/default_colors/default_colors.css.template'); | 59 | if (file_exists($file )) { |
50 | $content = ''; | 60 | $data['css_files'][] = $file ; |
51 | foreach (DEFAULT_COLORS_PLACEHOLDERS as $rule) { | ||
52 | $content .= ! empty($data[$rule]) | ||
53 | ? default_colors_format_css_rule($data, $rule) .';'. PHP_EOL | ||
54 | : ''; | ||
55 | } | ||
56 | |||
57 | if (! empty($content)) { | ||
58 | file_put_contents($file, sprintf($template, $content)); | ||
59 | } | 61 | } |
60 | 62 | ||
61 | return $data; | 63 | return $data; |
62 | } | 64 | } |
63 | 65 | ||
64 | /** | 66 | /** |
65 | * When linklist is displayed, include default_colors CSS file. | 67 | * Regenerate the custom CSS file with provided settings. |
66 | * | ||
67 | * @param array $data - header data. | ||
68 | * | 68 | * |
69 | * @return mixed - header data with default_colors CSS file added. | 69 | * @param array $params Plugin configuration (CSS rules) |
70 | */ | 70 | */ |
71 | function hook_default_colors_render_includes($data) | 71 | function default_colors_generate_css_file($params): void |
72 | { | 72 | { |
73 | $file = PluginManager::$PLUGINS_PATH . '/default_colors/default_colors.css'; | 73 | $file = PluginManager::$PLUGINS_PATH . '/default_colors/default_colors.css'; |
74 | if (file_exists($file )) { | 74 | $template = file_get_contents(PluginManager::$PLUGINS_PATH . '/default_colors/default_colors.css.template'); |
75 | $data['css_files'][] = $file ; | 75 | $content = ''; |
76 | foreach (DEFAULT_COLORS_PLACEHOLDERS as $rule) { | ||
77 | $content .= !empty($params[$rule]) | ||
78 | ? default_colors_format_css_rule($params, $rule) .';'. PHP_EOL | ||
79 | : ''; | ||
76 | } | 80 | } |
77 | 81 | ||
78 | return $data; | 82 | if (! empty($content)) { |
83 | file_put_contents($file, sprintf($template, $content)); | ||
84 | } | ||
79 | } | 85 | } |
80 | 86 | ||
81 | /** | 87 | /** |
diff --git a/plugins/demo_plugin/demo_plugin.php b/plugins/demo_plugin/demo_plugin.php index 71ba7495..defb01f7 100644 --- a/plugins/demo_plugin/demo_plugin.php +++ b/plugins/demo_plugin/demo_plugin.php | |||
@@ -2,8 +2,8 @@ | |||
2 | /** | 2 | /** |
3 | * Demo Plugin. | 3 | * Demo Plugin. |
4 | * | 4 | * |
5 | * This plugin try to cover Shaarli's plugin API entirely. | 5 | * This plugin tries to completely cover Shaarli's plugin API. |
6 | * Can be used by plugin developper to make their own. | 6 | * Can be used by plugin developers to make their own plugin. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* |
@@ -16,7 +16,7 @@ | |||
16 | 16 | ||
17 | use Shaarli\Config\ConfigManager; | 17 | use Shaarli\Config\ConfigManager; |
18 | use Shaarli\Plugin\PluginManager; | 18 | use Shaarli\Plugin\PluginManager; |
19 | use Shaarli\Router; | 19 | use Shaarli\Render\TemplatePage; |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * In the footer hook, there is a working example of a translation extension for Shaarli. | 22 | * In the footer hook, there is a working example of a translation extension for Shaarli. |
@@ -61,7 +61,7 @@ function demo_plugin_init($conf) | |||
61 | 61 | ||
62 | /** | 62 | /** |
63 | * Hook render_header. | 63 | * Hook render_header. |
64 | * Executed on every page redering. | 64 | * Executed on every page render. |
65 | * | 65 | * |
66 | * Template placeholders: | 66 | * Template placeholders: |
67 | * - buttons_toolbar | 67 | * - buttons_toolbar |
@@ -74,7 +74,7 @@ function demo_plugin_init($conf) | |||
74 | function hook_demo_plugin_render_header($data) | 74 | function hook_demo_plugin_render_header($data) |
75 | { | 75 | { |
76 | // Only execute when linklist is rendered. | 76 | // Only execute when linklist is rendered. |
77 | if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) { | 77 | if ($data['_PAGE_'] == TemplatePage::LINKLIST) { |
78 | // If loggedin | 78 | // If loggedin |
79 | if ($data['_LOGGEDIN_'] === true) { | 79 | if ($data['_LOGGEDIN_'] === true) { |
80 | /* | 80 | /* |
@@ -118,7 +118,7 @@ function hook_demo_plugin_render_header($data) | |||
118 | $form = array( | 118 | $form = array( |
119 | 'attr' => array( | 119 | 'attr' => array( |
120 | 'method' => 'GET', | 120 | 'method' => 'GET', |
121 | 'action' => '?', | 121 | 'action' => $data['_BASE_PATH_'] . '/', |
122 | 'class' => 'addform', | 122 | 'class' => 'addform', |
123 | ), | 123 | ), |
124 | 'inputs' => array( | 124 | 'inputs' => array( |
@@ -145,7 +145,7 @@ function hook_demo_plugin_render_header($data) | |||
145 | 145 | ||
146 | /** | 146 | /** |
147 | * Hook render_includes. | 147 | * Hook render_includes. |
148 | * Executed on every page redering. | 148 | * Executed on every page render. |
149 | * | 149 | * |
150 | * Template placeholders: | 150 | * Template placeholders: |
151 | * - css_files | 151 | * - css_files |
@@ -169,7 +169,7 @@ function hook_demo_plugin_render_includes($data) | |||
169 | 169 | ||
170 | /** | 170 | /** |
171 | * Hook render_footer. | 171 | * Hook render_footer. |
172 | * Executed on every page redering. | 172 | * Executed on every page render. |
173 | * | 173 | * |
174 | * Template placeholders: | 174 | * Template placeholders: |
175 | * - text | 175 | * - text |
@@ -186,7 +186,7 @@ function hook_demo_plugin_render_includes($data) | |||
186 | */ | 186 | */ |
187 | function hook_demo_plugin_render_footer($data) | 187 | function hook_demo_plugin_render_footer($data) |
188 | { | 188 | { |
189 | // footer text | 189 | // Footer text |
190 | $data['text'][] = '<br>'. demo_plugin_t('Shaarli is now enhanced by the awesome demo_plugin.'); | 190 | $data['text'][] = '<br>'. demo_plugin_t('Shaarli is now enhanced by the awesome demo_plugin.'); |
191 | 191 | ||
192 | // Free elements at the end of the page. | 192 | // Free elements at the end of the page. |
@@ -277,7 +277,7 @@ function hook_demo_plugin_render_editlink($data) | |||
277 | // Load HTML into a string | 277 | // Load HTML into a string |
278 | $html = file_get_contents(PluginManager::$PLUGINS_PATH .'/demo_plugin/field.html'); | 278 | $html = file_get_contents(PluginManager::$PLUGINS_PATH .'/demo_plugin/field.html'); |
279 | 279 | ||
280 | // replace value in HTML if it exists in $data | 280 | // Replace value in HTML if it exists in $data |
281 | if (!empty($data['link']['stuff'])) { | 281 | if (!empty($data['link']['stuff'])) { |
282 | $html = sprintf($html, $data['link']['stuff']); | 282 | $html = sprintf($html, $data['link']['stuff']); |
283 | } else { | 283 | } else { |
@@ -324,9 +324,7 @@ function hook_demo_plugin_render_tools($data) | |||
324 | */ | 324 | */ |
325 | function hook_demo_plugin_render_picwall($data) | 325 | function hook_demo_plugin_render_picwall($data) |
326 | { | 326 | { |
327 | // plugin_start_zone | ||
328 | $data['plugin_start_zone'][] = '<center>BEFORE</center>'; | 327 | $data['plugin_start_zone'][] = '<center>BEFORE</center>'; |
329 | // plugin_end_zone | ||
330 | $data['plugin_end_zone'][] = '<center>AFTER</center>'; | 328 | $data['plugin_end_zone'][] = '<center>AFTER</center>'; |
331 | 329 | ||
332 | return $data; | 330 | return $data; |
@@ -348,9 +346,7 @@ function hook_demo_plugin_render_picwall($data) | |||
348 | */ | 346 | */ |
349 | function hook_demo_plugin_render_tagcloud($data) | 347 | function hook_demo_plugin_render_tagcloud($data) |
350 | { | 348 | { |
351 | // plugin_start_zone | ||
352 | $data['plugin_start_zone'][] = '<center>BEFORE</center>'; | 349 | $data['plugin_start_zone'][] = '<center>BEFORE</center>'; |
353 | // plugin_end_zone | ||
354 | $data['plugin_end_zone'][] = '<center>AFTER</center>'; | 350 | $data['plugin_end_zone'][] = '<center>AFTER</center>'; |
355 | 351 | ||
356 | return $data; | 352 | return $data; |
@@ -372,9 +368,7 @@ function hook_demo_plugin_render_tagcloud($data) | |||
372 | */ | 368 | */ |
373 | function hook_demo_plugin_render_daily($data) | 369 | function hook_demo_plugin_render_daily($data) |
374 | { | 370 | { |
375 | // plugin_start_zone | ||
376 | $data['plugin_start_zone'][] = '<center>BEFORE</center>'; | 371 | $data['plugin_start_zone'][] = '<center>BEFORE</center>'; |
377 | // plugin_end_zone | ||
378 | $data['plugin_end_zone'][] = '<center>AFTER</center>'; | 372 | $data['plugin_end_zone'][] = '<center>AFTER</center>'; |
379 | 373 | ||
380 | 374 | ||
@@ -447,9 +441,9 @@ function hook_demo_plugin_delete_link($data) | |||
447 | function hook_demo_plugin_render_feed($data) | 441 | function hook_demo_plugin_render_feed($data) |
448 | { | 442 | { |
449 | foreach ($data['links'] as &$link) { | 443 | foreach ($data['links'] as &$link) { |
450 | if ($data['_PAGE_'] == Router::$PAGE_FEED_ATOM) { | 444 | if ($data['_PAGE_'] == TemplatePage::FEED_ATOM) { |
451 | $link['description'] .= ' - ATOM Feed' ; | 445 | $link['description'] .= ' - ATOM Feed' ; |
452 | } elseif ($data['_PAGE_'] == Router::$PAGE_FEED_RSS) { | 446 | } elseif ($data['_PAGE_'] == TemplatePage::FEED_RSS) { |
453 | $link['description'] .= ' - RSS Feed'; | 447 | $link['description'] .= ' - RSS Feed'; |
454 | } | 448 | } |
455 | } | 449 | } |
@@ -465,7 +459,8 @@ function hook_demo_plugin_render_feed($data) | |||
465 | */ | 459 | */ |
466 | function hook_demo_plugin_save_plugin_parameters($data) | 460 | function hook_demo_plugin_save_plugin_parameters($data) |
467 | { | 461 | { |
468 | // Here we edit the provided value, but we can use this to generate config files, etc. | 462 | // Here we edit the provided value. |
463 | // This hook can also be used to generate config files, etc. | ||
469 | if (! empty($data['DEMO_PLUGIN_PARAMETER']) && ! endsWith($data['DEMO_PLUGIN_PARAMETER'], '_SUFFIX')) { | 464 | if (! empty($data['DEMO_PLUGIN_PARAMETER']) && ! endsWith($data['DEMO_PLUGIN_PARAMETER'], '_SUFFIX')) { |
470 | $data['DEMO_PLUGIN_PARAMETER'] .= '_SUFFIX'; | 465 | $data['DEMO_PLUGIN_PARAMETER'] .= '_SUFFIX'; |
471 | } | 466 | } |
diff --git a/plugins/isso/isso.php b/plugins/isso/isso.php index dab75dd5..79e7380b 100644 --- a/plugins/isso/isso.php +++ b/plugins/isso/isso.php | |||
@@ -6,7 +6,7 @@ | |||
6 | 6 | ||
7 | use Shaarli\Config\ConfigManager; | 7 | use Shaarli\Config\ConfigManager; |
8 | use Shaarli\Plugin\PluginManager; | 8 | use Shaarli\Plugin\PluginManager; |
9 | use Shaarli\Router; | 9 | use Shaarli\Render\TemplatePage; |
10 | 10 | ||
11 | /** | 11 | /** |
12 | * Display an error everywhere if the plugin is enabled without configuration. | 12 | * Display an error everywhere if the plugin is enabled without configuration. |
@@ -49,7 +49,7 @@ function hook_isso_render_linklist($data, $conf) | |||
49 | $isso = sprintf($issoHtml, $issoUrl, $issoUrl, $link['id'], $link['id']); | 49 | $isso = sprintf($issoHtml, $issoUrl, $issoUrl, $link['id'], $link['id']); |
50 | $data['plugin_end_zone'][] = $isso; | 50 | $data['plugin_end_zone'][] = $isso; |
51 | } else { | 51 | } else { |
52 | $button = '<span><a href="?%s#isso-thread">'; | 52 | $button = '<span><a href="'. ($data['_BASE_PATH_'] ?? '') . '/shaare/%s#isso-thread">'; |
53 | // For the default theme we use a FontAwesome icon which is better than an image | 53 | // For the default theme we use a FontAwesome icon which is better than an image |
54 | if ($conf->get('resource.theme') === 'default') { | 54 | if ($conf->get('resource.theme') === 'default') { |
55 | $button .= '<i class="linklist-plugin-icon fa fa-comment"></i>'; | 55 | $button .= '<i class="linklist-plugin-icon fa fa-comment"></i>'; |
@@ -76,7 +76,7 @@ function hook_isso_render_linklist($data, $conf) | |||
76 | */ | 76 | */ |
77 | function hook_isso_render_includes($data) | 77 | function hook_isso_render_includes($data) |
78 | { | 78 | { |
79 | if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) { | 79 | if ($data['_PAGE_'] == TemplatePage::LINKLIST) { |
80 | $data['css_files'][] = PluginManager::$PLUGINS_PATH . '/isso/isso.css'; | 80 | $data['css_files'][] = PluginManager::$PLUGINS_PATH . '/isso/isso.css'; |
81 | } | 81 | } |
82 | 82 | ||
diff --git a/plugins/isso/isso_button.html b/plugins/isso/isso_button.html deleted file mode 100644 index 3f828480..00000000 --- a/plugins/isso/isso_button.html +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | <span> | ||
2 | <a href="?%s#isso-thread"> | ||
3 | <img class="linklist-plugin-icon" src="plugins/archiveorg/internetarchive.png" title="%s" alt="archive.org" /> | ||
4 | </a> | ||
5 | </span> | ||
diff --git a/plugins/markdown/README.md b/plugins/markdown/README.md deleted file mode 100644 index bc9427e2..00000000 --- a/plugins/markdown/README.md +++ /dev/null | |||
@@ -1,102 +0,0 @@ | |||
1 | ## Markdown Shaarli plugin | ||
2 | |||
3 | Convert all your shaares description to HTML formatted Markdown. | ||
4 | |||
5 | [Read more about Markdown syntax](http://daringfireball.net/projects/markdown/syntax). | ||
6 | |||
7 | Markdown processing is done with [Parsedown library](https://github.com/erusev/parsedown). | ||
8 | |||
9 | ### Installation | ||
10 | |||
11 | As a default plugin, it should already be in `tpl/plugins/` directory. | ||
12 | If not, download and unpack it there. | ||
13 | |||
14 | The directory structure should look like: | ||
15 | |||
16 | ``` | ||
17 | --- plugins | ||
18 | |--- markdown | ||
19 | |--- help.html | ||
20 | |--- markdown.css | ||
21 | |--- markdown.meta | ||
22 | |--- markdown.php | ||
23 | |--- README.md | ||
24 | ``` | ||
25 | |||
26 | To enable the plugin, just check it in the plugin administration page. | ||
27 | |||
28 | You can also add `markdown` to your list of enabled plugins in `data/config.json.php` | ||
29 | (`general.enabled_plugins` list). | ||
30 | |||
31 | This should look like: | ||
32 | |||
33 | ``` | ||
34 | "general": { | ||
35 | "enabled_plugins": [ | ||
36 | "markdown", | ||
37 | [...] | ||
38 | ], | ||
39 | } | ||
40 | ``` | ||
41 | |||
42 | Parsedown parsing library is imported using Composer. If you installed Shaarli using `git`, | ||
43 | or the `master` branch, run | ||
44 | |||
45 | composer update --no-dev --prefer-dist | ||
46 | |||
47 | ### No Markdown tag | ||
48 | |||
49 | If the tag `nomarkdown` is set for a shaare, it won't be converted to Markdown syntax. | ||
50 | |||
51 | > Note: this is a special tag, so it won't be displayed in link list. | ||
52 | |||
53 | ### HTML escape | ||
54 | |||
55 | By default, HTML tags are escaped. You can enable HTML tags rendering | ||
56 | by setting `security.markdwon_escape` to `false` in `data/config.json.php`: | ||
57 | |||
58 | ```json | ||
59 | { | ||
60 | "security": { | ||
61 | "markdown_escape": false | ||
62 | } | ||
63 | } | ||
64 | ``` | ||
65 | |||
66 | With this setting, Markdown support HTML tags. For example: | ||
67 | |||
68 | > <strong>strong</strong><strike>strike</strike> | ||
69 | |||
70 | Will render as: | ||
71 | |||
72 | > <strong>strong</strong><strike>strike</strike> | ||
73 | |||
74 | |||
75 | **Warning:** | ||
76 | |||
77 | * This setting might present **security risks** (XSS) on shared instances, even though tags | ||
78 | such as script, iframe, etc should be disabled. | ||
79 | * If you want to shaare HTML code, it is necessary to use inline code or code blocks. | ||
80 | * If your shaared descriptions contained HTML tags before enabling the markdown plugin, | ||
81 | enabling it might break your page. | ||
82 | |||
83 | ### Known issue | ||
84 | |||
85 | #### Redirector | ||
86 | |||
87 | If you're using a redirector, you *need* to add a space after a link, | ||
88 | otherwise the rest of the line will be `urlencode`. | ||
89 | |||
90 | ``` | ||
91 | [link](http://domain.tld)-->test | ||
92 | ``` | ||
93 | |||
94 | Will consider `http://domain.tld)-->test` as URL. | ||
95 | |||
96 | Instead, add an additional space. | ||
97 | |||
98 | ``` | ||
99 | [link](http://domain.tld) -->test | ||
100 | ``` | ||
101 | |||
102 | > Won't fix because a `)` is a valid part of an URL. | ||
diff --git a/plugins/markdown/help.html b/plugins/markdown/help.html deleted file mode 100644 index ded3d347..00000000 --- a/plugins/markdown/help.html +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | <div class="md_help"> | ||
2 | %s | ||
3 | <a href="http://daringfireball.net/projects/markdown/syntax" title="%s"> | ||
4 | %s</a>. | ||
5 | </div> | ||
diff --git a/plugins/markdown/markdown.css b/plugins/markdown/markdown.css deleted file mode 100644 index ce19cd2a..00000000 --- a/plugins/markdown/markdown.css +++ /dev/null | |||
@@ -1,173 +0,0 @@ | |||
1 | /** | ||
2 | * Credit to Simon Laroche <https://github.com/simonlc/Markdown-CSS> | ||
3 | * whom created the CSS which this file is based on. | ||
4 | * License: Unlicense <http://unlicense.org/> | ||
5 | */ | ||
6 | |||
7 | .markdown p{ | ||
8 | margin:0.75em 0; | ||
9 | } | ||
10 | |||
11 | .markdown img{ | ||
12 | max-width:100%; | ||
13 | } | ||
14 | |||
15 | .markdown h1, .markdown h2, .markdown h3, .markdown h4, .markdown h5, .markdown h6{ | ||
16 | font-weight:normal; | ||
17 | font-style:normal; | ||
18 | line-height:1em; | ||
19 | margin:0.75em 0; | ||
20 | } | ||
21 | .markdown h4, .markdown h5, .markdown h6{ font-weight: bold; } | ||
22 | .markdown h1{ font-size:2.5em; } | ||
23 | .markdown h2{ font-size:2em; } | ||
24 | .markdown h3{ font-size:1.5em; } | ||
25 | .markdown h4{ font-size:1.2em; } | ||
26 | .markdown h5{ font-size:1em; } | ||
27 | .markdown h6{ font-size:0.9em; } | ||
28 | |||
29 | .markdown blockquote{ | ||
30 | color:#666666; | ||
31 | padding-left: 3em; | ||
32 | border-left: 0.5em #EEE solid; | ||
33 | margin:0.75em 0; | ||
34 | } | ||
35 | .markdown hr { display: block; height: 2px; border: 0; border-top: 1px solid #aaa;border-bottom: 1px solid #eee; margin: 1em 0; padding: 0; } | ||
36 | .markdown pre, .markdown code, .markdown kbd, .markdown samp { | ||
37 | font-family: monospace, 'courier new'; | ||
38 | font-size: 0.98em; | ||
39 | } | ||
40 | .markdown pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; } | ||
41 | |||
42 | .markdown b, .markdown strong { font-weight: bold; } | ||
43 | |||
44 | .markdown dfn, .markdown em { font-style: italic; } | ||
45 | |||
46 | .markdown ins { background: #ff9; color: #000; text-decoration: none; } | ||
47 | |||
48 | .markdown mark { background: #ff0; color: #000; font-style: italic; font-weight: bold; } | ||
49 | |||
50 | .markdown sub, .markdown sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } | ||
51 | .markdown sup { top: -0.5em; } | ||
52 | .markdown sub { bottom: -0.25em; } | ||
53 | |||
54 | .markdown ul, .markdown ol { margin: 1em 0; padding: 0 0 0 2em; } | ||
55 | .markdown li p:last-child { margin:0 } | ||
56 | .markdown dd { margin: 0 0 0 2em; } | ||
57 | |||
58 | .markdown img { border: 0; -ms-interpolation-mode: bicubic; vertical-align: middle; } | ||
59 | |||
60 | .markdown table { border-collapse: collapse; border-spacing: 0; } | ||
61 | .markdown td { vertical-align: top; } | ||
62 | |||
63 | @media only screen and (min-width: 480px) { | ||
64 | .markdown {font-size:0.9em;} | ||
65 | } | ||
66 | |||
67 | @media only screen and (min-width: 768px) { | ||
68 | .markdown {font-size:1em;} | ||
69 | } | ||
70 | |||
71 | #linklist .markdown li { | ||
72 | padding: 0; | ||
73 | border: none; | ||
74 | background: none; | ||
75 | } | ||
76 | |||
77 | #linklist .markdown ul li { | ||
78 | list-style: circle; | ||
79 | } | ||
80 | |||
81 | #linklist .markdown ol li { | ||
82 | list-style: decimal; | ||
83 | } | ||
84 | |||
85 | .markdown table { | ||
86 | padding: 0; | ||
87 | } | ||
88 | .markdown table tr { | ||
89 | border-top: 1px solid #cccccc; | ||
90 | background-color: white; | ||
91 | margin: 0; | ||
92 | padding: 0; | ||
93 | } | ||
94 | .markdown table tr:nth-child(2n) { | ||
95 | background-color: #f8f8f8; | ||
96 | } | ||
97 | .markdown table tr th { | ||
98 | font-weight: bold; | ||
99 | border: 1px solid #cccccc; | ||
100 | text-align: left; | ||
101 | margin: 0; | ||
102 | padding: 6px 13px; | ||
103 | } | ||
104 | .markdown table tr td { | ||
105 | border: 1px solid #cccccc; | ||
106 | text-align: left; | ||
107 | margin: 0; | ||
108 | padding: 6px 13px; | ||
109 | } | ||
110 | .markdown table tr th :first-child, .markdown table tr td :first-child { | ||
111 | margin-top: 0; | ||
112 | } | ||
113 | .markdown table tr th :last-child, table tr td :last-child { | ||
114 | margin-bottom: 0; | ||
115 | } | ||
116 | |||
117 | .markdown pre { | ||
118 | background-color: #eee; | ||
119 | padding: 4px 9px; | ||
120 | -webkit-border-radius: 5px; | ||
121 | -moz-border-radius: 5px; | ||
122 | border-radius: 5px; | ||
123 | overflow: auto; | ||
124 | box-shadow: 0 -1px 0 #e5e5e5,0 0 1px rgba(0,0,0,0.12),0 1px 2px rgba(0,0,0,0.24); | ||
125 | } | ||
126 | |||
127 | .markdown pre code { | ||
128 | color: black; | ||
129 | font-family: 'Consolas', 'Monaco', 'Andale Mono', monospace; | ||
130 | direction: ltr; | ||
131 | text-align: left; | ||
132 | white-space: pre; | ||
133 | word-spacing: normal; | ||
134 | word-break: normal; | ||
135 | line-height: 1.7; | ||
136 | font-size: 11.5px; | ||
137 | -moz-tab-size: 4; | ||
138 | -o-tab-size: 4; | ||
139 | tab-size: 4; | ||
140 | -webkit-hyphens: none; | ||
141 | -moz-hyphens: none; | ||
142 | -ms-hyphens: none; | ||
143 | hyphens: none; | ||
144 | } | ||
145 | |||
146 | .markdown :not(pre) code { | ||
147 | background-color: #eee; | ||
148 | padding: 1px 3px; | ||
149 | border-radius: 1px; | ||
150 | box-shadow: 0 -1px 0 #e5e5e5,0 0 1px rgba(0,0,0,0.12),0 1px 1px rgba(0,0,0,0.24); | ||
151 | } | ||
152 | |||
153 | #pageheader .md_help { | ||
154 | color: white; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | Remove header links style | ||
159 | */ | ||
160 | #pageheader .md_help a { | ||
161 | color: lightgray; | ||
162 | font-weight: bold; | ||
163 | text-decoration: underline; | ||
164 | |||
165 | background: none; | ||
166 | box-shadow: none; | ||
167 | padding: 0; | ||
168 | margin: 0; | ||
169 | } | ||
170 | |||
171 | #pageheader .md_help a:hover { | ||
172 | color: white; | ||
173 | } | ||
diff --git a/plugins/markdown/markdown.meta b/plugins/markdown/markdown.meta deleted file mode 100644 index 322856ea..00000000 --- a/plugins/markdown/markdown.meta +++ /dev/null | |||
@@ -1,4 +0,0 @@ | |||
1 | description="Render shaare description with Markdown syntax.<br><strong>Warning</strong>: | ||
2 | If your shaared descriptions contained HTML tags before enabling the markdown plugin, | ||
3 | enabling it might break your page. | ||
4 | See the <a href=\"https://github.com/shaarli/Shaarli/tree/master/plugins/markdown#html-rendering\">README</a>." | ||
diff --git a/plugins/markdown/markdown.php b/plugins/markdown/markdown.php deleted file mode 100644 index 628970d6..00000000 --- a/plugins/markdown/markdown.php +++ /dev/null | |||
@@ -1,365 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Plugin Markdown. | ||
5 | * | ||
6 | * Shaare's descriptions are parsed with Markdown. | ||
7 | */ | ||
8 | |||
9 | use Shaarli\Config\ConfigManager; | ||
10 | use Shaarli\Plugin\PluginManager; | ||
11 | use Shaarli\Router; | ||
12 | |||
13 | /* | ||
14 | * If this tag is used on a shaare, the description won't be processed by Parsedown. | ||
15 | */ | ||
16 | define('NO_MD_TAG', 'nomarkdown'); | ||
17 | |||
18 | /** | ||
19 | * Parse linklist descriptions. | ||
20 | * | ||
21 | * @param array $data linklist data. | ||
22 | * @param ConfigManager $conf instance. | ||
23 | * | ||
24 | * @return mixed linklist data parsed in markdown (and converted to HTML). | ||
25 | */ | ||
26 | function hook_markdown_render_linklist($data, $conf) | ||
27 | { | ||
28 | foreach ($data['links'] as &$value) { | ||
29 | if (!empty($value['tags']) && noMarkdownTag($value['tags'])) { | ||
30 | $value = stripNoMarkdownTag($value); | ||
31 | continue; | ||
32 | } | ||
33 | $value['description_src'] = $value['description']; | ||
34 | $value['description'] = process_markdown( | ||
35 | $value['description'], | ||
36 | $conf->get('security.markdown_escape', true), | ||
37 | $conf->get('security.allowed_protocols') | ||
38 | ); | ||
39 | } | ||
40 | return $data; | ||
41 | } | ||
42 | |||
43 | /** | ||
44 | * Parse feed linklist descriptions. | ||
45 | * | ||
46 | * @param array $data linklist data. | ||
47 | * @param ConfigManager $conf instance. | ||
48 | * | ||
49 | * @return mixed linklist data parsed in markdown (and converted to HTML). | ||
50 | */ | ||
51 | function hook_markdown_render_feed($data, $conf) | ||
52 | { | ||
53 | foreach ($data['links'] as &$value) { | ||
54 | if (!empty($value['tags']) && noMarkdownTag($value['tags'])) { | ||
55 | $value = stripNoMarkdownTag($value); | ||
56 | continue; | ||
57 | } | ||
58 | $value['description'] = reverse_feed_permalink($value['description']); | ||
59 | $value['description'] = process_markdown( | ||
60 | $value['description'], | ||
61 | $conf->get('security.markdown_escape', true), | ||
62 | $conf->get('security.allowed_protocols') | ||
63 | ); | ||
64 | } | ||
65 | |||
66 | return $data; | ||
67 | } | ||
68 | |||
69 | /** | ||
70 | * Parse daily descriptions. | ||
71 | * | ||
72 | * @param array $data daily data. | ||
73 | * @param ConfigManager $conf instance. | ||
74 | * | ||
75 | * @return mixed daily data parsed in markdown (and converted to HTML). | ||
76 | */ | ||
77 | function hook_markdown_render_daily($data, $conf) | ||
78 | { | ||
79 | //var_dump($data);die; | ||
80 | // Manipulate columns data | ||
81 | foreach ($data['linksToDisplay'] as &$value) { | ||
82 | if (!empty($value['tags']) && noMarkdownTag($value['tags'])) { | ||
83 | $value = stripNoMarkdownTag($value); | ||
84 | continue; | ||
85 | } | ||
86 | $value['formatedDescription'] = process_markdown( | ||
87 | $value['formatedDescription'], | ||
88 | $conf->get('security.markdown_escape', true), | ||
89 | $conf->get('security.allowed_protocols') | ||
90 | ); | ||
91 | } | ||
92 | |||
93 | return $data; | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * Check if noMarkdown is set in tags. | ||
98 | * | ||
99 | * @param string $tags tag list | ||
100 | * | ||
101 | * @return bool true if markdown should be disabled on this link. | ||
102 | */ | ||
103 | function noMarkdownTag($tags) | ||
104 | { | ||
105 | return preg_match('/(^|\s)'. NO_MD_TAG .'(\s|$)/', $tags); | ||
106 | } | ||
107 | |||
108 | /** | ||
109 | * Remove the no-markdown meta tag so it won't be displayed. | ||
110 | * | ||
111 | * @param array $link Link data. | ||
112 | * | ||
113 | * @return array Updated link without no markdown tag. | ||
114 | */ | ||
115 | function stripNoMarkdownTag($link) | ||
116 | { | ||
117 | if (! empty($link['taglist'])) { | ||
118 | $offset = array_search(NO_MD_TAG, $link['taglist']); | ||
119 | if ($offset !== false) { | ||
120 | unset($link['taglist'][$offset]); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | if (!empty($link['tags'])) { | ||
125 | str_replace(NO_MD_TAG, '', $link['tags']); | ||
126 | } | ||
127 | |||
128 | return $link; | ||
129 | } | ||
130 | |||
131 | /** | ||
132 | * When link list is displayed, include markdown CSS. | ||
133 | * | ||
134 | * @param array $data includes data. | ||
135 | * | ||
136 | * @return mixed - includes data with markdown CSS file added. | ||
137 | */ | ||
138 | function hook_markdown_render_includes($data) | ||
139 | { | ||
140 | if ($data['_PAGE_'] == Router::$PAGE_LINKLIST | ||
141 | || $data['_PAGE_'] == Router::$PAGE_DAILY | ||
142 | || $data['_PAGE_'] == Router::$PAGE_EDITLINK | ||
143 | ) { | ||
144 | $data['css_files'][] = PluginManager::$PLUGINS_PATH . '/markdown/markdown.css'; | ||
145 | } | ||
146 | |||
147 | return $data; | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * Hook render_editlink. | ||
152 | * Adds an help link to markdown syntax. | ||
153 | * | ||
154 | * @param array $data data passed to plugin | ||
155 | * | ||
156 | * @return array altered $data. | ||
157 | */ | ||
158 | function hook_markdown_render_editlink($data) | ||
159 | { | ||
160 | // Load help HTML into a string | ||
161 | $txt = file_get_contents(PluginManager::$PLUGINS_PATH .'/markdown/help.html'); | ||
162 | $translations = [ | ||
163 | t('Description will be rendered with'), | ||
164 | t('Markdown syntax documentation'), | ||
165 | t('Markdown syntax'), | ||
166 | ]; | ||
167 | $data['edit_link_plugin'][] = vsprintf($txt, $translations); | ||
168 | // Add no markdown 'meta-tag' in tag list if it was never used, for autocompletion. | ||
169 | if (! in_array(NO_MD_TAG, $data['tags'])) { | ||
170 | $data['tags'][NO_MD_TAG] = 0; | ||
171 | } | ||
172 | |||
173 | return $data; | ||
174 | } | ||
175 | |||
176 | |||
177 | /** | ||
178 | * Remove HTML links auto generated by Shaarli core system. | ||
179 | * Keeps HREF attributes. | ||
180 | * | ||
181 | * @param string $description input description text. | ||
182 | * | ||
183 | * @return string $description without HTML links. | ||
184 | */ | ||
185 | function reverse_text2clickable($description) | ||
186 | { | ||
187 | $descriptionLines = explode(PHP_EOL, $description); | ||
188 | $descriptionOut = ''; | ||
189 | $codeBlockOn = false; | ||
190 | $lineCount = 0; | ||
191 | |||
192 | foreach ($descriptionLines as $descriptionLine) { | ||
193 | // Detect line of code: starting with 4 spaces, | ||
194 | // except lists which can start with +/*/- or `2.` after spaces. | ||
195 | $codeLineOn = preg_match('/^ +(?=[^\+\*\-])(?=(?!\d\.).)/', $descriptionLine) > 0; | ||
196 | // Detect and toggle block of code | ||
197 | if (!$codeBlockOn) { | ||
198 | $codeBlockOn = preg_match('/^```/', $descriptionLine) > 0; | ||
199 | } elseif (preg_match('/^```/', $descriptionLine) > 0) { | ||
200 | $codeBlockOn = false; | ||
201 | } | ||
202 | |||
203 | $hashtagTitle = ' title="Hashtag [^"]+"'; | ||
204 | // Reverse `inline code` hashtags. | ||
205 | $descriptionLine = preg_replace( | ||
206 | '!(`[^`\n]*)<a href="[^ ]*"'. $hashtagTitle .'>([^<]+)</a>([^`\n]*`)!m', | ||
207 | '$1$2$3', | ||
208 | $descriptionLine | ||
209 | ); | ||
210 | |||
211 | // Reverse all links in code blocks, only non hashtag elsewhere. | ||
212 | $hashtagFilter = (!$codeBlockOn && !$codeLineOn) ? '(?!'. $hashtagTitle .')': '(?:'. $hashtagTitle .')?'; | ||
213 | $descriptionLine = preg_replace( | ||
214 | '#<a href="[^ ]*"'. $hashtagFilter .'>([^<]+)</a>#m', | ||
215 | '$1', | ||
216 | $descriptionLine | ||
217 | ); | ||
218 | |||
219 | // Make hashtag links markdown ready, otherwise the links will be ignored with escape set to true | ||
220 | if (!$codeBlockOn && !$codeLineOn) { | ||
221 | $descriptionLine = preg_replace( | ||
222 | '#<a href="([^ ]*)"'. $hashtagTitle .'>([^<]+)</a>#m', | ||
223 | '[$2]($1)', | ||
224 | $descriptionLine | ||
225 | ); | ||
226 | } | ||
227 | |||
228 | $descriptionOut .= $descriptionLine; | ||
229 | if ($lineCount++ < count($descriptionLines) - 1) { | ||
230 | $descriptionOut .= PHP_EOL; | ||
231 | } | ||
232 | } | ||
233 | return $descriptionOut; | ||
234 | } | ||
235 | |||
236 | /** | ||
237 | * Remove <br> tag to let markdown handle it. | ||
238 | * | ||
239 | * @param string $description input description text. | ||
240 | * | ||
241 | * @return string $description without <br> tags. | ||
242 | */ | ||
243 | function reverse_nl2br($description) | ||
244 | { | ||
245 | return preg_replace('!<br */?>!im', '', $description); | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * Remove HTML spaces ' ' auto generated by Shaarli core system. | ||
250 | * | ||
251 | * @param string $description input description text. | ||
252 | * | ||
253 | * @return string $description without HTML links. | ||
254 | */ | ||
255 | function reverse_space2nbsp($description) | ||
256 | { | ||
257 | return preg_replace('/(^| ) /m', '$1 ', $description); | ||
258 | } | ||
259 | |||
260 | function reverse_feed_permalink($description) | ||
261 | { | ||
262 | return preg_replace('@— <a href="([^"]+)" title="[^"]+">(\w+)</a>$@im', '— [$2]($1)', $description); | ||
263 | } | ||
264 | |||
265 | /** | ||
266 | * Replace not whitelisted protocols with http:// in given description. | ||
267 | * | ||
268 | * @param string $description input description text. | ||
269 | * @param array $allowedProtocols list of allowed protocols. | ||
270 | * | ||
271 | * @return string $description without malicious link. | ||
272 | */ | ||
273 | function filter_protocols($description, $allowedProtocols) | ||
274 | { | ||
275 | return preg_replace_callback( | ||
276 | '#]\((.*?)\)#is', | ||
277 | function ($match) use ($allowedProtocols) { | ||
278 | return ']('. whitelist_protocols($match[1], $allowedProtocols) .')'; | ||
279 | }, | ||
280 | $description | ||
281 | ); | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * Remove dangerous HTML tags (tags, iframe, etc.). | ||
286 | * Doesn't affect <code> content (already escaped by Parsedown). | ||
287 | * | ||
288 | * @param string $description input description text. | ||
289 | * | ||
290 | * @return string given string escaped. | ||
291 | */ | ||
292 | function sanitize_html($description) | ||
293 | { | ||
294 | $escapeTags = array( | ||
295 | 'script', | ||
296 | 'style', | ||
297 | 'link', | ||
298 | 'iframe', | ||
299 | 'frameset', | ||
300 | 'frame', | ||
301 | ); | ||
302 | foreach ($escapeTags as $tag) { | ||
303 | $description = preg_replace_callback( | ||
304 | '#<\s*'. $tag .'[^>]*>(.*</\s*'. $tag .'[^>]*>)?#is', | ||
305 | function ($match) { | ||
306 | return escape($match[0]); | ||
307 | }, | ||
308 | $description | ||
309 | ); | ||
310 | } | ||
311 | $description = preg_replace( | ||
312 | '#(<[^>]+\s)on[a-z]*="?[^ "]*"?#is', | ||
313 | '$1', | ||
314 | $description | ||
315 | ); | ||
316 | return $description; | ||
317 | } | ||
318 | |||
319 | /** | ||
320 | * Render shaare contents through Markdown parser. | ||
321 | * 1. Remove HTML generated by Shaarli core. | ||
322 | * 2. Reverse the escape function. | ||
323 | * 3. Generate markdown descriptions. | ||
324 | * 4. Sanitize sensible HTML tags for security. | ||
325 | * 5. Wrap description in 'markdown' CSS class. | ||
326 | * | ||
327 | * @param string $description input description text. | ||
328 | * @param bool $escape escape HTML entities | ||
329 | * | ||
330 | * @return string HTML processed $description. | ||
331 | */ | ||
332 | function process_markdown($description, $escape = true, $allowedProtocols = []) | ||
333 | { | ||
334 | $parsedown = new Parsedown(); | ||
335 | |||
336 | $processedDescription = $description; | ||
337 | $processedDescription = reverse_nl2br($processedDescription); | ||
338 | $processedDescription = reverse_space2nbsp($processedDescription); | ||
339 | $processedDescription = reverse_text2clickable($processedDescription); | ||
340 | $processedDescription = filter_protocols($processedDescription, $allowedProtocols); | ||
341 | $processedDescription = unescape($processedDescription); | ||
342 | $processedDescription = $parsedown | ||
343 | ->setMarkupEscaped($escape) | ||
344 | ->setBreaksEnabled(true) | ||
345 | ->text($processedDescription); | ||
346 | $processedDescription = sanitize_html($processedDescription); | ||
347 | |||
348 | if (!empty($processedDescription)) { | ||
349 | $processedDescription = '<div class="markdown">'. $processedDescription . '</div>'; | ||
350 | } | ||
351 | |||
352 | return $processedDescription; | ||
353 | } | ||
354 | |||
355 | /** | ||
356 | * This function is never called, but contains translation calls for GNU gettext extraction. | ||
357 | */ | ||
358 | function markdown_dummy_translation() | ||
359 | { | ||
360 | // meta | ||
361 | t('Render shaare description with Markdown syntax.<br><strong>Warning</strong>: | ||
362 | If your shaared descriptions contained HTML tags before enabling the markdown plugin, | ||
363 | enabling it might break your page. | ||
364 | See the <a href="https://github.com/shaarli/Shaarli/tree/master/plugins/markdown#html-rendering">README</a>.'); | ||
365 | } | ||
diff --git a/plugins/playvideos/README.md b/plugins/playvideos/README.md index ab4be22a..32a94e88 100644 --- a/plugins/playvideos/README.md +++ b/plugins/playvideos/README.md | |||
@@ -8,22 +8,21 @@ This uses code from https://zaius.github.io/youtube_playlist/ and is currently o | |||
8 | 8 | ||
9 | #### Installation and setup | 9 | #### Installation and setup |
10 | 10 | ||
11 | This is a default Shaarli plugin, you just have to enable it. See https://shaarli.readthedocs.io/en/master/Shaarli-configuration/ | 11 | This is a default Shaarli plugin, you just have to enable it. See [Shaarli configuration](../../doc/md/Shaarli-configuration.md). |
12 | 12 | ||
13 | 13 | ||
14 | #### Troubleshooting | 14 | #### Troubleshooting |
15 | 15 | ||
16 | If your server has [Content Security Policy](http://content-security-policy.com/) headers enabled, this may prevent the script from loading fully. You should relax the CSP in your server settings. Example CSP rule for apache2: | 16 | If your server has [Content Security Policy](http://content-security-policy.com/) headers enabled, this may prevent the script from loading fully. You should relax the CSP in your server settings. Example CSP rule for apache2: |
17 | |||
18 | In `/etc/apache2/conf-available/shaarli-csp.conf`: | ||
19 | 17 | ||
20 | ```apache | 18 | ```apache |
21 | <Directory /path/to/shaarli> | 19 | <Directory /path/to/shaarli> |
20 | # Required for playvideos plugin | ||
22 | Header set Content-Security-Policy "script-src 'self' 'unsafe-inline' https://www.youtube.com https://s.ytimg.com 'unsafe-eval'" | 21 | Header set Content-Security-Policy "script-src 'self' 'unsafe-inline' https://www.youtube.com https://s.ytimg.com 'unsafe-eval'" |
23 | </Directory> | 22 | </Directory> |
24 | ``` | 23 | ``` |
25 | 24 | ||
26 | Then run `a2enconf shaarli-csp; service apache2 reload` | 25 | You may place the `Header` directive in the `<Directory...` section of your [webserver configuration](../../doc/md/Server-configuration.md)/virtualhost file, or write the above snippet to `/etc/apache2/conf-available/shaarli-csp.conf`; then run `a2enconf shaarli-csp; service apache2 reload`. |
27 | 26 | ||
28 | ### License | 27 | ### License |
29 | ``` | 28 | ``` |
diff --git a/plugins/playvideos/playvideos.php b/plugins/playvideos/playvideos.php index 0341ed59..91a9c1e5 100644 --- a/plugins/playvideos/playvideos.php +++ b/plugins/playvideos/playvideos.php | |||
@@ -7,7 +7,7 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | use Shaarli\Plugin\PluginManager; | 9 | use Shaarli\Plugin\PluginManager; |
10 | use Shaarli\Router; | 10 | use Shaarli\Render\TemplatePage; |
11 | 11 | ||
12 | /** | 12 | /** |
13 | * When linklist is displayed, add play videos to header's toolbar. | 13 | * When linklist is displayed, add play videos to header's toolbar. |
@@ -18,7 +18,7 @@ use Shaarli\Router; | |||
18 | */ | 18 | */ |
19 | function hook_playvideos_render_header($data) | 19 | function hook_playvideos_render_header($data) |
20 | { | 20 | { |
21 | if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) { | 21 | if ($data['_PAGE_'] == TemplatePage::LINKLIST) { |
22 | $playvideo = array( | 22 | $playvideo = array( |
23 | 'attr' => array( | 23 | 'attr' => array( |
24 | 'href' => '#', | 24 | 'href' => '#', |
@@ -42,7 +42,7 @@ function hook_playvideos_render_header($data) | |||
42 | */ | 42 | */ |
43 | function hook_playvideos_render_footer($data) | 43 | function hook_playvideos_render_footer($data) |
44 | { | 44 | { |
45 | if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) { | 45 | if ($data['_PAGE_'] == TemplatePage::LINKLIST) { |
46 | $data['js_files'][] = PluginManager::$PLUGINS_PATH . '/playvideos/jquery-1.11.2.min.js'; | 46 | $data['js_files'][] = PluginManager::$PLUGINS_PATH . '/playvideos/jquery-1.11.2.min.js'; |
47 | $data['js_files'][] = PluginManager::$PLUGINS_PATH . '/playvideos/youtube_playlist.js'; | 47 | $data['js_files'][] = PluginManager::$PLUGINS_PATH . '/playvideos/youtube_playlist.js'; |
48 | } | 48 | } |
diff --git a/plugins/pubsubhubbub/pubsubhubbub.php b/plugins/pubsubhubbub/pubsubhubbub.php index 2878c050..8fe6799c 100644 --- a/plugins/pubsubhubbub/pubsubhubbub.php +++ b/plugins/pubsubhubbub/pubsubhubbub.php | |||
@@ -13,7 +13,7 @@ use pubsubhubbub\publisher\Publisher; | |||
13 | use Shaarli\Config\ConfigManager; | 13 | use Shaarli\Config\ConfigManager; |
14 | use Shaarli\Feed\FeedBuilder; | 14 | use Shaarli\Feed\FeedBuilder; |
15 | use Shaarli\Plugin\PluginManager; | 15 | use Shaarli\Plugin\PluginManager; |
16 | use Shaarli\Router; | 16 | use Shaarli\Render\TemplatePage; |
17 | 17 | ||
18 | /** | 18 | /** |
19 | * Plugin init function - set the hub to the default appspot one. | 19 | * Plugin init function - set the hub to the default appspot one. |
@@ -41,7 +41,7 @@ function pubsubhubbub_init($conf) | |||
41 | */ | 41 | */ |
42 | function hook_pubsubhubbub_render_feed($data, $conf) | 42 | function hook_pubsubhubbub_render_feed($data, $conf) |
43 | { | 43 | { |
44 | $feedType = $data['_PAGE_'] == Router::$PAGE_FEED_RSS ? FeedBuilder::$FEED_RSS : FeedBuilder::$FEED_ATOM; | 44 | $feedType = $data['_PAGE_'] == TemplatePage::FEED_RSS ? FeedBuilder::$FEED_RSS : FeedBuilder::$FEED_ATOM; |
45 | $template = file_get_contents(PluginManager::$PLUGINS_PATH . '/pubsubhubbub/hub.'. $feedType .'.xml'); | 45 | $template = file_get_contents(PluginManager::$PLUGINS_PATH . '/pubsubhubbub/hub.'. $feedType .'.xml'); |
46 | $data['feed_plugins_header'][] = sprintf($template, $conf->get('plugins.PUBSUBHUB_URL')); | 46 | $data['feed_plugins_header'][] = sprintf($template, $conf->get('plugins.PUBSUBHUB_URL')); |
47 | 47 | ||
@@ -60,8 +60,8 @@ function hook_pubsubhubbub_render_feed($data, $conf) | |||
60 | function hook_pubsubhubbub_save_link($data, $conf) | 60 | function hook_pubsubhubbub_save_link($data, $conf) |
61 | { | 61 | { |
62 | $feeds = array( | 62 | $feeds = array( |
63 | index_url($_SERVER) .'?do=atom', | 63 | index_url($_SERVER) .'feed/atom', |
64 | index_url($_SERVER) .'?do=rss', | 64 | index_url($_SERVER) .'feed/rss', |
65 | ); | 65 | ); |
66 | 66 | ||
67 | $httpPost = function_exists('curl_version') ? false : 'nocurl_http_post'; | 67 | $httpPost = function_exists('curl_version') ? false : 'nocurl_http_post'; |
diff --git a/plugins/qrcode/qrcode.php b/plugins/qrcode/qrcode.php index c1d237d5..95499e39 100644 --- a/plugins/qrcode/qrcode.php +++ b/plugins/qrcode/qrcode.php | |||
@@ -6,7 +6,7 @@ | |||
6 | */ | 6 | */ |
7 | 7 | ||
8 | use Shaarli\Plugin\PluginManager; | 8 | use Shaarli\Plugin\PluginManager; |
9 | use Shaarli\Router; | 9 | use Shaarli\Render\TemplatePage; |
10 | 10 | ||
11 | /** | 11 | /** |
12 | * Add qrcode icon to link_plugin when rendering linklist. | 12 | * Add qrcode icon to link_plugin when rendering linklist. |
@@ -19,11 +19,12 @@ function hook_qrcode_render_linklist($data) | |||
19 | { | 19 | { |
20 | $qrcode_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/qrcode/qrcode.html'); | 20 | $qrcode_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/qrcode/qrcode.html'); |
21 | 21 | ||
22 | $path = ($data['_BASE_PATH_'] ?? '') . '/' . PluginManager::$PLUGINS_PATH; | ||
22 | foreach ($data['links'] as &$value) { | 23 | foreach ($data['links'] as &$value) { |
23 | $qrcode = sprintf( | 24 | $qrcode = sprintf( |
24 | $qrcode_html, | 25 | $qrcode_html, |
25 | $value['url'], | 26 | $value['url'], |
26 | PluginManager::$PLUGINS_PATH | 27 | $path |
27 | ); | 28 | ); |
28 | $value['link_plugin'][] = $qrcode; | 29 | $value['link_plugin'][] = $qrcode; |
29 | } | 30 | } |
@@ -40,7 +41,7 @@ function hook_qrcode_render_linklist($data) | |||
40 | */ | 41 | */ |
41 | function hook_qrcode_render_footer($data) | 42 | function hook_qrcode_render_footer($data) |
42 | { | 43 | { |
43 | if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) { | 44 | if ($data['_PAGE_'] == TemplatePage::LINKLIST) { |
44 | $data['js_files'][] = PluginManager::$PLUGINS_PATH . '/qrcode/shaarli-qrcode.js'; | 45 | $data['js_files'][] = PluginManager::$PLUGINS_PATH . '/qrcode/shaarli-qrcode.js'; |
45 | } | 46 | } |
46 | 47 | ||
@@ -56,7 +57,7 @@ function hook_qrcode_render_footer($data) | |||
56 | */ | 57 | */ |
57 | function hook_qrcode_render_includes($data) | 58 | function hook_qrcode_render_includes($data) |
58 | { | 59 | { |
59 | if ($data['_PAGE_'] == Router::$PAGE_LINKLIST) { | 60 | if ($data['_PAGE_'] == TemplatePage::LINKLIST) { |
60 | $data['css_files'][] = PluginManager::$PLUGINS_PATH . '/qrcode/qrcode.css'; | 61 | $data['css_files'][] = PluginManager::$PLUGINS_PATH . '/qrcode/qrcode.css'; |
61 | } | 62 | } |
62 | 63 | ||
diff --git a/plugins/qrcode/shaarli-qrcode.js b/plugins/qrcode/shaarli-qrcode.js index fe77c4cd..3316d6f6 100644 --- a/plugins/qrcode/shaarli-qrcode.js +++ b/plugins/qrcode/shaarli-qrcode.js | |||
@@ -28,14 +28,15 @@ | |||
28 | 28 | ||
29 | // Show the QR-Code of a permalink (when the QR-Code icon is clicked). | 29 | // Show the QR-Code of a permalink (when the QR-Code icon is clicked). |
30 | function showQrCode(caller,loading) | 30 | function showQrCode(caller,loading) |
31 | { | 31 | { |
32 | // Dynamic javascript lib loading: We only load qr.js if the QR code icon is clicked: | 32 | // Dynamic javascript lib loading: We only load qr.js if the QR code icon is clicked: |
33 | if (typeof(qr) == 'undefined') // Load qr.js only if not present. | 33 | if (typeof(qr) == 'undefined') // Load qr.js only if not present. |
34 | { | 34 | { |
35 | if (!loading) // If javascript lib is still loading, do not append script to body. | 35 | if (!loading) // If javascript lib is still loading, do not append script to body. |
36 | { | 36 | { |
37 | var element = document.createElement("script"); | 37 | var basePath = document.querySelector('input[name="js_base_path"]').value; |
38 | element.src = "plugins/qrcode/qr-1.1.3.min.js"; | 38 | var element = document.createElement("script"); |
39 | element.src = basePath + "/plugins/qrcode/qr-1.1.3.min.js"; | ||
39 | document.body.appendChild(element); | 40 | document.body.appendChild(element); |
40 | } | 41 | } |
41 | setTimeout(function() { showQrCode(caller,true);}, 200); // Retry in 200 milliseconds. | 42 | setTimeout(function() { showQrCode(caller,true);}, 200); // Retry in 200 milliseconds. |
@@ -44,7 +45,7 @@ function showQrCode(caller,loading) | |||
44 | 45 | ||
45 | // Remove previous qrcode if present. | 46 | // Remove previous qrcode if present. |
46 | removeQrcode(); | 47 | removeQrcode(); |
47 | 48 | ||
48 | // Build the div which contains the QR-Code: | 49 | // Build the div which contains the QR-Code: |
49 | var element = document.createElement('div'); | 50 | var element = document.createElement('div'); |
50 | element.id = 'permalinkQrcode'; | 51 | element.id = 'permalinkQrcode'; |
@@ -57,11 +58,11 @@ function showQrCode(caller,loading) | |||
57 | // Damn IE | 58 | // Damn IE |
58 | element.setAttribute('onclick', 'this.parentNode.removeChild(this);' ); | 59 | element.setAttribute('onclick', 'this.parentNode.removeChild(this);' ); |
59 | } | 60 | } |
60 | 61 | ||
61 | // Build the QR-Code: | 62 | // Build the QR-Code: |
62 | var image = qr.image({size: 8,value: caller.dataset.permalink}); | 63 | var image = qr.image({size: 8,value: caller.dataset.permalink}); |
63 | if (image) | 64 | if (image) |
64 | { | 65 | { |
65 | element.appendChild(image); | 66 | element.appendChild(image); |
66 | element.innerHTML += "<br>Click to close"; | 67 | element.innerHTML += "<br>Click to close"; |
67 | caller.parentNode.appendChild(element); | 68 | caller.parentNode.appendChild(element); |
@@ -87,4 +88,4 @@ function removeQrcode() | |||
87 | elem.parentNode.removeChild(elem); | 88 | elem.parentNode.removeChild(elem); |
88 | } | 89 | } |
89 | return false; | 90 | return false; |
90 | } \ No newline at end of file | 91 | } |
diff --git a/plugins/wallabag/README.md b/plugins/wallabag/README.md index ea21a519..c53a04d9 100644 --- a/plugins/wallabag/README.md +++ b/plugins/wallabag/README.md | |||
@@ -21,7 +21,7 @@ The directory structure should look like: | |||
21 | 21 | ||
22 | To enable the plugin, you can either: | 22 | To enable the plugin, you can either: |
23 | 23 | ||
24 | * enable it in the plugins administration page (`?do=pluginadmin`). | 24 | * enable it in the plugins administration page (`/admin/plugins`). |
25 | * add `wallabag` to your list of enabled plugins in `data/config.json.php` (`general.enabled_plugins` section). | 25 | * add `wallabag` to your list of enabled plugins in `data/config.json.php` (`general.enabled_plugins` section). |
26 | 26 | ||
27 | ### Configuration | 27 | ### Configuration |
diff --git a/plugins/wallabag/wallabag.php b/plugins/wallabag/wallabag.php index bc35df08..805c1ad9 100644 --- a/plugins/wallabag/wallabag.php +++ b/plugins/wallabag/wallabag.php | |||
@@ -45,12 +45,14 @@ function hook_wallabag_render_linklist($data, $conf) | |||
45 | $wallabagHtml = file_get_contents(PluginManager::$PLUGINS_PATH . '/wallabag/wallabag.html'); | 45 | $wallabagHtml = file_get_contents(PluginManager::$PLUGINS_PATH . '/wallabag/wallabag.html'); |
46 | 46 | ||
47 | $linkTitle = t('Save to wallabag'); | 47 | $linkTitle = t('Save to wallabag'); |
48 | $path = ($data['_BASE_PATH_'] ?? '') . '/' . PluginManager::$PLUGINS_PATH; | ||
49 | |||
48 | foreach ($data['links'] as &$value) { | 50 | foreach ($data['links'] as &$value) { |
49 | $wallabag = sprintf( | 51 | $wallabag = sprintf( |
50 | $wallabagHtml, | 52 | $wallabagHtml, |
51 | $wallabagInstance->getWallabagUrl(), | 53 | $wallabagInstance->getWallabagUrl(), |
52 | urlencode($value['url']), | 54 | urlencode($value['url']), |
53 | PluginManager::$PLUGINS_PATH, | 55 | $path, |
54 | $linkTitle | 56 | $linkTitle |
55 | ); | 57 | ); |
56 | $value['link_plugin'][] = $wallabag; | 58 | $value['link_plugin'][] = $wallabag; |