aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--application/config/ConfigPlugin.php17
-rw-r--r--application/front/ShaarliMiddleware.php4
-rw-r--r--application/front/controller/admin/ManageShaareController.php25
-rw-r--r--application/front/controller/admin/PluginsController.php17
-rw-r--r--application/front/controller/admin/ToolsController.php17
-rw-r--r--application/front/controller/visitor/BookmarkListController.php16
-rw-r--r--application/front/controller/visitor/DailyController.php22
-rw-r--r--application/front/controller/visitor/FeedController.php21
-rw-r--r--application/front/controller/visitor/PictureWallController.php23
-rw-r--r--application/front/controller/visitor/ShaarliVisitorController.php33
-rw-r--r--application/front/controller/visitor/TagCloudController.php24
-rw-r--r--application/plugin/PluginManager.php4
-rw-r--r--application/render/PageBuilder.php32
-rw-r--r--plugins/addlink_toolbar/addlink_toolbar.php2
-rw-r--r--plugins/archiveorg/archiveorg.html2
-rw-r--r--plugins/archiveorg/archiveorg.php3
-rw-r--r--plugins/demo_plugin/demo_plugin.php2
-rw-r--r--plugins/isso/isso_button.html5
-rw-r--r--plugins/qrcode/qrcode.php5
-rw-r--r--plugins/qrcode/shaarli-qrcode.js15
-rw-r--r--plugins/wallabag/wallabag.php4
-rw-r--r--tests/config/ConfigPluginTest.php16
-rw-r--r--tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php23
-rw-r--r--tests/front/controller/admin/PluginsControllerTest.php14
-rw-r--r--tests/front/controller/admin/SessionFilterControllerTest.php2
-rw-r--r--tests/front/controller/visitor/ShaarliVisitorControllerTest.php2
-rw-r--r--tests/plugins/PluginAddlinkTest.php4
-rw-r--r--tpl/vintage/changepassword.html4
-rw-r--r--tpl/vintage/changetag.html2
-rw-r--r--tpl/vintage/configure.html2
-rw-r--r--tpl/vintage/editlink.html4
-rw-r--r--tpl/vintage/export.html2
-rw-r--r--tpl/vintage/includes.html6
-rw-r--r--tpl/vintage/install.html2
-rw-r--r--tpl/vintage/linklist.html28
-rw-r--r--tpl/vintage/loginform.html2
-rw-r--r--tpl/vintage/page.footer.html4
-rw-r--r--tpl/vintage/pluginsadmin.html2
-rw-r--r--tpl/vintage/thumbnails.html1
39 files changed, 169 insertions, 244 deletions
diff --git a/application/config/ConfigPlugin.php b/application/config/ConfigPlugin.php
index dbb24937..ea8dfbda 100644
--- a/application/config/ConfigPlugin.php
+++ b/application/config/ConfigPlugin.php
@@ -1,6 +1,7 @@
1<?php 1<?php
2 2
3use Shaarli\Config\Exception\PluginConfigOrderException; 3use Shaarli\Config\Exception\PluginConfigOrderException;
4use Shaarli\Plugin\PluginManager;
4 5
5/** 6/**
6 * Plugin configuration helper functions. 7 * Plugin configuration helper functions.
@@ -19,6 +20,20 @@ use Shaarli\Config\Exception\PluginConfigOrderException;
19 */ 20 */
20function save_plugin_config($formData) 21function save_plugin_config($formData)
21{ 22{
23 // We can only save existing plugins
24 $directories = str_replace(
25 PluginManager::$PLUGINS_PATH . '/',
26 '',
27 glob(PluginManager::$PLUGINS_PATH . '/*')
28 );
29 $formData = array_filter(
30 $formData,
31 function ($value, string $key) use ($directories) {
32 return startsWith($key, 'order') || in_array($key, $directories);
33 },
34 ARRAY_FILTER_USE_BOTH
35 );
36
22 // Make sure there are no duplicates in orders. 37 // Make sure there are no duplicates in orders.
23 if (!validate_plugin_order($formData)) { 38 if (!validate_plugin_order($formData)) {
24 throw new PluginConfigOrderException(); 39 throw new PluginConfigOrderException();
@@ -69,7 +84,7 @@ function validate_plugin_order($formData)
69 $orders = array(); 84 $orders = array();
70 foreach ($formData as $key => $value) { 85 foreach ($formData as $key => $value) {
71 // No duplicate order allowed. 86 // No duplicate order allowed.
72 if (in_array($value, $orders)) { 87 if (in_array($value, $orders, true)) {
73 return false; 88 return false;
74 } 89 }
75 90
diff --git a/application/front/ShaarliMiddleware.php b/application/front/ShaarliMiddleware.php
index fd978e99..92c0e911 100644
--- a/application/front/ShaarliMiddleware.php
+++ b/application/front/ShaarliMiddleware.php
@@ -60,7 +60,7 @@ class ShaarliMiddleware
60 60
61 $response = $response->withStatus($e->getCode()); 61 $response = $response->withStatus($e->getCode());
62 62
63 return $response->write($this->container->pageBuilder->render('error')); 63 return $response->write($this->container->pageBuilder->render('error', $this->container->basePath));
64 } catch (UnauthorizedException $e) { 64 } catch (UnauthorizedException $e) {
65 $returnUrl = urlencode($this->container->environment['REQUEST_URI']); 65 $returnUrl = urlencode($this->container->environment['REQUEST_URI']);
66 66
@@ -80,7 +80,7 @@ class ShaarliMiddleware
80 80
81 $response = $response->withStatus(500); 81 $response = $response->withStatus(500);
82 82
83 return $response->write($this->container->pageBuilder->render('error')); 83 return $response->write($this->container->pageBuilder->render('error', $this->container->basePath));
84 } 84 }
85 } 85 }
86 86
diff --git a/application/front/controller/admin/ManageShaareController.php b/application/front/controller/admin/ManageShaareController.php
index 3aa48423..33e1188e 100644
--- a/application/front/controller/admin/ManageShaareController.php
+++ b/application/front/controller/admin/ManageShaareController.php
@@ -152,7 +152,7 @@ class ManageShaareController extends ShaarliAdminController
152 // To preserve backward compatibility with 3rd parties, plugins still use arrays 152 // To preserve backward compatibility with 3rd parties, plugins still use arrays
153 $formatter = $this->container->formatterFactory->getFormatter('raw'); 153 $formatter = $this->container->formatterFactory->getFormatter('raw');
154 $data = $formatter->format($bookmark); 154 $data = $formatter->format($bookmark);
155 $data = $this->executeHooks('save_link', $data); 155 $this->executePageHooks('save_link', $data);
156 156
157 $bookmark->fromArray($data); 157 $bookmark->fromArray($data);
158 $this->container->bookmarkService->set($bookmark); 158 $this->container->bookmarkService->set($bookmark);
@@ -211,7 +211,7 @@ class ManageShaareController extends ShaarliAdminController
211 } 211 }
212 212
213 $data = $formatter->format($bookmark); 213 $data = $formatter->format($bookmark);
214 $this->container->pluginManager->executeHooks('delete_link', $data); 214 $this->executePageHooks('delete_link', $data);
215 $this->container->bookmarkService->remove($bookmark, false); 215 $this->container->bookmarkService->remove($bookmark, false);
216 ++ $count; 216 ++ $count;
217 } 217 }
@@ -283,7 +283,7 @@ class ManageShaareController extends ShaarliAdminController
283 283
284 // To preserve backward compatibility with 3rd parties, plugins still use arrays 284 // To preserve backward compatibility with 3rd parties, plugins still use arrays
285 $data = $formatter->format($bookmark); 285 $data = $formatter->format($bookmark);
286 $this->container->pluginManager->executeHooks('save_link', $data); 286 $this->executePageHooks('save_link', $data);
287 $bookmark->fromArray($data); 287 $bookmark->fromArray($data);
288 288
289 $this->container->bookmarkService->set($bookmark, false); 289 $this->container->bookmarkService->set($bookmark, false);
@@ -325,7 +325,7 @@ class ManageShaareController extends ShaarliAdminController
325 325
326 // To preserve backward compatibility with 3rd parties, plugins still use arrays 326 // To preserve backward compatibility with 3rd parties, plugins still use arrays
327 $data = $formatter->format($bookmark); 327 $data = $formatter->format($bookmark);
328 $this->container->pluginManager->executeHooks('save_link', $data); 328 $this->executePageHooks('save_link', $data);
329 $bookmark->fromArray($data); 329 $bookmark->fromArray($data);
330 330
331 $this->container->bookmarkService->set($bookmark); 331 $this->container->bookmarkService->set($bookmark);
@@ -354,7 +354,7 @@ class ManageShaareController extends ShaarliAdminController
354 'default_private_links' => $this->container->conf->get('privacy.default_private_links', false), 354 'default_private_links' => $this->container->conf->get('privacy.default_private_links', false),
355 ]; 355 ];
356 356
357 $data = $this->executeHooks('render_editlink', $data); 357 $this->executePageHooks('render_editlink', $data, TemplatePage::EDIT_LINK);
358 358
359 foreach ($data as $key => $value) { 359 foreach ($data as $key => $value) {
360 $this->assignView($key, $value); 360 $this->assignView($key, $value);
@@ -368,19 +368,4 @@ class ManageShaareController extends ShaarliAdminController
368 368
369 return $response->write($this->render(TemplatePage::EDIT_LINK)); 369 return $response->write($this->render(TemplatePage::EDIT_LINK));
370 } 370 }
371
372 /**
373 * @param mixed[] $data Variables passed to the template engine
374 *
375 * @return mixed[] Template data after active plugins render_picwall hook execution.
376 */
377 protected function executeHooks(string $hook, array $data): array
378 {
379 $this->container->pluginManager->executeHooks(
380 $hook,
381 $data
382 );
383
384 return $data;
385 }
386} 371}
diff --git a/application/front/controller/admin/PluginsController.php b/application/front/controller/admin/PluginsController.php
index 1eb7e635..0e09116e 100644
--- a/application/front/controller/admin/PluginsController.php
+++ b/application/front/controller/admin/PluginsController.php
@@ -58,7 +58,7 @@ class PluginsController extends ShaarliAdminController
58 try { 58 try {
59 $parameters = $request->getParams() ?? []; 59 $parameters = $request->getParams() ?? [];
60 60
61 $this->executeHooks($parameters); 61 $this->executePageHooks('save_plugin_parameters', $parameters);
62 62
63 if (isset($parameters['parameters_form'])) { 63 if (isset($parameters['parameters_form'])) {
64 unset($parameters['parameters_form']); 64 unset($parameters['parameters_form']);
@@ -81,19 +81,4 @@ class PluginsController extends ShaarliAdminController
81 81
82 return $this->redirect($response, '/admin/plugins'); 82 return $this->redirect($response, '/admin/plugins');
83 } 83 }
84
85 /**
86 * @param mixed[] $data Variables passed to the template engine
87 *
88 * @return mixed[] Template data after active plugins render_picwall hook execution.
89 */
90 protected function executeHooks(array $data): array
91 {
92 $this->container->pluginManager->executeHooks(
93 'save_plugin_parameters',
94 $data
95 );
96
97 return $data;
98 }
99} 84}
diff --git a/application/front/controller/admin/ToolsController.php b/application/front/controller/admin/ToolsController.php
index a476e898..a87f20d2 100644
--- a/application/front/controller/admin/ToolsController.php
+++ b/application/front/controller/admin/ToolsController.php
@@ -22,7 +22,7 @@ class ToolsController extends ShaarliAdminController
22 'sslenabled' => is_https($this->container->environment), 22 'sslenabled' => is_https($this->container->environment),
23 ]; 23 ];
24 24
25 $data = $this->executeHooks($data); 25 $this->executePageHooks('render_tools', $data, TemplatePage::TOOLS);
26 26
27 foreach ($data as $key => $value) { 27 foreach ($data as $key => $value) {
28 $this->assignView($key, $value); 28 $this->assignView($key, $value);
@@ -32,19 +32,4 @@ class ToolsController extends ShaarliAdminController
32 32
33 return $response->write($this->render(TemplatePage::TOOLS)); 33 return $response->write($this->render(TemplatePage::TOOLS));
34 } 34 }
35
36 /**
37 * @param mixed[] $data Variables passed to the template engine
38 *
39 * @return mixed[] Template data after active plugins render_picwall hook execution.
40 */
41 protected function executeHooks(array $data): array
42 {
43 $this->container->pluginManager->executeHooks(
44 'render_tools',
45 $data
46 );
47
48 return $data;
49 }
50} 35}
diff --git a/application/front/controller/visitor/BookmarkListController.php b/application/front/controller/visitor/BookmarkListController.php
index a37a7f6b..23c4fbae 100644
--- a/application/front/controller/visitor/BookmarkListController.php
+++ b/application/front/controller/visitor/BookmarkListController.php
@@ -124,7 +124,7 @@ class BookmarkListController extends ShaarliVisitorController
124 124
125 $data['pagetitle'] = ($data['pagetitle'] ?? '') . $this->container->conf->get('general.title', 'Shaarli'); 125 $data['pagetitle'] = ($data['pagetitle'] ?? '') . $this->container->conf->get('general.title', 'Shaarli');
126 126
127 $this->executeHooks($data); 127 $this->executePageHooks('render_linklist', $data, TemplatePage::LINKLIST);
128 $this->assignAllView($data); 128 $this->assignAllView($data);
129 129
130 return $response->write($this->render(TemplatePage::LINKLIST)); 130 return $response->write($this->render(TemplatePage::LINKLIST));
@@ -153,7 +153,7 @@ class BookmarkListController extends ShaarliVisitorController
153 ] 153 ]
154 ); 154 );
155 155
156 $this->executeHooks($data); 156 $this->executePageHooks('render_linklist', $data, TemplatePage::LINKLIST);
157 $this->assignAllView($data); 157 $this->assignAllView($data);
158 158
159 return $response->write($this->render(TemplatePage::LINKLIST)); 159 return $response->write($this->render(TemplatePage::LINKLIST));
@@ -183,18 +183,6 @@ class BookmarkListController extends ShaarliVisitorController
183 } 183 }
184 184
185 /** 185 /**
186 * @param mixed[] $data Template vars to process in plugins, passed as reference.
187 */
188 protected function executeHooks(array &$data): void
189 {
190 $this->container->pluginManager->executeHooks(
191 'render_linklist',
192 $data,
193 ['loggedin' => $this->container->loginManager->isLoggedIn()]
194 );
195 }
196
197 /**
198 * @return string[] Default template variables without values. 186 * @return string[] Default template variables without values.
199 */ 187 */
200 protected function initializeTemplateVars(): array 188 protected function initializeTemplateVars(): array
diff --git a/application/front/controller/visitor/DailyController.php b/application/front/controller/visitor/DailyController.php
index 05b4f095..808ca5f7 100644
--- a/application/front/controller/visitor/DailyController.php
+++ b/application/front/controller/visitor/DailyController.php
@@ -72,13 +72,11 @@ class DailyController extends ShaarliVisitorController
72 ]; 72 ];
73 73
74 // Hooks are called before column construction so that plugins don't have to deal with columns. 74 // Hooks are called before column construction so that plugins don't have to deal with columns.
75 $data = $this->executeHooks($data); 75 $this->executePageHooks('render_daily', $data, TemplatePage::DAILY);
76 76
77 $data['cols'] = $this->calculateColumns($data['linksToDisplay']); 77 $data['cols'] = $this->calculateColumns($data['linksToDisplay']);
78 78
79 foreach ($data as $key => $value) { 79 $this->assignAllView($data);
80 $this->assignView($key, $value);
81 }
82 80
83 $mainTitle = $this->container->conf->get('general.title', 'Shaarli'); 81 $mainTitle = $this->container->conf->get('general.title', 'Shaarli');
84 $this->assignView( 82 $this->assignView(
@@ -190,20 +188,4 @@ class DailyController extends ShaarliVisitorController
190 188
191 return $columns; 189 return $columns;
192 } 190 }
193
194 /**
195 * @param mixed[] $data Variables passed to the template engine
196 *
197 * @return mixed[] Template data after active plugins render_picwall hook execution.
198 */
199 protected function executeHooks(array $data): array
200 {
201 $this->container->pluginManager->executeHooks(
202 'render_daily',
203 $data,
204 ['loggedin' => $this->container->loginManager->isLoggedIn()]
205 );
206
207 return $data;
208 }
209} 191}
diff --git a/application/front/controller/visitor/FeedController.php b/application/front/controller/visitor/FeedController.php
index f76f55fd..da2848c2 100644
--- a/application/front/controller/visitor/FeedController.php
+++ b/application/front/controller/visitor/FeedController.php
@@ -46,7 +46,7 @@ class FeedController extends ShaarliVisitorController
46 46
47 $data = $this->container->feedBuilder->buildData($feedType, $request->getParams()); 47 $data = $this->container->feedBuilder->buildData($feedType, $request->getParams());
48 48
49 $data = $this->executeHooks($data, $feedType); 49 $this->executePageHooks('render_feed', $data, $feedType);
50 $this->assignAllView($data); 50 $this->assignAllView($data);
51 51
52 $content = $this->render('feed.'. $feedType); 52 $content = $this->render('feed.'. $feedType);
@@ -55,23 +55,4 @@ class FeedController extends ShaarliVisitorController
55 55
56 return $response->write($content); 56 return $response->write($content);
57 } 57 }
58
59 /**
60 * @param mixed[] $data Template data
61 *
62 * @return mixed[] Template data after active plugins hook execution.
63 */
64 protected function executeHooks(array $data, string $feedType): array
65 {
66 $this->container->pluginManager->executeHooks(
67 'render_feed',
68 $data,
69 [
70 'loggedin' => $this->container->loginManager->isLoggedIn(),
71 'target' => $feedType,
72 ]
73 );
74
75 return $data;
76 }
77} 58}
diff --git a/application/front/controller/visitor/PictureWallController.php b/application/front/controller/visitor/PictureWallController.php
index 5ef2cb17..3c57f8dd 100644
--- a/application/front/controller/visitor/PictureWallController.php
+++ b/application/front/controller/visitor/PictureWallController.php
@@ -42,30 +42,13 @@ class PictureWallController extends ShaarliVisitorController
42 } 42 }
43 } 43 }
44 44
45 $data = $this->executeHooks($linksToDisplay); 45 $data = ['linksToDisplay' => $linksToDisplay];
46 $this->executePageHooks('render_picwall', $data, TemplatePage::PICTURE_WALL);
47
46 foreach ($data as $key => $value) { 48 foreach ($data as $key => $value) {
47 $this->assignView($key, $value); 49 $this->assignView($key, $value);
48 } 50 }
49 51
50 return $response->write($this->render(TemplatePage::PICTURE_WALL)); 52 return $response->write($this->render(TemplatePage::PICTURE_WALL));
51 } 53 }
52
53 /**
54 * @param mixed[] $linksToDisplay List of formatted bookmarks
55 *
56 * @return mixed[] Template data after active plugins render_picwall hook execution.
57 */
58 protected function executeHooks(array $linksToDisplay): array
59 {
60 $data = [
61 'linksToDisplay' => $linksToDisplay,
62 ];
63 $this->container->pluginManager->executeHooks(
64 'render_picwall',
65 $data,
66 ['loggedin' => $this->container->loginManager->isLoggedIn()]
67 );
68
69 return $data;
70 }
71} 54}
diff --git a/application/front/controller/visitor/ShaarliVisitorController.php b/application/front/controller/visitor/ShaarliVisitorController.php
index b494a8e6..47057d97 100644
--- a/application/front/controller/visitor/ShaarliVisitorController.php
+++ b/application/front/controller/visitor/ShaarliVisitorController.php
@@ -60,22 +60,9 @@ abstract class ShaarliVisitorController
60 $this->assignView('privateLinkcount', $this->container->bookmarkService->count(BookmarkFilter::$PRIVATE)); 60 $this->assignView('privateLinkcount', $this->container->bookmarkService->count(BookmarkFilter::$PRIVATE));
61 $this->assignView('plugin_errors', $this->container->pluginManager->getErrors()); 61 $this->assignView('plugin_errors', $this->container->pluginManager->getErrors());
62 62
63 /*
64 * Define base path (if Shaarli is installed in a domain's subfolder, e.g. `/shaarli`)
65 * and the asset path (subfolder/tpl/default for default theme).
66 * These MUST be used to create an internal link or to include an asset in templates.
67 */
68 $this->assignView('base_path', $this->container->basePath);
69 $this->assignView(
70 'asset_path',
71 $this->container->basePath . '/' .
72 rtrim($this->container->conf->get('resource.raintpl_tpl', 'tpl'), '/') . '/' .
73 $this->container->conf->get('resource.theme', 'default')
74 );
75
76 $this->executeDefaultHooks($template); 63 $this->executeDefaultHooks($template);
77 64
78 return $this->container->pageBuilder->render($template); 65 return $this->container->pageBuilder->render($template, $this->container->basePath);
79 } 66 }
80 67
81 /** 68 /**
@@ -97,13 +84,29 @@ abstract class ShaarliVisitorController
97 $pluginData, 84 $pluginData,
98 [ 85 [
99 'target' => $template, 86 'target' => $template,
100 'loggedin' => $this->container->loginManager->isLoggedIn() 87 'loggedin' => $this->container->loginManager->isLoggedIn(),
88 'basePath' => $this->container->basePath,
101 ] 89 ]
102 ); 90 );
103 $this->assignView('plugins_' . $name, $pluginData); 91 $this->assignView('plugins_' . $name, $pluginData);
104 } 92 }
105 } 93 }
106 94
95 protected function executePageHooks(string $hook, array &$data, string $template = null): void
96 {
97 $params = [
98 'target' => $template,
99 'loggedin' => $this->container->loginManager->isLoggedIn(),
100 'basePath' => $this->container->basePath,
101 ];
102
103 $this->container->pluginManager->executeHooks(
104 $hook,
105 $data,
106 $params
107 );
108 }
109
107 /** 110 /**
108 * Simple helper which prepend the base path to redirect path. 111 * Simple helper which prepend the base path to redirect path.
109 * 112 *
diff --git a/application/front/controller/visitor/TagCloudController.php b/application/front/controller/visitor/TagCloudController.php
index 15b6d7b7..f9c529bc 100644
--- a/application/front/controller/visitor/TagCloudController.php
+++ b/application/front/controller/visitor/TagCloudController.php
@@ -71,10 +71,8 @@ class TagCloudController extends ShaarliVisitorController
71 'search_tags' => $searchTags, 71 'search_tags' => $searchTags,
72 'tags' => $tags, 72 'tags' => $tags,
73 ]; 73 ];
74 $data = $this->executeHooks('tag' . $type, $data); 74 $this->executePageHooks('render_tag' . $type, $data, 'tag.' . $type);
75 foreach ($data as $key => $value) { 75 $this->assignAllView($data);
76 $this->assignView($key, $value);
77 }
78 76
79 $searchTags = !empty($searchTags) ? $searchTags .' - ' : ''; 77 $searchTags = !empty($searchTags) ? $searchTags .' - ' : '';
80 $this->assignView( 78 $this->assignView(
@@ -82,7 +80,7 @@ class TagCloudController extends ShaarliVisitorController
82 $searchTags . t('Tag '. $type) .' - '. $this->container->conf->get('general.title', 'Shaarli') 80 $searchTags . t('Tag '. $type) .' - '. $this->container->conf->get('general.title', 'Shaarli')
83 ); 81 );
84 82
85 return $response->write($this->render('tag.'. $type)); 83 return $response->write($this->render('tag.' . $type));
86 } 84 }
87 85
88 /** 86 /**
@@ -112,20 +110,4 @@ class TagCloudController extends ShaarliVisitorController
112 110
113 return $tagList; 111 return $tagList;
114 } 112 }
115
116 /**
117 * @param mixed[] $data Template data
118 *
119 * @return mixed[] Template data after active plugins hook execution.
120 */
121 protected function executeHooks(string $template, array $data): array
122 {
123 $this->container->pluginManager->executeHooks(
124 'render_'. $template,
125 $data,
126 ['loggedin' => $this->container->loginManager->isLoggedIn()]
127 );
128
129 return $data;
130 }
131} 113}
diff --git a/application/plugin/PluginManager.php b/application/plugin/PluginManager.php
index 591a9180..b3e8b2f8 100644
--- a/application/plugin/PluginManager.php
+++ b/application/plugin/PluginManager.php
@@ -108,6 +108,10 @@ class PluginManager
108 $data['_LOGGEDIN_'] = $params['loggedin']; 108 $data['_LOGGEDIN_'] = $params['loggedin'];
109 } 109 }
110 110
111 if (isset($params['basePath'])) {
112 $data['_BASE_PATH_'] = $params['basePath'];
113 }
114
111 foreach ($this->loadedPlugins as $plugin) { 115 foreach ($this->loadedPlugins as $plugin) {
112 $hookFunction = $this->buildHookName($hook, $plugin); 116 $hookFunction = $this->buildHookName($hook, $plugin);
113 117
diff --git a/application/render/PageBuilder.php b/application/render/PageBuilder.php
index 471724c0..7a716673 100644
--- a/application/render/PageBuilder.php
+++ b/application/render/PageBuilder.php
@@ -3,6 +3,7 @@
3namespace Shaarli\Render; 3namespace Shaarli\Render;
4 4
5use Exception; 5use Exception;
6use exceptions\MissingBasePathException;
6use RainTPL; 7use RainTPL;
7use Shaarli\ApplicationUtils; 8use Shaarli\ApplicationUtils;
8use Shaarli\Bookmark\BookmarkServiceInterface; 9use Shaarli\Bookmark\BookmarkServiceInterface;
@@ -156,7 +157,7 @@ class PageBuilder
156 * Affect variable after controller processing. 157 * Affect variable after controller processing.
157 * Used for alert messages. 158 * Used for alert messages.
158 */ 159 */
159 protected function finalize(): void 160 protected function finalize(string $basePath): void
160 { 161 {
161 // TODO: use the SessionManager 162 // TODO: use the SessionManager
162 $messageKeys = [ 163 $messageKeys = [
@@ -170,6 +171,14 @@ class PageBuilder
170 unset($_SESSION[$messageKey]); 171 unset($_SESSION[$messageKey]);
171 } 172 }
172 } 173 }
174
175 $this->assign('base_path', $basePath);
176 $this->assign(
177 'asset_path',
178 $basePath . '/' .
179 rtrim($this->conf->get('resource.raintpl_tpl', 'tpl'), '/') . '/' .
180 $this->conf->get('resource.theme', 'default')
181 );
173 } 182 }
174 183
175 /** 184 /**
@@ -210,23 +219,6 @@ class PageBuilder
210 } 219 }
211 220
212 /** 221 /**
213 * Render a specific page (using a template file).
214 * e.g. $pb->renderPage('picwall');
215 *
216 * @param string $page Template filename (without extension).
217 */
218 public function renderPage($page)
219 {
220 if ($this->tpl === false) {
221 $this->initialize();
222 }
223
224 $this->finalize();
225
226 $this->tpl->draw($page);
227 }
228
229 /**
230 * Render a specific page as string (using a template file). 222 * Render a specific page as string (using a template file).
231 * e.g. $pb->render('picwall'); 223 * e.g. $pb->render('picwall');
232 * 224 *
@@ -234,13 +226,13 @@ class PageBuilder
234 * 226 *
235 * @return string Processed template content 227 * @return string Processed template content
236 */ 228 */
237 public function render(string $page): string 229 public function render(string $page, string $basePath): string
238 { 230 {
239 if ($this->tpl === false) { 231 if ($this->tpl === false) {
240 $this->initialize(); 232 $this->initialize();
241 } 233 }
242 234
243 $this->finalize(); 235 $this->finalize($basePath);
244 236
245 return $this->tpl->draw($page, true); 237 return $this->tpl->draw($page, true);
246 } 238 }
diff --git a/plugins/addlink_toolbar/addlink_toolbar.php b/plugins/addlink_toolbar/addlink_toolbar.php
index c3e7abaf..ab6ed6de 100644
--- a/plugins/addlink_toolbar/addlink_toolbar.php
+++ b/plugins/addlink_toolbar/addlink_toolbar.php
@@ -20,7 +20,7 @@ function hook_addlink_toolbar_render_header($data)
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..f26e6129 100644
--- a/plugins/archiveorg/archiveorg.php
+++ b/plugins/archiveorg/archiveorg.php
@@ -17,12 +17,13 @@ use Shaarli\Plugin\PluginManager;
17function hook_archiveorg_render_linklist($data) 17function 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 if ($value['private'] && preg_match('/^\?[a-zA-Z0-9-_@]{6}($|&|#)/', $value['real_url'])) {
23 continue; 24 continue;
24 } 25 }
25 $archive = sprintf($archive_html, $value['url'], t('View on archive.org')); 26 $archive = sprintf($archive_html, $value['url'], $path, t('View on archive.org'));
26 $value['link_plugin'][] = $archive; 27 $value['link_plugin'][] = $archive;
27 } 28 }
28 29
diff --git a/plugins/demo_plugin/demo_plugin.php b/plugins/demo_plugin/demo_plugin.php
index dd73d6a2..defb01f7 100644
--- a/plugins/demo_plugin/demo_plugin.php
+++ b/plugins/demo_plugin/demo_plugin.php
@@ -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(
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/qrcode/qrcode.php b/plugins/qrcode/qrcode.php
index 2ec0cb65..3b5dae34 100644
--- a/plugins/qrcode/qrcode.php
+++ b/plugins/qrcode/qrcode.php
@@ -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 }
@@ -41,7 +42,7 @@ function hook_qrcode_render_linklist($data)
41function hook_qrcode_render_footer($data) 42function hook_qrcode_render_footer($data)
42{ 43{
43 if ($data['_PAGE_'] == TemplatePage::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
47 return $data; 48 return $data;
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).
30function showQrCode(caller,loading) 30function 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/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;
diff --git a/tests/config/ConfigPluginTest.php b/tests/config/ConfigPluginTest.php
index d7a70e68..b2cc0045 100644
--- a/tests/config/ConfigPluginTest.php
+++ b/tests/config/ConfigPluginTest.php
@@ -2,6 +2,7 @@
2namespace Shaarli\Config; 2namespace Shaarli\Config;
3 3
4use Shaarli\Config\Exception\PluginConfigOrderException; 4use Shaarli\Config\Exception\PluginConfigOrderException;
5use Shaarli\Plugin\PluginManager;
5 6
6require_once 'application/config/ConfigPlugin.php'; 7require_once 'application/config/ConfigPlugin.php';
7 8
@@ -17,23 +18,30 @@ class ConfigPluginTest extends \PHPUnit\Framework\TestCase
17 */ 18 */
18 public function testSavePluginConfigValid() 19 public function testSavePluginConfigValid()
19 { 20 {
20 $data = array( 21 $data = [
21 'order_plugin1' => 2, // no plugin related 22 'order_plugin1' => 2, // no plugin related
22 'plugin2' => 0, // new - at the end 23 'plugin2' => 0, // new - at the end
23 'plugin3' => 0, // 2nd 24 'plugin3' => 0, // 2nd
24 'order_plugin3' => 8, 25 'order_plugin3' => 8,
25 'plugin4' => 0, // 1st 26 'plugin4' => 0, // 1st
26 'order_plugin4' => 5, 27 'order_plugin4' => 5,
27 ); 28 ];
28 29
29 $expected = array( 30 $expected = [
30 'plugin3', 31 'plugin3',
31 'plugin4', 32 'plugin4',
32 'plugin2', 33 'plugin2',
33 ); 34 ];
35
36 mkdir($path = __DIR__ . '/folder');
37 PluginManager::$PLUGINS_PATH = $path;
38 array_map(function (string $plugin) use ($path) { touch($path . '/' . $plugin); }, $expected);
34 39
35 $out = save_plugin_config($data); 40 $out = save_plugin_config($data);
36 $this->assertEquals($expected, $out); 41 $this->assertEquals($expected, $out);
42
43 array_map(function (string $plugin) use ($path) { unlink($path . '/' . $plugin); }, $expected);
44 rmdir($path);
37 } 45 }
38 46
39 /** 47 /**
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php b/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php
index caaf549d..dee622bb 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php
+++ b/tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php
@@ -59,8 +59,12 @@ class DeleteBookmarkTest extends TestCase
59 ->with('raw') 59 ->with('raw')
60 ->willReturnCallback(function () use ($bookmark): BookmarkFormatter { 60 ->willReturnCallback(function () use ($bookmark): BookmarkFormatter {
61 $formatter = $this->createMock(BookmarkFormatter::class); 61 $formatter = $this->createMock(BookmarkFormatter::class);
62 62 $formatter
63 $formatter->expects(static::once())->method('format')->with($bookmark); 63 ->expects(static::once())
64 ->method('format')
65 ->with($bookmark)
66 ->willReturn(['formatted' => $bookmark])
67 ;
64 68
65 return $formatter; 69 return $formatter;
66 }) 70 })
@@ -70,7 +74,7 @@ class DeleteBookmarkTest extends TestCase
70 $this->container->pluginManager 74 $this->container->pluginManager
71 ->expects(static::once()) 75 ->expects(static::once())
72 ->method('executeHooks') 76 ->method('executeHooks')
73 ->with('delete_link') 77 ->with('delete_link', ['formatted' => $bookmark])
74 ; 78 ;
75 79
76 $result = $this->controller->deleteBookmark($request, $response); 80 $result = $this->controller->deleteBookmark($request, $response);
@@ -129,6 +133,9 @@ class DeleteBookmarkTest extends TestCase
129 ->withConsecutive(...array_map(function (Bookmark $bookmark): array { 133 ->withConsecutive(...array_map(function (Bookmark $bookmark): array {
130 return [$bookmark]; 134 return [$bookmark];
131 }, $bookmarks)) 135 }, $bookmarks))
136 ->willReturnOnConsecutiveCalls(...array_map(function (Bookmark $bookmark): array {
137 return ['formatted' => $bookmark];
138 }, $bookmarks))
132 ; 139 ;
133 140
134 return $formatter; 141 return $formatter;
@@ -254,6 +261,9 @@ class DeleteBookmarkTest extends TestCase
254 ->withConsecutive(...array_map(function (Bookmark $bookmark): array { 261 ->withConsecutive(...array_map(function (Bookmark $bookmark): array {
255 return [$bookmark]; 262 return [$bookmark];
256 }, $bookmarks)) 263 }, $bookmarks))
264 ->willReturnOnConsecutiveCalls(...array_map(function (Bookmark $bookmark): array {
265 return ['formatted' => $bookmark];
266 }, $bookmarks))
257 ; 267 ;
258 268
259 return $formatter; 269 return $formatter;
@@ -350,7 +360,12 @@ class DeleteBookmarkTest extends TestCase
350 $this->container->formatterFactory 360 $this->container->formatterFactory
351 ->expects(static::once()) 361 ->expects(static::once())
352 ->method('getFormatter') 362 ->method('getFormatter')
353 ->willReturn($this->createMock(BookmarkFormatter::class)) 363 ->willReturnCallback(function (): BookmarkFormatter {
364 $formatter = $this->createMock(BookmarkFormatter::class);
365 $formatter->method('format')->willReturn(['formatted']);
366
367 return $formatter;
368 })
354 ; 369 ;
355 370
356 $result = $this->controller->deleteBookmark($request, $response); 371 $result = $this->controller->deleteBookmark($request, $response);
diff --git a/tests/front/controller/admin/PluginsControllerTest.php b/tests/front/controller/admin/PluginsControllerTest.php
index ad0cda70..5b59285c 100644
--- a/tests/front/controller/admin/PluginsControllerTest.php
+++ b/tests/front/controller/admin/PluginsControllerTest.php
@@ -7,6 +7,7 @@ namespace Shaarli\Front\Controller\Admin;
7use PHPUnit\Framework\TestCase; 7use PHPUnit\Framework\TestCase;
8use Shaarli\Config\ConfigManager; 8use Shaarli\Config\ConfigManager;
9use Shaarli\Front\Exception\WrongTokenException; 9use Shaarli\Front\Exception\WrongTokenException;
10use Shaarli\Plugin\PluginManager;
10use Shaarli\Security\SessionManager; 11use Shaarli\Security\SessionManager;
11use Slim\Http\Request; 12use Slim\Http\Request;
12use Slim\Http\Response; 13use Slim\Http\Response;
@@ -15,6 +16,8 @@ class PluginsControllerTest extends TestCase
15{ 16{
16 use FrontAdminControllerMockHelper; 17 use FrontAdminControllerMockHelper;
17 18
19 const PLUGIN_NAMES = ['plugin1', 'plugin2', 'plugin3', 'plugin4'];
20
18 /** @var PluginsController */ 21 /** @var PluginsController */
19 protected $controller; 22 protected $controller;
20 23
@@ -23,6 +26,17 @@ class PluginsControllerTest extends TestCase
23 $this->createContainer(); 26 $this->createContainer();
24 27
25 $this->controller = new PluginsController($this->container); 28 $this->controller = new PluginsController($this->container);
29
30 mkdir($path = __DIR__ . '/folder');
31 PluginManager::$PLUGINS_PATH = $path;
32 array_map(function (string $plugin) use ($path) { touch($path . '/' . $plugin); }, static::PLUGIN_NAMES);
33 }
34
35 public function tearDown()
36 {
37 $path = __DIR__ . '/folder';
38 array_map(function (string $plugin) use ($path) { unlink($path . '/' . $plugin); }, static::PLUGIN_NAMES);
39 rmdir($path);
26 } 40 }
27 41
28 /** 42 /**
diff --git a/tests/front/controller/admin/SessionFilterControllerTest.php b/tests/front/controller/admin/SessionFilterControllerTest.php
index 124b0bf2..7d5511ed 100644
--- a/tests/front/controller/admin/SessionFilterControllerTest.php
+++ b/tests/front/controller/admin/SessionFilterControllerTest.php
@@ -23,7 +23,7 @@ class SessionFilterControllerTest extends TestCase
23 23
24 $this->controller = new SessionFilterController($this->container); 24 $this->controller = new SessionFilterController($this->container);
25 } 25 }
26 26
27 /** 27 /**
28 * Visibility - Default call for private filter while logged in without current value 28 * Visibility - Default call for private filter while logged in without current value
29 */ 29 */
diff --git a/tests/front/controller/visitor/ShaarliVisitorControllerTest.php b/tests/front/controller/visitor/ShaarliVisitorControllerTest.php
index 83d08358..316ce49c 100644
--- a/tests/front/controller/visitor/ShaarliVisitorControllerTest.php
+++ b/tests/front/controller/visitor/ShaarliVisitorControllerTest.php
@@ -96,8 +96,6 @@ class ShaarliVisitorControllerTest extends TestCase
96 static::assertSame(10, $this->assignedValues['linkcount']); 96 static::assertSame(10, $this->assignedValues['linkcount']);
97 static::assertSame(5, $this->assignedValues['privateLinkcount']); 97 static::assertSame(5, $this->assignedValues['privateLinkcount']);
98 static::assertSame(['error'], $this->assignedValues['plugin_errors']); 98 static::assertSame(['error'], $this->assignedValues['plugin_errors']);
99 static::assertSame('/subfolder', $this->assignedValues['base_path']);
100 static::assertSame('/subfolder/tpl/default', $this->assignedValues['asset_path']);
101 99
102 static::assertSame('templateName', $this->assignedValues['plugins_includes']['render_includes']['target']); 100 static::assertSame('templateName', $this->assignedValues['plugins_includes']['render_includes']['target']);
103 static::assertTrue($this->assignedValues['plugins_includes']['render_includes']['loggedin']); 101 static::assertTrue($this->assignedValues['plugins_includes']['render_includes']['loggedin']);
diff --git a/tests/plugins/PluginAddlinkTest.php b/tests/plugins/PluginAddlinkTest.php
index 4018c1a8..aa5c6988 100644
--- a/tests/plugins/PluginAddlinkTest.php
+++ b/tests/plugins/PluginAddlinkTest.php
@@ -28,6 +28,7 @@ class PluginAddlinkTest extends \PHPUnit\Framework\TestCase
28 $data = array($str => $str); 28 $data = array($str => $str);
29 $data['_PAGE_'] = TemplatePage::LINKLIST; 29 $data['_PAGE_'] = TemplatePage::LINKLIST;
30 $data['_LOGGEDIN_'] = true; 30 $data['_LOGGEDIN_'] = true;
31 $data['_BASE_PATH_'] = '/subfolder';
31 32
32 $data = hook_addlink_toolbar_render_header($data); 33 $data = hook_addlink_toolbar_render_header($data);
33 $this->assertEquals($str, $data[$str]); 34 $this->assertEquals($str, $data[$str]);
@@ -36,6 +37,8 @@ class PluginAddlinkTest extends \PHPUnit\Framework\TestCase
36 $data = array($str => $str); 37 $data = array($str => $str);
37 $data['_PAGE_'] = $str; 38 $data['_PAGE_'] = $str;
38 $data['_LOGGEDIN_'] = true; 39 $data['_LOGGEDIN_'] = true;
40 $data['_BASE_PATH_'] = '/subfolder';
41
39 $data = hook_addlink_toolbar_render_header($data); 42 $data = hook_addlink_toolbar_render_header($data);
40 $this->assertEquals($str, $data[$str]); 43 $this->assertEquals($str, $data[$str]);
41 $this->assertArrayNotHasKey('fields_toolbar', $data); 44 $this->assertArrayNotHasKey('fields_toolbar', $data);
@@ -50,6 +53,7 @@ class PluginAddlinkTest extends \PHPUnit\Framework\TestCase
50 $data = array($str => $str); 53 $data = array($str => $str);
51 $data['_PAGE_'] = TemplatePage::LINKLIST; 54 $data['_PAGE_'] = TemplatePage::LINKLIST;
52 $data['_LOGGEDIN_'] = false; 55 $data['_LOGGEDIN_'] = false;
56 $data['_BASE_PATH_'] = '/subfolder';
53 57
54 $data = hook_addlink_toolbar_render_header($data); 58 $data = hook_addlink_toolbar_render_header($data);
55 $this->assertEquals($str, $data[$str]); 59 $this->assertEquals($str, $data[$str]);
diff --git a/tpl/vintage/changepassword.html b/tpl/vintage/changepassword.html
index c40daf9d..7e37b9a3 100644
--- a/tpl/vintage/changepassword.html
+++ b/tpl/vintage/changepassword.html
@@ -4,7 +4,7 @@
4<body onload="document.changepasswordform.oldpassword.focus();"> 4<body onload="document.changepasswordform.oldpassword.focus();">
5<div id="pageheader"> 5<div id="pageheader">
6 {include="page.header"} 6 {include="page.header"}
7 <form method="POST" action="#" name="changepasswordform" id="changepasswordform"> 7 <form method="POST" action="{$base_path}/admin/password" name="changepasswordform" id="changepasswordform">
8 Old password: <input type="password" name="oldpassword">&nbsp; &nbsp; 8 Old password: <input type="password" name="oldpassword">&nbsp; &nbsp;
9 New password: <input type="password" name="setpassword"> 9 New password: <input type="password" name="setpassword">
10 <input type="hidden" name="token" value="{$token}"> 10 <input type="hidden" name="token" value="{$token}">
@@ -12,4 +12,4 @@
12</div> 12</div>
13{include="page.footer"} 13{include="page.footer"}
14</body> 14</body>
15</html> \ No newline at end of file 15</html>
diff --git a/tpl/vintage/changetag.html b/tpl/vintage/changetag.html
index 670a8dd7..6ef60252 100644
--- a/tpl/vintage/changetag.html
+++ b/tpl/vintage/changetag.html
@@ -5,7 +5,7 @@
5<body onload="document.changetag.fromtag.focus();"> 5<body onload="document.changetag.fromtag.focus();">
6<div id="pageheader"> 6<div id="pageheader">
7 {include="page.header"} 7 {include="page.header"}
8 <form method="POST" action="" name="changetag" id="changetag"> 8 <form method="POST" action="{$base_path}/admin/tags" name="changetag" id="changetag">
9 <input type="hidden" name="token" value="{$token}"> 9 <input type="hidden" name="token" value="{$token}">
10 <div> 10 <div>
11 <label for="fromtag">Tag:</label> 11 <label for="fromtag">Tag:</label>
diff --git a/tpl/vintage/configure.html b/tpl/vintage/configure.html
index c5861aae..ba4f3f71 100644
--- a/tpl/vintage/configure.html
+++ b/tpl/vintage/configure.html
@@ -4,7 +4,7 @@
4<body onload="document.configform.title.focus();"> 4<body onload="document.configform.title.focus();">
5<div id="pageheader"> 5<div id="pageheader">
6 {include="page.header"} 6 {include="page.header"}
7 <form method="POST" action="#" name="configform" id="configform"> 7 <form method="POST" action="{$base_path}/admin/configure" name="configform" id="configform">
8 <input type="hidden" name="token" value="{$token}"> 8 <input type="hidden" name="token" value="{$token}">
9 <table id="configuration_table"> 9 <table id="configuration_table">
10 10
diff --git a/tpl/vintage/editlink.html b/tpl/vintage/editlink.html
index ccf8c677..c3671b1f 100644
--- a/tpl/vintage/editlink.html
+++ b/tpl/vintage/editlink.html
@@ -1,7 +1,6 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html>
3<head>{include="includes"} 3<head>{include="includes"}
4 <link type="text/css" rel="stylesheet" href="inc/awesomplete.css#" />
5</head> 4</head>
6<body 5<body
7{if="$link.title==''"}onload="document.linkform.lf_title.focus();" 6{if="$link.title==''"}onload="document.linkform.lf_title.focus();"
@@ -10,9 +9,8 @@
10<div id="pageheader"> 9<div id="pageheader">
11 {include="page.header"} 10 {include="page.header"}
12 <div id="shaarli_title"><a href="{$titleLink}">{$shaarlititle}</a></div> 11 <div id="shaarli_title"><a href="{$titleLink}">{$shaarlititle}</a></div>
13 {/if}
14 <div id="editlinkform"> 12 <div id="editlinkform">
15 <form method="post" name="linkform"> 13 <form method="post" name="linkform" action="{$base_path}/admin/shaare">
16 <input type="hidden" name="lf_linkdate" value="{$link.linkdate}"> 14 <input type="hidden" name="lf_linkdate" value="{$link.linkdate}">
17 {if="isset($link.id)"} 15 {if="isset($link.id)"}
18 <input type="hidden" name="lf_id" value="{$link.id}"> 16 <input type="hidden" name="lf_id" value="{$link.id}">
diff --git a/tpl/vintage/export.html b/tpl/vintage/export.html
index feee307c..c30e3b0a 100644
--- a/tpl/vintage/export.html
+++ b/tpl/vintage/export.html
@@ -10,6 +10,8 @@
10 <input type="radio" name="selection" value="all" checked="true"> All<br> 10 <input type="radio" name="selection" value="all" checked="true"> All<br>
11 <input type="radio" name="selection" value="private"> Private<br> 11 <input type="radio" name="selection" value="private"> Private<br>
12 <input type="radio" name="selection" value="public"> Public<br> 12 <input type="radio" name="selection" value="public"> Public<br>
13 <input type="hidden" name="token" value="{$token}">
14
13 <br> 15 <br>
14 <input type="checkbox" name="prepend_note_url" id="prepend_note_url"> 16 <input type="checkbox" name="prepend_note_url" id="prepend_note_url">
15 <label for="prepend_note_url"> 17 <label for="prepend_note_url">
diff --git a/tpl/vintage/includes.html b/tpl/vintage/includes.html
index aa2381c6..eac05701 100644
--- a/tpl/vintage/includes.html
+++ b/tpl/vintage/includes.html
@@ -6,14 +6,14 @@
6<link rel="alternate" type="application/rss+xml" href="{$feedurl}feed/rss?{$searchcrits}#" title="RSS Feed" /> 6<link rel="alternate" type="application/rss+xml" href="{$feedurl}feed/rss?{$searchcrits}#" title="RSS Feed" />
7<link rel="alternate" type="application/atom+xml" href="{$feedurl}feed/atom?{$searchcrits}#" title="ATOM Feed" /> 7<link rel="alternate" type="application/atom+xml" href="{$feedurl}feed/atom?{$searchcrits}#" title="ATOM Feed" />
8<link href="img/favicon.ico" rel="shortcut icon" type="image/x-icon" /> 8<link href="img/favicon.ico" rel="shortcut icon" type="image/x-icon" />
9<link type="text/css" rel="stylesheet" href="css/shaarli.min.css" /> 9<link type="text/css" rel="stylesheet" href="{$asset_path}/css/shaarli.min.css#" />
10{if="$formatter==='markdown'"} 10{if="$formatter==='markdown'"}
11 <link type="text/css" rel="stylesheet" href="{$asset_path}/css/markdown.min.css?v={$version_hash}#" /> 11 <link type="text/css" rel="stylesheet" href="{$asset_path}/css/markdown.min.css?v={$version_hash}#" />
12{/if} 12{/if}
13{loop="$plugins_includes.css_files"} 13{loop="$plugins_includes.css_files"}
14<link type="text/css" rel="stylesheet" href="{$value}#"/> 14<link type="text/css" rel="stylesheet" href="{$base_path}/{$value}#"/>
15{/loop} 15{/loop}
16{if="is_file('data/user.css')"}<link type="text/css" rel="stylesheet" href="data/user.css#" />{/if} 16{if="is_file('data/user.css')"}<link type="text/css" rel="stylesheet" href="{$base_path}/data/user.css#" />{/if}
17<link rel="search" type="application/opensearchdescription+xml" href="{$base_path}/open-search#" 17<link rel="search" type="application/opensearchdescription+xml" href="{$base_path}/open-search#"
18 title="Shaarli search - {$shaarlititle|htmlspecialchars}" /> 18 title="Shaarli search - {$shaarlititle|htmlspecialchars}" />
19{if="! empty($links) && count($links) === 1"} 19{if="! empty($links) && count($links) === 1"}
diff --git a/tpl/vintage/install.html b/tpl/vintage/install.html
index aca890d6..8c10b2cb 100644
--- a/tpl/vintage/install.html
+++ b/tpl/vintage/install.html
@@ -5,7 +5,7 @@
5<div id="install"> 5<div id="install">
6 <h1>Shaarli</h1> 6 <h1>Shaarli</h1>
7 It looks like it's the first time you run Shaarli. Please configure it:<br> 7 It looks like it's the first time you run Shaarli. Please configure it:<br>
8 <form method="POST" action="#" name="installform" id="installform"> 8 <form method="POST" action="{$base_path}/install" name="installform" id="installform">
9 <table> 9 <table>
10 <tr><td><b>Login:</b></td><td><input type="text" name="setlogin" size="30"></td></tr> 10 <tr><td><b>Login:</b></td><td><input type="text" name="setlogin" size="30"></td></tr>
11 <tr><td><b>Password:</b></td><td><input type="password" name="setpassword" size="30"></td></tr> 11 <tr><td><b>Password:</b></td><td><input type="password" name="setpassword" size="30"></td></tr>
diff --git a/tpl/vintage/linklist.html b/tpl/vintage/linklist.html
index 8db8f70b..00896eb5 100644
--- a/tpl/vintage/linklist.html
+++ b/tpl/vintage/linklist.html
@@ -1,7 +1,6 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html>
3<head> 3<head>
4 <link type="text/css" rel="stylesheet" href="inc/awesomplete.css#" />
5 {include="includes"} 4 {include="includes"}
6</head> 5</head>
7<body> 6<body>
@@ -84,7 +83,7 @@
84 <div class="thumbnail"> 83 <div class="thumbnail">
85 <a href="{$value.real_url}"> 84 <a href="{$value.real_url}">
86 {ignore}RainTPL hack: put the 2 src on two different line to avoid path replace bug{/ignore} 85 {ignore}RainTPL hack: put the 2 src on two different line to avoid path replace bug{/ignore}
87 <img data-src="{$value.thumbnail}#" class="b-lazy" 86 <img data-src="{$base_path}/{$value.thumbnail}#" class="b-lazy"
88 src="" 87 src=""
89 alt="thumbnail" width="{$thumbnails_width}" height="{$thumbnails_height}" /> 88 alt="thumbnail" width="{$thumbnails_width}" height="{$thumbnails_height}" />
90 </a> 89 </a>
@@ -93,17 +92,16 @@
93 <div class="linkcontainer"> 92 <div class="linkcontainer">
94 {if="$is_logged_in"} 93 {if="$is_logged_in"}
95 <div class="linkeditbuttons"> 94 <div class="linkeditbuttons">
96 <form method="GET" class="buttoneditform"> 95 <a href="{$base_path}/admin/shaare/{$value.id}" title="Edit" class="button_edit">
97 <input type="hidden" name="edit_link" value="{$value.id}"> 96 <img src="{$asset_path}/img/edit_icon.png#">
98 <input type="image" alt="Edit" src="{$asset_path}/img/edit_icon.png#" title="Edit" class="button_edit"> 97 </a>
99 </form><br> 98 <br>
100 <form method="GET" class="buttoneditform"> 99 <a href="{$base_path}/admin/shaare/delete?id={$value.id}&amp;token={$token}" label="Delete"
101 <input type="hidden" name="lf_linkdate" value="{$value.id}"> 100 onClick="return confirmDeleteLink();"
102 <input type="hidden" name="token" value="{$token}"> 101 class="button_delete"
103 <input type="hidden" name="delete_link"> 102 >
104 <input type="image" alt="Delete" src="{$asset_path}/img/delete_icon.png#" title="Delete" 103 <img src="{$asset_path}/img/delete_icon.png#">
105 class="button_delete" onClick="return confirmDeleteLink();"> 104 </a>
106 </form>
107 </div> 105 </div>
108 {/if} 106 {/if}
109 <span class="linktitle"> 107 <span class="linktitle">
@@ -114,7 +112,7 @@
114 {if="!$hide_timestamps || $is_logged_in"} 112 {if="!$hide_timestamps || $is_logged_in"}
115 {$updated=$value.updated_timestamp ? 'Edited: '. format_date($value.updated) : 'Permalink'} 113 {$updated=$value.updated_timestamp ? 'Edited: '. format_date($value.updated) : 'Permalink'}
116 <span class="linkdate" title="Permalink"> 114 <span class="linkdate" title="Permalink">
117 <a href="{$base_path}/?{$value.shorturl}"> 115 <a href="{$base_path}/shaare/{$value.shorturl}">
118 <span title="{$updated}"> 116 <span title="{$updated}">
119 {$value.created|format_date} 117 {$value.created|format_date}
120 {if="$value.updated_timestamp"}*{/if} 118 {if="$value.updated_timestamp"}*{/if}
@@ -123,7 +121,7 @@
123 </a> - 121 </a> -
124 </span> 122 </span>
125 {else} 123 {else}
126 <span class="linkdate" title="Short link here"><a href="{$base_path}/?{$value.shorturl}">permalink</a> - </span> 124 <span class="linkdate" title="Short link here"><a href="{$base_path}/shaare/{$value.shorturl}">permalink</a> - </span>
127 {/if} 125 {/if}
128 126
129 {loop="$value.link_plugin"} 127 {loop="$value.link_plugin"}
diff --git a/tpl/vintage/loginform.html b/tpl/vintage/loginform.html
index a3792066..6aa20ab1 100644
--- a/tpl/vintage/loginform.html
+++ b/tpl/vintage/loginform.html
@@ -11,7 +11,7 @@
11 {include="page.header"} 11 {include="page.header"}
12 12
13 <div id="headerform"> 13 <div id="headerform">
14 <form method="post" name="loginform"> 14 <form method="post" name="loginform" action="{$base_path}/login">
15 <label for="login">Login: <input type="text" id="login" name="login" tabindex="1" 15 <label for="login">Login: <input type="text" id="login" name="login" tabindex="1"
16 {if="!empty($username)"}value="{$username}"{/if}> 16 {if="!empty($username)"}value="{$username}"{/if}>
17 </label> 17 </label>
diff --git a/tpl/vintage/page.footer.html b/tpl/vintage/page.footer.html
index 6d9021e3..0fe4c736 100644
--- a/tpl/vintage/page.footer.html
+++ b/tpl/vintage/page.footer.html
@@ -30,5 +30,7 @@
30{/if} 30{/if}
31 31
32{loop="$plugins_footer.js_files"} 32{loop="$plugins_footer.js_files"}
33 <script src="{$value}#"></script> 33 <script src="{$base_path}/{$value}#"></script>
34{/loop} 34{/loop}
35
36<input type="hidden" name="js_base_path" value="{$base_path}" />
diff --git a/tpl/vintage/pluginsadmin.html b/tpl/vintage/pluginsadmin.html
index a04c77c2..d0972cd1 100644
--- a/tpl/vintage/pluginsadmin.html
+++ b/tpl/vintage/pluginsadmin.html
@@ -86,6 +86,7 @@
86 <input type="submit" value="Save"/> 86 <input type="submit" value="Save"/>
87 </div> 87 </div>
88 </section> 88 </section>
89 <input type="hidden" name="token" value="{$token}">
89 </form> 90 </form>
90 91
91 <form action="{$base_path}/admin/plugins" method="POST"> 92 <form action="{$base_path}/admin/plugins" method="POST">
@@ -124,6 +125,7 @@
124 </div> 125 </div>
125 </div> 126 </div>
126 </section> 127 </section>
128 <input type="hidden" name="token" value="{$token}">
127 </form> 129 </form>
128 130
129</div> 131</div>
diff --git a/tpl/vintage/thumbnails.html b/tpl/vintage/thumbnails.html
index a1537f9c..18f296f7 100644
--- a/tpl/vintage/thumbnails.html
+++ b/tpl/vintage/thumbnails.html
@@ -23,7 +23,6 @@
23<input type="hidden" name="ids" value="{function="implode(',', $ids)"}" /> 23<input type="hidden" name="ids" value="{function="implode(',', $ids)"}" />
24 24
25{include="page.footer"} 25{include="page.footer"}
26<input type="hidden" name="js_base_path" value="{$base_path}" />
27<script src="{$asset_path}/js/thumbnails_update.min.js?v={$version_hash}#"></script> 26<script src="{$asset_path}/js/thumbnails_update.min.js?v={$version_hash}#"></script>
28</body> 27</body>
29</html> 28</html>