diff --git a/.dev/.sasslintrc b/.dev/.sasslintrc index ac406d7..47c3145 100644 --- a/.dev/.sasslintrc +++ b/.dev/.sasslintrc @@ -2,9 +2,11 @@ options: max-warnings: 0 rules: property-sort-order: - - 1 - - - order: 'concentric' + - 0 +# Sort order rule does not work with CSS variables: https://github.com/sasstools/sass-lint/issues/1161 +# - 1 +# - +# order: 'concentric' no-important: - 0 no-vendor-prefixes: diff --git a/.gitignore b/.gitignore index c54d9b6..b21d211 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ phpdoc.xml # User plugin configuration plugins/*/config.php +plugins/default_colors/default_colors.css # HTML documentation doc/html/ diff --git a/assets/default/scss/shaarli.scss b/assets/default/scss/shaarli.scss index 9e5464a..1d89f99 100644 --- a/assets/default/scss/shaarli.scss +++ b/assets/default/scss/shaarli.scss @@ -25,9 +25,15 @@ $warning-text: #97600d; $form-input-border: #d8d8d8; $form-input-background: #eee; +:root { + --main-color: #{$main-green}; + --background-color: #{$background-color}; + --dark-main-color: #{$dark-green}; +} + // General body { - background: $background-color; + background: var(--background-color); } .strong { @@ -143,7 +149,7 @@ body, } .pure-alert-success { - background-color: $main-green; + background-color: var(--main-color); } .pure-alert-warning { @@ -169,7 +175,7 @@ body, top: 0; transition: max-height .5s; z-index: 999; - background: $main-green; + background: var(--main-color); width: 100%; // Hack to transition with auto height: http://stackoverflow.com/a/8331169/1484919 max-height: 45px; @@ -322,7 +328,7 @@ body, button { border: 0; border-radius: 2px; - background-color: $main-green; + background-color: var(--main-color); padding: 4px 8px 6px; color: $almost-white; } @@ -358,7 +364,7 @@ body, .search-tagcloud { button { &:hover { - color: $background-color; + color: var(--background-color); } } } @@ -389,7 +395,7 @@ body, position: fixed; visibility: hidden; z-index: 999; - background: $main-green; + background: var(--main-color); padding: 5px 0; width: 100%; height: 30px; @@ -411,7 +417,7 @@ body, margin: 0 0 5px; border: 1px solid $almost-white; border-radius: 2px; - background: $main-green; + background: var(--main-color); padding: 4px 0; width: 100px; height: 28px; @@ -419,7 +425,7 @@ body, &:hover { background: $almost-white; - color: $main-green; + color: var(--main-color); } } @@ -558,7 +564,7 @@ body, } .filter-on { - background: $main-green; + background: var(--main-color); color: $light-green; } @@ -697,7 +703,7 @@ body, &:visited { .linklist-link { - color: $dark-green; + color: var(--dark-main-color); } } @@ -708,7 +714,7 @@ body, } .linklist-link { - color: $main-green; + color: var(--main-color); font-size: 1.1em; &:hover { @@ -783,14 +789,14 @@ body, a { text-decoration: none; - color: $main-green; + color: var(--main-color); &:hover { color: $dark-grey; } &:visited { - color: $dark-green; + color: var(--dark-main-color); } } } @@ -888,7 +894,7 @@ body, &::before { display: block; margin: 10px auto; - background: linear-gradient(to right, $background-color, $dark-grey, $background-color); + background: linear-gradient(to right, var(--background-color), $dark-grey, var(--background-color)); width: 80%; height: 1px; content: ''; @@ -917,7 +923,7 @@ body, margin: 15px 5px; border: 0; box-shadow: 1px 1px 1px $form-input-border, -1px -1px 6px $form-input-border, -1px 1px 2px $form-input-border, 1px -1px 2px $form-input-border; - background: $main-green; + background: var(--main-color); min-width: 150px; height: 35px; vertical-align: center; @@ -941,7 +947,7 @@ body, padding: 10px 0; width: 100%; text-align: center; - color: $main-green; + color: var(--main-color); } .window-subtitle { @@ -950,7 +956,7 @@ body, a { text-decoration: none; - color: $main-green; + color: var(--main-color); font-weight: bold; &.button { @@ -1278,7 +1284,7 @@ form { .pure-button { &:hover { - background-color: $main-green; + background-color: var(--main-color); background-image: none; color: $almost-white; } @@ -1362,7 +1368,7 @@ form { } .validate-rename-tag { - color: $main-green; + color: var(--main-color); } } @@ -1458,7 +1464,7 @@ form { &::after { display: block; margin: 10px auto; - background: linear-gradient(to right, $background-color, $dark-grey, $background-color); + background: linear-gradient(to right, var(--background-color), $dark-grey, var(--background-color)); width: 90%; height: 1px; content: ''; @@ -1508,14 +1514,14 @@ form { .daily-entry-description { a { text-decoration: none; - color: $main-green; + color: var(--main-color); &:hover { text-shadow: 1px 1px $background-linklist-info; } &:visited { - color: $dark-green; + color: var(--dark-main-color); } } } @@ -1572,12 +1578,12 @@ form { } .pure-button-shaarli { - background-color: $main-green; + background-color: var(--main-color); } .progressbar { border-radius: 6px; - background-color: $main-green; + background-color: var(--main-color); padding: 1px; > div { @@ -1586,8 +1592,8 @@ form { -45deg, $almost-white, $almost-white 6px, - $background-color 6px, - $background-color 12px + var(--background-color) 6px, + var(--background-color) 12px ); width: 0%; height: 10px; diff --git a/doc/md/Plugin-System.md b/doc/md/Plugin-System.md index cbec04c..9b0d3a7 100644 --- a/doc/md/Plugin-System.md +++ b/doc/md/Plugin-System.md @@ -137,6 +137,7 @@ If it's still not working, please [open an issue](https://github.com/shaarli/Sha | [render_feed](#render_feed) | Allow to do add tags in RSS and ATOM feeds. | | [save_link](#save_link) | Allow to alter the link being saved in the datastore. | | [delete_link](#delete_link) | Allow to do an action before a link is deleted from the datastore. | +| [save_plugin_parameters](#save_plugin_parameters) | Allow to manipulate plugin parameters before they're saved. | @@ -471,6 +472,22 @@ Allow to execute any action before the link is actually removed from the datasto - created - updated + +#### save_plugin_parameters + +Triggered when the plugin parameters are saved from the plugin administration page. + +Plugins can perform an action every times their settings are updated. +For example it is used to update the CSS file of the `default_colors` plugins. + +##### Data + +`$data` input contains the `$_POST` array. + +So if the plugin has a parameter called `MYPLUGIN_PARAMETER`, +the array will contain an entry with `MYPLUGIN_PARAMETER` as a key. + + ## Guide for template designer ### Plugin administration diff --git a/doc/md/Plugins.md b/doc/md/Plugins.md index 954442e..3e26181 100644 --- a/doc/md/Plugins.md +++ b/doc/md/Plugins.md @@ -63,8 +63,12 @@ Usage of each plugin is documented in it's README file: * `addlink-toolbar`: Adds the addlink input on the linklist page * `archiveorg`: For each link, add an Archive.org icon + * `default_colors`: Override default theme colors. + * `isso`: Let visitor comment your shaares on permalinks with Isso. * [`markdown`](https://github.com/shaarli/Shaarli/blob/master/plugins/markdown/README.md): Render shaare description with Markdown syntax. + * `piwik`: A plugin that adds Piwik tracking code to Shaarli pages. * [`playvideos`](https://github.com/shaarli/Shaarli/blob/master/plugins/playvideos/README.md): Add a button in the toolbar allowing to watch all videos. + * `pubsubhubbub`: Enable PubSubHubbub feed publishing * `qrcode`: For each link, add a QRCode icon. * [`wallabag`](https://github.com/shaarli/Shaarli/blob/master/plugins/wallabag/README.md): For each link, add a Wallabag icon to save it in your instance. diff --git a/inc/languages/fr/LC_MESSAGES/shaarli.po b/inc/languages/fr/LC_MESSAGES/shaarli.po index 611296f..026d010 100644 --- a/inc/languages/fr/LC_MESSAGES/shaarli.po +++ b/inc/languages/fr/LC_MESSAGES/shaarli.po @@ -1,8 +1,8 @@ msgid "" msgstr "" "Project-Id-Version: Shaarli\n" -"POT-Creation-Date: 2019-07-06 12:14+0200\n" -"PO-Revision-Date: 2019-07-06 12:17+0200\n" +"POT-Creation-Date: 2019-07-13 10:45+0200\n" +"PO-Revision-Date: 2019-07-13 10:49+0200\n" "Last-Translator: \n" "Language-Team: Shaarli\n" "Language: fr_FR\n" @@ -403,7 +403,7 @@ msgstr "Note : " #: index.php:1424 msgid "Invalid link ID provided" -msgstr "" +msgstr "ID du lien non valide" #: index.php:1444 tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:65 msgid "Export" @@ -428,15 +428,15 @@ msgstr "" msgid "Plugin administration" msgstr "Administration des plugins" -#: index.php:1615 tmp/thumbnails.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 +#: index.php:1616 tmp/thumbnails.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 msgid "Thumbnails update" msgstr "Mise à jour des miniatures" -#: index.php:1781 +#: index.php:1782 msgid "Search: " msgstr "Recherche : " -#: index.php:1824 +#: index.php:1825 #, php-format msgid "" "
Sessions do not seem to work correctly on your server.
Make sure the " @@ -455,7 +455,7 @@ msgstr "" "des cookies. Nous vous recommandons d'accéder à votre serveur depuis son " "adresse IP ou un Fully Qualified Domain Name.
" -#: index.php:1834 +#: index.php:1835 msgid "Click to try again." msgstr "Cliquer ici pour réessayer." @@ -480,7 +480,33 @@ msgstr "Voir sur archive.org" msgid "For each link, add an Archive.org icon." msgstr "Pour chaque lien, ajoute une icône pour Archive.org." -#: plugins/demo_plugin/demo_plugin.php:465 +#: plugins/default_colors/default_colors.php:33 +msgid "" +"Default colors plugin error: This plugin is active and no custom color is " +"configured." +msgstr "" +"Erreur du plugin default colors : ce plugin est actif et aucune couleur " +"n'est configurée." + +#: plugins/default_colors/default_colors.php:107 +msgid "Override default theme colors. Use any CSS valid color." +msgstr "" +"Remplacer les couleurs du thème par défaut. Utiliser n'importe quelle " +"couleur CSS valide." + +#: plugins/default_colors/default_colors.php:108 +msgid "Main color (navbar green)" +msgstr "Couleur principale (vert de la barre de navigation)" + +#: plugins/default_colors/default_colors.php:109 +msgid "Background color (light grey)" +msgstr "Couleur de fond (gris léger)" + +#: plugins/default_colors/default_colors.php:110 +msgid "Dark main color (e.g. visited links)" +msgstr "Couleur principale sombre (ex : les liens visités)" + +#: plugins/demo_plugin/demo_plugin.php:482 msgid "" "A demo plugin covering all use cases for template designers and plugin " "developers." @@ -488,6 +514,14 @@ msgstr "" "Une extension de démonstration couvrant tous les cas d'utilisation pour les " "designers de thèmes et les développeurs d'extensions." +#: plugins/demo_plugin/demo_plugin.php:483 +msgid "This is a parameter dedicated to the demo plugin. It'll be suffixed." +msgstr "Ceci est un paramètre dédié au plugin de démo. Il sera suffixé." + +#: plugins/demo_plugin/demo_plugin.php:484 +msgid "Other demo parameter" +msgstr "Un autre paramètre de démo" + #: plugins/isso/isso.php:22 msgid "" "Isso plugin error: Please define the \"ISSO_SERVER\" setting in the plugin " @@ -703,9 +737,8 @@ msgstr "" "miniatures." #: tmp/configure.90100d2eaf5d3705e14b9b4f78ecddc9.rtpl.php:162 -#| msgid "Enable thumbnails" msgid "Synchonize thumbnails" -msgstr "" +msgstr "Synchroniser les miniatures" #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29 msgid "title" diff --git a/index.php b/index.php index 957d8d9..f0f71db 100644 --- a/index.php +++ b/index.php @@ -1567,6 +1567,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, if ($targetPage == Router::$PAGE_SAVE_PLUGINSADMIN) { try { if (isset($_POST['parameters_form'])) { + $pluginManager->executeHooks('save_plugin_parameters', $_POST); unset($_POST['parameters_form']); foreach ($_POST as $param => $value) { $conf->set('plugins.'. $param, escape($value)); diff --git a/plugins/default_colors/default_colors.css.template b/plugins/default_colors/default_colors.css.template new file mode 100644 index 0000000..87e22a0 --- /dev/null +++ b/plugins/default_colors/default_colors.css.template @@ -0,0 +1,3 @@ +:root { +%s +} diff --git a/plugins/default_colors/default_colors.meta b/plugins/default_colors/default_colors.meta new file mode 100644 index 0000000..108962c --- /dev/null +++ b/plugins/default_colors/default_colors.meta @@ -0,0 +1,5 @@ +description="Override default theme colors. Use any CSS valid color." +parameters="DEFAULT_COLORS_MAIN;DEFAULT_COLORS_BACKGROUND;DEFAULT_COLORS_DARK_MAIN" +parameter.DEFAULT_COLORS_MAIN="Main color (navbar green)" +parameter.DEFAULT_COLORS_BACKGROUND="Background color (light grey)" +parameter.DEFAULT_COLORS_DARK_MAIN="Dark main color (e.g. visited links)" diff --git a/plugins/default_colors/default_colors.php b/plugins/default_colors/default_colors.php new file mode 100644 index 0000000..1928cc9 --- /dev/null +++ b/plugins/default_colors/default_colors.php @@ -0,0 +1,111 @@ +get('plugins.'. $placeholder, '')); + } + + if (empty($params)) { + $error = t('Default colors plugin error: '. + 'This plugin is active and no custom color is configured.'); + return array($error); + } +} + +/** + * When plugin parameters are saved, we regenerate the custom CSS file with provided settings. + * + * @param array $data $_POST array + * + * @return array Updated $_POST array + */ +function hook_default_colors_save_plugin_parameters($data) +{ + $file = PluginManager::$PLUGINS_PATH . '/default_colors/default_colors.css'; + $template = file_get_contents(PluginManager::$PLUGINS_PATH . '/default_colors/default_colors.css.template'); + $content = ''; + foreach (DEFAULT_COLORS_PLACEHOLDERS as $rule) { + $content .= ! empty($data[$rule]) + ? default_colors_format_css_rule($data, $rule) .';'. PHP_EOL + : ''; + } + + if (! empty($content)) { + file_put_contents($file, sprintf($template, $content)); + } + + return $data; +} + +/** + * When linklist is displayed, include default_colors CSS file. + * + * @param array $data - header data. + * + * @return mixed - header data with default_colors CSS file added. + */ +function hook_default_colors_render_includes($data) +{ + $file = PluginManager::$PLUGINS_PATH . '/default_colors/default_colors.css'; + if (file_exists($file )) { + $data['css_files'][] = $file ; + } + + return $data; +} + +/** + * Create a valid CSS rule from parameters settings and plugin parameter. + * + * @param array $data $_POST array + * @param string $parameter Plugin parameter name + * + * @return string CSS rules for the provided parameter and its matching value. + */ +function default_colors_format_css_rule($data, $parameter) +{ + if (empty($data[$parameter])) { + return ''; + } + + $key = str_replace('DEFAULT_COLORS_', '', $parameter); + $key = str_replace('_', '-', strtolower($key)) .'-color'; + return ' --'. $key .': '. $data[$parameter]; +} + + +/** + * This function is never called, but contains translation calls for GNU gettext extraction. + */ +function default_colors_translation() +{ + // meta + t('Override default theme colors. Use any CSS valid color.'); + t('Main color (navbar green)'); + t('Background color (light grey)'); + t('Dark main color (e.g. visited links)'); +} diff --git a/plugins/demo_plugin/demo_plugin.meta b/plugins/demo_plugin/demo_plugin.meta index b063ecb..cd61644 100644 --- a/plugins/demo_plugin/demo_plugin.meta +++ b/plugins/demo_plugin/demo_plugin.meta @@ -1 +1,4 @@ description="A demo plugin covering all use cases for template designers and plugin developers." +parameters="DEMO_PLUGIN_PARAMETER;DEMO_PLUGIN_OTHER_PARAMETER" +parameter.DEMO_PLUGIN_PARAMETER="This is a parameter dedicated to the demo plugin. It'll be suffixed." +parameter.DEMO_PLUGIN_OTHER_PARAMETER="Other demo parameter" diff --git a/plugins/demo_plugin/demo_plugin.php b/plugins/demo_plugin/demo_plugin.php index 95ea7fe..71ba749 100644 --- a/plugins/demo_plugin/demo_plugin.php +++ b/plugins/demo_plugin/demo_plugin.php @@ -456,6 +456,23 @@ function hook_demo_plugin_render_feed($data) return $data; } +/** + * When plugin parameters are saved. + * + * @param array $data $_POST array + * + * @return array Updated $_POST array + */ +function hook_demo_plugin_save_plugin_parameters($data) +{ + // Here we edit the provided value, but we can use this to generate config files, etc. + if (! empty($data['DEMO_PLUGIN_PARAMETER']) && ! endsWith($data['DEMO_PLUGIN_PARAMETER'], '_SUFFIX')) { + $data['DEMO_PLUGIN_PARAMETER'] .= '_SUFFIX'; + } + + return $data; +} + /** * This function is never called, but contains translation calls for GNU gettext extraction. */ @@ -463,4 +480,6 @@ function demo_dummy_translation() { // meta t('A demo plugin covering all use cases for template designers and plugin developers.'); + t('This is a parameter dedicated to the demo plugin. It\'ll be suffixed.'); + t('Other demo parameter'); } diff --git a/tests/plugins/PluginDefaultColorsTest.php b/tests/plugins/PluginDefaultColorsTest.php new file mode 100644 index 0000000..b9951cc --- /dev/null +++ b/tests/plugins/PluginDefaultColorsTest.php @@ -0,0 +1,195 @@ +set('plugins.DEFAULT_COLORS_BACKGROUND', 'value'); + $errors = default_colors_init($conf); + $this->assertEmpty($errors); + } + + /** + * Test DefaultColors init with errors. + */ + public function testDefaultColorsInitError() + { + $conf = new ConfigManager(''); + $errors = default_colors_init($conf); + $this->assertNotEmpty($errors); + } + + /** + * Test the save plugin parameters hook with all colors specified. + */ + public function testSavePluginParametersAll() + { + $post = [ + 'other1' => true, + 'DEFAULT_COLORS_MAIN' => 'blue', + 'DEFAULT_COLORS_BACKGROUND' => 'pink', + 'other2' => ['yep'], + 'DEFAULT_COLORS_DARK_MAIN' => 'green', + ]; + + hook_default_colors_save_plugin_parameters($post); + $this->assertFileExists($file = 'sandbox/default_colors/default_colors.css'); + $content = file_get_contents($file); + $expected = ':root { + --main-color: blue; + --background-color: pink; + --dark-main-color: green; + +} +'; + $this->assertEquals($expected, $content); + } + + /** + * Test the save plugin parameters hook with only one color specified. + */ + public function testSavePluginParametersSingle() + { + $post = [ + 'other1' => true, + 'DEFAULT_COLORS_BACKGROUND' => 'pink', + 'other2' => ['yep'], + 'DEFAULT_COLORS_DARK_MAIN' => '', + ]; + + hook_default_colors_save_plugin_parameters($post); + $this->assertFileExists($file = 'sandbox/default_colors/default_colors.css'); + $content = file_get_contents($file); + $expected = ':root { + --background-color: pink; + +} +'; + $this->assertEquals($expected, $content); + } + + /** + * Test the save plugin parameters hook with no color specified. + */ + public function testSavePluginParametersNone() + { + hook_default_colors_save_plugin_parameters([]); + $this->assertFileNotExists($file = 'sandbox/default_colors/default_colors.css'); + } + + /** + * Make sure that the CSS is properly included by the include hook. + */ + public function testIncludeWithFile() + { + $data = [ + 'css_files' => ['file1'], + 'js_files' => ['file2'], + ]; + touch($file = 'sandbox/default_colors/default_colors.css'); + $processedData = hook_default_colors_render_includes($data); + + $this->assertCount(2, $processedData['css_files']); + $this->assertEquals($file, $processedData['css_files'][1]); + $this->assertCount(1, $processedData['js_files']); + } + + /** + * Make sure that the CSS is not included by the include hook if the CSS file does not exist. + */ + public function testIncludeWithoutFile() + { + $data = [ + 'css_files' => ['file1'], + 'js_files' => ['file2'], + ]; + $processedData = hook_default_colors_render_includes($data); + + $this->assertEquals($data, $processedData); + } + + /** + * Test helper function which generates CSS rules with valid input. + */ + public function testFormatCssRuleValid() + { + $data = [ + 'other1' => true, + 'DEFAULT_COLORS_BLIP_BLOP' => 'shinyColor', + 'other2' => ['yep'], + ]; + $result = default_colors_format_css_rule($data, 'DEFAULT_COLORS_BLIP_BLOP'); + $this->assertEquals(' --blip-blop-color: shinyColor', $result); + + $data = ['unknown-parameter' => true]; + $result = default_colors_format_css_rule($data, 'unknown-parameter'); + $this->assertEquals(' --unknown-parameter-color: 1', $result); + } + + /** + * Test helper function which generates CSS rules with invalid input. + */ + public function testFormatCssRuleInvalid() + { + $result = default_colors_format_css_rule([], 'DEFAULT_COLORS_BLIP_BLOP'); + $this->assertEmpty($result); + + $data = [ + 'other1' => true, + 'DEFAULT_COLORS_BLIP_BLOP' => 'shinyColor', + 'other2' => ['yep'], + ]; + $result = default_colors_format_css_rule($data, ''); + $this->assertEmpty($result); + } +}