]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Merge pull request #1276 from ArthurHoaro/feature/bulk-visibility
authorArthurHoaro <arthur@hoa.ro>
Mon, 22 Apr 2019 10:31:09 +0000 (12:31 +0200)
committerGitHub <noreply@github.com>
Mon, 22 Apr 2019 10:31:09 +0000 (12:31 +0200)
Bulk action: set visibility

46 files changed:
.readthedocs.yml [new file with mode: 0644]
AUTHORS
CHANGELOG.md
README.md
application/Thumbnailer.php
application/api/ApiMiddleware.php
application/api/ApiUtils.php
application/bookmark/LinkDB.php
application/bookmark/LinkUtils.php
application/config/ConfigManager.php
application/feed/FeedBuilder.php
application/netscape/NetscapeBookmarkUtils.php
application/render/PageBuilder.php
application/updater/Updater.php
assets/default/scss/shaarli.scss
doc/md/Download-and-Installation.md
doc/md/Server-configuration.md
doc/md/Shaarli-configuration.md
inc/languages/fr/LC_MESSAGES/shaarli.po
index.php
tests/bookmark/LinkDBTest.php
tests/bookmark/LinkUtilsTest.php
tests/plugins/PluginMarkdownTest.php
tests/updater/UpdaterTest.php
tpl/default/404.html
tpl/default/addlink.html
tpl/default/changepassword.html
tpl/default/changetag.html
tpl/default/configure.html
tpl/default/daily.html
tpl/default/editlink.html
tpl/default/export.html
tpl/default/import.html
tpl/default/install.html
tpl/default/linklist.html
tpl/default/linklist.paging.html
tpl/default/loginform.html
tpl/default/page.footer.html
tpl/default/page.header.html
tpl/default/picwall.html
tpl/default/pluginsadmin.html
tpl/default/tag.cloud.html
tpl/default/tag.list.html
tpl/default/tag.sort.html
tpl/default/thumbnails.html
tpl/default/tools.html

diff --git a/.readthedocs.yml b/.readthedocs.yml
new file mode 100644 (file)
index 0000000..09e5a6a
--- /dev/null
@@ -0,0 +1,15 @@
+# .readthedocs.yml
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+# Build documentation with MkDocs
+mkdocs:
+  configuration: mkdocs.yml
+
+# Optionally set the version of Python and requirements required to build your docs
+# https://github.com/rtfd/readthedocs.org/issues/5250
+python:
+  version: 3.5
\ No newline at end of file
diff --git a/AUTHORS b/AUTHORS
index db23ad322f18ea1bbf5728cf5b24a365571410f7..7fa2734ac65ecb24b9e04e092b005c8970c20b26 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,13 +1,15 @@
-   687 ArthurHoaro <arthur@hoa.ro>
-   355 VirtualTam <virtualtam@flibidi.net>
-   195 nodiscc <nodiscc@gmail.com>
+   734 ArthurHoaro <arthur@hoa.ro>
+   400 VirtualTam <virtualtam@flibidi.net>
+   215 nodiscc <nodiscc@gmail.com>
     56 Sébastien Sauvage <sebsauvage@sebsauvage.net>
     15 Florian Eula <eula.florian@gmail.com>
     13 Emilien Klein <emilien@klein.st>
     12 Nicolas Danelon <hi@nicolasmd.com.ar>
      9 Willi Eggeling <thewilli@gmail.com>
      8 Christophe HENRY <christophe.henry@sbgodin.fr>
+     7 Luce Carević <lcarevic@access42.net>
      6 B. van Berkum <dev@dotmpe.com>
+     6 llune <llune@users.noreply.github.com>
      5 Lucas Cimon <lucas.cimon@gmail.com>
      5 Mark Schmitz <kramred@gmail.com>
      5 kalvn <kalvnthereal@gmail.com>
@@ -15,7 +17,7 @@
      4 David Sferruzza <david.sferruzza@gmail.com>
      4 Immánuel Fodor <immanuelfactor+github@gmail.com>
      3 Teromene <teromene@teromene.fr>
-     3 llune <llune@users.noreply.github.com>
+     2 Alexandre G.-Raymond <alex@ndre.gr>
      2 Chris Kuethe <chris.kuethe@gmail.com>
      2 Felix Bartels <felix@host-consultants.de>
      2 Knah Tsaeb <Knah-Tsaeb@knah-tsaeb.org>
      2 julienCXX <software@chmodplusx.eu>
      2 philipp-r <philipp-r@users.noreply.github.com>
      2 pips <pips@e5150.fr>
+     2 trailjeep <trailjeep@gmail.com>
      1 Adrien Oliva <adrien.oliva@yapbreak.fr>
      1 Adrien le Maire <adrien@alemaire.be>
-     1 Alexandre G.-Raymond <alex@ndre.gr>
      1 Alexis J <alexis@effingo.be>
      1 Angristan <angristan@users.noreply.github.com>
+     1 Bish Erbas <42714627+bisherbas@users.noreply.github.com>
      1 BoboTiG <bobotig@gmail.com>
      1 Bronco <bronco@warriordudimanche.net>
      1 Buster One <37770318+buster-one@users.noreply.github.com>
index aa1f0d8aa30cf74d9f2bbbf87b4603ac8068e87c..865e037068cd0480eea6c5efad271d078547b4da 100644 (file)
@@ -4,6 +4,41 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
+
+## [v0.10.4](https://github.com/shaarli/Shaarli/releases/tag/v0.10.4) - 2019-04-16
+### Fixed
+- Fix thumbnails disabling if PHP GD is not installed
+- Fix a warning if links sticky status isn't set
+
+## [v0.10.3](https://github.com/shaarli/Shaarli/releases/tag/v0.10.3) - 2019-02-23
+### Added
+- Add OpenGraph metadata tags on permalink page
+- Add CORS headers to REST API reponses
+- Add a button to toggle checkboxes of displayed links
+- Add an icon to the link list when the Isso plugin is enabled
+- Add noindex, nofollow to documentation pages
+- Document usage of robots.txt
+- Add a button to set links as sticky
+
+### Changed
+- Update French translation
+- Refactor the documentation homepage
+- Bump netscape-bookmark-parser
+- Update session_start condition
+- Improve accessibility
+- Cleanup and refactor lint tooling
+
+### Fixed
+- Fix input size for dropdown search form
+- Fix history for bulk link deletion
+- Fix thumbnail requests
+- Fix hashtag rendering when markdown escaping is enabled
+- Fix AJAX tag deletion
+- Fix lint errors and improve PSR-1 and PSR-2 compliance
+
+### Removed
+- Remove Firefox Share documentation
+
 ## [v0.10.2](https://github.com/shaarli/Shaarli/releases/tag/v0.10.2) - 2018-08-11
 
 ### Fixed
