aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.readthedocs.yml15
-rw-r--r--AUTHORS13
-rw-r--r--CHANGELOG.md39
-rw-r--r--README.md4
-rw-r--r--application/Thumbnailer.php2
-rw-r--r--application/api/ApiMiddleware.php4
-rw-r--r--application/api/ApiUtils.php2
-rw-r--r--application/bookmark/LinkDB.php47
-rw-r--r--application/bookmark/LinkUtils.php37
-rw-r--r--application/config/ConfigManager.php4
-rw-r--r--application/feed/FeedBuilder.php6
-rw-r--r--application/netscape/NetscapeBookmarkUtils.php2
-rw-r--r--application/render/PageBuilder.php2
-rw-r--r--application/updater/Updater.php11
-rw-r--r--assets/default/scss/shaarli.scss3
-rw-r--r--doc/md/Download-and-Installation.md6
-rw-r--r--doc/md/Server-configuration.md2
-rw-r--r--doc/md/Shaarli-configuration.md17
-rw-r--r--inc/languages/fr/LC_MESSAGES/shaarli.po3
-rw-r--r--index.php40
-rw-r--r--tests/bookmark/LinkDBTest.php32
-rw-r--r--tests/bookmark/LinkUtilsTest.php61
-rw-r--r--tests/plugins/PluginMarkdownTest.php2
-rw-r--r--tests/updater/UpdaterTest.php19
-rw-r--r--tpl/default/404.html2
-rw-r--r--tpl/default/addlink.html2
-rw-r--r--tpl/default/changepassword.html2
-rw-r--r--tpl/default/changetag.html2
-rw-r--r--tpl/default/configure.html2
-rw-r--r--tpl/default/daily.html2
-rw-r--r--tpl/default/editlink.html2
-rw-r--r--tpl/default/export.html2
-rw-r--r--tpl/default/import.html2
-rw-r--r--tpl/default/install.html2
-rw-r--r--tpl/default/linklist.html24
-rw-r--r--tpl/default/linklist.paging.html24
-rw-r--r--tpl/default/loginform.html2
-rw-r--r--tpl/default/page.footer.html4
-rw-r--r--tpl/default/page.header.html18
-rw-r--r--tpl/default/picwall.html2
-rw-r--r--tpl/default/pluginsadmin.html2
-rw-r--r--tpl/default/tag.cloud.html2
-rw-r--r--tpl/default/tag.list.html2
-rw-r--r--tpl/default/tag.sort.html6
-rw-r--r--tpl/default/thumbnails.html2
-rw-r--r--tpl/default/tools.html2
46 files changed, 233 insertions, 250 deletions
diff --git a/.readthedocs.yml b/.readthedocs.yml
new file mode 100644
index 00000000..09e5a6a5
--- /dev/null
+++ b/.readthedocs.yml
@@ -0,0 +1,15 @@
1# .readthedocs.yml
2# Read the Docs configuration file
3# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
4
5# Required
6version: 2
7
8# Build documentation with MkDocs
9mkdocs:
10 configuration: mkdocs.yml
11
12# Optionally set the version of Python and requirements required to build your docs
13# https://github.com/rtfd/readthedocs.org/issues/5250
14python:
15 version: 3.5 \ No newline at end of file
diff --git a/AUTHORS b/AUTHORS
index db23ad32..7fa2734a 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,13 +1,15 @@
1 687 ArthurHoaro <arthur@hoa.ro> 1 734 ArthurHoaro <arthur@hoa.ro>
2 355 VirtualTam <virtualtam@flibidi.net> 2 400 VirtualTam <virtualtam@flibidi.net>
3 195 nodiscc <nodiscc@gmail.com> 3 215 nodiscc <nodiscc@gmail.com>
4 56 Sébastien Sauvage <sebsauvage@sebsauvage.net> 4 56 Sébastien Sauvage <sebsauvage@sebsauvage.net>
5 15 Florian Eula <eula.florian@gmail.com> 5 15 Florian Eula <eula.florian@gmail.com>
6 13 Emilien Klein <emilien@klein.st> 6 13 Emilien Klein <emilien@klein.st>
7 12 Nicolas Danelon <hi@nicolasmd.com.ar> 7 12 Nicolas Danelon <hi@nicolasmd.com.ar>
8 9 Willi Eggeling <thewilli@gmail.com> 8 9 Willi Eggeling <thewilli@gmail.com>
9 8 Christophe HENRY <christophe.henry@sbgodin.fr> 9 8 Christophe HENRY <christophe.henry@sbgodin.fr>
10 7 Luce Carević <lcarevic@access42.net>
10 6 B. van Berkum <dev@dotmpe.com> 11 6 B. van Berkum <dev@dotmpe.com>
12 6 llune <llune@users.noreply.github.com>
11 5 Lucas Cimon <lucas.cimon@gmail.com> 13 5 Lucas Cimon <lucas.cimon@gmail.com>
12 5 Mark Schmitz <kramred@gmail.com> 14 5 Mark Schmitz <kramred@gmail.com>
13 5 kalvn <kalvnthereal@gmail.com> 15 5 kalvn <kalvnthereal@gmail.com>
@@ -15,7 +17,7 @@
15 4 David Sferruzza <david.sferruzza@gmail.com> 17 4 David Sferruzza <david.sferruzza@gmail.com>
16 4 Immánuel Fodor <immanuelfactor+github@gmail.com> 18 4 Immánuel Fodor <immanuelfactor+github@gmail.com>
17 3 Teromene <teromene@teromene.fr> 19 3 Teromene <teromene@teromene.fr>
18 3 llune <llune@users.noreply.github.com> 20 2 Alexandre G.-Raymond <alex@ndre.gr>
19 2 Chris Kuethe <chris.kuethe@gmail.com> 21 2 Chris Kuethe <chris.kuethe@gmail.com>
20 2 Felix Bartels <felix@host-consultants.de> 22 2 Felix Bartels <felix@host-consultants.de>
21 2 Knah Tsaeb <Knah-Tsaeb@knah-tsaeb.org> 23 2 Knah Tsaeb <Knah-Tsaeb@knah-tsaeb.org>
@@ -27,11 +29,12 @@
27 2 julienCXX <software@chmodplusx.eu> 29 2 julienCXX <software@chmodplusx.eu>
28 2 philipp-r <philipp-r@users.noreply.github.com> 30 2 philipp-r <philipp-r@users.noreply.github.com>
29 2 pips <pips@e5150.fr> 31 2 pips <pips@e5150.fr>
32 2 trailjeep <trailjeep@gmail.com>
30 1 Adrien Oliva <adrien.oliva@yapbreak.fr> 33 1 Adrien Oliva <adrien.oliva@yapbreak.fr>
31 1 Adrien le Maire <adrien@alemaire.be> 34 1 Adrien le Maire <adrien@alemaire.be>
32 1 Alexandre G.-Raymond <alex@ndre.gr>
33 1 Alexis J <alexis@effingo.be> 35 1 Alexis J <alexis@effingo.be>
34 1 Angristan <angristan@users.noreply.github.com> 36 1 Angristan <angristan@users.noreply.github.com>
37 1 Bish Erbas <42714627+bisherbas@users.noreply.github.com>
35 1 BoboTiG <bobotig@gmail.com> 38 1 BoboTiG <bobotig@gmail.com>
36 1 Bronco <bronco@warriordudimanche.net> 39 1 Bronco <bronco@warriordudimanche.net>
37 1 Buster One <37770318+buster-one@users.noreply.github.com> 40 1 Buster One <37770318+buster-one@users.noreply.github.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aa1f0d8a..865e0370 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,41 @@ All notable changes to this project will be documented in this file.
4The format is based on [Keep a Changelog](http://keepachangelog.com/) 4The format is based on [Keep a Changelog](http://keepachangelog.com/)
5and this project adheres to [Semantic Versioning](http://semver.org/). 5and this project adheres to [Semantic Versioning](http://semver.org/).
6 6
7
8## [v0.10.4](https://github.com/shaarli/Shaarli/releases/tag/v0.10.4) - 2019-04-16
9### Fixed
10- Fix thumbnails disabling if PHP GD is not installed
11- Fix a warning if links sticky status isn't set
12
13## [v0.10.3](https://github.com/shaarli/Shaarli/releases/tag/v0.10.3) - 2019-02-23
14### Added
15- Add OpenGraph metadata tags on permalink page
16- Add CORS headers to REST API reponses
17- Add a button to toggle checkboxes of displayed links
18- Add an icon to the link list when the Isso plugin is enabled
19- Add noindex, nofollow to documentation pages
20- Document usage of robots.txt
21- Add a button to set links as sticky
22
23### Changed
24- Update French translation
25- Refactor the documentation homepage
26- Bump netscape-bookmark-parser
27- Update session_start condition
28- Improve accessibility
29- Cleanup and refactor lint tooling
30
31### Fixed
32- Fix input size for dropdown search form
33- Fix history for bulk link deletion
34- Fix thumbnail requests
35- Fix hashtag rendering when markdown escaping is enabled
36- Fix AJAX tag deletion
37- Fix lint errors and improve PSR-1 and PSR-2 compliance
38
39### Removed
40- Remove Firefox Share documentation
41
7## [v0.10.2](https://github.com/shaarli/Shaarli/releases/tag/v0.10.2) - 2018-08-11 42## [v0.10.2](https://github.com/shaarli/Shaarli/releases/tag/v0.10.2) - 2018-08-11
8 43
9### Fixed 44### Fixed
@@ -12,7 +47,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
12 47
13## [v0.10.1](https://github.com/shaarli/Shaarli/releases/tag/v0.10.1) - 2018-08-11 48## [v0.10.1](https://github.com/shaarli/Shaarli/releases/tag/v0.10.1) - 2018-08-11
14 49
15### Changed 50### Changed
16 51
17- Accessibility: 52- Accessibility:
18 - Remove alt text on the logo 53 - Remove alt text on the logo
@@ -46,7 +81,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
46- Use Travis matrix and stages to run Javascript tests in a dedicated environment 81- Use Travis matrix and stages to run Javascript tests in a dedicated environment
47- Add tag endpoint in the REST API 82- Add tag endpoint in the REST API
48- Build the documentation in Travis builds 83- Build the documentation in Travis builds
49- Provide a Docker Compose example 84- Provide a Docker Compose example
50 85
51### Changed 86### Changed
52- Use web-thumbnailer to retrieve thumbnails (see #687) 87- Use web-thumbnailer to retrieve thumbnails (see #687)
diff --git a/README.md b/README.md
index 0e23e33d..21f2eae7 100644
--- a/README.md
+++ b/README.md
@@ -9,10 +9,10 @@ _It is designed to be personal (single-user), fast and handy._
9[![](https://img.shields.io/badge/stable-v0.9.7-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.9.7) 9[![](https://img.shields.io/badge/stable-v0.9.7-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.9.7)
10[![](https://img.shields.io/travis/shaarli/Shaarli/stable.svg?label=stable)](https://travis-ci.org/shaarli/Shaarli) 10[![](https://img.shields.io/travis/shaarli/Shaarli/stable.svg?label=stable)](https://travis-ci.org/shaarli/Shaarli)
11&bull; 11&bull;
12[![](https://img.shields.io/badge/latest-v0.10.2-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.10.2) 12[![](https://img.shields.io/badge/latest-v0.10.4-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.10.4)
13[![](https://img.shields.io/travis/shaarli/Shaarli/latest.svg?label=latest)](https://travis-ci.org/shaarli/Shaarli) 13[![](https://img.shields.io/travis/shaarli/Shaarli/latest.svg?label=latest)](https://travis-ci.org/shaarli/Shaarli)
14&bull; 14&bull;
15[![](https://img.shields.io/badge/master-v0.10.x-blue.svg)](https://github.com/shaarli/Shaarli) 15[![](https://img.shields.io/badge/master-v0.11.x-blue.svg)](https://github.com/shaarli/Shaarli)
16[![](https://img.shields.io/travis/shaarli/Shaarli.svg?label=master)](https://travis-ci.org/shaarli/Shaarli) 16[![](https://img.shields.io/travis/shaarli/Shaarli.svg?label=master)](https://travis-ci.org/shaarli/Shaarli)
17 17
18[![Join the chat at https://gitter.im/shaarli/Shaarli](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/shaarli/Shaarli) 18[![Join the chat at https://gitter.im/shaarli/Shaarli](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/shaarli/Shaarli)
diff --git a/application/Thumbnailer.php b/application/Thumbnailer.php
index a23f98e9..d5f5ac28 100644
--- a/application/Thumbnailer.php
+++ b/application/Thumbnailer.php
@@ -55,7 +55,7 @@ class Thumbnailer
55 $this->conf = $conf; 55 $this->conf = $conf;
56 56
57 if (! $this->checkRequirements()) { 57 if (! $this->checkRequirements()) {
58 $this->conf->set('thumbnails.enabled', false); 58 $this->conf->set('thumbnails.mode', Thumbnailer::MODE_NONE);
59 $this->conf->write(true); 59 $this->conf->write(true);
60 // TODO: create a proper error handling system able to catch exceptions... 60 // TODO: create a proper error handling system able to catch exceptions...
61 die(t( 61 die(t(
diff --git a/application/api/ApiMiddleware.php b/application/api/ApiMiddleware.php
index 5ffb8c6d..2d55bda6 100644
--- a/application/api/ApiMiddleware.php
+++ b/application/api/ApiMiddleware.php
@@ -129,9 +129,7 @@ class ApiMiddleware
129 $linkDb = new \Shaarli\Bookmark\LinkDB( 129 $linkDb = new \Shaarli\Bookmark\LinkDB(
130 $conf->get('resource.datastore'), 130 $conf->get('resource.datastore'),
131 true, 131 true,
132 $conf->get('privacy.hide_public_links'), 132 $conf->get('privacy.hide_public_links')
133 $conf->get('redirector.url'),
134 $conf->get('redirector.encode_url')
135 ); 133 );
136 $this->container['db'] = $linkDb; 134 $this->container['db'] = $linkDb;
137 } 135 }
diff --git a/application/api/ApiUtils.php b/application/api/ApiUtils.php
index 1824b5d0..1e3ac02e 100644
--- a/application/api/ApiUtils.php
+++ b/application/api/ApiUtils.php
@@ -59,7 +59,7 @@ class ApiUtils
59 { 59 {
60 $out['id'] = $link['id']; 60 $out['id'] = $link['id'];
61 // Not an internal link 61 // Not an internal link
62 if ($link['url'][0] != '?') { 62 if (! is_note($link['url'])) {
63 $out['url'] = $link['url']; 63 $out['url'] = $link['url'];
64 } else { 64 } else {
65 $out['url'] = $indexUrl . $link['url']; 65 $out['url'] = $indexUrl . $link['url'];
diff --git a/application/bookmark/LinkDB.php b/application/bookmark/LinkDB.php
index c13a1141..efde8468 100644
--- a/application/bookmark/LinkDB.php
+++ b/application/bookmark/LinkDB.php
@@ -29,10 +29,10 @@ use Shaarli\FileUtils;
29 * - private: Is this link private? 0=no, other value=yes 29 * - private: Is this link private? 0=no, other value=yes
30 * - tags: tags attached to this entry (separated by spaces) 30 * - tags: tags attached to this entry (separated by spaces)
31 * - title Title of the link 31 * - title Title of the link
32 * - url URL of the link. Used for displayable links (no redirector, relative, etc.). 32 * - url URL of the link. Used for displayable links.
33 * Can be absolute or relative. 33 * Can be absolute or relative in the database but the relative links
34 * Relative URLs are permalinks (e.g.'?m-ukcw') 34 * will be converted to absolute ones in templates.
35 * - real_url Absolute processed URL. 35 * - real_url Raw URL in stored in the DB (absolute or relative).
36 * - shorturl Permalink smallhash 36 * - shorturl Permalink smallhash
37 * 37 *
38 * Implements 3 interfaces: 38 * Implements 3 interfaces:
@@ -88,19 +88,6 @@ class LinkDB implements Iterator, Countable, ArrayAccess
88 // Hide public links 88 // Hide public links
89 private $hidePublicLinks; 89 private $hidePublicLinks;
90 90
91 // link redirector set in user settings.
92 private $redirector;
93
94 /**
95 * Set this to `true` to urlencode link behind redirector link, `false` to leave it untouched.
96 *
97 * Example:
98 * anonym.to needs clean URL while dereferer.org needs urlencoded URL.
99 *
100 * @var boolean $redirectorEncode parameter: true or false
101 */
102 private $redirectorEncode;
103
104 /** 91 /**
105 * Creates a new LinkDB 92 * Creates a new LinkDB
106 * 93 *
@@ -109,22 +96,16 @@ class LinkDB implements Iterator, Countable, ArrayAccess
109 * @param string $datastore datastore file path. 96 * @param string $datastore datastore file path.
110 * @param boolean $isLoggedIn is the user logged in? 97 * @param boolean $isLoggedIn is the user logged in?
111 * @param boolean $hidePublicLinks if true all links are private. 98 * @param boolean $hidePublicLinks if true all links are private.
112 * @param string $redirector link redirector set in user settings.
113 * @param boolean $redirectorEncode Enable urlencode on redirected urls (default: true).
114 */ 99 */
115 public function __construct( 100 public function __construct(
116 $datastore, 101 $datastore,
117 $isLoggedIn, 102 $isLoggedIn,
118 $hidePublicLinks, 103 $hidePublicLinks
119 $redirector = '',
120 $redirectorEncode = true
121 ) { 104 ) {
122 105
123 $this->datastore = $datastore; 106 $this->datastore = $datastore;
124 $this->loggedIn = $isLoggedIn; 107 $this->loggedIn = $isLoggedIn;
125 $this->hidePublicLinks = $hidePublicLinks; 108 $this->hidePublicLinks = $hidePublicLinks;
126 $this->redirector = $redirector;
127 $this->redirectorEncode = $redirectorEncode === true;
128 $this->check(); 109 $this->check();
129 $this->read(); 110 $this->read();
130 } 111 }
@@ -271,7 +252,8 @@ You use the community supported version of the original Shaarli project, by Seba
271 ), 252 ),
272 'private' => 0, 253 'private' => 0,
273 'created' => new DateTime(), 254 'created' => new DateTime(),
274 'tags' => 'opensource software' 255 'tags' => 'opensource software',
256 'sticky' => false,
275 ); 257 );
276 $link['shorturl'] = link_small_hash($link['created'], $link['id']); 258 $link['shorturl'] = link_small_hash($link['created'], $link['id']);
277 $this->links[1] = $link; 259 $this->links[1] = $link;
@@ -284,6 +266,7 @@ You use the community supported version of the original Shaarli project, by Seba
284 'private' => 1, 266 'private' => 1,
285 'created' => new DateTime('1 minute ago'), 267 'created' => new DateTime('1 minute ago'),
286 'tags' => 'secretstuff', 268 'tags' => 'secretstuff',
269 'sticky' => false,
287 ); 270 );
288 $link['shorturl'] = link_small_hash($link['created'], $link['id']); 271 $link['shorturl'] = link_small_hash($link['created'], $link['id']);
289 $this->links[0] = $link; 272 $this->links[0] = $link;
@@ -323,17 +306,9 @@ You use the community supported version of the original Shaarli project, by Seba
323 $link['tags'] = preg_replace('/(^|\s+)\.[^($|\s)]+\s*/', ' ', $link['tags']); 306 $link['tags'] = preg_replace('/(^|\s+)\.[^($|\s)]+\s*/', ' ', $link['tags']);
324 } 307 }
325 308
326 // Do not use the redirector for internal links (Shaarli note URL starting with a '?'). 309 $link['real_url'] = $link['url'];
327 if (!empty($this->redirector) && !startsWith($link['url'], '?')) { 310
328 $link['real_url'] = $this->redirector; 311 $link['sticky'] = isset($link['sticky']) ? $link['sticky'] : false;
329 if ($this->redirectorEncode) {
330 $link['real_url'] .= urlencode(unescape($link['url']));
331 } else {
332 $link['real_url'] .= $link['url'];
333 }
334 } else {
335 $link['real_url'] = $link['url'];
336 }
337 312
338 // To be able to load links before running the update, and prepare the update 313 // To be able to load links before running the update, and prepare the update
339 if (!isset($link['created'])) { 314 if (!isset($link['created'])) {
diff --git a/application/bookmark/LinkUtils.php b/application/bookmark/LinkUtils.php
index de5b61cb..35a5b290 100644
--- a/application/bookmark/LinkUtils.php
+++ b/application/bookmark/LinkUtils.php
@@ -133,29 +133,15 @@ function count_private($links)
133 * In a string, converts URLs to clickable links. 133 * In a string, converts URLs to clickable links.
134 * 134 *
135 * @param string $text input string. 135 * @param string $text input string.
136 * @param string $redirector if a redirector is set, use it to gerenate links.
137 * @param bool $urlEncode Use `urlencode()` on the URL after the redirector or not.
138 * 136 *
139 * @return string returns $text with all links converted to HTML links. 137 * @return string returns $text with all links converted to HTML links.
140 * 138 *
141 * @see Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722 139 * @see Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722
142 */ 140 */
143function text2clickable($text, $redirector = '', $urlEncode = true) 141function text2clickable($text)
144{ 142{
145 $regex = '!(((?:https?|ftp|file)://|apt:|magnet:)\S+[a-z0-9\(\)]/?)!si'; 143 $regex = '!(((?:https?|ftp|file)://|apt:|magnet:)\S+[a-z0-9\(\)]/?)!si';
146 144 return preg_replace($regex, '<a href="$1">$1</a>', $text);
147 if (empty($redirector)) {
148 return preg_replace($regex, '<a href="$1">$1</a>', $text);
149 }
150 // Redirector is set, urlencode the final URL.
151 return preg_replace_callback(
152 $regex,
153 function ($matches) use ($redirector, $urlEncode) {
154 $url = $urlEncode ? urlencode($matches[1]) : $matches[1];
155 return '<a href="' . $redirector . $url .'">'. $matches[1] .'</a>';
156 },
157 $text
158 );
159} 145}
160 146
161/** 147/**
@@ -197,15 +183,13 @@ function space2nbsp($text)
197 * Format Shaarli's description 183 * Format Shaarli's description
198 * 184 *
199 * @param string $description shaare's description. 185 * @param string $description shaare's description.
200 * @param string $redirector if a redirector is set, use it to gerenate links.
201 * @param bool $urlEncode Use `urlencode()` on the URL after the redirector or not.
202 * @param string $indexUrl URL to Shaarli's index. 186 * @param string $indexUrl URL to Shaarli's index.
203 187
204 * @return string formatted description. 188 * @return string formatted description.
205 */ 189 */
206function format_description($description, $redirector = '', $urlEncode = true, $indexUrl = '') 190function format_description($description, $indexUrl = '')
207{ 191{
208 return nl2br(space2nbsp(hashtag_autolink(text2clickable($description, $redirector, $urlEncode), $indexUrl))); 192 return nl2br(space2nbsp(hashtag_autolink(text2clickable($description), $indexUrl)));
209} 193}
210 194
211/** 195/**
@@ -220,3 +204,16 @@ function link_small_hash($date, $id)
220{ 204{
221 return smallHash($date->format(LinkDB::LINK_DATE_FORMAT) . $id); 205 return smallHash($date->format(LinkDB::LINK_DATE_FORMAT) . $id);
222} 206}
207
208/**
209 * Returns whether or not the link is an internal note.
210 * Its URL starts by `?` because it's actually a permalink.
211 *
212 * @param string $linkUrl
213 *
214 * @return bool true if internal note, false otherwise.
215 */
216function is_note($linkUrl)
217{
218 return isset($linkUrl[0]) && $linkUrl[0] === '?';
219}
diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php
index e6c35073..30993928 100644
--- a/application/config/ConfigManager.php
+++ b/application/config/ConfigManager.php
@@ -221,7 +221,6 @@ class ConfigManager
221 'general.title', 221 'general.title',
222 'general.header_link', 222 'general.header_link',
223 'privacy.default_private_links', 223 'privacy.default_private_links',
224 'redirector.url',
225 ); 224 );
226 225
227 // Only logged in user can alter config. 226 // Only logged in user can alter config.
@@ -381,9 +380,6 @@ class ConfigManager
381 // default state of the 'remember me' checkbox of the login form 380 // default state of the 'remember me' checkbox of the login form
382 $this->setEmpty('privacy.remember_user_default', true); 381 $this->setEmpty('privacy.remember_user_default', true);
383 382
384 $this->setEmpty('redirector.url', '');
385 $this->setEmpty('redirector.encode_url', true);
386
387 $this->setEmpty('thumbnails.width', '125'); 383 $this->setEmpty('thumbnails.width', '125');
388 $this->setEmpty('thumbnails.height', '90'); 384 $this->setEmpty('thumbnails.height', '90');
389 385
diff --git a/application/feed/FeedBuilder.php b/application/feed/FeedBuilder.php
index b66f2f91..7c859474 100644
--- a/application/feed/FeedBuilder.php
+++ b/application/feed/FeedBuilder.php
@@ -147,8 +147,8 @@ class FeedBuilder
147 protected function buildItem($link, $pageaddr) 147 protected function buildItem($link, $pageaddr)
148 { 148 {
149 $link['guid'] = $pageaddr . '?' . $link['shorturl']; 149 $link['guid'] = $pageaddr . '?' . $link['shorturl'];
150 // Check for both signs of a note: starting with ? and 7 chars long. 150 // Prepend the root URL for notes
151 if ($link['url'][0] === '?' && strlen($link['url']) === 7) { 151 if (is_note($link['url'])) {
152 $link['url'] = $pageaddr . $link['url']; 152 $link['url'] = $pageaddr . $link['url'];
153 } 153 }
154 if ($this->usePermalinks === true) { 154 if ($this->usePermalinks === true) {
@@ -156,7 +156,7 @@ class FeedBuilder
156 } else { 156 } else {
157 $permalink = '<a href="' . $link['guid'] . '" title="' . t('Permalink') . '">' . t('Permalink') . '</a>'; 157 $permalink = '<a href="' . $link['guid'] . '" title="' . t('Permalink') . '">' . t('Permalink') . '</a>';
158 } 158 }
159 $link['description'] = format_description($link['description'], '', false, $pageaddr); 159 $link['description'] = format_description($link['description'], $pageaddr);
160 $link['description'] .= PHP_EOL . '<br>&#8212; ' . $permalink; 160 $link['description'] .= PHP_EOL . '<br>&#8212; ' . $permalink;
161 161
162 $pubDate = $link['created']; 162 $pubDate = $link['created'];
diff --git a/application/netscape/NetscapeBookmarkUtils.php b/application/netscape/NetscapeBookmarkUtils.php
index 2fb1a4a6..28665941 100644
--- a/application/netscape/NetscapeBookmarkUtils.php
+++ b/application/netscape/NetscapeBookmarkUtils.php
@@ -54,7 +54,7 @@ class NetscapeBookmarkUtils
54 $link['timestamp'] = $date->getTimestamp(); 54 $link['timestamp'] = $date->getTimestamp();
55 $link['taglist'] = str_replace(' ', ',', $link['tags']); 55 $link['taglist'] = str_replace(' ', ',', $link['tags']);
56 56
57 if (startsWith($link['url'], '?') && $prependNoteUrl) { 57 if (is_note($link['url']) && $prependNoteUrl) {
58 $link['url'] = $indexUrl . $link['url']; 58 $link['url'] = $indexUrl . $link['url'];
59 } 59 }
60 60
diff --git a/application/render/PageBuilder.php b/application/render/PageBuilder.php
index 0569b67f..3f86fc26 100644
--- a/application/render/PageBuilder.php
+++ b/application/render/PageBuilder.php
@@ -123,6 +123,8 @@ class PageBuilder
123 $this->tpl->assign('hide_timestamps', $this->conf->get('privacy.hide_timestamps', false)); 123 $this->tpl->assign('hide_timestamps', $this->conf->get('privacy.hide_timestamps', false));
124 $this->tpl->assign('token', $this->token); 124 $this->tpl->assign('token', $this->token);
125 125
126 $this->tpl->assign('language', $this->conf->get('translation.language'));
127
126 if ($this->linkDB !== null) { 128 if ($this->linkDB !== null) {
127 $this->tpl->assign('tags', $this->linkDB->linksCountPerTag()); 129 $this->tpl->assign('tags', $this->linkDB->linksCountPerTag());
128 } 130 }
diff --git a/application/updater/Updater.php b/application/updater/Updater.php
index f12e3516..beb9ea9b 100644
--- a/application/updater/Updater.php
+++ b/application/updater/Updater.php
@@ -218,7 +218,6 @@ class Updater
218 try { 218 try {
219 $this->conf->set('general.title', escape($this->conf->get('general.title'))); 219 $this->conf->set('general.title', escape($this->conf->get('general.title')));
220 $this->conf->set('general.header_link', escape($this->conf->get('general.header_link'))); 220 $this->conf->set('general.header_link', escape($this->conf->get('general.header_link')));
221 $this->conf->set('redirector.url', escape($this->conf->get('redirector.url')));
222 $this->conf->write($this->isLoggedIn); 221 $this->conf->write($this->isLoggedIn);
223 } catch (Exception $e) { 222 } catch (Exception $e) {
224 error_log($e->getMessage()); 223 error_log($e->getMessage());
@@ -550,4 +549,14 @@ class Updater
550 549
551 return true; 550 return true;
552 } 551 }
552
553 /**
554 * Remove redirector settings.
555 */
556 public function updateMethodRemoveRedirector()
557 {
558 $this->conf->remove('redirector');
559 $this->conf->write(true);
560 return true;
561 }
553} 562}
diff --git a/assets/default/scss/shaarli.scss b/assets/default/scss/shaarli.scss
index 760d8d6a..691b2b37 100644
--- a/assets/default/scss/shaarli.scss
+++ b/assets/default/scss/shaarli.scss
@@ -544,7 +544,10 @@ body,
544 color: $dark-grey; 544 color: $dark-grey;
545 font-size: .9em; 545 font-size: .9em;
546 546
547
547 a { 548 a {
549 display: inline-block;
550 margin: 3px 0;
548 padding: 5px 8px; 551 padding: 5px 8px;
549 text-decoration: none; 552 text-decoration: none;
550 } 553 }
diff --git a/doc/md/Download-and-Installation.md b/doc/md/Download-and-Installation.md
index 14649e06..8c9e8a32 100644
--- a/doc/md/Download-and-Installation.md
+++ b/doc/md/Download-and-Installation.md
@@ -24,11 +24,11 @@ Using one of the following methods:
24 24
25In 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. 25In 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.
26 26
27The current latest released version is `v0.9.7` 27The current latest released version is `v0.10.4`
28 28
29```bash 29```bash
30$ wget https://github.com/shaarli/Shaarli/releases/download/v0.9.7/shaarli-v0.9.7-full.zip 30$ wget https://github.com/shaarli/Shaarli/releases/download/v0.10.4/shaarli-v0.10.4-full.zip
31$ unzip shaarli-v0.9.7-full.zip 31$ unzip shaarli-v0.10.4-full.zip
32$ mv Shaarli /path/to/shaarli/ 32$ mv Shaarli /path/to/shaarli/
33``` 33```
34 34
diff --git a/doc/md/Server-configuration.md b/doc/md/Server-configuration.md
index 78083a46..4753df1d 100644
--- a/doc/md/Server-configuration.md
+++ b/doc/md/Server-configuration.md
@@ -17,7 +17,7 @@ Version | Status | Shaarli compatibility
17:---:|:---:|:---: 17:---:|:---:|:---:
187.2 | Supported | Yes 187.2 | Supported | Yes
197.1 | Supported | Yes 197.1 | Supported | Yes
207.0 | Supported | Yes 207.0 | EOL: 2018-12-03 | Yes (up to Shaarli 0.10.x)
215.6 | EOL: 2018-12-31 | Yes (up to Shaarli 0.10.x) 215.6 | EOL: 2018-12-31 | Yes (up to Shaarli 0.10.x)
225.5 | EOL: 2016-07-10 | Yes 225.5 | EOL: 2016-07-10 | Yes
235.4 | EOL: 2015-09-14 | Yes (up to Shaarli 0.8.x) 235.4 | EOL: 2015-09-14 | Yes (up to Shaarli 0.8.x)
diff --git a/doc/md/Shaarli-configuration.md b/doc/md/Shaarli-configuration.md
index 920c7e27..a931ab1e 100644
--- a/doc/md/Shaarli-configuration.md
+++ b/doc/md/Shaarli-configuration.md
@@ -4,7 +4,7 @@
4 4
5Once your Shaarli instance is installed, the file `data/config.json.php` is generated: 5Once your Shaarli instance is installed, the file `data/config.json.php` is generated:
6* it contains all settings in JSON format, and can be edited to customize values 6* it contains all settings in JSON format, and can be edited to customize values
7* it defines which [plugins](Plugin-System) are enabled[](.html) 7* it defines which [plugins](Plugin-System) are enabled
8* its values override those defined in `index.php` 8* its values override those defined in `index.php`
9* it is wrap in a PHP comment to prevent anyone accessing it, regardless of server configuration 9* it is wrap in a PHP comment to prevent anyone accessing it, regardless of server configuration
10 10
@@ -32,13 +32,13 @@ On a Linux distribution:
32- to give it access to Shaarli, either: 32- to give it access to Shaarli, either:
33 - unzip Shaarli in the default web server location (usually `/var/www/`) and set the web server user as the owner 33 - unzip Shaarli in the default web server location (usually `/var/www/`) and set the web server user as the owner
34 - put users in the same group as the web server, and set the appropriate access rights 34 - put users in the same group as the web server, and set the appropriate access rights
35- if you have a domain / subdomain to serve Shaarli, [configure the server](Server-configuration) accordingly[](.html) 35- if you have a domain / subdomain to serve Shaarli, [configure the server](Server-configuration) accordingly
36 36
37## Configuration 37## Configuration
38 38
39In `data/config.json.php`. 39In `data/config.json.php`.
40 40
41See also [Plugin System](Plugin-System.html). 41See also [Plugin System](Plugin-System).
42 42
43### Credentials 43### Credentials
44 44
@@ -120,11 +120,6 @@ Must be an associative array: `translation domain => translation path`.
120- **enable_thumbnails**: Enable or disable thumbnail display. 120- **enable_thumbnails**: Enable or disable thumbnail display.
121- **enable_localcache**: Enable or disable local cache. 121- **enable_localcache**: Enable or disable local cache.
122 122
123### Redirector
124
125- **url**: Redirector URL, such as `anonym.to`.
126- **encode_url**: Enable this if the redirector needs encoded URL to work properly.
127
128## Configuration file example 123## Configuration file example
129 124
130```json 125```json
@@ -185,8 +180,6 @@ Must be an associative array: `translation domain => translation path`.
185 "hide_public_links": false, 180 "hide_public_links": false,
186 "hide_timestamps": false, 181 "hide_timestamps": false,
187 "open_shaarli": false, 182 "open_shaarli": false,
188 "redirector": "http://anonym.to/?",
189 "redirector_encode_url": false
190 }, 183 },
191 "general": { 184 "general": {
192 "header_link": "?", 185 "header_link": "?",
@@ -218,10 +211,6 @@ Must be an associative array: `translation domain => translation path`.
218 "enable_thumbnails": true, 211 "enable_thumbnails": true,
219 "enable_localcache": true 212 "enable_localcache": true
220 }, 213 },
221 "redirector": {
222 "url": "http://anonym.to/?",
223 "encode_url": false
224 },
225 "plugins": { 214 "plugins": {
226 "WALLABAG_URL": "http://demo.wallabag.org", 215 "WALLABAG_URL": "http://demo.wallabag.org",
227 "WALLABAG_VERSION": "1" 216 "WALLABAG_VERSION": "1"
diff --git a/inc/languages/fr/LC_MESSAGES/shaarli.po b/inc/languages/fr/LC_MESSAGES/shaarli.po
index 102c80da..649f6dd5 100644
--- a/inc/languages/fr/LC_MESSAGES/shaarli.po
+++ b/inc/languages/fr/LC_MESSAGES/shaarli.po
@@ -1255,6 +1255,9 @@ msgstr ""
1255#~ msgid "Selection" 1255#~ msgid "Selection"
1256#~ msgstr "Choisir" 1256#~ msgstr "Choisir"
1257 1257
1258#~ msgid "Select all"
1259#~ msgstr "Tout sélectionner"
1260
1258#~ msgid "Public" 1261#~ msgid "Public"
1259#~ msgstr "Publics" 1262#~ msgstr "Publics"
1260 1263
diff --git a/index.php b/index.php
index 322c360c..68e0364c 100644
--- a/index.php
+++ b/index.php
@@ -312,9 +312,7 @@ function showDailyRSS($conf, $loginManager)
312 $LINKSDB = new LinkDB( 312 $LINKSDB = new LinkDB(
313 $conf->get('resource.datastore'), 313 $conf->get('resource.datastore'),
314 $loginManager->isLoggedIn(), 314 $loginManager->isLoggedIn(),
315 $conf->get('privacy.hide_public_links'), 315 $conf->get('privacy.hide_public_links')
316 $conf->get('redirector.url'),
317 $conf->get('redirector.encode_url')
318 ); 316 );
319 317
320 /* Some Shaarlies may have very few links, so we need to look 318 /* Some Shaarlies may have very few links, so we need to look
@@ -356,13 +354,9 @@ function showDailyRSS($conf, $loginManager)
356 354
357 // We pre-format some fields for proper output. 355 // We pre-format some fields for proper output.
358 foreach ($links as &$link) { 356 foreach ($links as &$link) {
359 $link['formatedDescription'] = format_description( 357 $link['formatedDescription'] = format_description($link['description']);
360 $link['description'],
361 $conf->get('redirector.url'),
362 $conf->get('redirector.encode_url')
363 );
364 $link['timestamp'] = $link['created']->getTimestamp(); 358 $link['timestamp'] = $link['created']->getTimestamp();
365 if (startsWith($link['url'], '?')) { 359 if (is_note($link['url'])) {
366 $link['url'] = index_url($_SERVER) . $link['url']; // make permalink URL absolute 360 $link['url'] = index_url($_SERVER) . $link['url']; // make permalink URL absolute
367 } 361 }
368 } 362 }
@@ -433,11 +427,7 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager, $loginManager)
433 $taglist = explode(' ', $link['tags']); 427 $taglist = explode(' ', $link['tags']);
434 uasort($taglist, 'strcasecmp'); 428 uasort($taglist, 'strcasecmp');
435 $linksToDisplay[$key]['taglist']=$taglist; 429 $linksToDisplay[$key]['taglist']=$taglist;
436 $linksToDisplay[$key]['formatedDescription'] = format_description( 430 $linksToDisplay[$key]['formatedDescription'] = format_description($link['description']);
437 $link['description'],
438 $conf->get('redirector.url'),
439 $conf->get('redirector.encode_url')
440 );
441 $linksToDisplay[$key]['timestamp'] = $link['created']->getTimestamp(); 431 $linksToDisplay[$key]['timestamp'] = $link['created']->getTimestamp();
442 } 432 }
443 433
@@ -1074,7 +1064,6 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
1074 $PAGE->assign('api_enabled', $conf->get('api.enabled', true)); 1064 $PAGE->assign('api_enabled', $conf->get('api.enabled', true));
1075 $PAGE->assign('api_secret', $conf->get('api.secret')); 1065 $PAGE->assign('api_secret', $conf->get('api.secret'));
1076 $PAGE->assign('languages', Languages::getAvailableLanguages()); 1066 $PAGE->assign('languages', Languages::getAvailableLanguages());
1077 $PAGE->assign('language', $conf->get('translation.language'));
1078 $PAGE->assign('gd_enabled', extension_loaded('gd')); 1067 $PAGE->assign('gd_enabled', extension_loaded('gd'));
1079 $PAGE->assign('thumbnails_mode', $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE)); 1068 $PAGE->assign('thumbnails_mode', $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE));
1080 $PAGE->assign('pagetitle', t('Configure') .' - '. $conf->get('general.title', 'Shaarli')); 1069 $PAGE->assign('pagetitle', t('Configure') .' - '. $conf->get('general.title', 'Shaarli'));
@@ -1176,11 +1165,15 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
1176 $link['title'] = $link['url']; 1165 $link['title'] = $link['url'];
1177 } 1166 }
1178 1167
1179 if ($conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE) { 1168 if ($conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE
1169 && ! is_note($link['url'])
1170 ) {
1180 $thumbnailer = new Thumbnailer($conf); 1171 $thumbnailer = new Thumbnailer($conf);
1181 $link['thumbnail'] = $thumbnailer->get($url); 1172 $link['thumbnail'] = $thumbnailer->get($url);
1182 } 1173 }
1183 1174
1175 $link['sticky'] = isset($link['sticky']) ? $link['sticky'] : false;
1176
1184 $pluginManager->executeHooks('save_link', $link); 1177 $pluginManager->executeHooks('save_link', $link);
1185 1178
1186 $LINKSDB[$id] = $link; 1179 $LINKSDB[$id] = $link;
@@ -1603,7 +1596,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
1603 $ids = []; 1596 $ids = [];
1604 foreach ($LINKSDB as $link) { 1597 foreach ($LINKSDB as $link) {
1605 // A note or not HTTP(S) 1598 // A note or not HTTP(S)
1606 if ($link['url'][0] === '?' || ! startsWith(strtolower($link['url']), 'http')) { 1599 if (is_note($link['url']) || ! startsWith(strtolower($link['url']), 'http')) {
1607 continue; 1600 continue;
1608 } 1601 }
1609 $ids[] = $link['id']; 1602 $ids[] = $link['id'];
@@ -1707,11 +1700,7 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
1707 $linkDisp = array(); 1700 $linkDisp = array();
1708 while ($i<$end && $i<count($keys)) { 1701 while ($i<$end && $i<count($keys)) {
1709 $link = $linksToDisplay[$keys[$i]]; 1702 $link = $linksToDisplay[$keys[$i]];
1710 $link['description'] = format_description( 1703 $link['description'] = format_description($link['description']);
1711 $link['description'],
1712 $conf->get('redirector.url'),
1713 $conf->get('redirector.encode_url')
1714 );
1715 $classLi = ($i % 2) != 0 ? '' : 'publicLinkHightLight'; 1704 $classLi = ($i % 2) != 0 ? '' : 'publicLinkHightLight';
1716 $link['class'] = $link['private'] == 0 ? $classLi : 'private'; 1705 $link['class'] = $link['private'] == 0 ? $classLi : 'private';
1717 $link['timestamp'] = $link['created']->getTimestamp(); 1706 $link['timestamp'] = $link['created']->getTimestamp();
@@ -1772,7 +1761,6 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
1772 'search_term' => $searchterm, 1761 'search_term' => $searchterm,
1773 'search_tags' => $searchtags, 1762 'search_tags' => $searchtags,
1774 'visibility' => ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : '', 1763 'visibility' => ! empty($_SESSION['visibility']) ? $_SESSION['visibility'] : '',
1775 'redirector' => $conf->get('redirector.url'), // Optional redirector URL.
1776 'links' => $linkDisp, 1764 'links' => $linkDisp,
1777 ); 1765 );
1778 1766
@@ -1922,9 +1910,7 @@ try {
1922$linkDb = new LinkDB( 1910$linkDb = new LinkDB(
1923 $conf->get('resource.datastore'), 1911 $conf->get('resource.datastore'),
1924 $loginManager->isLoggedIn(), 1912 $loginManager->isLoggedIn(),
1925 $conf->get('privacy.hide_public_links'), 1913 $conf->get('privacy.hide_public_links')
1926 $conf->get('redirector.url'),
1927 $conf->get('redirector.encode_url')
1928); 1914);
1929 1915
1930$container = new \Slim\Container(); 1916$container = new \Slim\Container();
@@ -1947,7 +1933,7 @@ $app->group('/api/v1', function () {
1947 $this->put('/tags/{tagName:[\w]+}', '\Shaarli\Api\Controllers\Tags:putTag')->setName('putTag'); 1933 $this->put('/tags/{tagName:[\w]+}', '\Shaarli\Api\Controllers\Tags:putTag')->setName('putTag');
1948 $this->delete('/tags/{tagName:[\w]+}', '\Shaarli\Api\Controllers\Tags:deleteTag')->setName('deleteTag'); 1934 $this->delete('/tags/{tagName:[\w]+}', '\Shaarli\Api\Controllers\Tags:deleteTag')->setName('deleteTag');
1949 1935
1950 $this->get('/history', '\Shaarli\Api\Controllers\History:getHistory')->setName('getHistory'); 1936 $this->get('/history', '\Shaarli\Api\Controllers\HistoryController:getHistory')->setName('getHistory');
1951})->add('\Shaarli\Api\ApiMiddleware'); 1937})->add('\Shaarli\Api\ApiMiddleware');
1952 1938
1953$response = $app->run(true); 1939$response = $app->run(true);
diff --git a/tests/bookmark/LinkDBTest.php b/tests/bookmark/LinkDBTest.php
index ff5c0b97..2990a6b5 100644
--- a/tests/bookmark/LinkDBTest.php
+++ b/tests/bookmark/LinkDBTest.php
@@ -362,36 +362,6 @@ class LinkDBTest extends \PHPUnit\Framework\TestCase
362 } 362 }
363 363
364 /** 364 /**
365 * Test real_url without redirector.
366 */
367 public function testLinkRealUrlWithoutRedirector()
368 {
369 $db = new LinkDB(self::$testDatastore, false, false);
370 foreach ($db as $link) {
371 $this->assertEquals($link['url'], $link['real_url']);
372 }
373 }
374
375 /**
376 * Test real_url with redirector.
377 */
378 public function testLinkRealUrlWithRedirector()
379 {
380 $redirector = 'http://redirector.to?';
381 $db = new LinkDB(self::$testDatastore, false, false, $redirector);
382 foreach ($db as $link) {
383 $this->assertStringStartsWith($redirector, $link['real_url']);
384 $this->assertNotFalse(strpos($link['real_url'], urlencode('://')));
385 }
386
387 $db = new LinkDB(self::$testDatastore, false, false, $redirector, false);
388 foreach ($db as $link) {
389 $this->assertStringStartsWith($redirector, $link['real_url']);
390 $this->assertFalse(strpos($link['real_url'], urlencode('://')));
391 }
392 }
393
394 /**
395 * Test filter with string. 365 * Test filter with string.
396 */ 366 */
397 public function testFilterString() 367 public function testFilterString()
@@ -516,7 +486,7 @@ class LinkDBTest extends \PHPUnit\Framework\TestCase
516 public function testRenameTagCaseSensitive() 486 public function testRenameTagCaseSensitive()
517 { 487 {
518 self::$refDB->write(self::$testDatastore); 488 self::$refDB->write(self::$testDatastore);
519 $linkDB = new LinkDB(self::$testDatastore, true, false, ''); 489 $linkDB = new LinkDB(self::$testDatastore, true, false);
520 490
521 $res = $linkDB->renameTag('sTuff', 'Taz'); 491 $res = $linkDB->renameTag('sTuff', 'Taz');
522 $this->assertEquals(1, count($res)); 492 $this->assertEquals(1, count($res));
diff --git a/tests/bookmark/LinkUtilsTest.php b/tests/bookmark/LinkUtilsTest.php
index 1b8688e6..25fb3043 100644
--- a/tests/bookmark/LinkUtilsTest.php
+++ b/tests/bookmark/LinkUtilsTest.php
@@ -216,56 +216,27 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase
216 } 216 }
217 217
218 /** 218 /**
219 * Test text2clickable without a redirector being set. 219 * Test text2clickable.
220 */ 220 */
221 public function testText2clickableWithoutRedirector() 221 public function testText2clickable()
222 { 222 {
223 $text = 'stuff http://hello.there/is=someone#here otherstuff'; 223 $text = 'stuff http://hello.there/is=someone#here otherstuff';
224 $expectedText = 'stuff <a href="http://hello.there/is=someone#here">' 224 $expectedText = 'stuff <a href="http://hello.there/is=someone#here">'
225 . 'http://hello.there/is=someone#here</a> otherstuff'; 225 . 'http://hello.there/is=someone#here</a> otherstuff';
226 $processedText = text2clickable($text, ''); 226 $processedText = text2clickable($text);
227 $this->assertEquals($expectedText, $processedText); 227 $this->assertEquals($expectedText, $processedText);
228 228
229 $text = 'stuff http://hello.there/is=someone#here(please) otherstuff'; 229 $text = 'stuff http://hello.there/is=someone#here(please) otherstuff';
230 $expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)">' 230 $expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)">'
231 . 'http://hello.there/is=someone#here(please)</a> otherstuff'; 231 . 'http://hello.there/is=someone#here(please)</a> otherstuff';
232 $processedText = text2clickable($text, ''); 232 $processedText = text2clickable($text);
233 $this->assertEquals($expectedText, $processedText); 233 $this->assertEquals($expectedText, $processedText);
234 234
235 $text = 'stuff http://hello.there/is=someone#here(please)&no otherstuff'; 235 $text = 'stuff http://hello.there/is=someone#here(please)&no otherstuff';
236 $text = 'stuff http://hello.there/is=someone#here(please)&no otherstuff';
236 $expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)&no">' 237 $expectedText = 'stuff <a href="http://hello.there/is=someone#here(please)&no">'
237 . 'http://hello.there/is=someone#here(please)&no</a> otherstuff'; 238 . 'http://hello.there/is=someone#here(please)&no</a> otherstuff';
238 $processedText = text2clickable($text, ''); 239 $processedText = text2clickable($text);
239 $this->assertEquals($expectedText, $processedText);
240 }
241
242 /**
243 * Test text2clickable with a redirector set.
244 */
245 public function testText2clickableWithRedirector()
246 {
247 $text = 'stuff http://hello.there/is=someone#here otherstuff';
248 $redirector = 'http://redirector.to';
249 $expectedText = 'stuff <a href="' .
250 $redirector .
251 urlencode('http://hello.there/is=someone#here') .
252 '">http://hello.there/is=someone#here</a> otherstuff';
253 $processedText = text2clickable($text, $redirector);
254 $this->assertEquals($expectedText, $processedText);
255 }
256
257 /**
258 * Test text2clickable a redirector set and without URL encode.
259 */
260 public function testText2clickableWithRedirectorDontEncode()
261 {
262 $text = 'stuff http://hello.there/?is=someone&or=something#here otherstuff';
263 $redirector = 'http://redirector.to';
264 $expectedText = 'stuff <a href="' .
265 $redirector .
266 'http://hello.there/?is=someone&or=something#here' .
267 '">http://hello.there/?is=someone&or=something#here</a> otherstuff';
268 $processedText = text2clickable($text, $redirector, false);
269 $this->assertEquals($expectedText, $processedText); 240 $this->assertEquals($expectedText, $processedText);
270 } 241 }
271 242
@@ -318,6 +289,26 @@ class LinkUtilsTest extends \PHPUnit\Framework\TestCase
318 } 289 }
319 290
320 /** 291 /**
292 * Test is_note with note URLs.
293 */
294 public function testIsNote()
295 {
296 $this->assertTrue(is_note('?'));
297 $this->assertTrue(is_note('?abcDEf'));
298 $this->assertTrue(is_note('?_abcDEf#123'));
299 }
300
301 /**
302 * Test is_note with non note URLs.
303 */
304 public function testIsNotNote()
305 {
306 $this->assertFalse(is_note(''));
307 $this->assertFalse(is_note('nope'));
308 $this->assertFalse(is_note('https://github.com/shaarli/Shaarli/?hi'));
309 }
310
311 /**
321 * Util function to build an hashtag link. 312 * Util function to build an hashtag link.
322 * 313 *
323 * @param string $hashtag Hashtag name. 314 * @param string $hashtag Hashtag name.
diff --git a/tests/plugins/PluginMarkdownTest.php b/tests/plugins/PluginMarkdownTest.php
index 5e7c02b0..9ddbc558 100644
--- a/tests/plugins/PluginMarkdownTest.php
+++ b/tests/plugins/PluginMarkdownTest.php
@@ -107,7 +107,7 @@ class PluginMarkdownTest extends \PHPUnit\Framework\TestCase
107 public function testReverseText2clickable() 107 public function testReverseText2clickable()
108 { 108 {
109 $text = 'stuff http://hello.there/is=someone#here otherstuff'; 109 $text = 'stuff http://hello.there/is=someone#here otherstuff';
110 $clickableText = text2clickable($text, ''); 110 $clickableText = text2clickable($text);
111 $reversedText = reverse_text2clickable($clickableText); 111 $reversedText = reverse_text2clickable($clickableText);
112 $this->assertEquals($text, $reversedText); 112 $this->assertEquals($text, $reversedText);
113 } 113 }
diff --git a/tests/updater/UpdaterTest.php b/tests/updater/UpdaterTest.php
index d7df5963..93bc86c1 100644
--- a/tests/updater/UpdaterTest.php
+++ b/tests/updater/UpdaterTest.php
@@ -287,17 +287,14 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
287 $this->conf = new ConfigManager($sandbox); 287 $this->conf = new ConfigManager($sandbox);
288 $title = '<script>alert("title");</script>'; 288 $title = '<script>alert("title");</script>';
289 $headerLink = '<script>alert("header_link");</script>'; 289 $headerLink = '<script>alert("header_link");</script>';
290 $redirectorUrl = '<script>alert("redirector");</script>';
291 $this->conf->set('general.title', $title); 290 $this->conf->set('general.title', $title);
292 $this->conf->set('general.header_link', $headerLink); 291 $this->conf->set('general.header_link', $headerLink);
293 $this->conf->set('redirector.url', $redirectorUrl);
294 $updater = new Updater(array(), array(), $this->conf, true); 292 $updater = new Updater(array(), array(), $this->conf, true);
295 $done = $updater->updateMethodEscapeUnescapedConfig(); 293 $done = $updater->updateMethodEscapeUnescapedConfig();
296 $this->assertTrue($done); 294 $this->assertTrue($done);
297 $this->conf->reload(); 295 $this->conf->reload();
298 $this->assertEquals(escape($title), $this->conf->get('general.title')); 296 $this->assertEquals(escape($title), $this->conf->get('general.title'));
299 $this->assertEquals(escape($headerLink), $this->conf->get('general.header_link')); 297 $this->assertEquals(escape($headerLink), $this->conf->get('general.header_link'));
300 $this->assertEquals(escape($redirectorUrl), $this->conf->get('redirector.url'));
301 unlink($sandbox . '.json.php'); 298 unlink($sandbox . '.json.php');
302 } 299 }
303 300
@@ -707,7 +704,6 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
707 } 704 }
708 705
709 /** 706 /**
710<<<<<<< HEAD
711 * Test updateMethodWebThumbnailer with thumbnails enabled. 707 * Test updateMethodWebThumbnailer with thumbnails enabled.
712 */ 708 */
713 public function testUpdateMethodWebThumbnailerEnabled() 709 public function testUpdateMethodWebThumbnailerEnabled()
@@ -812,4 +808,19 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
812 $linkDB = new LinkDB(self::$testDatastore, true, false); 808 $linkDB = new LinkDB(self::$testDatastore, true, false);
813 $this->assertTrue($linkDB[1]['sticky']); 809 $this->assertTrue($linkDB[1]['sticky']);
814 } 810 }
811
812 /**
813 * Test updateMethodRemoveRedirector().
814 */
815 public function testUpdateRemoveRedirector()
816 {
817 $sandboxConf = 'sandbox/config';
818 copy(self::$configFile . '.json.php', $sandboxConf . '.json.php');
819 $this->conf = new ConfigManager($sandboxConf);
820 $updater = new Updater([], null, $this->conf, true);
821 $this->assertTrue($updater->updateMethodRemoveRedirector());
822 $this->assertFalse($this->conf->exists('redirector'));
823 $this->conf = new ConfigManager($sandboxConf);
824 $this->assertFalse($this->conf->exists('redirector'));
825 }
815} 826}
diff --git a/tpl/default/404.html b/tpl/default/404.html
index fd337cad..10a9458a 100644
--- a/tpl/default/404.html
+++ b/tpl/default/404.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/addlink.html b/tpl/default/addlink.html
index 55864a02..b4b4a0ec 100644
--- a/tpl/default/addlink.html
+++ b/tpl/default/addlink.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/changepassword.html b/tpl/default/changepassword.html
index 2d15c92a..3867e3ca 100644
--- a/tpl/default/changepassword.html
+++ b/tpl/default/changepassword.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/changetag.html b/tpl/default/changetag.html
index 6606c4fa..0da6a5eb 100644
--- a/tpl/default/changetag.html
+++ b/tpl/default/changetag.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/configure.html b/tpl/default/configure.html
index 42e32230..7a87c05d 100644
--- a/tpl/default/configure.html
+++ b/tpl/default/configure.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/daily.html b/tpl/default/daily.html
index 2c409478..359ecbd0 100644
--- a/tpl/default/daily.html
+++ b/tpl/default/daily.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/editlink.html b/tpl/default/editlink.html
index d8c57155..df14535d 100644
--- a/tpl/default/editlink.html
+++ b/tpl/default/editlink.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/export.html b/tpl/default/export.html
index af1d6e33..99c01b11 100644
--- a/tpl/default/export.html
+++ b/tpl/default/export.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/import.html b/tpl/default/import.html
index bdc9086e..20f854d1 100644
--- a/tpl/default/import.html
+++ b/tpl/default/import.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/install.html b/tpl/default/install.html
index 6199b33d..f0e7040e 100644
--- a/tpl/default/install.html
+++ b/tpl/default/install.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/linklist.html b/tpl/default/linklist.html
index ed78f40a..1cf00783 100644
--- a/tpl/default/linklist.html
+++ b/tpl/default/linklist.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
@@ -94,7 +94,7 @@
94 {'tagged'|t} 94 {'tagged'|t}
95 {loop="$exploded_tags"} 95 {loop="$exploded_tags"}
96 <span class="label label-tag" title="{'Remove tag'|t}"> 96 <span class="label label-tag" title="{'Remove tag'|t}">
97 <a href="?removetag={function="urlencode($value)"}">{$value}<span class="remove"><i class="fa fa-times"></i></span></a> 97 <a href="?removetag={function="urlencode($value)"}">{$value}<span class="remove"><i class="fa fa-times" aria-hidden="true"></i></span></a>
98 </span> 98 </span>
99 {/loop} 99 {/loop}
100 {/if} 100 {/if}
@@ -195,18 +195,18 @@
195 <input type="checkbox" class="link-checkbox" value="{$value.id}"> 195 <input type="checkbox" class="link-checkbox" value="{$value.id}">
196 </span> 196 </span>
197 <span class="linklist-item-infos-controls-item ctrl-edit"> 197 <span class="linklist-item-infos-controls-item ctrl-edit">
198 <a href="?edit_link={$value.id}" title="{$strEdit}"><i class="fa fa-pencil-square-o edit-link"></i></a> 198 <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>
199 </span> 199 </span>
200 <span class="linklist-item-infos-controls-item ctrl-delete"> 200 <span class="linklist-item-infos-controls-item ctrl-delete">
201 <a href="?delete_link&amp;lf_linkdate={$value.id}&amp;token={$token}" 201 <a href="?delete_link&amp;lf_linkdate={$value.id}&amp;token={$token}" aria-label="{$strDelete}"
202 title="{$strDelete}" class="delete-link pure-u-0 pure-u-lg-visible confirm-delete"> 202 title="{$strDelete}" class="delete-link pure-u-0 pure-u-lg-visible confirm-delete">
203 <i class="fa fa-trash"></i> 203 <i class="fa fa-trash" aria-hidden="true"></i>
204 </a> 204 </a>
205 </span> 205 </span>
206 <span class="linklist-item-infos-controls-item ctrl-pin"> 206 <span class="linklist-item-infos-controls-item ctrl-pin">
207 <a href="?do=pin&amp;id={$value.id}&amp;token={$token}" 207 <a href="?do=pin&amp;id={$value.id}&amp;token={$token}"
208 title="{$strToggleSticky}" class="pin-link {if="$value.sticky"}pinned-link{/if} pure-u-0 pure-u-lg-visible"> 208 title="{$strToggleSticky}" aria-label="{$strToggleSticky}" class="pin-link {if="$value.sticky"}pinned-link{/if} pure-u-0 pure-u-lg-visible">
209 <i class="fa fa-thumb-tack"></i> 209 <i class="fa fa-thumb-tack" aria-hidden="true"></i>
210 </a> 210 </a>
211 </span> 211 </span>
212 </div> 212 </div>
@@ -248,10 +248,10 @@
248 {ignore}do not add space or line break between these div - Firefox issue{/ignore} 248 {ignore}do not add space or line break between these div - Firefox issue{/ignore}
249 class="linklist-item-infos-url pure-u-lg-5-12 pure-u-1"> 249 class="linklist-item-infos-url pure-u-lg-5-12 pure-u-1">
250 <a href="{$value.real_url}" title="{$value.title}"> 250 <a href="{$value.real_url}" title="{$value.title}">
251 <i class="fa fa-link"></i> {$value.url} 251 <i class="fa fa-link" aria-hidden="true"></i> {$value.url}
252 </a> 252 </a>
253 <div class="linklist-item-buttons pure-u-0 pure-u-lg-visible"> 253 <div class="linklist-item-buttons pure-u-0 pure-u-lg-visible">
254 <a href="#" title="{$strFold}" class="fold-button"><i class="fa fa-chevron-up"></i></a> 254 <a href="#" aria-label="{$strFold}" title="{$strFold}" class="fold-button"><i class="fa fa-chevron-up" aria-hidden="true"></i></a>
255 </div> 255 </div>
256 </div> 256 </div>
257 <div class="mobile-buttons pure-u-1 pure-u-lg-0"> 257 <div class="mobile-buttons pure-u-1 pure-u-lg-0">
@@ -264,12 +264,12 @@
264 {/if} 264 {/if}
265 {if="$is_logged_in"} 265 {if="$is_logged_in"}
266 &middot; 266 &middot;
267 <a href="?delete_link&amp;lf_linkdate={$value.id}&amp;token={$token}" 267 <a href="?delete_link&amp;lf_linkdate={$value.id}&amp;token={$token}" aria-label="{$strDelete}"
268 title="{$strDelete}" class="delete-link confirm-delete"> 268 title="{$strDelete}" class="delete-link confirm-delete">
269 <i class="fa fa-trash"></i> 269 <i class="fa fa-trash" aria-hidden="true"></i>
270 </a> 270 </a>
271 &middot; 271 &middot;
272 <a href="?edit_link={$value.id}" title="{$strEdit}"><i class="fa fa-pencil-square-o edit-link"></i></a> 272 <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>
273 {/if} 273 {/if}
274 </div> 274 </div>
275 </div> 275 </div>
diff --git a/tpl/default/linklist.paging.html b/tpl/default/linklist.paging.html
index fe665a84..4e50495a 100644
--- a/tpl/default/linklist.paging.html
+++ b/tpl/default/linklist.paging.html
@@ -6,21 +6,21 @@
6 {'Filters'|t} 6 {'Filters'|t}
7 </span> 7 </span>
8 {if="$is_logged_in"} 8 {if="$is_logged_in"}
9 <a href="?visibility=private" title="{'Only display private links'|t}" 9 <a href="?visibility=private" aria-label="{'Only display private links'|t}" title="{'Only display private links'|t}"
10 class="{if="$visibility==='private'"}filter-on{else}filter-off{/if}" 10 class="{if="$visibility==='private'"}filter-on{else}filter-off{/if}"
11 ><i class="fa fa-user-secret"></i></a> 11 ><i class="fa fa-user-secret" aria-hidden="true"></i></a>
12 <a href="?visibility=public" title="{'Only display public links'|t}" 12 <a href="?visibility=public" aria-label="{'Only display public links'|t}" title="{'Only display public links'|t}"
13 class="{if="$visibility==='public'"}filter-on{else}filter-off{/if}" 13 class="{if="$visibility==='public'"}filter-on{else}filter-off{/if}"
14 ><i class="fa fa-globe"></i></a> 14 ><i class="fa fa-globe" aria-hidden="true"></i></a>
15 {/if} 15 {/if}
16 <a href="?untaggedonly" title="{'Filter untagged links'|t}" 16 <a href="?untaggedonly" aria-label="{'Filter untagged links'|t}" title="{'Filter untagged links'|t}"
17 class={if="$untaggedonly"}"filter-on"{else}"filter-off"{/if} 17 class={if="$untaggedonly"}"filter-on"{else}"filter-off"{/if}
18 ><i class="fa fa-tag"></i></a> 18 ><i class="fa fa-tag" aria-hidden="true"></i></a>
19 <a href="#" title="{'Select all'|t}" 19 <a href="#" aria-label="{'Select all'|t}" title="{'Select all'|t}"
20 class="filter-off select-all-button" 20 class="filter-off select-all-button"
21 ><i class="fa fa-check-square-o"></i></a> 21 ><i class="fa fa-check-square-o" aria-hidden="true"></i></a>
22 <a href="#" class="filter-off fold-all pure-u-lg-0" title="{'Fold all'|t}"> 22 <a href="#" class="filter-off fold-all pure-u-lg-0" aria-label="{'Fold all'|t}" title="{'Fold all'|t}">
23 <i class="fa fa-chevron-up"></i> 23 <i class="fa fa-chevron-up" aria-hidden="true"></i>
24 </a> 24 </a>
25 {loop="$action_plugin"} 25 {loop="$action_plugin"}
26 {$value.attr.class=isset($value.attr.class) ? $value.attr.class : ''} 26 {$value.attr.class=isset($value.attr.class) ? $value.attr.class : ''}
@@ -59,8 +59,8 @@
59 <form method="GET" class="pure-u-0 pure-u-lg-visible"> 59 <form method="GET" class="pure-u-0 pure-u-lg-visible">
60 <input type="text" name="linksperpage" placeholder="133"> 60 <input type="text" name="linksperpage" placeholder="133">
61 </form> 61 </form>
62 <a href="#" class="filter-off fold-all pure-u-0 pure-u-lg-visible" title="{'Fold all'|t}"> 62 <a href="#" class="filter-off fold-all pure-u-0 pure-u-lg-visible" aria-label="{'Fold all'|t}" title="{'Fold all'|t}">
63 <i class="fa fa-chevron-up"></i> 63 <i class="fa fa-chevron-up" aria-hidden="true"></i>
64 </a> 64 </a>
65 </div> 65 </div>
66 </div> 66 </div>
diff --git a/tpl/default/loginform.html b/tpl/default/loginform.html
index 3cdab65a..bfc54815 100644
--- a/tpl/default/loginform.html
+++ b/tpl/default/loginform.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/page.footer.html b/tpl/default/page.footer.html
index 5af39be7..f7ae2b84 100644
--- a/tpl/default/page.footer.html
+++ b/tpl/default/page.footer.html
@@ -2,7 +2,7 @@
2 2
3<div class="pure-g"> 3<div class="pure-g">
4 <div class="pure-u-2-24"></div> 4 <div class="pure-u-2-24"></div>
5 <div id="footer" class="pure-u-20-24 footer-container"> 5 <footer id="footer" class="pure-u-20-24 footer-container" role="contentinfo">
6 <strong><a href="https://github.com/shaarli/Shaarli">Shaarli</a></strong> 6 <strong><a href="https://github.com/shaarli/Shaarli">Shaarli</a></strong>
7 {if="$is_logged_in===true"} 7 {if="$is_logged_in===true"}
8 {$version} 8 {$version}
@@ -13,7 +13,7 @@
13 {loop="$plugins_footer.text"} 13 {loop="$plugins_footer.text"}
14 {$value} 14 {$value}
15 {/loop} 15 {/loop}
16 </div> 16 </footer>
17 <div class="pure-u-2-24"></div> 17 <div class="pure-u-2-24"></div>
18</div> 18</div>
19 19
diff --git a/tpl/default/page.header.html b/tpl/default/page.header.html
index 4b665023..2832ebbb 100644
--- a/tpl/default/page.header.html
+++ b/tpl/default/page.header.html
@@ -20,7 +20,7 @@
20 {if="$is_logged_in || $openshaarli"} 20 {if="$is_logged_in || $openshaarli"}
21 <li class="pure-menu-item"> 21 <li class="pure-menu-item">
22 <a href="?do=addlink" class="pure-menu-link" id="shaarli-menu-shaare"> 22 <a href="?do=addlink" class="pure-menu-link" id="shaarli-menu-shaare">
23 <i class="fa fa-plus" ></i> {'Shaare'|t} 23 <i class="fa fa-plus" aria-hidden="true"></i> {'Shaare'|t}
24 </a> 24 </a>
25 </li> 25 </li>
26 <li class="pure-menu-item" id="shaarli-menu-tools"> 26 <li class="pure-menu-item" id="shaarli-menu-tools">
@@ -67,27 +67,27 @@
67 <li class="pure-menu-item" id="shaarli-menu-desktop-search"> 67 <li class="pure-menu-item" id="shaarli-menu-desktop-search">
68 <a href="#" class="pure-menu-link subheader-opener" 68 <a href="#" class="pure-menu-link subheader-opener"
69 data-open-id="search" 69 data-open-id="search"
70 id="search-button" title="{'Search'|t}"> 70 id="search-button" aria-label="{'Search'|t}" title="{'Search'|t}">
71 <i class="fa fa-search"></i> 71 <i class="fa fa-search" aria-hidden="true"></i>
72 </a> 72 </a>
73 </li> 73 </li>
74 <li class="pure-menu-item" id="shaarli-menu-desktop-rss"> 74 <li class="pure-menu-item" id="shaarli-menu-desktop-rss">
75 <a href="?do={$feed_type}{$searchcrits}" class="pure-menu-link" title="{'RSS Feed'|t}"> 75 <a href="?do={$feed_type}{$searchcrits}" class="pure-menu-link" title="{'RSS Feed'|t}" aria-label="{'RSS Feed'|t}">
76 <i class="fa fa-rss"></i> 76 <i class="fa fa-rss" aria-hidden="true"></i>
77 </a> 77 </a>
78 </li> 78 </li>
79 {if="!$is_logged_in"} 79 {if="!$is_logged_in"}
80 <li class="pure-menu-item" id="shaarli-menu-desktop-login"> 80 <li class="pure-menu-item" id="shaarli-menu-desktop-login">
81 <a href="?do=login" class="pure-menu-link" 81 <a href="?do=login" class="pure-menu-link"
82 data-open-id="header-login-form" 82 data-open-id="header-login-form"
83 id="login-button" title="{'Login'|t}"> 83 id="login-button" aria-label="{'Login'|t}" title="{'Login'|t}">
84 <i class="fa fa-user"></i> 84 <i class="fa fa-user" aria-hidden="true"></i>
85 </a> 85 </a>
86 </li> 86 </li>
87 {else} 87 {else}
88 <li class="pure-menu-item" id="shaarli-menu-desktop-logout"> 88 <li class="pure-menu-item" id="shaarli-menu-desktop-logout">
89 <a href="?do=logout" class="pure-menu-link" title="{'Logout'|t}"> 89 <a href="?do=logout" class="pure-menu-link" aria-label="{'Logout'|t}" title="{'Logout'|t}">
90 <i class="fa fa-sign-out"></i> 90 <i class="fa fa-sign-out" aria-hidden="true"></i>
91 </a> 91 </a>
92 </li> 92 </li>
93 {/if} 93 {/if}
diff --git a/tpl/default/picwall.html b/tpl/default/picwall.html
index 4c325487..5a959244 100644
--- a/tpl/default/picwall.html
+++ b/tpl/default/picwall.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/pluginsadmin.html b/tpl/default/pluginsadmin.html
index 82041972..4bfaa934 100644
--- a/tpl/default/pluginsadmin.html
+++ b/tpl/default/pluginsadmin.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/tag.cloud.html b/tpl/default/tag.cloud.html
index 9e52158d..bedf3f8c 100644
--- a/tpl/default/tag.cloud.html
+++ b/tpl/default/tag.cloud.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/tag.list.html b/tpl/default/tag.list.html
index bcddcd56..41eab246 100644
--- a/tpl/default/tag.list.html
+++ b/tpl/default/tag.list.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/tag.sort.html b/tpl/default/tag.sort.html
index 89acda0d..d24c9f64 100644
--- a/tpl/default/tag.sort.html
+++ b/tpl/default/tag.sort.html
@@ -1,8 +1,8 @@
1<div class="pure-g"> 1<div class="pure-g">
2 <div class="pure-u-1 pure-alert pure-alert-success tag-sort"> 2 <div class="pure-u-1 pure-alert pure-alert-success tag-sort">
3 {'Sort by:'|t} 3 {'Sort by:'|t}
4 <a href="?do=tagcloud" title="cloud">{'Cloud'|t}</a> &middot; 4 <a href="?do=tagcloud">{'Cloud'|t}</a> &middot;
5 <a href="?do=taglist&sort=usage" title="cloud">{'Most used'|t}</a> &middot; 5 <a href="?do=taglist&sort=usage">{'Most used'|t}</a> &middot;
6 <a href="?do=taglist&sort=alpha" title="cloud">{'Alphabetical'|t}</a> 6 <a href="?do=taglist&sort=alpha">{'Alphabetical'|t}</a>
7 </div> 7 </div>
8</div> \ No newline at end of file 8</div> \ No newline at end of file
diff --git a/tpl/default/thumbnails.html b/tpl/default/thumbnails.html
index a8cf904e..f1939798 100644
--- a/tpl/default/thumbnails.html
+++ b/tpl/default/thumbnails.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>
diff --git a/tpl/default/tools.html b/tpl/default/tools.html
index c9ce1eaf..20d0c893 100644
--- a/tpl/default/tools.html
+++ b/tpl/default/tools.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html> 2<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
3<head> 3<head>
4 {include="includes"} 4 {include="includes"}
5</head> 5</head>