@@ -12,7 +47,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 
 ## [v0.10.1](https://github.com/shaarli/Shaarli/releases/tag/v0.10.1) - 2018-08-11
 
-### Changed 
+### Changed
 
 - Accessibility:
     - Remove alt text on the logo
@@ -46,7 +81,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 - Use Travis matrix and stages to run Javascript tests in a dedicated environment
 - Add tag endpoint in the REST API
 - Build the documentation in Travis builds
-- Provide a Docker Compose example 
+- Provide a Docker Compose example
 
 ### Changed
 - Use web-thumbnailer to retrieve thumbnails (see #687)
index 0e23e33d395a1d8bf4d52b6c1af46ad1a5dc0fb2..21f2eae75013f7c7ad9551e0f55947ec7eeae09b 100644 (file)
--- a/README.md
+++ b/README.md
@@ -9,10 +9,10 @@ _It is designed to be personal (single-user), fast and handy._
 [![](https://img.shields.io/badge/stable-v0.9.7-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.9.7)
 [![](https://img.shields.io/travis/shaarli/Shaarli/stable.svg?label=stable)](https://travis-ci.org/shaarli/Shaarli)
 &bull;
-[![](https://img.shields.io/badge/latest-v0.10.2-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.10.2)
+[![](https://img.shields.io/badge/latest-v0.10.4-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.10.4)
 [![](https://img.shields.io/travis/shaarli/Shaarli/latest.svg?label=latest)](https://travis-ci.org/shaarli/Shaarli)
 &bull;
-[![](https://img.shields.io/badge/master-v0.10.x-blue.svg)](https://github.com/shaarli/Shaarli)
+[![](https://img.shields.io/badge/master-v0.11.x-blue.svg)](https://github.com/shaarli/Shaarli)
 [![](https://img.shields.io/travis/shaarli/Shaarli.svg?label=master)](https://travis-ci.org/shaarli/Shaarli)
 
 [![Join the chat at https://gitter.im/shaarli/Shaarli](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/shaarli/Shaarli)
index a23f98e9df226204efeb5166bc5e3bbab4f348c9..d5f5ac2828b61026fb5fbc68f8db1f00cd37b182 100644 (file)
@@ -55,7 +55,7 @@ class Thumbnailer
         $this->conf = $conf;
 
         if (! $this->checkRequirements()) {
-            $this->conf->set('thumbnails.enabled', false);
+            $this->conf->set('thumbnails.mode', Thumbnailer::MODE_NONE);
             $this->conf->write(true);
             // TODO: create a proper error handling system able to catch exceptions...
             die(t(
index 5ffb8c6d06653fc527df1caca85d58004d41def8..2d55bda65eb2e24fd7348abaafac4f2f12567a8e 100644 (file)
@@ -129,9 +129,7 @@ class ApiMiddleware
         $linkDb = new \Shaarli\Bookmark\LinkDB(
             $conf->get('resource.datastore'),
             true,
-            $conf->get('privacy.hide_public_links'),
-            $conf->get('redirector.url'),
-            $conf->get('redirector.encode_url')
+            $conf->get('privacy.hide_public_links')
         );
         $this->container['db'] = $linkDb;
     }
index 1824b5d08171f19c27ebb28d3831eacbfc040538..1e3ac02e110bdb137d7f52a2ce521d079ef13875 100644 (file)
@@ -59,7 +59,7 @@ class ApiUtils
     {
         $out['id'] = $link['id'];
         // Not an internal link
-        if ($link['url'][0] != '?') {
+        if (! is_note($link['url'])) {
             $out['url'] = $link['url'];
         } else {
             $out['url'] = $indexUrl . $link['url'];
index c13a11417b5fb66af9a7df5597ad2f2a09298936..efde8468fca97e896f1da161e444993bdd711b4d 100644 (file)
@@ -29,10 +29,10 @@ use Shaarli\FileUtils;
  *  - private:  Is this link private? 0=no, other value=yes
  *  - tags:     tags attached to this entry (separated by spaces)
  *  - title     Title of the link
- *  - url       URL of the link. Used for displayable links (no redirector, relative, etc.).
- *              Can be absolute or relative.
- *              Relative URLs are permalinks (e.g.'?m-ukcw')
- *  - real_url  Absolute processed URL.
+ *  - url       URL of the link. Used for displayable links.
+ *              Can be absolute or relative in the database but the relative links
+ *              will be converted to absolute ones in templates.
+ *  - real_url  Raw URL in stored in the DB (absolute or relative).
  *  - shorturl  Permalink smallhash
  *
  * Implements 3 interfaces:
@@ -88,19 +88,6 @@ class LinkDB implements Iterator, Countable, ArrayAccess
     // Hide public links
     private $hidePublicLinks;
 
-    // link redirector set in user settings.
-    private $redirector;
-
-    /**
-     * Set this to `true` to urlencode link behind redirector link, `false` to leave it untouched.
-     *
-     * Example:
-     *   anonym.to needs clean URL while dereferer.org needs urlencoded URL.
-     *
-     * @var boolean $redirectorEncode parameter: true or false
-     */
-    private $redirectorEncode;
-
     /**
      * Creates a new LinkDB
      *
@@ -109,22 +96,16 @@ class LinkDB implements Iterator, Countable, ArrayAccess
      * @param string  $datastore        datastore file path.
      * @param boolean $isLoggedIn       is the user logged in?
      * @param boolean $hidePublicLinks  if true all links are private.
-     * @param string  $redirector       link redirector set in user settings.
-     * @param boolean $redirectorEncode Enable urlencode on redirected urls (default: true).
      */
     public function __construct(
         $datastore,
         $isLoggedIn,
-        $hidePublicLinks,
-        $redirector = '',
-        $redirectorEncode = true
+        $hidePublicLinks
     ) {
     
         $this->datastore = $datastore;
         $this->loggedIn = $isLoggedIn;
         $this->hidePublicLinks = $hidePublicLinks;
-        $this->redirector = $redirector;
-        $this->redirectorEncode = $redirectorEncode === true;
         $this->check();
         $this->read();
     }
@@ -271,7 +252,8 @@ You use the community supported version of the original Shaarli project, by Seba
             ),
             'private' => 0,
             'created' => new DateTime(),
-            'tags' => 'opensource software'
+            'tags' => 'opensource software',
+            'sticky' => false,
         );
         $link['shorturl'] = link_small_hash($link['created'], $link['id']);
         $this->links[1] = $link;
@@ -284,6 +266,7 @@ You use the community supported version of the original Shaarli project, by Seba
             'private' => 1,
             'created' => new DateTime('1 minute ago'),
             'tags' => 'secretstuff',
+            'sticky' => false,
         );
         $link['shorturl'] = link_small_hash($link['created'], $link['id']);
         $this->links[0] = $link;
@@ -323,17 +306,9 @@ You use the community supported version of the original Shaarli project, by Seba
                 $link['tags'] = preg_replace('/(^|\s+)\.[^($|\s)]+\s*/', ' ', $link['tags']);
             }
 
-            // Do not use the redirector for internal links (Shaarli note URL starting with a '?').
-            if (!empty($this->redirector) && !startsWith($link['url'], '?')) {
-                $link['real_url'] = $this->redirector;
-                if ($this->redirectorEncode) {
-                    $link['real_url'] .= urlencode(unescape($link['url']));
-                } else {
-                    $link['real_url'] .= $link['url'];
-                }
-            } else {
-                $link['real_url'] = $link['url'];
-            }
+            $link['real_url'] = $link['url'];
+
+            $link['sticky'] = isset($link['sticky']) ? $link['sticky'] : false;
 
             // To be able to load links before running the update, and prepare the update
             if (!isset($link['created'])) {
index de5b61cbcaf6e8467d57eb9c49aa009d0a832754..35a5b290454b32870464c6457fea73059d613f4c 100644 (file)
@@ -133,29 +133,15 @@ function count_private($links)
  * In a string, converts URLs to clickable links.
  *
  * @param string $text       input string.
- * @param string $redirector if a redirector is set, use it to gerenate links.
- * @param bool   $urlEncode  Use `urlencode()` on the URL after the redirector or not.
  *
  * @return string returns $text with all links converted to HTML links.
  *
  * @see Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722
  */
-function text2clickable($text, $redirector = '', $urlEncode = true)
+function text2clickable($text)
 {
     $regex = '!(((?:https?|ftp|file)://|apt:|magnet:)\S+[a-z0-9\(\)]/?)!si';
-
-    if (empty($redirector)) {
-        return preg_replace($regex, '<a href="$1">$1</a>', $text);
-    }
-    // Redirector is set, urlencode the final URL.
-    return preg_replace_callback(
-        $regex,
-        function ($matches) use ($redirector, $urlEncode) {
-            $url = $urlEncode ? urlencode($matches[1]) : $matches[1];
-            return '<a href="' . $redirector . $url .'">'. $matches[1] .'</a>';
-        },
-        $text
-    );
+    return preg_replace($regex, '<a href="$1">$1</a>', $text);
 }
 
 /**
@@ -197,15 +183,13 @@ function space2nbsp($text)
  * Format Shaarli's description
  *
  * @param string $description shaare's description.
- * @param string $redirector  if a redirector is set, use it to gerenate links.
- * @param bool   $urlEncode   Use `urlencode()` on the URL after the redirector or not.
  * @param string $indexUrl    URL to Shaarli's index.
 
  * @return string formatted description.
  */
-function format_description($description, $redirector = '', $urlEncode = true, $indexUrl = '')
+function format_description($description, $indexUrl = '')
 {
-    return nl2br(space2nbsp(hashtag_autolink(text2clickable($description, $redirector, $urlEncode), $indexUrl)));
+    return nl2br(space2nbsp(hashtag_autolink(text2clickable($description), $indexUrl)));
 }
 
 /**
@@ -220,3 +204,16 @@ function link_small_hash($date, $id)
 {
     return smallHash($date->format(LinkDB::LINK_DATE_FORMAT) . $id);
 }
+
+/**
+ * Returns whether or not the link is an internal note.
+ * Its URL starts by `?` because it's actually a permalink.
+ *
+ * @param string $linkUrl
+ *
+ * @return bool true if internal note, false otherwise.
+ */
+function is_note($linkUrl)
+{
+    return isset($linkUrl[0]) && $linkUrl[0] === '?';
+}
index e6c3507329dc7e39a162c6fc4ec1103da8fadff2..3099392807bd41d0d48146be66a40461607f24ae 100644 (file)
@@ -221,7 +221,6 @@ class ConfigManager
             'general.title',
             'general.header_link',
             'privacy.default_private_links',
-            'redirector.url',
         );
 
         // Only logged in user can alter config.
@@ -381,9 +380,6 @@ class ConfigManager
         // default state of the 'remember me' checkbox of the login form
         $this->setEmpty('privacy.remember_user_default', true);
 
-        $this->setEmpty('redirector.url', '');
-        $this->setEmpty('redirector.encode_url', true);
-
         $this->setEmpty('thumbnails.width', '125');
         $this->setEmpty('thumbnails.height', '90');
 
index b66f2f918edd494f1d11090892fbcfda7d073e59..7c859474de414773052c0c5e79dd1583dfcd046f 100644 (file)
@@ -147,8 +147,8 @@ class FeedBuilder
     protected function buildItem($link, $pageaddr)
     {
         $link['guid'] = $pageaddr . '?' . $link['shorturl'];
-        // Check for both signs of a note: starting with ? and 7 chars long.
-        if ($link['url'][0] === '?' && strlen($link['url']) === 7) {
+        // Prepend the root URL for notes
+        if (is_note($link['url'])) {
             $link['url'] = $pageaddr . $link['url'];
         }
         if ($this->usePermalinks === true) {
@@ -156,7 +156,7 @@ class FeedBuilder
         } else {
             $permalink = '<a href="' . $link['guid'] . '" title="' . t('Permalink') . '">' . t('Permalink') . '</a>';
         }
-        $link['description'] = format_description($link['description'], '', false, $pageaddr);
+        $link['description'] = format_description($link['description'], $pageaddr);
         $link['description'] .= PHP_EOL . '<br>&#8212; ' . $permalink;
 
         $pubDate = $link['created'];
index 2fb1a4a6943674c557188e28bb5df206867f3857..28665941507366a364930f4adcdde702cf983a25 100644 (file)
@@ -54,7 +54,7 @@ class NetscapeBookmarkUtils
             $link['timestamp'] = $date->getTimestamp();
             $link['taglist'] = str_replace(' ', ',', $link['tags']);
 
-            if (startsWith($link['url'], '?') && $prependNoteUrl) {
+            if (is_note($link['url']) && $prependNoteUrl) {
                 $link['url'] = $indexUrl . $link['url'];
             }
 
index 0569b67f93e4ded88780e1d52ee2c22a4e2054e1..3f86fc2681010c99b724ffbcef2cc758b0240418 100644 (file)
@@ -123,6 +123,8 @@ class PageBuilder
         $this->tpl->assign('hide_timestamps', $this->conf->get('privacy.hide_timestamps', false));
         $this->tpl->assign('token', $this->token);
 
+        $this->tpl->assign('language', $this->conf->get('translation.language'));
+
         if ($this->linkDB !== null) {
             $this->tpl->assign('tags', $this->linkDB->linksCountPerTag());
         }
index f12e351673640ddff963981d1232543a4f17979a..beb9ea9b7517613cd9c2ca01c884ba239f250355 100644 (file)
@@ -218,7 +218,6 @@ class Updater
         try {
             $this->conf->set('general.title', escape($this->conf->get('general.title')));
             $this->conf->set('general.header_link', escape($this->conf->get('general.header_link')));
-            $this->conf->set('redirector.url', escape($this->conf->get('redirector.url')));
             $this->conf->write($this->isLoggedIn);
         } catch (Exception $e) {
             error_log($e->getMessage());
@@ -550,4 +549,14 @@ class Updater
 
         return true;
     }
+
+    /**
+     * Remove redirector settings.
+     */
+    public function updateMethodRemoveRedirector()
+    {
+        $this->conf->remove('redirector');
+        $this->conf->write(true);
+        return true;
+    }
 }
index 760d8d6ab7272a5d8c929ccb8425fc5a8f7f054d..691b2b37fdb060e303003e9679ae9e828a67daac 100644 (file)
@@ -544,7 +544,10 @@ body,
   color: $dark-grey;
   font-size: .9em;
 
+
   a {
+    display: inline-block;
+    margin: 3px 0;
     padding: 5px 8px;
     text-decoration: none;
   }
index 14649e0607b15b76b6062b35ff5c75b4e8d6a6d1..8c9e8a325f123033dbcd988206978a7fba09f9d1 100644 (file)
@@ -24,11 +24,11 @@ Using one of the following methods:
 
 In most cases, you should download the latest Shaarli release from the [releases](https://github.com/shaarli/Shaarli/releases) page. Download our **shaarli-full** archive to include dependencies.
 
-The current latest released version is `v0.9.7`
+The current latest released version is `v0.10.4`
 
 ```bash
-$ wget https://github.com/shaarli/Shaarli/releases/download/v0.9.7/shaarli-v0.9.7-full.zip
-$ unzip shaarli-v0.9.7-full.zip
+$ wget https://github.com/shaarli/Shaarli/releases/download/v0.10.4/shaarli-v0.10.4-full.zip
+$ unzip shaarli-v0.10.4-full.zip
 $ mv Shaarli /path/to/shaarli/
 ```
 
index 78083a466729e2b7466f9d017823a99edaa160fa..4753df1d5fa817cb02a714423b962b5cce531703 100644 (file)
@@ -17,7 +17,7 @@ Version | Status | Shaarli compatibility
 :---:|:---:|:---:
 7.2 | Supported | Yes
 7.1 | Supported | Yes
-7.0 | Supported | Yes
+7.0 | EOL: 2018-12-03 | Yes (up to Shaarli 0.10.x)
 5.6 | EOL: 2018-12-31 | Yes (up to Shaarli 0.10.x)
 5.5 | EOL: 2016-07-10 | Yes
 5.4 | EOL: 2015-09-14 | Yes (up to Shaarli 0.8.x)
index 920c7e27e151a3cf1a870a46ee0b2e8c1ced9505..a931ab1e783eb60cf2c810ee37ec38d01da22b76 100644 (file)
@@ -4,7 +4,7 @@
 
 Once your Shaarli instance is installed, the file `data/config.json.php` is generated:
 * it contains all settings in JSON format, and can be edited to customize values
-* it defines which [plugins](Plugin-System) are enabled[](.html)
+* it defines which [plugins](Plugin-System) are enabled
 * its values override those defined in `index.php`
 * it is wrap in a PHP comment to prevent anyone accessing it, regardless of server configuration
 
@@ -32,13 +32,13 @@ On a Linux distribution:
 - to give it access to Shaarli, either:
     - unzip Shaarli in the default web server location (usually `/var/www/`) and set the web server user as the owner
     - put users in the same group as the web server, and set the appropriate access rights
-- if you have a domain / subdomain to serve Shaarli, [configure the server](Server-configuration) accordingly[](.html)
+- if you have a domain / subdomain to serve Shaarli, [configure the server](Server-configuration) accordingly
 
 ## Configuration
 
 In `data/config.json.php`.
 
-See also [Plugin System](Plugin-System.html).
+See also [Plugin System](Plugin-System).
 
 ### Credentials
  
@@ -120,11 +120,6 @@ Must be an associative array: `translation domain => translation path`.
 - **enable_thumbnails**: Enable or disable thumbnail display.  
 - **enable_localcache**: Enable or disable local cache.
 
-### Redirector
-
-- **url**: Redirector URL, such as `anonym.to`.  
-- **encode_url**: Enable this if the redirector needs encoded URL to work properly.
-
 ## Configuration file example
 
 ```json
@@ -185,8 +180,6 @@ Must be an associative array: `translation domain => translation path`.
         "hide_public_links": false,
         "hide_timestamps": false,
         "open_shaarli": false,
-        "redirector": "http://anonym.to/?",
-        "redirector_encode_url": false
     },
     "general": {
         "header_link": "?",
@@ -218,10 +211,6 @@ Must be an associative array: `translation domain => translation path`.
         "enable_thumbnails": true,
         "enable_localcache": true
     },
-    "redirector": {
-        "url": "http://anonym.to/?",
-        "encode_url": false
-    },
     "plugins": {
         "WALLABAG_URL": "http://demo.wallabag.org",
         "WALLABAG_VERSION": "1"
index 102c80da93636a5de87d265c4cbc25100dd739de..649f6dd5506a9a0aa5098d38eeeb5a71eab09237 100644 (file)
@@ -1255,6 +1255,9 @@ msgstr ""
 #~ msgid "Selection"
 #~ msgstr "Choisir"
 
+#~ msgid "Select all"
+#~ msgstr "Tout sélectionner"
+
 #~ msgid "Public"
 #~ msgstr "Publics"
 
index 322c360c650a9ce5ecbcdfebaea71bb553546535..68e0364cbdba182af47337f52d4767e9f7e982a2 100644 (file)
--- a/index.php
+++ b/index.php
@@ -312,9 +312,7 @@ function showDailyRSS($conf, $loginManager)
     $LINKSDB = new LinkDB(
         $conf->get('resource.datastore'),
         $loginManager->isLoggedIn(),
-        $conf->get('privacy.hide_public_links'),
-        $conf->get('redirector.url'),
-        $conf->get('redirector.encode_url')
+        $conf->get('privacy.hide_public_links')
     );
 
     /* Some Shaarlies may have very few links, so we need to look
@@ -356,13 +354,9 @@ function showDailyRSS($conf, $loginManager)
 
         // We pre-format some fields for proper output.
         foreach ($links as &$link) {
-            $link['formatedDescription'] = format_description(
-                $link['description'],
-                $conf->get('redirector.url'),
-                $conf->get('redirector.encode_url')
-            );
+            $link['formatedDescription'] = format_description($link['description']);
             $link['timestamp'] = $link['created']->getTimestamp();
-            if (startsWith($link['url'], '?')) {
+            if (is_note($link['url'])) {
                 $link['url'] = index_url($_SERVER) . $link['url'];  // make permalink URL absolute
             }
         }
@@ -433,11 +427,7 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager, $loginManager)
         $taglist = explode(' ', $link['tags']);
         uasort($taglist, 'strcasecmp');
         $linksToDisplay[$key]['taglist']=$taglist;
-        $linksToDisplay[$key]['formatedDescription'] = format_description(
-            $link['description'],
-            $conf->get('redirector.url'),
-            $conf->get('redirector.encode_url')
-        );
+        $linksToDisplay[$key]['formatedDescription'] = format_description($link['description']);
         $linksToDisplay[$key]['timestamp'] =  $link['created']->getTimestamp();
     }
 
@@ -1074,7 +1064,6 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
             $PAGE->assign('api_enabled', $conf->get('api.enabled', true));
             $PAGE->assign('api_secret', $conf->get('api.secret'));
             $PAGE->assign('languages', Languages::getAvailableLanguages());
-            $PAGE->assign('language', $conf->get('translation.language'));
             $PAGE->assign('gd_enabled', extension_loaded('gd'));
             $PAGE->assign('thumbnails_mode', $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE));
             $PAGE->assign('pagetitle', t('Configure') .' - '. $conf->get('general.title', 'Shaarli'));
@@ -1176,11 +1165,15 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
             $link['title'] = $link['url'];
         }
 
-        if ($conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE) {
+        if ($conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE
+            && ! is_note($link['url'])
+        ) {
             $thumbnailer = new Thumbnailer($conf);
             $link['thumbnail'] = $thumbnailer->get($url);
         }
 
+        $link['sticky'] = isset($link['sticky']) ? $link['sticky'] : false;
+
         $pluginManager->executeHooks('save_link', $link);
 
         $LINKSDB[$id] = $link;
@@ -1603,7 +1596,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
         $ids = [];
         foreach ($LINKSDB as $link) {
             // A note or not HTTP(S)
-            if ($link['url'][0] === '?' || ! startsWith(strtolower($link['url']), 'http')) {
+            if (is_note($link['url']) || ! startsWith(strtolower($link['url']), 'http')) {
                 continue;
             }
             $ids[] = $link['id'];
@@ -1707,11 +1700,7 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
     $linkDisp = array();
     while ($i<$end && $i<count($keys)) {
         $link = $linksToDisplay[$keys[$i]];
-        $link['description'] = format_description(
-            $link['description'],
-            $conf->get('redirector.url'),
-            $conf->get('redirector.encode_url')
-        );
+        $link['description'] = format_description($link['description']);
         $classLi =  ($i % 2) != 0 ? '' : 'publicLinkHightLight';
         $link['class'] = $link['private'] == 0 ? $classLi : 'private';
         $link['timestamp'] = $link['created']->getTimestamp();
@@ -1772,7 +1761,6 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
         'search_term' => $searchterm,
         'search_tags' => $searchtags,
         'visibility' => ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : '',
-        'redirector' => $conf->get('redirector.url'),  // Optional redirector URL.
         'links' => $linkDisp,
     );
 
@@ -1922,9 +1910,7 @@ try {
 $linkDb = new LinkDB(
     $conf->get('resource.datastore'),
     $loginManager->isLoggedIn(),
-    $conf->get('privacy.hide_public_links'),
-    $conf->get('redirector.url'),
-    $conf->get('redirector.encode_url')
+    $conf->get('privacy.hide_public_links')
 );
 
 $container = new \Slim\Container();
@@ -1947,7 +1933,7 @@ $app->group('/api/v1', function () {
     $this->put('/tags/{tagName:[\w]+}', '\Shaarli\Api\Controllers\Tags:putTag')->setName('putTag');
     $this->delete('/tags/{tagName:[\w]+}', '\Shaarli\Api\Controllers\Tags:deleteTag')->setName('deleteTag');
 
-    $this->get('/history', '\Shaarli\Api\Controllers\History:getHistory')->setName('getHistory');
+    $this->get('/history', '\Shaarli\Api\Controllers\HistoryController:getHistory')->setName('getHistory');
 })->add('\Shaarli\Api\ApiMiddleware');
 
 $response = $app->run(true);
index ff5c0b970af1e8283d71e68606c3337e3d4c5936..2990a6b56a0360756b3b8ee157fc7125e4372a21 100644 (file)
@@ -361,36 +361,6 @@ class LinkDBTest extends \PHPUnit\Framework\TestCase
         );
     }
 
-    /**
-     * Test real_url without redirector.
-     */
-    public function testLinkRealUrlWithoutRedirector()
-    {
-        $db = new LinkDB(self::$testDatastore, false, false);
-        foreach ($db as $link) {
-            $this->assertEquals($link['url'], $link['real_url']);
-        }
-    }
-
-    /**
-     * Test real_url with redirector.
-     */
-    public function testLinkRealUrlWithRedirector()
-    {
-        $redirector = 'http://redirector.to?';
-        $db = new LinkDB(self::$testDatastore, false, false, $redirector);
-        foreach ($db as $link) {
-            $this->assertStringStartsWith($redirector, $link['real_url']);
-            $this->assertNotFalse(strpos($link['real_url'], urlencode('://')));
-        }
-
-        $db = new LinkDB(self::$testDatastore, false, false, $redirector, false);
-        foreach ($db as $link) {
-            $this->assertStringStartsWith($redirector, $link['real_url']);
-            $this->assertFalse(strpos($link['real_url'], urlencode('://')));
-        }
-    }
-
     /**
      * Test filter with string.
      */
@@ -516,7 +486,7 @@ class LinkDBTest extends \PHPUnit\Framework\TestCase
     public function testRenameTagCaseSensitive()
     {
         self::$refDB->write(self::$testDatastore);
-        $linkDB = new LinkDB(self::$testDatastore, true, false, '');
+        $linkDB = new LinkDB(self::$testDatastore, true, false);
 
         $res = $linkDB->renameTag('sTuff', 'Taz');
         $this->assertEquals(1, count($res));
index 1b8688e6d398fc1381e6b2acc586ae2562c282f2..25fb30435c8ef09c91623f6b416c1b6300ff459e 100644 (file)
@@ -216,56 +216,27 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase
     }
 
     /**
-     * Test text2clickable without a redirector being set.
+     * Test text2clickable.
      */
-    public function testText2clickableWithoutRedirector()
+    public function testText2clickable()
     {
         $text = 'stuff http://hello.there/is=someone#here otherstuff';
         $expectedText = 'stuff <a href="http://hello.there/is=someone#here">'
             . 'http://hello.there/is=someone#here</a> otherstuff';
-        $processedText = text2clickable($text, '');
+        $processedText = text2clickable($text);
         $this->assertEquals($expectedText, $processedText);
 
         $text = 'stuff http://hello.there/is=someone#here(please) otherstuff';
         $expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)">'
             . 'http://hello.there/is=someone#here(please)</a> otherstuff';
-        $processedText = text2clickable($text, '');
+        $processedText = text2clickable($text);
         $this->assertEquals($expectedText, $processedText);
 
+        $text = 'stuff http://hello.there/is=someone#here(please)&no otherstuff';
         $text = 'stuff http://hello.there/is=someone#here(please)&no otherstuff';
         $expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)&no">'
             . 'http://hello.there/is=someone#here(please)&no</a> otherstuff';
-        $processedText = text2clickable($text, '');
-        $this->assertEquals($expectedText, $processedText);
-    }
-
-    /**
-     * Test text2clickable with a redirector set.
-     */
-    public function testText2clickableWithRedirector()
-    {
-        $text = 'stuff http://hello.there/is=someone#here otherstuff';
-        $redirector = 'http://redirector.to';
-        $expectedText = 'stuff <a href="' .
-            $redirector .
-            urlencode('http://hello.there/is=someone#here') .
-            '">http://hello.there/is=someone#here</a> otherstuff';
-        $processedText = text2clickable($text, $redirector);
-        $this->assertEquals($expectedText, $processedText);
-    }
-
-    /**
-     * Test text2clickable a redirector set and without URL encode.
-     */
-    public function testText2clickableWithRedirectorDontEncode()
-    {
-        $text = 'stuff http://hello.there/?is=someone&or=something#here otherstuff';
-        $redirector = 'http://redirector.to';
-        $expectedText = 'stuff <a href="' .
-            $redirector .
-            'http://hello.there/?is=someone&or=something#here' .
-            '">http://hello.there/?is=someone&or=something#here</a> otherstuff';
-        $processedText = text2clickable($text, $redirector, false);
+        $processedText = text2clickable($text);
         $this->assertEquals($expectedText, $processedText);
     }
 
@@ -317,6 +288,26 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase
         $this->assertNotContains('>#nothashtag', $autolinkedDescription);
     }
 
+    /**
+     * Test is_note with note URLs.
+     */
+    public function testIsNote()
+    {
+        $this->assertTrue(is_note('?'));
+        $this->assertTrue(is_note('?abcDEf'));
+        $this->assertTrue(is_note('?_abcDEf#123'));
+    }
+
+    /**
+     * Test is_note with non note URLs.
+     */
+    public function testIsNotNote()
+    {
+        $this->assertFalse(is_note(''));
+        $this->assertFalse(is_note('nope'));
+        $this->assertFalse(is_note('https://github.com/shaarli/Shaarli/?hi'));
+    }
+
     /**
      * Util function to build an hashtag link.
      *
index 5e7c02b0c8f5b95407733d73cf01f95b26ccf3e8..9ddbc558f3d50294fe286322877d099c30ce0b4a 100644 (file)
@@ -107,7 +107,7 @@ class PluginMarkdownTest extends \PHPUnit\Framework\TestCase
     public function testReverseText2clickable()
     {
         $text = 'stuff http://hello.there/is=someone#here otherstuff';
-        $clickableText = text2clickable($text, '');
+        $clickableText = text2clickable($text);
         $reversedText = reverse_text2clickable($clickableText);
         $this->assertEquals($text, $reversedText);
     }
index d7df59637395ddf9a7d4760eecefa5db4a32a97e..93bc86c1b72a1ae5457fbd89847bbcf2f4730803 100644 (file)
@@ -287,17 +287,14 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
         $this->conf = new ConfigManager($sandbox);
         $title = '<script>alert("title");</script>';
         $headerLink = '<script>alert("header_link");</script>';
-        $redirectorUrl = '<script>alert("redirector");</script>';
         $this->conf->set('general.title', $title);
         $this->conf->set('general.header_link', $headerLink);
-        $this->conf->set('redirector.url', $redirectorUrl);
         $updater = new Updater(array(), array(), $this->conf, true);
         $done = $updater->updateMethodEscapeUnescapedConfig();
         $this->assertTrue($done);
         $this->conf->reload();
         $this->assertEquals(escape($title), $this->conf->get('general.title'));
         $this->assertEquals(escape($headerLink), $this->conf->get('general.header_link'));
-        $this->assertEquals(escape($redirectorUrl), $this->conf->get('redirector.url'));
         unlink($sandbox . '.json.php');
     }
 
@@ -707,7 +704,6 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
     }
 
     /**
-<<<<<<< HEAD
      * Test updateMethodWebThumbnailer with thumbnails enabled.
      */
     public function testUpdateMethodWebThumbnailerEnabled()
@@ -812,4 +808,19 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
         $linkDB = new LinkDB(self::$testDatastore, true, false);
         $this->assertTrue($linkDB[1]['sticky']);
     }
+
+    /**
+     * Test updateMethodRemoveRedirector().
+     */
+    public function testUpdateRemoveRedirector()
+    {
+        $sandboxConf = 'sandbox/config';
+        copy(self::$configFile . '.json.php', $sandboxConf . '.json.php');
+        $this->conf = new ConfigManager($sandboxConf);
+        $updater = new Updater([], null, $this->conf, true);
+        $this->assertTrue($updater->updateMethodRemoveRedirector());
+        $this->assertFalse($this->conf->exists('redirector'));
+        $this->conf = new ConfigManager($sandboxConf);
+        $this->assertFalse($this->conf->exists('redirector'));
+    }
 }
index fd337cada52332a7850fb75ce3cb0808d235104c..10a9458a6d7f467977756a0e0b374c1161d0182b 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index 55864a023947c201ad09fd32754452f45bb02c6d..b4b4a0ec1e3a5443d6923dc72fca9535806ba132 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index 2d15c92ac81e2775d9992626b4384a1954dd15c3..3867e3ca45d4bffe0fb4b13e9ab244e18a8ca1ac 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index 6606c4fa6bacb6495f2185ee3b03798520fdde42..0da6a5ebf39aa0bf8e4db70b5db900789e089c80 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index 42e32230b7bacb88cad86354e06072bac72078c0..7a87c05dfe0f6ce17272e5d3be281372e992e8ff 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index 2c409478bed424edd51700855ed2f352c70dd9df..359ecbd0ec206d1b4116e9c076db6711e49facd2 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index d8c571552aced2a76cfb44a54dc22ded64622d5e..df14535d610ce5ce8008b3205d79121332065afe 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index af1d6e330218c75df41b2bb2c0f1a0aff5ddcfdc..99c01b11523a39fa72bc7da02e3b4582d01faa7f 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index bdc9086e304e1fbaf1e9accf58617e34be5a974d..20f854d10d2f2be3736a55c4faea8ea4acfcf046 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index 6199b33d6499bfbf988c65ccc16dc00880c78e51..f0e7040e0545c56eefe78aaf42e6e58d71107486 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index ed78f40a7502f625e60659a92738ef91fc669226..1cf00783c486e9ca371548dc84b1dbffb844e4eb 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
@@ -94,7 +94,7 @@
           {'tagged'|t}
           {loop="$exploded_tags"}
               <span class="label label-tag" title="{'Remove tag'|t}">
-                <a href="?removetag={function="urlencode($value)"}">{$value}<span class="remove"><i class="fa fa-times"></i></span></a>
+                <a href="?removetag={function="urlencode($value)"}">{$value}<span class="remove"><i class="fa fa-times" aria-hidden="true"></i></span></a>
               </span>
           {/loop}
         {/if}
                       <input type="checkbox" class="link-checkbox" value="{$value.id}">
                     </span>
                     <span class="linklist-item-infos-controls-item ctrl-edit">
-                      <a href="?edit_link={$value.id}" title="{$strEdit}"><i class="fa fa-pencil-square-o edit-link"></i></a>
+                      <a href="?edit_link={$value.id}" aria-label="{$strEdit}" title="{$strEdit}"><i class="fa fa-pencil-square-o edit-link" aria-hidden="true"></i></a>
                     </span>
                     <span class="linklist-item-infos-controls-item ctrl-delete">
-                      <a href="?delete_link&amp;lf_linkdate={$value.id}&amp;token={$token}"
+                      <a href="?delete_link&amp;lf_linkdate={$value.id}&amp;token={$token}" aria-label="{$strDelete}"
                          title="{$strDelete}" class="delete-link pure-u-0 pure-u-lg-visible confirm-delete">
-                        <i class="fa fa-trash"></i>
+                        <i class="fa fa-trash" aria-hidden="true"></i>
                       </a>
                     </span>
                     <span class="linklist-item-infos-controls-item ctrl-pin">
                       <a href="?do=pin&amp;id={$value.id}&amp;token={$token}"
-                         title="{$strToggleSticky}" class="pin-link {if="$value.sticky"}pinned-link{/if} pure-u-0 pure-u-lg-visible">
-                        <i class="fa fa-thumb-tack"></i>
+                         title="{$strToggleSticky}" aria-label="{$strToggleSticky}" class="pin-link {if="$value.sticky"}pinned-link{/if} pure-u-0 pure-u-lg-visible">
+                        <i class="fa fa-thumb-tack" aria-hidden="true"></i>
                       </a>
                     </span>
                   </div>
                 {ignore}do not add space or line break between these div - Firefox issue{/ignore}
                 class="linklist-item-infos-url pure-u-lg-5-12 pure-u-1">
                 <a href="{$value.real_url}" title="{$value.title}">
-                  <i class="fa fa-link"></i> {$value.url}
+                  <i class="fa fa-link" aria-hidden="true"></i> {$value.url}
                 </a>
                 <div class="linklist-item-buttons pure-u-0 pure-u-lg-visible">
-                  <a href="#" title="{$strFold}" class="fold-button"><i class="fa fa-chevron-up"></i></a>
+                  <a href="#" aria-label="{$strFold}" title="{$strFold}" class="fold-button"><i class="fa fa-chevron-up" aria-hidden="true"></i></a>
                 </div>
               </div>
               <div class="mobile-buttons pure-u-1 pure-u-lg-0">
                 {/if}
                 {if="$is_logged_in"}
                   &middot;
-                  <a href="?delete_link&amp;lf_linkdate={$value.id}&amp;token={$token}"
+                  <a href="?delete_link&amp;lf_linkdate={$value.id}&amp;token={$token}" aria-label="{$strDelete}"
                      title="{$strDelete}" class="delete-link confirm-delete">
-                    <i class="fa fa-trash"></i>
+                    <i class="fa fa-trash" aria-hidden="true"></i>
                   </a>
                   &middot;
-                  <a href="?edit_link={$value.id}" title="{$strEdit}"><i class="fa fa-pencil-square-o edit-link"></i></a>
+                  <a href="?edit_link={$value.id}" aria-label="{$strEdit}" title="{$strEdit}"><i class="fa fa-pencil-square-o edit-link" aria-hidden="true"></i></a>
                 {/if}
               </div>
             </div>
index fe665a840293fa2396ff4b0ea9470ce6a091cc4a..4e50495a75bb801e8e026b25c4a2e152c29ad873 100644 (file)
@@ -6,21 +6,21 @@
           {'Filters'|t}
         </span>
         {if="$is_logged_in"}
-        <a href="?visibility=private" title="{'Only display private links'|t}"
+        <a href="?visibility=private" aria-label="{'Only display private links'|t}" title="{'Only display private links'|t}"
            class="{if="$visibility==='private'"}filter-on{else}filter-off{/if}"
-        ><i class="fa fa-user-secret"></i></a>
-        <a href="?visibility=public" title="{'Only display public links'|t}"
+        ><i class="fa fa-user-secret" aria-hidden="true"></i></a>
+        <a href="?visibility=public" aria-label="{'Only display public links'|t}" title="{'Only display public links'|t}"
            class="{if="$visibility==='public'"}filter-on{else}filter-off{/if}"
-        ><i class="fa fa-globe"></i></a>
+        ><i class="fa fa-globe" aria-hidden="true"></i></a>
         {/if}
-        <a href="?untaggedonly" title="{'Filter untagged links'|t}"
+        <a href="?untaggedonly" aria-label="{'Filter untagged links'|t}" title="{'Filter untagged links'|t}"
            class={if="$untaggedonly"}"filter-on"{else}"filter-off"{/if}
-        ><i class="fa fa-tag"></i></a>
-        <a href="#" title="{'Select all'|t}"
+        ><i class="fa fa-tag" aria-hidden="true"></i></a>
+        <a href="#" aria-label="{'Select all'|t}" title="{'Select all'|t}"
            class="filter-off select-all-button"
-        ><i class="fa fa-check-square-o"></i></a>
-        <a href="#" class="filter-off fold-all pure-u-lg-0" title="{'Fold all'|t}">
-          <i class="fa fa-chevron-up"></i>
+        ><i class="fa fa-check-square-o" aria-hidden="true"></i></a>
+        <a href="#" class="filter-off fold-all pure-u-lg-0" aria-label="{'Fold all'|t}" title="{'Fold all'|t}">
+          <i class="fa fa-chevron-up" aria-hidden="true"></i>
         </a>
         {loop="$action_plugin"}
           {$value.attr.class=isset($value.attr.class) ? $value.attr.class : ''}
@@ -59,8 +59,8 @@
       <form method="GET" class="pure-u-0 pure-u-lg-visible">
         <input type="text" name="linksperpage" placeholder="133">
       </form>
-      <a href="#" class="filter-off fold-all pure-u-0 pure-u-lg-visible" title="{'Fold all'|t}">
-        <i class="fa fa-chevron-up"></i>
+      <a href="#" class="filter-off fold-all pure-u-0 pure-u-lg-visible" aria-label="{'Fold all'|t}" title="{'Fold all'|t}">
+        <i class="fa fa-chevron-up" aria-hidden="true"></i>
       </a>
     </div>
   </div>
index 3cdab65ac367b47fb08b61c3030aff1a6660c1f3..bfc548154b982add5db736e90be864a6584589fc 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index 5af39be7d5d7ec2c6fd5a448b47953d0a0752156..f7ae2b84d403c24e4608a52271d8277bbce04a5f 100644 (file)
@@ -2,7 +2,7 @@
 
 <div class="pure-g">
   <div class="pure-u-2-24"></div>
-  <div id="footer" class="pure-u-20-24 footer-container">
+  <footer id="footer" class="pure-u-20-24 footer-container" role="contentinfo">
     <strong><a href="https://github.com/shaarli/Shaarli">Shaarli</a></strong>
     {if="$is_logged_in===true"}
       {$version}
@@ -13,7 +13,7 @@
       {loop="$plugins_footer.text"}
           {$value}
       {/loop}
-  </div>
+  </footer>
   <div class="pure-u-2-24"></div>
 </div>
 
index 4b66502349d7a78e34fcad2c95817813c87eea3f..2832ebbb49601c761274978bd777a7d88f1734f2 100644 (file)
@@ -20,7 +20,7 @@
         {if="$is_logged_in || $openshaarli"}
           <li class="pure-menu-item">
             <a href="?do=addlink" class="pure-menu-link" id="shaarli-menu-shaare">
-              <i class="fa fa-plus" ></i> {'Shaare'|t}
+              <i class="fa fa-plus" aria-hidden="true"></i> {'Shaare'|t}
             </a>
           </li>
           <li class="pure-menu-item" id="shaarli-menu-tools">
           <li class="pure-menu-item" id="shaarli-menu-desktop-search">
             <a href="#" class="pure-menu-link subheader-opener"
                data-open-id="search"
-               id="search-button" title="{'Search'|t}">
-              <i class="fa fa-search"></i>
+               id="search-button" aria-label="{'Search'|t}" title="{'Search'|t}">
+              <i class="fa fa-search" aria-hidden="true"></i>
             </a>
           </li>
           <li class="pure-menu-item" id="shaarli-menu-desktop-rss">
-            <a href="?do={$feed_type}{$searchcrits}" class="pure-menu-link" title="{'RSS Feed'|t}">
-              <i class="fa fa-rss"></i>
+            <a href="?do={$feed_type}{$searchcrits}" class="pure-menu-link" title="{'RSS Feed'|t}" aria-label="{'RSS Feed'|t}">
+              <i class="fa fa-rss" aria-hidden="true"></i>
             </a>
           </li>
           {if="!$is_logged_in"}
             <li class="pure-menu-item" id="shaarli-menu-desktop-login">
               <a href="?do=login" class="pure-menu-link"
                  data-open-id="header-login-form"
-                 id="login-button" title="{'Login'|t}">
-                <i class="fa fa-user"></i>
+                 id="login-button" aria-label="{'Login'|t}" title="{'Login'|t}">
+                <i class="fa fa-user" aria-hidden="true"></i>
               </a>
             </li>
           {else}
             <li class="pure-menu-item" id="shaarli-menu-desktop-logout">
-              <a href="?do=logout" class="pure-menu-link" title="{'Logout'|t}">
-                <i class="fa fa-sign-out"></i>
+              <a href="?do=logout" class="pure-menu-link" aria-label="{'Logout'|t}" title="{'Logout'|t}">
+                <i class="fa fa-sign-out" aria-hidden="true"></i>
               </a>
             </li>
           {/if}
index 4c325487ac0dbfe10328f79205a4f4e9a4d1f242..5a95924497f10540b706b64a66fc7343699ae3aa 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index 820419725f7469e1f96fe94a46293b5ed9f97578..4bfaa934381893d09dd46388b34cd4ac3d4448e3 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index 9e52158dead46f29be307d8c6800100006f6ddeb..bedf3f8cbdc48badba69a568f2e5b71cd33a3d70 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index bcddcd56337a745c5a06d87a0476572ada9201aa..41eab246896b6d932644bb39ca9dcdb6dbf7c8a8 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index 89acda0d56353a77ea7088f93c49a4e4cc1ff118..d24c9f645ae3f9feecc541bb8ff22eeb2c258cbe 100644 (file)
@@ -1,8 +1,8 @@
 <div class="pure-g">
   <div class="pure-u-1 pure-alert pure-alert-success tag-sort">
     {'Sort by:'|t}
-    <a href="?do=tagcloud" title="cloud">{'Cloud'|t}</a> &middot;
-    <a href="?do=taglist&sort=usage" title="cloud">{'Most used'|t}</a> &middot;
-    <a href="?do=taglist&sort=alpha" title="cloud">{'Alphabetical'|t}</a>
+    <a href="?do=tagcloud">{'Cloud'|t}</a> &middot;
+    <a href="?do=taglist&sort=usage">{'Most used'|t}</a> &middot;
+    <a href="?do=taglist&sort=alpha">{'Alphabetical'|t}</a>
   </div>
 </div>
\ No newline at end of file
index a8cf904e1a81c3657b09bbc6319c1a2340fe3542..f193979894b61c9a270a4c2a853405774dbd2b11 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>
index c9ce1eaf4970b61ecc40f0e0e96ce47b56f666e9..20d0c893cb8d80d7dce271d8937189daa7775ac1 100644 (file)
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html>
+<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
 <head>
   {include="includes"}
 </head>