diff options
author | ArthurHoaro <arthur@hoa.ro> | 2018-07-28 09:41:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-28 09:41:29 +0200 |
commit | ad5f47adbaee1eef85e90950ab8a45fe82959924 (patch) | |
tree | d23a186661db00d36cb2b2287a7bf890fbc62cfb | |
parent | 8fdd65b88412a0db28c723a486650c434fe5668c (diff) | |
parent | 7b4fea0e39be9e74e9aef13e73af9bbd2b1a6397 (diff) | |
download | Shaarli-ad5f47adbaee1eef85e90950ab8a45fe82959924.tar.gz Shaarli-ad5f47adbaee1eef85e90950ab8a45fe82959924.tar.zst Shaarli-ad5f47adbaee1eef85e90950ab8a45fe82959924.zip |
Merge pull request #687 from ArthurHoaro/web-thumb
Use web-thumbnailer to retrieve thumbnails
34 files changed, 1489 insertions, 763 deletions
diff --git a/application/PageBuilder.php b/application/PageBuilder.php index a4483870..b1abe0d0 100644 --- a/application/PageBuilder.php +++ b/application/PageBuilder.php | |||
@@ -1,6 +1,7 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | use Shaarli\Config\ConfigManager; | 3 | use Shaarli\Config\ConfigManager; |
4 | use Shaarli\Thumbnailer; | ||
4 | 5 | ||
5 | /** | 6 | /** |
6 | * This class is in charge of building the final page. | 7 | * This class is in charge of building the final page. |
@@ -22,10 +23,20 @@ class PageBuilder | |||
22 | protected $conf; | 23 | protected $conf; |
23 | 24 | ||
24 | /** | 25 | /** |
26 | * @var array $_SESSION | ||
27 | */ | ||
28 | protected $session; | ||
29 | |||
30 | /** | ||
25 | * @var LinkDB $linkDB instance. | 31 | * @var LinkDB $linkDB instance. |
26 | */ | 32 | */ |
27 | protected $linkDB; | 33 | protected $linkDB; |
28 | 34 | ||
35 | /** | ||
36 | * @var null|string XSRF token | ||
37 | */ | ||
38 | protected $token; | ||
39 | |||
29 | /** @var bool $isLoggedIn Whether the user is logged in **/ | 40 | /** @var bool $isLoggedIn Whether the user is logged in **/ |
30 | protected $isLoggedIn = false; | 41 | protected $isLoggedIn = false; |
31 | 42 | ||
@@ -33,14 +44,17 @@ class PageBuilder | |||
33 | * PageBuilder constructor. | 44 | * PageBuilder constructor. |
34 | * $tpl is initialized at false for lazy loading. | 45 | * $tpl is initialized at false for lazy loading. |
35 | * | 46 | * |
36 | * @param ConfigManager $conf Configuration Manager instance (reference). | 47 | * @param ConfigManager $conf Configuration Manager instance (reference). |
37 | * @param LinkDB $linkDB instance. | 48 | * @param array $session $_SESSION array |
38 | * @param string $token Session token | 49 | * @param LinkDB $linkDB instance. |
50 | * @param string $token Session token | ||
51 | * @param bool $isLoggedIn | ||
39 | */ | 52 | */ |
40 | public function __construct(&$conf, $linkDB = null, $token = null, $isLoggedIn = false) | 53 | public function __construct(&$conf, $session, $linkDB = null, $token = null, $isLoggedIn = false) |
41 | { | 54 | { |
42 | $this->tpl = false; | 55 | $this->tpl = false; |
43 | $this->conf = $conf; | 56 | $this->conf = $conf; |
57 | $this->session = $session; | ||
44 | $this->linkDB = $linkDB; | 58 | $this->linkDB = $linkDB; |
45 | $this->token = $token; | 59 | $this->token = $token; |
46 | $this->isLoggedIn = $isLoggedIn; | 60 | $this->isLoggedIn = $isLoggedIn; |
@@ -105,6 +119,19 @@ class PageBuilder | |||
105 | if ($this->linkDB !== null) { | 119 | if ($this->linkDB !== null) { |
106 | $this->tpl->assign('tags', $this->linkDB->linksCountPerTag()); | 120 | $this->tpl->assign('tags', $this->linkDB->linksCountPerTag()); |
107 | } | 121 | } |
122 | |||
123 | $this->tpl->assign( | ||
124 | 'thumbnails_enabled', | ||
125 | $this->conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE | ||
126 | ); | ||
127 | $this->tpl->assign('thumbnails_width', $this->conf->get('thumbnails.width')); | ||
128 | $this->tpl->assign('thumbnails_height', $this->conf->get('thumbnails.height')); | ||
129 | |||
130 | if (! empty($_SESSION['warnings'])) { | ||
131 | $this->tpl->assign('global_warnings', $_SESSION['warnings']); | ||
132 | unset($_SESSION['warnings']); | ||
133 | } | ||
134 | |||
108 | // To be removed with a proper theme configuration. | 135 | // To be removed with a proper theme configuration. |
109 | $this->tpl->assign('conf', $this->conf); | 136 | $this->tpl->assign('conf', $this->conf); |
110 | } | 137 | } |
diff --git a/application/Router.php b/application/Router.php index 4df0387c..bf86b884 100644 --- a/application/Router.php +++ b/application/Router.php | |||
@@ -7,6 +7,8 @@ | |||
7 | */ | 7 | */ |
8 | class Router | 8 | class Router |
9 | { | 9 | { |
10 | public static $AJAX_THUMB_UPDATE = 'ajax_thumb_update'; | ||
11 | |||
10 | public static $PAGE_LOGIN = 'login'; | 12 | public static $PAGE_LOGIN = 'login'; |
11 | 13 | ||
12 | public static $PAGE_PICWALL = 'picwall'; | 14 | public static $PAGE_PICWALL = 'picwall'; |
@@ -47,6 +49,8 @@ class Router | |||
47 | 49 | ||
48 | public static $PAGE_SAVE_PLUGINSADMIN = 'save_pluginadmin'; | 50 | public static $PAGE_SAVE_PLUGINSADMIN = 'save_pluginadmin'; |
49 | 51 | ||
52 | public static $PAGE_THUMBS_UPDATE = 'thumbs_update'; | ||
53 | |||
50 | public static $GET_TOKEN = 'token'; | 54 | public static $GET_TOKEN = 'token'; |
51 | 55 | ||
52 | /** | 56 | /** |
@@ -101,6 +105,14 @@ class Router | |||
101 | return self::$PAGE_FEED_RSS; | 105 | return self::$PAGE_FEED_RSS; |
102 | } | 106 | } |
103 | 107 | ||
108 | if (startsWith($query, 'do='. self::$PAGE_THUMBS_UPDATE)) { | ||
109 | return self::$PAGE_THUMBS_UPDATE; | ||
110 | } | ||
111 | |||
112 | if (startsWith($query, 'do='. self::$AJAX_THUMB_UPDATE)) { | ||
113 | return self::$AJAX_THUMB_UPDATE; | ||
114 | } | ||
115 | |||
104 | // At this point, only loggedin pages. | 116 | // At this point, only loggedin pages. |
105 | if (!$loggedIn) { | 117 | if (!$loggedIn) { |
106 | return self::$PAGE_LINKLIST; | 118 | return self::$PAGE_LINKLIST; |
diff --git a/application/Thumbnailer.php b/application/Thumbnailer.php new file mode 100644 index 00000000..7d0d9c33 --- /dev/null +++ b/application/Thumbnailer.php | |||
@@ -0,0 +1,127 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Shaarli; | ||
4 | |||
5 | use Shaarli\Config\ConfigManager; | ||
6 | use WebThumbnailer\Exception\WebThumbnailerException; | ||
7 | use WebThumbnailer\WebThumbnailer; | ||
8 | use WebThumbnailer\Application\ConfigManager as WTConfigManager; | ||
9 | |||
10 | /** | ||
11 | * Class Thumbnailer | ||
12 | * | ||
13 | * Utility class used to retrieve thumbnails using web-thumbnailer dependency. | ||
14 | */ | ||
15 | class Thumbnailer | ||
16 | { | ||
17 | const COMMON_MEDIA_DOMAINS = [ | ||
18 | 'imgur.com', | ||
19 | 'flickr.com', | ||
20 | 'youtube.com', | ||
21 | 'wikimedia.org', | ||
22 | 'redd.it', | ||
23 | 'gfycat.com', | ||
24 | 'media.giphy.com', | ||
25 | 'twitter.com', | ||
26 | 'twimg.com', | ||
27 | 'instagram.com', | ||
28 | 'pinterest.com', | ||
29 | 'pinterest.fr', | ||
30 | 'tumblr.com', | ||
31 | 'deviantart.com', | ||
32 | ]; | ||
33 | |||
34 | const MODE_ALL = 'all'; | ||
35 | const MODE_COMMON = 'common'; | ||
36 | const MODE_NONE = 'none'; | ||
37 | |||
38 | /** | ||
39 | * @var WebThumbnailer instance. | ||
40 | */ | ||
41 | protected $wt; | ||
42 | |||
43 | /** | ||
44 | * @var ConfigManager instance. | ||
45 | */ | ||
46 | protected $conf; | ||
47 | |||
48 | /** | ||
49 | * Thumbnailer constructor. | ||
50 | * | ||
51 | * @param ConfigManager $conf instance. | ||
52 | */ | ||
53 | public function __construct($conf) | ||
54 | { | ||
55 | $this->conf = $conf; | ||
56 | |||
57 | if (! $this->checkRequirements()) { | ||
58 | $this->conf->set('thumbnails.enabled', false); | ||
59 | $this->conf->write(true); | ||
60 | // TODO: create a proper error handling system able to catch exceptions... | ||
61 | die(t('php-gd extension must be loaded to use thumbnails. Thumbnails are now disabled. Please reload the page.')); | ||
62 | } | ||
63 | |||
64 | $this->wt = new WebThumbnailer(); | ||
65 | WTConfigManager::addFile('inc/web-thumbnailer.json'); | ||
66 | $this->wt->maxWidth($this->conf->get('thumbnails.width')) | ||
67 | ->maxHeight($this->conf->get('thumbnails.height')) | ||
68 | ->crop(true) | ||
69 | ->debug($this->conf->get('dev.debug', false)); | ||
70 | } | ||
71 | |||
72 | /** | ||
73 | * Retrieve a thumbnail for given URL | ||
74 | * | ||
75 | * @param string $url where to look for a thumbnail. | ||
76 | * | ||
77 | * @return bool|string The thumbnail relative cache file path, or false if none has been found. | ||
78 | */ | ||
79 | public function get($url) | ||
80 | { | ||
81 | if ($this->conf->get('thumbnails.mode') === self::MODE_COMMON | ||
82 | && ! $this->isCommonMediaOrImage($url) | ||
83 | ) { | ||
84 | return false; | ||
85 | } | ||
86 | |||
87 | try { | ||
88 | return $this->wt->thumbnail($url); | ||
89 | } catch (WebThumbnailerException $e) { | ||
90 | // Exceptions are only thrown in debug mode. | ||
91 | error_log(get_class($e) . ': ' . $e->getMessage()); | ||
92 | } | ||
93 | return false; | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * We check weather the given URL is from a common media domain, | ||
98 | * or if the file extension is an image. | ||
99 | * | ||
100 | * @param string $url to check | ||
101 | * | ||
102 | * @return bool true if it's an image or from a common media domain, false otherwise. | ||
103 | */ | ||
104 | public function isCommonMediaOrImage($url) | ||
105 | { | ||
106 | foreach (self::COMMON_MEDIA_DOMAINS as $domain) { | ||
107 | if (strpos($url, $domain) !== false) { | ||
108 | return true; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | if (endsWith($url, '.jpg') || endsWith($url, '.png') || endsWith($url, '.jpeg')) { | ||
113 | return true; | ||
114 | } | ||
115 | |||
116 | return false; | ||
117 | } | ||
118 | |||
119 | /** | ||
120 | * Make sure that requirements are match to use thumbnails: | ||
121 | * - php-gd is loaded | ||
122 | */ | ||
123 | protected function checkRequirements() | ||
124 | { | ||
125 | return extension_loaded('gd'); | ||
126 | } | ||
127 | } | ||
diff --git a/application/Updater.php b/application/Updater.php index dece2c02..c2aa1568 100644 --- a/application/Updater.php +++ b/application/Updater.php | |||
@@ -2,6 +2,7 @@ | |||
2 | use Shaarli\Config\ConfigJson; | 2 | use Shaarli\Config\ConfigJson; |
3 | use Shaarli\Config\ConfigPhp; | 3 | use Shaarli\Config\ConfigPhp; |
4 | use Shaarli\Config\ConfigManager; | 4 | use Shaarli\Config\ConfigManager; |
5 | use Shaarli\Thumbnailer; | ||
5 | 6 | ||
6 | /** | 7 | /** |
7 | * Class Updater. | 8 | * Class Updater. |
@@ -31,6 +32,11 @@ class Updater | |||
31 | protected $isLoggedIn; | 32 | protected $isLoggedIn; |
32 | 33 | ||
33 | /** | 34 | /** |
35 | * @var array $_SESSION | ||
36 | */ | ||
37 | protected $session; | ||
38 | |||
39 | /** | ||
34 | * @var ReflectionMethod[] List of current class methods. | 40 | * @var ReflectionMethod[] List of current class methods. |
35 | */ | 41 | */ |
36 | protected $methods; | 42 | protected $methods; |
@@ -42,13 +48,17 @@ class Updater | |||
42 | * @param LinkDB $linkDB LinkDB instance. | 48 | * @param LinkDB $linkDB LinkDB instance. |
43 | * @param ConfigManager $conf Configuration Manager instance. | 49 | * @param ConfigManager $conf Configuration Manager instance. |
44 | * @param boolean $isLoggedIn True if the user is logged in. | 50 | * @param boolean $isLoggedIn True if the user is logged in. |
51 | * @param array $session $_SESSION (by reference) | ||
52 | * | ||
53 | * @throws ReflectionException | ||
45 | */ | 54 | */ |
46 | public function __construct($doneUpdates, $linkDB, $conf, $isLoggedIn) | 55 | public function __construct($doneUpdates, $linkDB, $conf, $isLoggedIn, &$session = []) |
47 | { | 56 | { |
48 | $this->doneUpdates = $doneUpdates; | 57 | $this->doneUpdates = $doneUpdates; |
49 | $this->linkDB = $linkDB; | 58 | $this->linkDB = $linkDB; |
50 | $this->conf = $conf; | 59 | $this->conf = $conf; |
51 | $this->isLoggedIn = $isLoggedIn; | 60 | $this->isLoggedIn = $isLoggedIn; |
61 | $this->session = &$session; | ||
52 | 62 | ||
53 | // Retrieve all update methods. | 63 | // Retrieve all update methods. |
54 | $class = new ReflectionClass($this); | 64 | $class = new ReflectionClass($this); |
@@ -480,6 +490,30 @@ class Updater | |||
480 | } | 490 | } |
481 | 491 | ||
482 | $this->conf->write($this->isLoggedIn); | 492 | $this->conf->write($this->isLoggedIn); |
493 | return true; | ||
494 | } | ||
495 | |||
496 | /** | ||
497 | * * Move thumbnails management to WebThumbnailer, coming with new settings. | ||
498 | */ | ||
499 | public function updateMethodWebThumbnailer() | ||
500 | { | ||
501 | if ($this->conf->exists('thumbnails.mode')) { | ||
502 | return true; | ||
503 | } | ||
504 | |||
505 | $thumbnailsEnabled = $this->conf->get('thumbnail.enable_thumbnails', true); | ||
506 | $this->conf->set('thumbnails.mode', $thumbnailsEnabled ? Thumbnailer::MODE_ALL : Thumbnailer::MODE_NONE); | ||
507 | $this->conf->set('thumbnails.width', 125); | ||
508 | $this->conf->set('thumbnails.height', 90); | ||
509 | $this->conf->remove('thumbnail'); | ||
510 | $this->conf->write(true); | ||
511 | |||
512 | if ($thumbnailsEnabled) { | ||
513 | $this->session['warnings'][] = t( | ||
514 | 'You have enabled or changed thumbnails mode. <a href="?do=thumbs_update">Please synchronize them</a>.' | ||
515 | ); | ||
516 | } | ||
483 | 517 | ||
484 | return true; | 518 | return true; |
485 | } | 519 | } |
diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php index 82f4a368..32aaea48 100644 --- a/application/config/ConfigManager.php +++ b/application/config/ConfigManager.php | |||
@@ -148,6 +148,33 @@ class ConfigManager | |||
148 | } | 148 | } |
149 | 149 | ||
150 | /** | 150 | /** |
151 | * Remove a config element from the config file. | ||
152 | * | ||
153 | * @param string $setting Asked setting, keys separated with dots. | ||
154 | * @param bool $write Write the new setting in the config file, default false. | ||
155 | * @param bool $isLoggedIn User login state, default false. | ||
156 | * | ||
157 | * @throws \Exception Invalid | ||
158 | */ | ||
159 | public function remove($setting, $write = false, $isLoggedIn = false) | ||
160 | { | ||
161 | if (empty($setting) || ! is_string($setting)) { | ||
162 | throw new \Exception(t('Invalid setting key parameter. String expected, got: '). gettype($setting)); | ||
163 | } | ||
164 | |||
165 | // During the ConfigIO transition, map legacy settings to the new ones. | ||
166 | if ($this->configIO instanceof ConfigPhp && isset(ConfigPhp::$LEGACY_KEYS_MAPPING[$setting])) { | ||
167 | $setting = ConfigPhp::$LEGACY_KEYS_MAPPING[$setting]; | ||
168 | } | ||
169 | |||
170 | $settings = explode('.', $setting); | ||
171 | self::removeConfig($settings, $this->loadedConfig); | ||
172 | if ($write) { | ||
173 | $this->write($isLoggedIn); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | /** | ||
151 | * Check if a settings exists. | 178 | * Check if a settings exists. |
152 | * | 179 | * |
153 | * Supports nested settings with dot separated keys. | 180 | * Supports nested settings with dot separated keys. |
@@ -272,7 +299,7 @@ class ConfigManager | |||
272 | * | 299 | * |
273 | * @param array $settings Ordered array which contains keys to find. | 300 | * @param array $settings Ordered array which contains keys to find. |
274 | * @param mixed $value | 301 | * @param mixed $value |
275 | * @param array $conf Loaded settings, then sub-array. | 302 | * @param array $conf Loaded settings, then sub-array. |
276 | * | 303 | * |
277 | * @return mixed Found setting or NOT_FOUND flag. | 304 | * @return mixed Found setting or NOT_FOUND flag. |
278 | */ | 305 | */ |
@@ -290,6 +317,27 @@ class ConfigManager | |||
290 | } | 317 | } |
291 | 318 | ||
292 | /** | 319 | /** |
320 | * Recursive function which find asked setting in the loaded config and deletes it. | ||
321 | * | ||
322 | * @param array $settings Ordered array which contains keys to find. | ||
323 | * @param array $conf Loaded settings, then sub-array. | ||
324 | * | ||
325 | * @return mixed Found setting or NOT_FOUND flag. | ||
326 | */ | ||
327 | protected static function removeConfig($settings, &$conf) | ||
328 | { | ||
329 | if (!is_array($settings) || count($settings) == 0) { | ||
330 | return self::$NOT_FOUND; | ||
331 | } | ||
332 | |||
333 | $setting = array_shift($settings); | ||
334 | if (count($settings) > 0) { | ||
335 | return self::removeConfig($settings, $conf[$setting]); | ||
336 | } | ||
337 | unset($conf[$setting]); | ||
338 | } | ||
339 | |||
340 | /** | ||
293 | * Set a bunch of default values allowing Shaarli to start without a config file. | 341 | * Set a bunch of default values allowing Shaarli to start without a config file. |
294 | */ | 342 | */ |
295 | protected function setDefaultValues() | 343 | protected function setDefaultValues() |
@@ -333,12 +381,12 @@ class ConfigManager | |||
333 | // default state of the 'remember me' checkbox of the login form | 381 | // default state of the 'remember me' checkbox of the login form |
334 | $this->setEmpty('privacy.remember_user_default', true); | 382 | $this->setEmpty('privacy.remember_user_default', true); |
335 | 383 | ||
336 | $this->setEmpty('thumbnail.enable_thumbnails', true); | ||
337 | $this->setEmpty('thumbnail.enable_localcache', true); | ||
338 | |||
339 | $this->setEmpty('redirector.url', ''); | 384 | $this->setEmpty('redirector.url', ''); |
340 | $this->setEmpty('redirector.encode_url', true); | 385 | $this->setEmpty('redirector.encode_url', true); |
341 | 386 | ||
387 | $this->setEmpty('thumbnails.width', '125'); | ||
388 | $this->setEmpty('thumbnails.height', '90'); | ||
389 | |||
342 | $this->setEmpty('translation.language', 'auto'); | 390 | $this->setEmpty('translation.language', 'auto'); |
343 | $this->setEmpty('translation.mode', 'php'); | 391 | $this->setEmpty('translation.mode', 'php'); |
344 | $this->setEmpty('translation.extensions', []); | 392 | $this->setEmpty('translation.extensions', []); |
diff --git a/assets/common/js/picwall.js b/assets/common/js/picwall.js deleted file mode 100644 index 87a93fc3..00000000 --- a/assets/common/js/picwall.js +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | import Blazy from 'blazy'; | ||
2 | |||
3 | (() => { | ||
4 | const picwall = document.getElementById('picwall_container'); | ||
5 | if (picwall != null) { | ||
6 | // Suppress ESLint error because that's how bLazy works | ||
7 | /* eslint-disable no-new */ | ||
8 | new Blazy(); | ||
9 | } | ||
10 | })(); | ||
diff --git a/assets/common/js/thumbnails-update.js b/assets/common/js/thumbnails-update.js new file mode 100644 index 00000000..b66ca3ae --- /dev/null +++ b/assets/common/js/thumbnails-update.js | |||
@@ -0,0 +1,51 @@ | |||
1 | /** | ||
2 | * Script used in the thumbnails update page. | ||
3 | * | ||
4 | * It retrieves the list of link IDs to update, and execute AJAX requests | ||
5 | * to update their thumbnails, while updating the progress bar. | ||
6 | */ | ||
7 | |||
8 | /** | ||
9 | * Update the thumbnail of the link with the current i index in ids. | ||
10 | * It contains a recursive call to retrieve the thumb of the next link when it succeed. | ||
11 | * It also update the progress bar and other visual feedback elements. | ||
12 | * | ||
13 | * @param {array} ids List of LinkID to update | ||
14 | * @param {int} i Current index in ids | ||
15 | * @param {object} elements List of DOM element to avoid retrieving them at each iteration | ||
16 | */ | ||
17 | function updateThumb(ids, i, elements) { | ||
18 | const xhr = new XMLHttpRequest(); | ||
19 | xhr.open('POST', '?do=ajax_thumb_update'); | ||
20 | xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); | ||
21 | xhr.responseType = 'json'; | ||
22 | xhr.onload = () => { | ||
23 | if (xhr.status !== 200) { | ||
24 | alert(`An error occurred. Return code: ${xhr.status}`); | ||
25 | } else { | ||
26 | const { response } = xhr; | ||
27 | i += 1; | ||
28 | elements.progressBar.style.width = `${(i * 100) / ids.length}%`; | ||
29 | elements.current.innerHTML = i; | ||
30 | elements.title.innerHTML = response.title; | ||
31 | if (response.thumbnail !== false) { | ||
32 | elements.thumbnail.innerHTML = `<img src="${response.thumbnail}">`; | ||
33 | } | ||
34 | if (i < ids.length) { | ||
35 | updateThumb(ids, i, elements); | ||
36 | } | ||
37 | } | ||
38 | }; | ||
39 | xhr.send(`id=${ids[i]}`); | ||
40 | } | ||
41 | |||
42 | (() => { | ||
43 | const ids = document.getElementsByName('ids')[0].value.split(','); | ||
44 | const elements = { | ||
45 | progressBar: document.querySelector('.progressbar > div'), | ||
46 | current: document.querySelector('.progress-current'), | ||
47 | thumbnail: document.querySelector('.thumbnail-placeholder'), | ||
48 | title: document.querySelector('.thumbnail-link-title'), | ||
49 | }; | ||
50 | updateThumb(ids, 0, elements); | ||
51 | })(); | ||
diff --git a/assets/common/js/thumbnails.js b/assets/common/js/thumbnails.js new file mode 100644 index 00000000..c28322bb --- /dev/null +++ b/assets/common/js/thumbnails.js | |||
@@ -0,0 +1,7 @@ | |||
1 | import Blazy from 'blazy'; | ||
2 | |||
3 | (() => { | ||
4 | // Suppress ESLint error because that's how bLazy works | ||
5 | /* eslint-disable no-new */ | ||
6 | new Blazy(); | ||
7 | })(); | ||
diff --git a/assets/default/scss/shaarli.scss b/assets/default/scss/shaarli.scss index 09d5efbe..6b286f1e 100644 --- a/assets/default/scss/shaarli.scss +++ b/assets/default/scss/shaarli.scss | |||
@@ -146,6 +146,17 @@ body, | |||
146 | background-color: $main-green; | 146 | background-color: $main-green; |
147 | } | 147 | } |
148 | 148 | ||
149 | .pure-alert-warning { | ||
150 | a { | ||
151 | color: $warning-text; | ||
152 | font-weight: bold; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | .page-single-alert { | ||
157 | margin-top: 100px; | ||
158 | } | ||
159 | |||
149 | .anchor { | 160 | .anchor { |
150 | &:target { | 161 | &:target { |
151 | padding-top: 40px; | 162 | padding-top: 40px; |
@@ -625,23 +636,22 @@ body, | |||
625 | } | 636 | } |
626 | 637 | ||
627 | .linklist-item { | 638 | .linklist-item { |
639 | position: relative; | ||
628 | margin: 0 0 10px; | 640 | margin: 0 0 10px; |
629 | box-shadow: 1px 1px 3px $light-grey; | 641 | box-shadow: 1px 1px 3px $light-grey; |
630 | background: $almost-white; | 642 | background: $almost-white; |
631 | 643 | ||
632 | &.private { | 644 | &.private { |
633 | .linklist-item-title { | 645 | &::before { |
634 | &::before { | 646 | display: block; |
635 | @extend %private-border; | 647 | position: absolute; |
636 | margin-top: 3px; | 648 | top: 0; |
637 | } | 649 | left: 0; |
638 | } | 650 | z-index: 1; |
639 | 651 | background: $orange; | |
640 | .linklist-item-description { | 652 | width: 2px; |
641 | &::before { | 653 | height: 100%; |
642 | @extend %private-border; | 654 | content: ''; |
643 | height: 100%; | ||
644 | } | ||
645 | } | 655 | } |
646 | } | 656 | } |
647 | } | 657 | } |
@@ -1543,3 +1553,40 @@ form { | |||
1543 | .pure-button-shaarli { | 1553 | .pure-button-shaarli { |
1544 | background-color: $main-green; | 1554 | background-color: $main-green; |
1545 | } | 1555 | } |
1556 | |||
1557 | .progressbar { | ||
1558 | border-radius: 6px; | ||
1559 | background-color: $main-green; | ||
1560 | padding: 1px; | ||
1561 | |||
1562 | > div { | ||
1563 | border-radius: 10px; | ||
1564 | background: repeating-linear-gradient( | ||
1565 | -45deg, | ||
1566 | $almost-white, | ||
1567 | $almost-white 6px, | ||
1568 | $background-color 6px, | ||
1569 | $background-color 12px | ||
1570 | ); | ||
1571 | width: 0%; | ||
1572 | height: 10px; | ||
1573 | } | ||
1574 | } | ||
1575 | |||
1576 | .thumbnails-page-container { | ||
1577 | .progress-counter { | ||
1578 | padding: 10px 0 20px; | ||
1579 | } | ||
1580 | |||
1581 | .thumbnail-placeholder { | ||
1582 | margin: 10px auto; | ||
1583 | background-color: $light-grey; | ||
1584 | } | ||
1585 | |||
1586 | .thumbnail-link-title { | ||
1587 | padding-bottom: 20px; | ||
1588 | overflow: hidden; | ||
1589 | text-overflow: ellipsis; | ||
1590 | white-space: nowrap; | ||
1591 | } | ||
1592 | } | ||
diff --git a/assets/vintage/css/shaarli.css b/assets/vintage/css/shaarli.css index c919339b..87c440c8 100644 --- a/assets/vintage/css/shaarli.css +++ b/assets/vintage/css/shaarli.css | |||
@@ -701,8 +701,8 @@ a.bigbutton, #pageheader a.bigbutton { | |||
701 | position: relative; | 701 | position: relative; |
702 | display: table-cell; | 702 | display: table-cell; |
703 | vertical-align: middle; | 703 | vertical-align: middle; |
704 | width: 90px; | 704 | width: 120px; |
705 | height: 90px; | 705 | height: 120px; |
706 | overflow: hidden; | 706 | overflow: hidden; |
707 | text-align: center; | 707 | text-align: center; |
708 | float: left; | 708 | float: left; |
@@ -739,9 +739,9 @@ a.bigbutton, #pageheader a.bigbutton { | |||
739 | position: absolute; | 739 | position: absolute; |
740 | top: 0; | 740 | top: 0; |
741 | left: 0; | 741 | left: 0; |
742 | width: 90px; | 742 | width: 120px; |
743 | font-weight: bold; | 743 | font-weight: bold; |
744 | font-size: 8pt; | 744 | font-size: 9pt; |
745 | color: #fff; | 745 | color: #fff; |
746 | text-align: left; | 746 | text-align: left; |
747 | background-color: transparent; | 747 | background-color: transparent; |
@@ -1210,3 +1210,43 @@ ul.errors { | |||
1210 | width: 13px; | 1210 | width: 13px; |
1211 | height: 13px; | 1211 | height: 13px; |
1212 | } | 1212 | } |
1213 | |||
1214 | .thumbnails-update-container { | ||
1215 | padding: 20px 0; | ||
1216 | width: 50%; | ||
1217 | margin: auto; | ||
1218 | } | ||
1219 | |||
1220 | .thumbnails-update-container .thumbnail-placeholder { | ||
1221 | background: grey; | ||
1222 | margin: auto; | ||
1223 | } | ||
1224 | |||
1225 | .thumbnails-update-container .thumbnail-link-title { | ||
1226 | width: 75%; | ||
1227 | margin: auto; | ||
1228 | |||
1229 | padding-bottom: 20px; | ||
1230 | overflow: hidden; | ||
1231 | text-overflow: ellipsis; | ||
1232 | white-space: nowrap; | ||
1233 | } | ||
1234 | |||
1235 | .progressbar { | ||
1236 | border-radius: 6px; | ||
1237 | background-color: #111; | ||
1238 | padding: 1px; | ||
1239 | } | ||
1240 | |||
1241 | .progressbar > div { | ||
1242 | border-radius: 10px; | ||
1243 | background: repeating-linear-gradient( | ||
1244 | -45deg, | ||
1245 | #f5f5f5, | ||
1246 | #f5f5f5 6px, | ||
1247 | #d0d0d0 6px, | ||
1248 | #d0d0d0 12px | ||
1249 | ); | ||
1250 | width: 0%; | ||
1251 | height: 10px; | ||
1252 | } | ||
diff --git a/composer.json b/composer.json index 0d4c623c..99ef0b5e 100644 --- a/composer.json +++ b/composer.json | |||
@@ -19,6 +19,7 @@ | |||
19 | "shaarli/netscape-bookmark-parser": "^2.0", | 19 | "shaarli/netscape-bookmark-parser": "^2.0", |
20 | "erusev/parsedown": "^1.6", | 20 | "erusev/parsedown": "^1.6", |
21 | "slim/slim": "^3.0", | 21 | "slim/slim": "^3.0", |
22 | "arthurhoaro/web-thumbnailer": "^1.1", | ||
22 | "pubsubhubbub/publisher": "dev-master", | 23 | "pubsubhubbub/publisher": "dev-master", |
23 | "gettext/gettext": "^4.4" | 24 | "gettext/gettext": "^4.4" |
24 | }, | 25 | }, |
diff --git a/composer.lock b/composer.lock index ee762c0e..08e915cf 100644 --- a/composer.lock +++ b/composer.lock | |||
@@ -1,12 +1,60 @@ | |||
1 | { | 1 | { |
2 | "_readme": [ | 2 | "_readme": [ |
3 | "This file locks the dependencies of your project to a known state", | 3 | "This file locks the dependencies of your project to a known state", |
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", | 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", |
5 | "This file is @generated automatically" | 5 | "This file is @generated automatically" |
6 | ], | 6 | ], |
7 | "content-hash": "308a35eab91602fbb449f2c669c445ed", | 7 | "content-hash": "da7a0c081b61d949154c5d2e5370cbab", |
8 | "packages": [ | 8 | "packages": [ |
9 | { | 9 | { |
10 | "name": "arthurhoaro/web-thumbnailer", | ||
11 | "version": "v1.2.1", | ||
12 | "source": { | ||
13 | "type": "git", | ||
14 | "url": "https://github.com/ArthurHoaro/web-thumbnailer.git", | ||
15 | "reference": "a5a52f69e8e8f3c71fab9649e2a927e2d3f418f1" | ||
16 | }, | ||
17 | "dist": { | ||
18 | "type": "zip", | ||
19 | "url": "https://api.github.com/repos/ArthurHoaro/web-thumbnailer/zipball/a5a52f69e8e8f3c71fab9649e2a927e2d3f418f1", | ||
20 | "reference": "a5a52f69e8e8f3c71fab9649e2a927e2d3f418f1", | ||
21 | "shasum": "" | ||
22 | }, | ||
23 | "require": { | ||
24 | "php": ">=5.6", | ||
25 | "phpunit/php-text-template": "^1.2" | ||
26 | }, | ||
27 | "conflict": { | ||
28 | "phpunit/php-timer": ">=2" | ||
29 | }, | ||
30 | "require-dev": { | ||
31 | "php-coveralls/php-coveralls": "^2.0", | ||
32 | "phpunit/phpunit": "5.2.*", | ||
33 | "squizlabs/php_codesniffer": "^3.2" | ||
34 | }, | ||
35 | "type": "library", | ||
36 | "autoload": { | ||
37 | "psr-0": { | ||
38 | "WebThumbnailer\\": [ | ||
39 | "src/", | ||
40 | "tests/" | ||
41 | ] | ||
42 | } | ||
43 | }, | ||
44 | "notification-url": "https://packagist.org/downloads/", | ||
45 | "license": [ | ||
46 | "MIT" | ||
47 | ], | ||
48 | "authors": [ | ||
49 | { | ||
50 | "name": "Arthur Hoaro", | ||
51 | "homepage": "http://hoa.ro" | ||
52 | } | ||
53 | ], | ||
54 | "description": "PHP library which will retrieve a thumbnail for any given URL", | ||
55 | "time": "2018-07-17T10:21:14+00:00" | ||
56 | }, | ||
57 | { | ||
10 | "name": "container-interop/container-interop", | 58 | "name": "container-interop/container-interop", |
11 | "version": "1.2.0", | 59 | "version": "1.2.0", |
12 | "source": { | 60 | "source": { |
@@ -85,16 +133,16 @@ | |||
85 | }, | 133 | }, |
86 | { | 134 | { |
87 | "name": "gettext/gettext", | 135 | "name": "gettext/gettext", |
88 | "version": "v4.4.4", | 136 | "version": "v4.6.0", |
89 | "source": { | 137 | "source": { |
90 | "type": "git", | 138 | "type": "git", |
91 | "url": "https://github.com/oscarotero/Gettext.git", | 139 | "url": "https://github.com/oscarotero/Gettext.git", |
92 | "reference": "ab5e863de2f60806d02e6e6081e21efd45249168" | 140 | "reference": "cae84aff39a87e07bd6e5cddb5adb720a0ffa357" |
93 | }, | 141 | }, |
94 | "dist": { | 142 | "dist": { |
95 | "type": "zip", | 143 | "type": "zip", |
96 | "url": "https://api.github.com/repos/oscarotero/Gettext/zipball/ab5e863de2f60806d02e6e6081e21efd45249168", | 144 | "url": "https://api.github.com/repos/oscarotero/Gettext/zipball/cae84aff39a87e07bd6e5cddb5adb720a0ffa357", |
97 | "reference": "ab5e863de2f60806d02e6e6081e21efd45249168", | 145 | "reference": "cae84aff39a87e07bd6e5cddb5adb720a0ffa357", |
98 | "shasum": "" | 146 | "shasum": "" |
99 | }, | 147 | }, |
100 | "require": { | 148 | "require": { |
@@ -103,7 +151,7 @@ | |||
103 | }, | 151 | }, |
104 | "require-dev": { | 152 | "require-dev": { |
105 | "illuminate/view": "*", | 153 | "illuminate/view": "*", |
106 | "phpunit/phpunit": "^4.8|^5.7", | 154 | "phpunit/phpunit": "^4.8|^5.7|^6.5", |
107 | "squizlabs/php_codesniffer": "^3.0", | 155 | "squizlabs/php_codesniffer": "^3.0", |
108 | "symfony/yaml": "~2", | 156 | "symfony/yaml": "~2", |
109 | "twig/extensions": "*", | 157 | "twig/extensions": "*", |
@@ -143,20 +191,20 @@ | |||
143 | "po", | 191 | "po", |
144 | "translation" | 192 | "translation" |
145 | ], | 193 | ], |
146 | "time": "2018-02-21T18:49:59+00:00" | 194 | "time": "2018-06-26T16:51:09+00:00" |
147 | }, | 195 | }, |
148 | { | 196 | { |
149 | "name": "gettext/languages", | 197 | "name": "gettext/languages", |
150 | "version": "2.3.0", | 198 | "version": "2.4.0", |
151 | "source": { | 199 | "source": { |
152 | "type": "git", | 200 | "type": "git", |
153 | "url": "https://github.com/mlocati/cldr-to-gettext-plural-rules.git", | 201 | "url": "https://github.com/mlocati/cldr-to-gettext-plural-rules.git", |
154 | "reference": "49c39e51569963cc917a924b489e7025bfb9d8c7" | 202 | "reference": "1b74377bd0c4cd87e8d72b948f5d8867e23505a5" |
155 | }, | 203 | }, |
156 | "dist": { | 204 | "dist": { |
157 | "type": "zip", | 205 | "type": "zip", |
158 | "url": "https://api.github.com/repos/mlocati/cldr-to-gettext-plural-rules/zipball/49c39e51569963cc917a924b489e7025bfb9d8c7", | 206 | "url": "https://api.github.com/repos/mlocati/cldr-to-gettext-plural-rules/zipball/1b74377bd0c4cd87e8d72b948f5d8867e23505a5", |
159 | "reference": "49c39e51569963cc917a924b489e7025bfb9d8c7", | 207 | "reference": "1b74377bd0c4cd87e8d72b948f5d8867e23505a5", |
160 | "shasum": "" | 208 | "shasum": "" |
161 | }, | 209 | }, |
162 | "require": { | 210 | "require": { |
@@ -204,7 +252,7 @@ | |||
204 | "translations", | 252 | "translations", |
205 | "unicode" | 253 | "unicode" |
206 | ], | 254 | ], |
207 | "time": "2017-03-23T17:02:28+00:00" | 255 | "time": "2018-06-21T15:58:36+00:00" |
208 | }, | 256 | }, |
209 | { | 257 | { |
210 | "name": "katzgrau/klogger", | 258 | "name": "katzgrau/klogger", |
@@ -303,6 +351,47 @@ | |||
303 | "time": "2018-02-13T20:26:39+00:00" | 351 | "time": "2018-02-13T20:26:39+00:00" |
304 | }, | 352 | }, |
305 | { | 353 | { |
354 | "name": "phpunit/php-text-template", | ||
355 | "version": "1.2.1", | ||
356 | "source": { | ||
357 | "type": "git", | ||
358 | "url": "https://github.com/sebastianbergmann/php-text-template.git", | ||
359 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" | ||
360 | }, | ||
361 | "dist": { | ||
362 | "type": "zip", | ||
363 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", | ||
364 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", | ||
365 | "shasum": "" | ||
366 | }, | ||
367 | "require": { | ||
368 | "php": ">=5.3.3" | ||
369 | }, | ||
370 | "type": "library", | ||
371 | "autoload": { | ||
372 | "classmap": [ | ||
373 | "src/" | ||
374 | ] | ||
375 | }, | ||
376 | "notification-url": "https://packagist.org/downloads/", | ||
377 | "license": [ | ||
378 | "BSD-3-Clause" | ||
379 | ], | ||
380 | "authors": [ | ||
381 | { | ||
382 | "name": "Sebastian Bergmann", | ||
383 | "email": "sebastian@phpunit.de", | ||
384 | "role": "lead" | ||
385 | } | ||
386 | ], | ||
387 | "description": "Simple template engine.", | ||
388 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", | ||
389 | "keywords": [ | ||
390 | "template" | ||
391 | ], | ||
392 | "time": "2015-06-21T13:50:34+00:00" | ||
393 | }, | ||
394 | { | ||
306 | "name": "pimple/pimple", | 395 | "name": "pimple/pimple", |
307 | "version": "v3.2.3", | 396 | "version": "v3.2.3", |
308 | "source": { | 397 | "source": { |
@@ -504,12 +593,12 @@ | |||
504 | "source": { | 593 | "source": { |
505 | "type": "git", | 594 | "type": "git", |
506 | "url": "https://github.com/pubsubhubbub/php-publisher.git", | 595 | "url": "https://github.com/pubsubhubbub/php-publisher.git", |
507 | "reference": "0d224daebd504ab61c22fee4db58f8d1fc18945f" | 596 | "reference": "5008fc529b057251b48f4d17a10fdb20047ea8f5" |
508 | }, | 597 | }, |
509 | "dist": { | 598 | "dist": { |
510 | "type": "zip", | 599 | "type": "zip", |
511 | "url": "https://api.github.com/repos/pubsubhubbub/php-publisher/zipball/0d224daebd504ab61c22fee4db58f8d1fc18945f", | 600 | "url": "https://api.github.com/repos/pubsubhubbub/php-publisher/zipball/5008fc529b057251b48f4d17a10fdb20047ea8f5", |
512 | "reference": "0d224daebd504ab61c22fee4db58f8d1fc18945f", | 601 | "reference": "5008fc529b057251b48f4d17a10fdb20047ea8f5", |
513 | "shasum": "" | 602 | "shasum": "" |
514 | }, | 603 | }, |
515 | "require": { | 604 | "require": { |
@@ -539,7 +628,7 @@ | |||
539 | "publishers", | 628 | "publishers", |
540 | "pubsubhubbub" | 629 | "pubsubhubbub" |
541 | ], | 630 | ], |
542 | "time": "2017-10-08T10:59:41+00:00" | 631 | "time": "2018-05-22T11:56:26+00:00" |
543 | }, | 632 | }, |
544 | { | 633 | { |
545 | "name": "shaarli/netscape-bookmark-parser", | 634 | "name": "shaarli/netscape-bookmark-parser", |
@@ -598,16 +687,16 @@ | |||
598 | }, | 687 | }, |
599 | { | 688 | { |
600 | "name": "slim/slim", | 689 | "name": "slim/slim", |
601 | "version": "3.9.2", | 690 | "version": "3.10.0", |
602 | "source": { | 691 | "source": { |
603 | "type": "git", | 692 | "type": "git", |
604 | "url": "https://github.com/slimphp/Slim.git", | 693 | "url": "https://github.com/slimphp/Slim.git", |
605 | "reference": "4086d0106cf5a7135c69fce4161fe355a8feb118" | 694 | "reference": "d8aabeacc3688b25e2f2dd2db91df91ec6fdd748" |
606 | }, | 695 | }, |
607 | "dist": { | 696 | "dist": { |
608 | "type": "zip", | 697 | "type": "zip", |
609 | "url": "https://api.github.com/repos/slimphp/Slim/zipball/4086d0106cf5a7135c69fce4161fe355a8feb118", | 698 | "url": "https://api.github.com/repos/slimphp/Slim/zipball/d8aabeacc3688b25e2f2dd2db91df91ec6fdd748", |
610 | "reference": "4086d0106cf5a7135c69fce4161fe355a8feb118", | 699 | "reference": "d8aabeacc3688b25e2f2dd2db91df91ec6fdd748", |
611 | "shasum": "" | 700 | "shasum": "" |
612 | }, | 701 | }, |
613 | "require": { | 702 | "require": { |
@@ -665,7 +754,7 @@ | |||
665 | "micro", | 754 | "micro", |
666 | "router" | 755 | "router" |
667 | ], | 756 | ], |
668 | "time": "2017-11-26T19:13:09+00:00" | 757 | "time": "2018-04-19T19:29:08+00:00" |
669 | } | 758 | } |
670 | ], | 759 | ], |
671 | "packages-dev": [ | 760 | "packages-dev": [ |
@@ -1022,23 +1111,23 @@ | |||
1022 | }, | 1111 | }, |
1023 | { | 1112 | { |
1024 | "name": "phpspec/prophecy", | 1113 | "name": "phpspec/prophecy", |
1025 | "version": "1.7.5", | 1114 | "version": "1.7.6", |
1026 | "source": { | 1115 | "source": { |
1027 | "type": "git", | 1116 | "type": "git", |
1028 | "url": "https://github.com/phpspec/prophecy.git", | 1117 | "url": "https://github.com/phpspec/prophecy.git", |
1029 | "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401" | 1118 | "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" |
1030 | }, | 1119 | }, |
1031 | "dist": { | 1120 | "dist": { |
1032 | "type": "zip", | 1121 | "type": "zip", |
1033 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401", | 1122 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", |
1034 | "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401", | 1123 | "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", |
1035 | "shasum": "" | 1124 | "shasum": "" |
1036 | }, | 1125 | }, |
1037 | "require": { | 1126 | "require": { |
1038 | "doctrine/instantiator": "^1.0.2", | 1127 | "doctrine/instantiator": "^1.0.2", |
1039 | "php": "^5.3|^7.0", | 1128 | "php": "^5.3|^7.0", |
1040 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", | 1129 | "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", |
1041 | "sebastian/comparator": "^1.1|^2.0", | 1130 | "sebastian/comparator": "^1.1|^2.0|^3.0", |
1042 | "sebastian/recursion-context": "^1.0|^2.0|^3.0" | 1131 | "sebastian/recursion-context": "^1.0|^2.0|^3.0" |
1043 | }, | 1132 | }, |
1044 | "require-dev": { | 1133 | "require-dev": { |
@@ -1081,7 +1170,7 @@ | |||
1081 | "spy", | 1170 | "spy", |
1082 | "stub" | 1171 | "stub" |
1083 | ], | 1172 | ], |
1084 | "time": "2018-02-19T10:16:54+00:00" | 1173 | "time": "2018-04-18T13:57:24+00:00" |
1085 | }, | 1174 | }, |
1086 | { | 1175 | { |
1087 | "name": "phpunit/php-code-coverage", | 1176 | "name": "phpunit/php-code-coverage", |
@@ -1194,47 +1283,6 @@ | |||
1194 | "time": "2017-11-27T13:52:08+00:00" | 1283 | "time": "2017-11-27T13:52:08+00:00" |
1195 | }, | 1284 | }, |
1196 | { | 1285 | { |
1197 | "name": "phpunit/php-text-template", | ||
1198 | "version": "1.2.1", | ||
1199 | "source": { | ||
1200 | "type": "git", | ||
1201 | "url": "https://github.com/sebastianbergmann/php-text-template.git", | ||
1202 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" | ||
1203 | }, | ||
1204 | "dist": { | ||
1205 | "type": "zip", | ||
1206 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", | ||
1207 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", | ||
1208 | "shasum": "" | ||
1209 | }, | ||
1210 | "require": { | ||
1211 | "php": ">=5.3.3" | ||
1212 | }, | ||
1213 | "type": "library", | ||
1214 | "autoload": { | ||
1215 | "classmap": [ | ||
1216 | "src/" | ||
1217 | ] | ||
1218 | }, | ||
1219 | "notification-url": "https://packagist.org/downloads/", | ||
1220 | "license": [ | ||
1221 | "BSD-3-Clause" | ||
1222 | ], | ||
1223 | "authors": [ | ||
1224 | { | ||
1225 | "name": "Sebastian Bergmann", | ||
1226 | "email": "sebastian@phpunit.de", | ||
1227 | "role": "lead" | ||
1228 | } | ||
1229 | ], | ||
1230 | "description": "Simple template engine.", | ||
1231 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", | ||
1232 | "keywords": [ | ||
1233 | "template" | ||
1234 | ], | ||
1235 | "time": "2015-06-21T13:50:34+00:00" | ||
1236 | }, | ||
1237 | { | ||
1238 | "name": "phpunit/php-timer", | 1286 | "name": "phpunit/php-timer", |
1239 | "version": "1.0.9", | 1287 | "version": "1.0.9", |
1240 | "source": { | 1288 | "source": { |
@@ -2207,21 +2255,22 @@ | |||
2207 | }, | 2255 | }, |
2208 | { | 2256 | { |
2209 | "name": "symfony/config", | 2257 | "name": "symfony/config", |
2210 | "version": "v3.4.6", | 2258 | "version": "v3.4.12", |
2211 | "source": { | 2259 | "source": { |
2212 | "type": "git", | 2260 | "type": "git", |
2213 | "url": "https://github.com/symfony/config.git", | 2261 | "url": "https://github.com/symfony/config.git", |
2214 | "reference": "05e10567b529476a006b00746c5f538f1636810e" | 2262 | "reference": "1fffdeb349ff36a25184e5564c25289b1dbfc402" |
2215 | }, | 2263 | }, |
2216 | "dist": { | 2264 | "dist": { |
2217 | "type": "zip", | 2265 | "type": "zip", |
2218 | "url": "https://api.github.com/repos/symfony/config/zipball/05e10567b529476a006b00746c5f538f1636810e", | 2266 | "url": "https://api.github.com/repos/symfony/config/zipball/1fffdeb349ff36a25184e5564c25289b1dbfc402", |
2219 | "reference": "05e10567b529476a006b00746c5f538f1636810e", | 2267 | "reference": "1fffdeb349ff36a25184e5564c25289b1dbfc402", |
2220 | "shasum": "" | 2268 | "shasum": "" |
2221 | }, | 2269 | }, |
2222 | "require": { | 2270 | "require": { |
2223 | "php": "^5.5.9|>=7.0.8", | 2271 | "php": "^5.5.9|>=7.0.8", |
2224 | "symfony/filesystem": "~2.8|~3.0|~4.0" | 2272 | "symfony/filesystem": "~2.8|~3.0|~4.0", |
2273 | "symfony/polyfill-ctype": "~1.8" | ||
2225 | }, | 2274 | }, |
2226 | "conflict": { | 2275 | "conflict": { |
2227 | "symfony/dependency-injection": "<3.3", | 2276 | "symfony/dependency-injection": "<3.3", |
@@ -2266,20 +2315,20 @@ | |||
2266 | ], | 2315 | ], |
2267 | "description": "Symfony Config Component", | 2316 | "description": "Symfony Config Component", |
2268 | "homepage": "https://symfony.com", | 2317 | "homepage": "https://symfony.com", |
2269 | "time": "2018-02-14T10:03:57+00:00" | 2318 | "time": "2018-06-19T14:02:58+00:00" |
2270 | }, | 2319 | }, |
2271 | { | 2320 | { |
2272 | "name": "symfony/console", | 2321 | "name": "symfony/console", |
2273 | "version": "v3.4.6", | 2322 | "version": "v3.4.12", |
2274 | "source": { | 2323 | "source": { |
2275 | "type": "git", | 2324 | "type": "git", |
2276 | "url": "https://github.com/symfony/console.git", | 2325 | "url": "https://github.com/symfony/console.git", |
2277 | "reference": "067339e9b8ec30d5f19f5950208893ff026b94f7" | 2326 | "reference": "1b97071a26d028c9bd4588264e101e14f6e7cd00" |
2278 | }, | 2327 | }, |
2279 | "dist": { | 2328 | "dist": { |
2280 | "type": "zip", | 2329 | "type": "zip", |
2281 | "url": "https://api.github.com/repos/symfony/console/zipball/067339e9b8ec30d5f19f5950208893ff026b94f7", | 2330 | "url": "https://api.github.com/repos/symfony/console/zipball/1b97071a26d028c9bd4588264e101e14f6e7cd00", |
2282 | "reference": "067339e9b8ec30d5f19f5950208893ff026b94f7", | 2331 | "reference": "1b97071a26d028c9bd4588264e101e14f6e7cd00", |
2283 | "shasum": "" | 2332 | "shasum": "" |
2284 | }, | 2333 | }, |
2285 | "require": { | 2334 | "require": { |
@@ -2300,7 +2349,7 @@ | |||
2300 | "symfony/process": "~3.3|~4.0" | 2349 | "symfony/process": "~3.3|~4.0" |
2301 | }, | 2350 | }, |
2302 | "suggest": { | 2351 | "suggest": { |
2303 | "psr/log": "For using the console logger", | 2352 | "psr/log-implementation": "For using the console logger", |
2304 | "symfony/event-dispatcher": "", | 2353 | "symfony/event-dispatcher": "", |
2305 | "symfony/lock": "", | 2354 | "symfony/lock": "", |
2306 | "symfony/process": "" | 2355 | "symfony/process": "" |
@@ -2335,20 +2384,20 @@ | |||
2335 | ], | 2384 | ], |
2336 | "description": "Symfony Console Component", | 2385 | "description": "Symfony Console Component", |
2337 | "homepage": "https://symfony.com", | 2386 | "homepage": "https://symfony.com", |
2338 | "time": "2018-02-26T15:46:28+00:00" | 2387 | "time": "2018-05-23T05:02:55+00:00" |
2339 | }, | 2388 | }, |
2340 | { | 2389 | { |
2341 | "name": "symfony/debug", | 2390 | "name": "symfony/debug", |
2342 | "version": "v3.4.6", | 2391 | "version": "v3.4.12", |
2343 | "source": { | 2392 | "source": { |
2344 | "type": "git", | 2393 | "type": "git", |
2345 | "url": "https://github.com/symfony/debug.git", | 2394 | "url": "https://github.com/symfony/debug.git", |
2346 | "reference": "9b1071f86e79e1999b3d3675d2e0e7684268b9bc" | 2395 | "reference": "47e6788c5b151cf0cfdf3329116bf33800632d75" |
2347 | }, | 2396 | }, |
2348 | "dist": { | 2397 | "dist": { |
2349 | "type": "zip", | 2398 | "type": "zip", |
2350 | "url": "https://api.github.com/repos/symfony/debug/zipball/9b1071f86e79e1999b3d3675d2e0e7684268b9bc", | 2399 | "url": "https://api.github.com/repos/symfony/debug/zipball/47e6788c5b151cf0cfdf3329116bf33800632d75", |
2351 | "reference": "9b1071f86e79e1999b3d3675d2e0e7684268b9bc", | 2400 | "reference": "47e6788c5b151cf0cfdf3329116bf33800632d75", |
2352 | "shasum": "" | 2401 | "shasum": "" |
2353 | }, | 2402 | }, |
2354 | "require": { | 2403 | "require": { |
@@ -2391,20 +2440,20 @@ | |||
2391 | ], | 2440 | ], |
2392 | "description": "Symfony Debug Component", | 2441 | "description": "Symfony Debug Component", |
2393 | "homepage": "https://symfony.com", | 2442 | "homepage": "https://symfony.com", |
2394 | "time": "2018-02-28T21:49:22+00:00" | 2443 | "time": "2018-06-25T11:10:40+00:00" |
2395 | }, | 2444 | }, |
2396 | { | 2445 | { |
2397 | "name": "symfony/dependency-injection", | 2446 | "name": "symfony/dependency-injection", |
2398 | "version": "v3.4.6", | 2447 | "version": "v3.4.12", |
2399 | "source": { | 2448 | "source": { |
2400 | "type": "git", | 2449 | "type": "git", |
2401 | "url": "https://github.com/symfony/dependency-injection.git", | 2450 | "url": "https://github.com/symfony/dependency-injection.git", |
2402 | "reference": "12e901abc1cb0d637a0e5abe9923471361d96b07" | 2451 | "reference": "a0be80e3f8c11aca506e250c00bb100c04c35d10" |
2403 | }, | 2452 | }, |
2404 | "dist": { | 2453 | "dist": { |
2405 | "type": "zip", | 2454 | "type": "zip", |
2406 | "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/12e901abc1cb0d637a0e5abe9923471361d96b07", | 2455 | "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/a0be80e3f8c11aca506e250c00bb100c04c35d10", |
2407 | "reference": "12e901abc1cb0d637a0e5abe9923471361d96b07", | 2456 | "reference": "a0be80e3f8c11aca506e250c00bb100c04c35d10", |
2408 | "shasum": "" | 2457 | "shasum": "" |
2409 | }, | 2458 | }, |
2410 | "require": { | 2459 | "require": { |
@@ -2462,24 +2511,25 @@ | |||
2462 | ], | 2511 | ], |
2463 | "description": "Symfony DependencyInjection Component", | 2512 | "description": "Symfony DependencyInjection Component", |
2464 | "homepage": "https://symfony.com", | 2513 | "homepage": "https://symfony.com", |
2465 | "time": "2018-03-04T03:54:53+00:00" | 2514 | "time": "2018-06-25T08:36:56+00:00" |
2466 | }, | 2515 | }, |
2467 | { | 2516 | { |
2468 | "name": "symfony/filesystem", | 2517 | "name": "symfony/filesystem", |
2469 | "version": "v3.4.6", | 2518 | "version": "v3.4.12", |
2470 | "source": { | 2519 | "source": { |
2471 | "type": "git", | 2520 | "type": "git", |
2472 | "url": "https://github.com/symfony/filesystem.git", | 2521 | "url": "https://github.com/symfony/filesystem.git", |
2473 | "reference": "253a4490b528597aa14d2bf5aeded6f5e5e4a541" | 2522 | "reference": "8a721a5f2553c6c3482b1c5b22ed60fe94dd63ed" |
2474 | }, | 2523 | }, |
2475 | "dist": { | 2524 | "dist": { |
2476 | "type": "zip", | 2525 | "type": "zip", |
2477 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/253a4490b528597aa14d2bf5aeded6f5e5e4a541", | 2526 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/8a721a5f2553c6c3482b1c5b22ed60fe94dd63ed", |
2478 | "reference": "253a4490b528597aa14d2bf5aeded6f5e5e4a541", | 2527 | "reference": "8a721a5f2553c6c3482b1c5b22ed60fe94dd63ed", |
2479 | "shasum": "" | 2528 | "shasum": "" |
2480 | }, | 2529 | }, |
2481 | "require": { | 2530 | "require": { |
2482 | "php": "^5.5.9|>=7.0.8" | 2531 | "php": "^5.5.9|>=7.0.8", |
2532 | "symfony/polyfill-ctype": "~1.8" | ||
2483 | }, | 2533 | }, |
2484 | "type": "library", | 2534 | "type": "library", |
2485 | "extra": { | 2535 | "extra": { |
@@ -2511,20 +2561,20 @@ | |||
2511 | ], | 2561 | ], |
2512 | "description": "Symfony Filesystem Component", | 2562 | "description": "Symfony Filesystem Component", |
2513 | "homepage": "https://symfony.com", | 2563 | "homepage": "https://symfony.com", |
2514 | "time": "2018-02-22T10:48:49+00:00" | 2564 | "time": "2018-06-21T11:10:19+00:00" |
2515 | }, | 2565 | }, |
2516 | { | 2566 | { |
2517 | "name": "symfony/finder", | 2567 | "name": "symfony/finder", |
2518 | "version": "v3.4.6", | 2568 | "version": "v3.4.12", |
2519 | "source": { | 2569 | "source": { |
2520 | "type": "git", | 2570 | "type": "git", |
2521 | "url": "https://github.com/symfony/finder.git", | 2571 | "url": "https://github.com/symfony/finder.git", |
2522 | "reference": "a479817ce0a9e4adfd7d39c6407c95d97c254625" | 2572 | "reference": "3a8c3de91d2b2c68cd2d665cf9d00f7ef9eaa394" |
2523 | }, | 2573 | }, |
2524 | "dist": { | 2574 | "dist": { |
2525 | "type": "zip", | 2575 | "type": "zip", |
2526 | "url": "https://api.github.com/repos/symfony/finder/zipball/a479817ce0a9e4adfd7d39c6407c95d97c254625", | 2576 | "url": "https://api.github.com/repos/symfony/finder/zipball/3a8c3de91d2b2c68cd2d665cf9d00f7ef9eaa394", |
2527 | "reference": "a479817ce0a9e4adfd7d39c6407c95d97c254625", | 2577 | "reference": "3a8c3de91d2b2c68cd2d665cf9d00f7ef9eaa394", |
2528 | "shasum": "" | 2578 | "shasum": "" |
2529 | }, | 2579 | }, |
2530 | "require": { | 2580 | "require": { |
@@ -2560,20 +2610,75 @@ | |||
2560 | ], | 2610 | ], |
2561 | "description": "Symfony Finder Component", | 2611 | "description": "Symfony Finder Component", |
2562 | "homepage": "https://symfony.com", | 2612 | "homepage": "https://symfony.com", |
2563 | "time": "2018-03-05T18:28:11+00:00" | 2613 | "time": "2018-06-19T20:52:10+00:00" |
2614 | }, | ||
2615 | { | ||
2616 | "name": "symfony/polyfill-ctype", | ||
2617 | "version": "v1.8.0", | ||
2618 | "source": { | ||
2619 | "type": "git", | ||
2620 | "url": "https://github.com/symfony/polyfill-ctype.git", | ||
2621 | "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae" | ||
2622 | }, | ||
2623 | "dist": { | ||
2624 | "type": "zip", | ||
2625 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/7cc359f1b7b80fc25ed7796be7d96adc9b354bae", | ||
2626 | "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae", | ||
2627 | "shasum": "" | ||
2628 | }, | ||
2629 | "require": { | ||
2630 | "php": ">=5.3.3" | ||
2631 | }, | ||
2632 | "type": "library", | ||
2633 | "extra": { | ||
2634 | "branch-alias": { | ||
2635 | "dev-master": "1.8-dev" | ||
2636 | } | ||
2637 | }, | ||
2638 | "autoload": { | ||
2639 | "psr-4": { | ||
2640 | "Symfony\\Polyfill\\Ctype\\": "" | ||
2641 | }, | ||
2642 | "files": [ | ||
2643 | "bootstrap.php" | ||
2644 | ] | ||
2645 | }, | ||
2646 | "notification-url": "https://packagist.org/downloads/", | ||
2647 | "license": [ | ||
2648 | "MIT" | ||
2649 | ], | ||
2650 | "authors": [ | ||
2651 | { | ||
2652 | "name": "Symfony Community", | ||
2653 | "homepage": "https://symfony.com/contributors" | ||
2654 | }, | ||
2655 | { | ||
2656 | "name": "Gert de Pagter", | ||
2657 | "email": "BackEndTea@gmail.com" | ||
2658 | } | ||
2659 | ], | ||
2660 | "description": "Symfony polyfill for ctype functions", | ||
2661 | "homepage": "https://symfony.com", | ||
2662 | "keywords": [ | ||
2663 | "compatibility", | ||
2664 | "ctype", | ||
2665 | "polyfill", | ||
2666 | "portable" | ||
2667 | ], | ||
2668 | "time": "2018-04-30T19:57:29+00:00" | ||
2564 | }, | 2669 | }, |
2565 | { | 2670 | { |
2566 | "name": "symfony/polyfill-mbstring", | 2671 | "name": "symfony/polyfill-mbstring", |
2567 | "version": "v1.7.0", | 2672 | "version": "v1.8.0", |
2568 | "source": { | 2673 | "source": { |
2569 | "type": "git", | 2674 | "type": "git", |
2570 | "url": "https://github.com/symfony/polyfill-mbstring.git", | 2675 | "url": "https://github.com/symfony/polyfill-mbstring.git", |
2571 | "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b" | 2676 | "reference": "3296adf6a6454a050679cde90f95350ad604b171" |
2572 | }, | 2677 | }, |
2573 | "dist": { | 2678 | "dist": { |
2574 | "type": "zip", | 2679 | "type": "zip", |
2575 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b", | 2680 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171", |
2576 | "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b", | 2681 | "reference": "3296adf6a6454a050679cde90f95350ad604b171", |
2577 | "shasum": "" | 2682 | "shasum": "" |
2578 | }, | 2683 | }, |
2579 | "require": { | 2684 | "require": { |
@@ -2585,7 +2690,7 @@ | |||
2585 | "type": "library", | 2690 | "type": "library", |
2586 | "extra": { | 2691 | "extra": { |
2587 | "branch-alias": { | 2692 | "branch-alias": { |
2588 | "dev-master": "1.7-dev" | 2693 | "dev-master": "1.8-dev" |
2589 | } | 2694 | } |
2590 | }, | 2695 | }, |
2591 | "autoload": { | 2696 | "autoload": { |
@@ -2619,24 +2724,25 @@ | |||
2619 | "portable", | 2724 | "portable", |
2620 | "shim" | 2725 | "shim" |
2621 | ], | 2726 | ], |
2622 | "time": "2018-01-30T19:27:44+00:00" | 2727 | "time": "2018-04-26T10:06:28+00:00" |
2623 | }, | 2728 | }, |
2624 | { | 2729 | { |
2625 | "name": "symfony/yaml", | 2730 | "name": "symfony/yaml", |
2626 | "version": "v3.4.6", | 2731 | "version": "v3.4.12", |
2627 | "source": { | 2732 | "source": { |
2628 | "type": "git", | 2733 | "type": "git", |
2629 | "url": "https://github.com/symfony/yaml.git", | 2734 | "url": "https://github.com/symfony/yaml.git", |
2630 | "reference": "6af42631dcf89e9c616242c900d6c52bd53bd1bb" | 2735 | "reference": "c5010cc1692ce1fa328b1fb666961eb3d4a85bb0" |
2631 | }, | 2736 | }, |
2632 | "dist": { | 2737 | "dist": { |
2633 | "type": "zip", | 2738 | "type": "zip", |
2634 | "url": "https://api.github.com/repos/symfony/yaml/zipball/6af42631dcf89e9c616242c900d6c52bd53bd1bb", | 2739 | "url": "https://api.github.com/repos/symfony/yaml/zipball/c5010cc1692ce1fa328b1fb666961eb3d4a85bb0", |
2635 | "reference": "6af42631dcf89e9c616242c900d6c52bd53bd1bb", | 2740 | "reference": "c5010cc1692ce1fa328b1fb666961eb3d4a85bb0", |
2636 | "shasum": "" | 2741 | "shasum": "" |
2637 | }, | 2742 | }, |
2638 | "require": { | 2743 | "require": { |
2639 | "php": "^5.5.9|>=7.0.8" | 2744 | "php": "^5.5.9|>=7.0.8", |
2745 | "symfony/polyfill-ctype": "~1.8" | ||
2640 | }, | 2746 | }, |
2641 | "conflict": { | 2747 | "conflict": { |
2642 | "symfony/console": "<3.4" | 2748 | "symfony/console": "<3.4" |
@@ -2677,7 +2783,7 @@ | |||
2677 | ], | 2783 | ], |
2678 | "description": "Symfony Yaml Component", | 2784 | "description": "Symfony Yaml Component", |
2679 | "homepage": "https://symfony.com", | 2785 | "homepage": "https://symfony.com", |
2680 | "time": "2018-02-16T09:50:28+00:00" | 2786 | "time": "2018-05-03T23:18:14+00:00" |
2681 | }, | 2787 | }, |
2682 | { | 2788 | { |
2683 | "name": "theseer/fdomdocument", | 2789 | "name": "theseer/fdomdocument", |
diff --git a/doc/md/Link-structure.md b/doc/md/Link-structure.md new file mode 100644 index 00000000..0a2d0f88 --- /dev/null +++ b/doc/md/Link-structure.md | |||
@@ -0,0 +1,18 @@ | |||
1 | ## Link structure | ||
2 | |||
3 | Every link available through the `LinkDB` object is represented as an array | ||
4 | containing the following fields: | ||
5 | |||
6 | * `id` (integer): Unique identifier. | ||
7 | * `title` (string): Title of the link. | ||
8 | * `url` (string): URL of the link. Used for displayable links (without redirector, url encoding, etc.). | ||
9 | Can be absolute or relative for Notes. | ||
10 | * `real_url` (string): Real destination URL, can be redirected, encoded, etc. | ||
11 | * `shorturl` (string): Permalink small hash. | ||
12 | * `description` (string): Link text description. | ||
13 | * `private` (boolean): whether the link is private or not. | ||
14 | * `tags` (string): all link tags separated by a single space | ||
15 | * `thumbnail` (string|boolean): relative path of the thumbnail cache file, or false if there isn't any. | ||
16 | * `created` (DateTime): link creation date time. | ||
17 | * `updated` (DateTime): last modification date time. | ||
18 | \ No newline at end of file | ||
diff --git a/doc/md/Server-configuration.md b/doc/md/Server-configuration.md index ca82b2ec..e281dc85 100644 --- a/doc/md/Server-configuration.md +++ b/doc/md/Server-configuration.md | |||
@@ -29,7 +29,7 @@ Extension | Required? | Usage | |||
29 | ---|:---:|--- | 29 | ---|:---:|--- |
30 | [`openssl`](http://php.net/manual/en/book.openssl.php) | All | OpenSSL, HTTPS | 30 | [`openssl`](http://php.net/manual/en/book.openssl.php) | All | OpenSSL, HTTPS |
31 | [`php-mbstring`](http://php.net/manual/en/book.mbstring.php) | CentOS, Fedora, RHEL, Windows, some hosting providers | multibyte (Unicode) string support | 31 | [`php-mbstring`](http://php.net/manual/en/book.mbstring.php) | CentOS, Fedora, RHEL, Windows, some hosting providers | multibyte (Unicode) string support |
32 | [`php-gd`](http://php.net/manual/en/book.image.php) | optional | thumbnail resizing | 32 | [`php-gd`](http://php.net/manual/en/book.image.php) | optional | required to use thumbnails |
33 | [`php-intl`](http://php.net/manual/en/book.intl.php) | optional | localized text sorting (e.g. `e->è->f`) | 33 | [`php-intl`](http://php.net/manual/en/book.intl.php) | optional | localized text sorting (e.g. `e->è->f`) |
34 | [`php-curl`](http://php.net/manual/en/book.curl.php) | optional | using cURL for fetching webpages and thumbnails in a more robust way | 34 | [`php-curl`](http://php.net/manual/en/book.curl.php) | optional | using cURL for fetching webpages and thumbnails in a more robust way |
35 | [`php-gettext`](http://php.net/manual/en/book.gettext.php) | optional | Use the translation system in gettext mode (faster) | 35 | [`php-gettext`](http://php.net/manual/en/book.gettext.php) | optional | Use the translation system in gettext mode (faster) |
diff --git a/inc/languages/fr/LC_MESSAGES/shaarli.po b/inc/languages/fr/LC_MESSAGES/shaarli.po index 2ebeccbc..155eb52e 100644 --- a/inc/languages/fr/LC_MESSAGES/shaarli.po +++ b/inc/languages/fr/LC_MESSAGES/shaarli.po | |||
@@ -1,15 +1,15 @@ | |||
1 | msgid "" | 1 | msgid "" |
2 | msgstr "" | 2 | msgstr "" |
3 | "Project-Id-Version: Shaarli\n" | 3 | "Project-Id-Version: Shaarli\n" |
4 | "POT-Creation-Date: 2018-01-24 18:43+0100\n" | 4 | "POT-Creation-Date: 2018-07-17 13:04+0200\n" |
5 | "PO-Revision-Date: 2018-03-06 18:44+0100\n" | 5 | "PO-Revision-Date: 2018-07-17 13:07+0200\n" |
6 | "Last-Translator: \n" | 6 | "Last-Translator: \n" |
7 | "Language-Team: Shaarli\n" | 7 | "Language-Team: Shaarli\n" |
8 | "Language: fr_FR\n" | 8 | "Language: fr_FR\n" |
9 | "MIME-Version: 1.0\n" | 9 | "MIME-Version: 1.0\n" |
10 | "Content-Type: text/plain; charset=UTF-8\n" | 10 | "Content-Type: text/plain; charset=UTF-8\n" |
11 | "Content-Transfer-Encoding: 8bit\n" | 11 | "Content-Transfer-Encoding: 8bit\n" |
12 | "X-Generator: Poedit 2.0.6\n" | 12 | "X-Generator: Poedit 2.0.9\n" |
13 | "X-Poedit-Basepath: ../../../..\n" | 13 | "X-Poedit-Basepath: ../../../..\n" |
14 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" | 14 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" |
15 | "X-Poedit-SourceCharset: UTF-8\n" | 15 | "X-Poedit-SourceCharset: UTF-8\n" |
@@ -56,7 +56,7 @@ msgstr "Liens directs" | |||
56 | 56 | ||
57 | #: application/FeedBuilder.php:153 | 57 | #: application/FeedBuilder.php:153 |
58 | #: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:88 | 58 | #: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:88 |
59 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:178 | 59 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:177 |
60 | msgid "Permalink" | 60 | msgid "Permalink" |
61 | msgstr "Permalien" | 61 | msgstr "Permalien" |
62 | 62 | ||
@@ -68,18 +68,22 @@ msgstr "Le fichier d'historique n'est pas accessible en lecture ou en écriture" | |||
68 | msgid "Could not parse history file" | 68 | msgid "Could not parse history file" |
69 | msgstr "Format incorrect pour le fichier d'historique" | 69 | msgstr "Format incorrect pour le fichier d'historique" |
70 | 70 | ||
71 | #: application/Languages.php:161 | 71 | #: application/Languages.php:177 |
72 | msgid "Automatic" | 72 | msgid "Automatic" |
73 | msgstr "Automatique" | 73 | msgstr "Automatique" |
74 | 74 | ||
75 | #: application/Languages.php:162 | 75 | #: application/Languages.php:178 |
76 | msgid "English" | 76 | msgid "English" |
77 | msgstr "Anglais" | 77 | msgstr "Anglais" |
78 | 78 | ||
79 | #: application/Languages.php:163 | 79 | #: application/Languages.php:179 |
80 | msgid "French" | 80 | msgid "French" |
81 | msgstr "Français" | 81 | msgstr "Français" |
82 | 82 | ||
83 | #: application/Languages.php:180 | ||
84 | msgid "German" | ||
85 | msgstr "Allemand" | ||
86 | |||
83 | #: application/LinkDB.php:136 | 87 | #: application/LinkDB.php:136 |
84 | msgid "You are not authorized to add a link." | 88 | msgid "You are not authorized to add a link." |
85 | msgstr "Vous n'êtes pas autorisé à ajouter un lien." | 89 | msgstr "Vous n'êtes pas autorisé à ajouter un lien." |
@@ -163,11 +167,11 @@ msgstr "" | |||
163 | "a été importé avec succès en %d secondes : %d liens importés, %d liens " | 167 | "a été importé avec succès en %d secondes : %d liens importés, %d liens " |
164 | "écrasés, %d liens ignorés." | 168 | "écrasés, %d liens ignorés." |
165 | 169 | ||
166 | #: application/PageBuilder.php:168 | 170 | #: application/PageBuilder.php:200 |
167 | msgid "The page you are trying to reach does not exist or has been deleted." | 171 | msgid "The page you are trying to reach does not exist or has been deleted." |
168 | msgstr "La page que vous essayez de consulter n'existe pas ou a été supprimée." | 172 | msgstr "La page que vous essayez de consulter n'existe pas ou a été supprimée." |
169 | 173 | ||
170 | #: application/PageBuilder.php:170 | 174 | #: application/PageBuilder.php:202 |
171 | msgid "404 Not Found" | 175 | msgid "404 Not Found" |
172 | msgstr "404 Introuvable" | 176 | msgstr "404 Introuvable" |
173 | 177 | ||
@@ -176,21 +180,37 @@ msgstr "404 Introuvable" | |||
176 | msgid "Plugin \"%s\" files not found." | 180 | msgid "Plugin \"%s\" files not found." |
177 | msgstr "Les fichiers de l'extension \"%s\" sont introuvables." | 181 | msgstr "Les fichiers de l'extension \"%s\" sont introuvables." |
178 | 182 | ||
179 | #: application/Updater.php:76 | 183 | #: application/Thumbnailer.php:61 |
184 | msgid "" | ||
185 | "php-gd extension must be loaded to use thumbnails. Thumbnails are now " | ||
186 | "disabled. Please reload the page." | ||
187 | msgstr "" | ||
188 | "php-gd extension must be loaded to use thumbnails. Thumbnails are now " | ||
189 | "disabled. Please reload the page." | ||
190 | |||
191 | #: application/Updater.php:86 | ||
180 | msgid "Couldn't retrieve Updater class methods." | 192 | msgid "Couldn't retrieve Updater class methods." |
181 | msgstr "Impossible de récupérer les méthodes de la classe Updater." | 193 | msgstr "Impossible de récupérer les méthodes de la classe Updater." |
182 | 194 | ||
183 | #: application/Updater.php:506 | 195 | #: application/Updater.php:514 index.php:1023 |
196 | msgid "" | ||
197 | "You have enabled or changed thumbnails mode. <a href=\"?do=thumbs_update" | ||
198 | "\">Please synchronize them</a>." | ||
199 | msgstr "" | ||
200 | "Vous avez activé ou changé le mode de miniatures. <a href=\"?do=thumbs_update" | ||
201 | "\">Merci de les synchroniser</a>." | ||
202 | |||
203 | #: application/Updater.php:566 | ||
184 | msgid "An error occurred while running the update " | 204 | msgid "An error occurred while running the update " |
185 | msgstr "Une erreur s'est produite lors de l'exécution de la mise à jour " | 205 | msgstr "Une erreur s'est produite lors de l'exécution de la mise à jour " |
186 | 206 | ||
187 | #: application/Updater.php:546 | 207 | #: application/Updater.php:606 |
188 | msgid "Updates file path is not set, can't write updates." | 208 | msgid "Updates file path is not set, can't write updates." |
189 | msgstr "" | 209 | msgstr "" |
190 | "Le chemin vers le fichier de mise à jour n'est pas défini, impossible " | 210 | "Le chemin vers le fichier de mise à jour n'est pas défini, impossible " |
191 | "d'écrire les mises à jour." | 211 | "d'écrire les mises à jour." |
192 | 212 | ||
193 | #: application/Updater.php:551 | 213 | #: application/Updater.php:611 |
194 | msgid "Unable to write updates in " | 214 | msgid "Unable to write updates in " |
195 | msgstr "Impossible d'écrire les mises à jour dans " | 215 | msgstr "Impossible d'écrire les mises à jour dans " |
196 | 216 | ||
@@ -230,6 +250,7 @@ msgstr "" | |||
230 | "Shaarli a les droits d'écriture dans le dossier dans lequel il est installé." | 250 | "Shaarli a les droits d'écriture dans le dossier dans lequel il est installé." |
231 | 251 | ||
232 | #: application/config/ConfigManager.php:135 | 252 | #: application/config/ConfigManager.php:135 |
253 | #: application/config/ConfigManager.php:162 | ||
233 | msgid "Invalid setting key parameter. String expected, got: " | 254 | msgid "Invalid setting key parameter. String expected, got: " |
234 | msgstr "Clé de paramétrage invalide. Chaîne de caractères obtenue, attendu : " | 255 | msgstr "Clé de paramétrage invalide. Chaîne de caractères obtenue, attendu : " |
235 | 256 | ||
@@ -251,135 +272,133 @@ msgstr "Vous n'êtes pas autorisé à modifier la configuration." | |||
251 | msgid "Error accessing" | 272 | msgid "Error accessing" |
252 | msgstr "Une erreur s'est produite en accédant à " | 273 | msgstr "Une erreur s'est produite en accédant à " |
253 | 274 | ||
254 | #: index.php:142 | 275 | #: index.php:143 |
255 | msgid "Shared links on " | 276 | msgid "Shared links on " |
256 | msgstr "Liens partagés sur " | 277 | msgstr "Liens partagés sur " |
257 | 278 | ||
258 | #: index.php:164 | 279 | #: index.php:165 |
259 | msgid "Insufficient permissions:" | 280 | msgid "Insufficient permissions:" |
260 | msgstr "Permissions insuffisantes :" | 281 | msgstr "Permissions insuffisantes :" |
261 | 282 | ||
262 | #: index.php:303 | 283 | #: index.php:201 |
263 | msgid "I said: NO. You are banned for the moment. Go away." | 284 | msgid "I said: NO. You are banned for the moment. Go away." |
264 | msgstr "NON. Vous êtes banni pour le moment. Revenez plus tard." | 285 | msgstr "NON. Vous êtes banni pour le moment. Revenez plus tard." |
265 | 286 | ||
266 | #: index.php:368 | 287 | #: index.php:273 |
267 | msgid "Wrong login/password." | 288 | msgid "Wrong login/password." |
268 | msgstr "Nom d'utilisateur ou mot de passe incorrects." | 289 | msgstr "Nom d'utilisateur ou mot de passe incorrects." |
269 | 290 | ||
270 | #: index.php:576 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 | 291 | #: index.php:483 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:46 |
271 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:42 | 292 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:46 |
272 | msgid "Daily" | 293 | msgid "Daily" |
273 | msgstr "Quotidien" | 294 | msgstr "Quotidien" |
274 | 295 | ||
275 | #: index.php:681 tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28 | 296 | #: index.php:589 tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28 |
276 | #: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:44 | 297 | #: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:44 |
277 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:71 | 298 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:75 |
278 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:95 | 299 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:99 |
279 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:71 | 300 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:75 |
280 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:95 | 301 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:99 |
281 | msgid "Login" | 302 | msgid "Login" |
282 | msgstr "Connexion" | 303 | msgstr "Connexion" |
283 | 304 | ||
284 | #: index.php:722 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:39 | 305 | #: index.php:606 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 |
285 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:39 | 306 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:41 |
286 | msgid "Picture wall" | 307 | msgid "Picture wall" |
287 | msgstr "Mur d'images" | 308 | msgstr "Mur d'images" |
288 | 309 | ||
289 | #: index.php:770 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 | 310 | #: index.php:683 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 |
290 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:36 | 311 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:36 |
291 | #: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 | 312 | #: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 |
292 | msgid "Tag cloud" | 313 | msgid "Tag cloud" |
293 | msgstr "Nuage de tags" | 314 | msgstr "Nuage de tags" |
294 | 315 | ||
295 | #: index.php:803 tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 | 316 | #: index.php:716 tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 |
296 | msgid "Tag list" | 317 | msgid "Tag list" |
297 | msgstr "Liste des tags" | 318 | msgstr "Liste des tags" |
298 | 319 | ||
299 | #: index.php:1028 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31 | 320 | #: index.php:941 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31 |
300 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:31 | 321 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:31 |
301 | msgid "Tools" | 322 | msgid "Tools" |
302 | msgstr "Outils" | 323 | msgstr "Outils" |
303 | 324 | ||
304 | #: index.php:1037 | 325 | #: index.php:950 |
305 | msgid "You are not supposed to change a password on an Open Shaarli." | 326 | msgid "You are not supposed to change a password on an Open Shaarli." |
306 | msgstr "" | 327 | msgstr "" |
307 | "Vous n'êtes pas censé modifier le mot de passe d'un Shaarli en mode ouvert." | 328 | "Vous n'êtes pas censé modifier le mot de passe d'un Shaarli en mode ouvert." |
308 | 329 | ||
309 | #: index.php:1042 index.php:1084 index.php:1162 index.php:1193 index.php:1293 | 330 | #: index.php:955 index.php:997 index.php:1085 index.php:1116 index.php:1221 |
310 | msgid "Wrong token." | 331 | msgid "Wrong token." |
311 | msgstr "Jeton invalide." | 332 | msgstr "Jeton invalide." |
312 | 333 | ||
313 | #: index.php:1047 | 334 | #: index.php:960 |
314 | msgid "The old password is not correct." | 335 | msgid "The old password is not correct." |
315 | msgstr "L'ancien mot de passe est incorrect." | 336 | msgstr "L'ancien mot de passe est incorrect." |
316 | 337 | ||
317 | #: index.php:1067 | 338 | #: index.php:980 |
318 | msgid "Your password has been changed" | 339 | msgid "Your password has been changed" |
319 | msgstr "Votre mot de passe a été modifié" | 340 | msgstr "Votre mot de passe a été modifié" |
320 | 341 | ||
321 | #: index.php:1072 | 342 | #: index.php:985 |
322 | #: tmp/changepassword.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 | 343 | #: tmp/changepassword.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 |
323 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29 | 344 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29 |
324 | msgid "Change password" | 345 | msgid "Change password" |
325 | msgstr "Modification du mot de passe" | 346 | msgstr "Modification du mot de passe" |
326 | 347 | ||
327 | #: index.php:1121 | 348 | #: index.php:1043 |
328 | msgid "Configuration was saved." | 349 | msgid "Configuration was saved." |
329 | msgstr "La configuration a été sauvegardé." | 350 | msgstr "La configuration a été sauvegardé." |
330 | 351 | ||
331 | #: index.php:1145 tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:24 | 352 | #: index.php:1068 tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:24 |
332 | msgid "Configure" | 353 | msgid "Configure" |
333 | msgstr "Configurer" | 354 | msgstr "Configurer" |
334 | 355 | ||
335 | #: index.php:1156 tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 | 356 | #: index.php:1079 tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 |
336 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 | 357 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 |
337 | msgid "Manage tags" | 358 | msgid "Manage tags" |
338 | msgstr "Gérer les tags" | 359 | msgstr "Gérer les tags" |
339 | 360 | ||
340 | #: index.php:1174 | 361 | #: index.php:1097 |
341 | #, php-format | 362 | #, php-format |
342 | msgid "The tag was removed from %d link." | 363 | msgid "The tag was removed from %d link." |
343 | msgid_plural "The tag was removed from %d links." | 364 | msgid_plural "The tag was removed from %d links." |
344 | msgstr[0] "Le tag a été supprimé de %d lien." | 365 | msgstr[0] "Le tag a été supprimé de %d lien." |
345 | msgstr[1] "Le tag a été supprimé de %d liens." | 366 | msgstr[1] "Le tag a été supprimé de %d liens." |
346 | 367 | ||
347 | #: index.php:1175 | 368 | #: index.php:1098 |
348 | #, php-format | 369 | #, php-format |
349 | msgid "The tag was renamed in %d link." | 370 | msgid "The tag was renamed in %d link." |
350 | msgid_plural "The tag was renamed in %d links." | 371 | msgid_plural "The tag was renamed in %d links." |
351 | msgstr[0] "Le tag a été renommé dans %d lien." | 372 | msgstr[0] "Le tag a été renommé dans %d lien." |
352 | msgstr[1] "Le tag a été renommé dans %d liens." | 373 | msgstr[1] "Le tag a été renommé dans %d liens." |
353 | 374 | ||
354 | #: index.php:1183 tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 | 375 | #: index.php:1106 tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 |
355 | msgid "Shaare a new link" | 376 | msgid "Shaare a new link" |
356 | msgstr "Partager un nouveau lien" | 377 | msgstr "Partager un nouveau lien" |
357 | 378 | ||
358 | #: index.php:1353 tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 | 379 | #: index.php:1281 tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:169 |
359 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:170 | ||
360 | msgid "Edit" | 380 | msgid "Edit" |
361 | msgstr "Modifier" | 381 | msgstr "Modifier" |
362 | 382 | ||
363 | #: index.php:1353 index.php:1418 | 383 | #: index.php:1281 index.php:1351 |
364 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 | ||
365 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 | 384 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 |
366 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:26 | 385 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:26 |
367 | msgid "Shaare" | 386 | msgid "Shaare" |
368 | msgstr "Shaare" | 387 | msgstr "Shaare" |
369 | 388 | ||
370 | #: index.php:1387 | 389 | #: index.php:1320 |
371 | msgid "Note: " | 390 | msgid "Note: " |
372 | msgstr "Note : " | 391 | msgstr "Note : " |
373 | 392 | ||
374 | #: index.php:1427 tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:65 | 393 | #: index.php:1360 tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:65 |
375 | msgid "Export" | 394 | msgid "Export" |
376 | msgstr "Exporter" | 395 | msgstr "Exporter" |
377 | 396 | ||
378 | #: index.php:1489 tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:83 | 397 | #: index.php:1422 tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:83 |
379 | msgid "Import" | 398 | msgid "Import" |
380 | msgstr "Importer" | 399 | msgstr "Importer" |
381 | 400 | ||
382 | #: index.php:1499 | 401 | #: index.php:1432 |
383 | #, php-format | 402 | #, php-format |
384 | msgid "" | 403 | msgid "" |
385 | "The file you are trying to upload is probably bigger than what this " | 404 | "The file you are trying to upload is probably bigger than what this " |
@@ -389,16 +408,20 @@ msgstr "" | |||
389 | "le serveur web peut accepter (%s). Merci de l'envoyer en parties plus " | 408 | "le serveur web peut accepter (%s). Merci de l'envoyer en parties plus " |
390 | "légères." | 409 | "légères." |
391 | 410 | ||
392 | #: index.php:1538 tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 | 411 | #: index.php:1471 tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 |
393 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:22 | 412 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:22 |
394 | msgid "Plugin administration" | 413 | msgid "Plugin administration" |
395 | msgstr "Administration des extensions" | 414 | msgstr "Administration des extensions" |
396 | 415 | ||
397 | #: index.php:1703 | 416 | #: index.php:1523 tmp/thumbnails.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 |
417 | msgid "Thumbnails update" | ||
418 | msgstr "Mise à jour des miniatures" | ||
419 | |||
420 | #: index.php:1695 | ||
398 | msgid "Search: " | 421 | msgid "Search: " |
399 | msgstr "Recherche : " | 422 | msgstr "Recherche : " |
400 | 423 | ||
401 | #: index.php:1930 | 424 | #: index.php:1735 |
402 | #, php-format | 425 | #, php-format |
403 | msgid "" | 426 | msgid "" |
404 | "<pre>Sessions do not seem to work correctly on your server.<br>Make sure the " | 427 | "<pre>Sessions do not seem to work correctly on your server.<br>Make sure the " |
@@ -417,7 +440,7 @@ msgstr "" | |||
417 | "cookies. Nous vous recommandons d'accéder à votre serveur depuis son adresse " | 440 | "cookies. Nous vous recommandons d'accéder à votre serveur depuis son adresse " |
418 | "IP ou un <em>Fully Qualified Domain Name</em>.<br>" | 441 | "IP ou un <em>Fully Qualified Domain Name</em>.<br>" |
419 | 442 | ||
420 | #: index.php:1940 | 443 | #: index.php:1745 |
421 | msgid "Click to try again." | 444 | msgid "Click to try again." |
422 | msgstr "Cliquer ici pour réessayer." | 445 | msgstr "Cliquer ici pour réessayer." |
423 | 446 | ||
@@ -467,19 +490,19 @@ msgstr "" | |||
467 | msgid "Isso server URL (without 'http://')" | 490 | msgid "Isso server URL (without 'http://')" |
468 | msgstr "URL du serveur Isso (sans 'http://')" | 491 | msgstr "URL du serveur Isso (sans 'http://')" |
469 | 492 | ||
470 | #: plugins/markdown/markdown.php:158 | 493 | #: plugins/markdown/markdown.php:161 |
471 | msgid "Description will be rendered with" | 494 | msgid "Description will be rendered with" |
472 | msgstr "La description sera générée avec" | 495 | msgstr "La description sera générée avec" |
473 | 496 | ||
474 | #: plugins/markdown/markdown.php:159 | 497 | #: plugins/markdown/markdown.php:162 |
475 | msgid "Markdown syntax documentation" | 498 | msgid "Markdown syntax documentation" |
476 | msgstr "Documentation sur la syntaxe Markdown" | 499 | msgstr "Documentation sur la syntaxe Markdown" |
477 | 500 | ||
478 | #: plugins/markdown/markdown.php:160 | 501 | #: plugins/markdown/markdown.php:163 |
479 | msgid "Markdown syntax" | 502 | msgid "Markdown syntax" |
480 | msgstr "la syntaxe Markdown" | 503 | msgstr "la syntaxe Markdown" |
481 | 504 | ||
482 | #: plugins/markdown/markdown.php:339 | 505 | #: plugins/markdown/markdown.php:347 |
483 | msgid "" | 506 | msgid "" |
484 | "Render shaare description with Markdown syntax.<br><strong>Warning</" | 507 | "Render shaare description with Markdown syntax.<br><strong>Warning</" |
485 | "strong>:\n" | 508 | "strong>:\n" |
@@ -577,11 +600,11 @@ msgstr "URL de l'API Wallabag" | |||
577 | msgid "Wallabag API version (1 or 2)" | 600 | msgid "Wallabag API version (1 or 2)" |
578 | msgstr "Version de l'API Wallabag (1 ou 2)" | 601 | msgstr "Version de l'API Wallabag (1 ou 2)" |
579 | 602 | ||
580 | #: tests/LanguagesTest.php:188 tests/LanguagesTest.php:201 | 603 | #: tests/LanguagesTest.php:214 tests/LanguagesTest.php:227 |
581 | #: tests/languages/fr/LanguagesFrTest.php:160 | 604 | #: tests/languages/fr/LanguagesFrTest.php:160 |
582 | #: tests/languages/fr/LanguagesFrTest.php:173 | 605 | #: tests/languages/fr/LanguagesFrTest.php:173 |
583 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:81 | 606 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:85 |
584 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:81 | 607 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:85 |
585 | msgid "Search" | 608 | msgid "Search" |
586 | msgid_plural "Search" | 609 | msgid_plural "Search" |
587 | msgstr[0] "Rechercher" | 610 | msgstr[0] "Rechercher" |
@@ -625,8 +648,8 @@ msgid "Rename" | |||
625 | msgstr "Renommer" | 648 | msgstr "Renommer" |
626 | 649 | ||
627 | #: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:35 | 650 | #: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:35 |
628 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:79 | 651 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:77 |
629 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:172 | 652 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:171 |
630 | msgid "Delete" | 653 | msgid "Delete" |
631 | msgstr "Supprimer" | 654 | msgstr "Supprimer" |
632 | 655 | ||
@@ -736,8 +759,36 @@ msgstr "" | |||
736 | msgid "API secret" | 759 | msgid "API secret" |
737 | msgstr "Clé d'API secrète" | 760 | msgstr "Clé d'API secrète" |
738 | 761 | ||
739 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:274 | 762 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:277 |
740 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:74 | 763 | msgid "Enable thumbnails" |
764 | msgstr "Activer les miniatures" | ||
765 | |||
766 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:281 | ||
767 | msgid "You need to enable the extension <code>php-gd</code> to use thumbnails." | ||
768 | msgstr "" | ||
769 | "Vous devez activer l'extension <code>php-gd</code> pour utiliser les " | ||
770 | "miniatures." | ||
771 | |||
772 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:285 | ||
773 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:56 | ||
774 | msgid "Synchronize thumbnails" | ||
775 | msgstr "Synchroniser les miniatures" | ||
776 | |||
777 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:296 | ||
778 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31 | ||
779 | msgid "All" | ||
780 | msgstr "Tous" | ||
781 | |||
782 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:300 | ||
783 | msgid "Only common media hosts" | ||
784 | msgstr "Seulement les hébergeurs de média connus" | ||
785 | |||
786 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:304 | ||
787 | msgid "None" | ||
788 | msgstr "Aucune" | ||
789 | |||
790 | #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:312 | ||
791 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:72 | ||
741 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:139 | 792 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:139 |
742 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:199 | 793 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:199 |
743 | msgid "Save" | 794 | msgid "Save" |
@@ -763,25 +814,27 @@ msgstr "Tous les liens d'un jour sur une page." | |||
763 | msgid "Next day" | 814 | msgid "Next day" |
764 | msgstr "Jour suivant" | 815 | msgstr "Jour suivant" |
765 | 816 | ||
766 | #: tpl/editlink.html | 817 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 |
767 | msgid "Edit Shaare" | 818 | msgid "Edit Shaare" |
768 | msgstr "Modifier le Shaare" | 819 | msgstr "Modifier le Shaare" |
820 | |||
821 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 | ||
769 | msgid "New Shaare" | 822 | msgid "New Shaare" |
770 | msgstr "Nouveau Shaare" | 823 | msgstr "Nouveau Shaare" |
771 | 824 | ||
772 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:25 | 825 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:23 |
773 | msgid "Created:" | 826 | msgid "Created:" |
774 | msgstr "Création :" | 827 | msgstr "Création :" |
775 | 828 | ||
776 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28 | 829 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 |
777 | msgid "URL" | 830 | msgid "URL" |
778 | msgstr "URL" | 831 | msgstr "URL" |
779 | 832 | ||
780 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:34 | 833 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:32 |
781 | msgid "Title" | 834 | msgid "Title" |
782 | msgstr "Titre" | 835 | msgstr "Titre" |
783 | 836 | ||
784 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:40 | 837 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:38 |
785 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 | 838 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 |
786 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:75 | 839 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:75 |
787 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:99 | 840 | #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:99 |
@@ -789,17 +842,17 @@ msgstr "Titre" | |||
789 | msgid "Description" | 842 | msgid "Description" |
790 | msgstr "Description" | 843 | msgstr "Description" |
791 | 844 | ||
792 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:46 | 845 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:44 |
793 | msgid "Tags" | 846 | msgid "Tags" |
794 | msgstr "Tags" | 847 | msgstr "Tags" |
795 | 848 | ||
796 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:59 | 849 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:57 |
797 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 | 850 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 |
798 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:168 | 851 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:167 |
799 | msgid "Private" | 852 | msgid "Private" |
800 | msgstr "Privé" | 853 | msgstr "Privé" |
801 | 854 | ||
802 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:74 | 855 | #: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:72 |
803 | msgid "Apply Changes" | 856 | msgid "Apply Changes" |
804 | msgstr "Appliquer" | 857 | msgstr "Appliquer" |
805 | 858 | ||
@@ -811,10 +864,6 @@ msgstr "Exporter les données" | |||
811 | msgid "Selection" | 864 | msgid "Selection" |
812 | msgstr "Choisir" | 865 | msgstr "Choisir" |
813 | 866 | ||
814 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31 | ||
815 | msgid "All" | ||
816 | msgstr "Tous" | ||
817 | |||
818 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 | 867 | #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 |
819 | msgid "Public" | 868 | msgid "Public" |
820 | msgstr "Publics" | 869 | msgstr "Publics" |
@@ -876,15 +925,15 @@ msgstr "" | |||
876 | 925 | ||
877 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:33 | 926 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:33 |
878 | #: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:30 | 927 | #: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:30 |
879 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:147 | 928 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:151 |
880 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:147 | 929 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:151 |
881 | msgid "Username" | 930 | msgid "Username" |
882 | msgstr "Nom d'utilisateur" | 931 | msgstr "Nom d'utilisateur" |
883 | 932 | ||
884 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48 | 933 | #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48 |
885 | #: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:34 | 934 | #: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:34 |
886 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:148 | 935 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:152 |
887 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:148 | 936 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:152 |
888 | msgid "Password" | 937 | msgid "Password" |
889 | msgstr "Mot de passe" | 938 | msgstr "Mot de passe" |
890 | 939 | ||
@@ -901,28 +950,28 @@ msgid "Install" | |||
901 | msgstr "Installer" | 950 | msgstr "Installer" |
902 | 951 | ||
903 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 | 952 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 |
904 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:80 | 953 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:79 |
905 | msgid "shaare" | 954 | msgid "shaare" |
906 | msgid_plural "shaares" | 955 | msgid_plural "shaares" |
907 | msgstr[0] "shaare" | 956 | msgstr[0] "shaare" |
908 | msgstr[1] "shaares" | 957 | msgstr[1] "shaares" |
909 | 958 | ||
910 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:18 | 959 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:18 |
911 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:84 | 960 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:83 |
912 | msgid "private link" | 961 | msgid "private link" |
913 | msgid_plural "private links" | 962 | msgid_plural "private links" |
914 | msgstr[0] "lien privé" | 963 | msgstr[0] "lien privé" |
915 | msgstr[1] "liens privés" | 964 | msgstr[1] "liens privés" |
916 | 965 | ||
917 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31 | 966 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:30 |
918 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:117 | 967 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:121 |
919 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:117 | 968 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:121 |
920 | msgid "Search text" | 969 | msgid "Search text" |
921 | msgstr "Recherche texte" | 970 | msgstr "Recherche texte" |
922 | 971 | ||
923 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:38 | 972 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:37 |
924 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:124 | 973 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:128 |
925 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:124 | 974 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:128 |
926 | #: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 | 975 | #: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 |
927 | #: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:64 | 976 | #: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:64 |
928 | #: tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 | 977 | #: tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 |
@@ -930,52 +979,52 @@ msgstr "Recherche texte" | |||
930 | msgid "Filter by tag" | 979 | msgid "Filter by tag" |
931 | msgstr "Filtrer par tag" | 980 | msgstr "Filtrer par tag" |
932 | 981 | ||
933 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:111 | 982 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:110 |
934 | msgid "Nothing found." | 983 | msgid "Nothing found." |
935 | msgstr "Aucun résultat." | 984 | msgstr "Aucun résultat." |
936 | 985 | ||
937 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:119 | 986 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:118 |
938 | #, php-format | 987 | #, php-format |
939 | msgid "%s result" | 988 | msgid "%s result" |
940 | msgid_plural "%s results" | 989 | msgid_plural "%s results" |
941 | msgstr[0] "%s résultat" | 990 | msgstr[0] "%s résultat" |
942 | msgstr[1] "%s résultats" | 991 | msgstr[1] "%s résultats" |
943 | 992 | ||
944 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:123 | 993 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:122 |
945 | msgid "for" | 994 | msgid "for" |
946 | msgstr "pour" | 995 | msgstr "pour" |
947 | 996 | ||
948 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:130 | 997 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:129 |
949 | msgid "tagged" | 998 | msgid "tagged" |
950 | msgstr "taggé" | 999 | msgstr "taggé" |
951 | 1000 | ||
952 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:134 | 1001 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:133 |
953 | msgid "Remove tag" | 1002 | msgid "Remove tag" |
954 | msgstr "Retirer le tag" | 1003 | msgstr "Retirer le tag" |
955 | 1004 | ||
956 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:143 | 1005 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:142 |
957 | msgid "with status" | 1006 | msgid "with status" |
958 | msgstr "avec le statut" | 1007 | msgstr "avec le statut" |
959 | 1008 | ||
960 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:154 | 1009 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:153 |
961 | msgid "without any tag" | 1010 | msgid "without any tag" |
962 | msgstr "sans tag" | 1011 | msgstr "sans tag" |
963 | 1012 | ||
964 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:174 | 1013 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:173 |
965 | #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 | 1014 | #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 |
966 | #: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:42 | 1015 | #: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:42 |
967 | msgid "Fold" | 1016 | msgid "Fold" |
968 | msgstr "Replier" | 1017 | msgstr "Replier" |
969 | 1018 | ||
970 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:176 | 1019 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:175 |
971 | msgid "Edited: " | 1020 | msgid "Edited: " |
972 | msgstr "Modifié : " | 1021 | msgstr "Modifié : " |
973 | 1022 | ||
974 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:180 | 1023 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:179 |
975 | msgid "permalink" | 1024 | msgid "permalink" |
976 | msgstr "permalien" | 1025 | msgstr "permalien" |
977 | 1026 | ||
978 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:182 | 1027 | #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:181 |
979 | msgid "Add tag" | 1028 | msgid "Add tag" |
980 | msgstr "Ajouter un tag" | 1029 | msgstr "Ajouter un tag" |
981 | 1030 | ||
@@ -1021,8 +1070,8 @@ msgstr "" | |||
1021 | "réessayer plus tard." | 1070 | "réessayer plus tard." |
1022 | 1071 | ||
1023 | #: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 | 1072 | #: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 |
1024 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:151 | 1073 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:155 |
1025 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:151 | 1074 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:155 |
1026 | msgid "Remember me" | 1075 | msgid "Remember me" |
1027 | msgstr "Rester connecté" | 1076 | msgstr "Rester connecté" |
1028 | 1077 | ||
@@ -1053,35 +1102,52 @@ msgstr "Déplier tout" | |||
1053 | msgid "Are you sure you want to delete this link?" | 1102 | msgid "Are you sure you want to delete this link?" |
1054 | msgstr "Êtes-vous sûr de vouloir supprimer ce lien ?" | 1103 | msgstr "Êtes-vous sûr de vouloir supprimer ce lien ?" |
1055 | 1104 | ||
1056 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:61 | 1105 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:65 |
1057 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:86 | 1106 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:90 |
1058 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:61 | 1107 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:65 |
1059 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:86 | 1108 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:90 |
1060 | msgid "RSS Feed" | 1109 | msgid "RSS Feed" |
1061 | msgstr "Flux RSS" | 1110 | msgstr "Flux RSS" |
1062 | 1111 | ||
1063 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:66 | 1112 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:70 |
1064 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:102 | 1113 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:106 |
1065 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:66 | 1114 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:70 |
1066 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:102 | 1115 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:106 |
1067 | msgid "Logout" | 1116 | msgid "Logout" |
1068 | msgstr "Déconnexion" | 1117 | msgstr "Déconnexion" |
1069 | 1118 | ||
1070 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:169 | 1119 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:173 |
1071 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:169 | 1120 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:173 |
1072 | msgid "is available" | 1121 | msgid "is available" |
1073 | msgstr "est disponible" | 1122 | msgstr "est disponible" |
1074 | 1123 | ||
1075 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:176 | 1124 | #: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:180 |
1076 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:176 | 1125 | #: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:180 |
1077 | msgid "Error" | 1126 | msgid "Error" |
1078 | msgstr "Erreur" | 1127 | msgstr "Erreur" |
1079 | 1128 | ||
1080 | #: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 | 1129 | #: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 |
1130 | msgid "Picture wall unavailable (thumbnails are disabled)." | ||
1131 | msgstr "" | ||
1132 | "Le mur d'images n'est pas disponible (les miniatures sont désactivées)." | ||
1133 | |||
1134 | #: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:24 | ||
1135 | #, fuzzy | ||
1136 | #| msgid "" | ||
1137 | #| "You don't have any cached thumbnail. Try to <a href=\"?do=thumbs_update" | ||
1138 | #| "\">synchronize them</a>." | ||
1139 | msgid "" | ||
1140 | "There is no cached thumbnail. Try to <a href=\"?do=thumbs_update" | ||
1141 | "\">synchronize them</a>." | ||
1142 | msgstr "" | ||
1143 | "Il n'y a aucune miniature en cache. Essayer de <a href=\"?do=thumbs_update" | ||
1144 | "\">les synchroniser</a>." | ||
1145 | |||
1146 | #: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 | ||
1081 | msgid "Picture Wall" | 1147 | msgid "Picture Wall" |
1082 | msgstr "Mur d'images" | 1148 | msgstr "Mur d'images" |
1083 | 1149 | ||
1084 | #: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 | 1150 | #: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 |
1085 | msgid "pics" | 1151 | msgid "pics" |
1086 | msgstr "images" | 1152 | msgstr "images" |
1087 | 1153 | ||
@@ -1223,7 +1289,11 @@ msgstr "" | |||
1223 | msgid "Export database" | 1289 | msgid "Export database" |
1224 | msgstr "Exporter les données" | 1290 | msgstr "Exporter les données" |
1225 | 1291 | ||
1226 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:71 | 1292 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:55 |
1293 | msgid "Synchronize all link thumbnails" | ||
1294 | msgstr "Synchroniser toutes les miniatures" | ||
1295 | |||
1296 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:81 | ||
1227 | msgid "" | 1297 | msgid "" |
1228 | "Drag one of these button to your bookmarks toolbar or right-click it and " | 1298 | "Drag one of these button to your bookmarks toolbar or right-click it and " |
1229 | "\"Bookmark This Link\"" | 1299 | "\"Bookmark This Link\"" |
@@ -1231,13 +1301,13 @@ msgstr "" | |||
1231 | "Glisser un de ces bouttons dans votre barre de favoris ou cliquer droit " | 1301 | "Glisser un de ces bouttons dans votre barre de favoris ou cliquer droit " |
1232 | "dessus et « Ajouter aux favoris »" | 1302 | "dessus et « Ajouter aux favoris »" |
1233 | 1303 | ||
1234 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:72 | 1304 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:82 |
1235 | msgid "then click on the bookmarklet in any page you want to share." | 1305 | msgid "then click on the bookmarklet in any page you want to share." |
1236 | msgstr "" | 1306 | msgstr "" |
1237 | "puis cliquer sur le marque page depuis un site que vous souhaitez partager." | 1307 | "puis cliquer sur le marque page depuis un site que vous souhaitez partager." |
1238 | 1308 | ||
1239 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:76 | 1309 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:86 |
1240 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:100 | 1310 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:110 |
1241 | msgid "" | 1311 | msgid "" |
1242 | "Drag this link to your bookmarks toolbar or right-click it and Bookmark This " | 1312 | "Drag this link to your bookmarks toolbar or right-click it and Bookmark This " |
1243 | "Link" | 1313 | "Link" |
@@ -1245,31 +1315,31 @@ msgstr "" | |||
1245 | "Glisser ce lien dans votre barre de favoris ou cliquer droit dessus et « " | 1315 | "Glisser ce lien dans votre barre de favoris ou cliquer droit dessus et « " |
1246 | "Ajouter aux favoris »" | 1316 | "Ajouter aux favoris »" |
1247 | 1317 | ||
1248 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:77 | 1318 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:87 |
1249 | msgid "then click ✚Shaare link button in any page you want to share" | 1319 | msgid "then click ✚Shaare link button in any page you want to share" |
1250 | msgstr "puis cliquer sur ✚Shaare depuis un site que vous souhaitez partager" | 1320 | msgstr "puis cliquer sur ✚Shaare depuis un site que vous souhaitez partager" |
1251 | 1321 | ||
1252 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:86 | 1322 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:96 |
1253 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:108 | 1323 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:118 |
1254 | msgid "The selected text is too long, it will be truncated." | 1324 | msgid "The selected text is too long, it will be truncated." |
1255 | msgstr "Le texte sélectionné est trop long, il sera tronqué." | 1325 | msgstr "Le texte sélectionné est trop long, il sera tronqué." |
1256 | 1326 | ||
1257 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:96 | 1327 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:106 |
1258 | msgid "Shaare link" | 1328 | msgid "Shaare link" |
1259 | msgstr "Shaare" | 1329 | msgstr "Shaare" |
1260 | 1330 | ||
1261 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:101 | 1331 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:111 |
1262 | msgid "" | 1332 | msgid "" |
1263 | "Then click ✚Add Note button anytime to start composing a private Note (text " | 1333 | "Then click ✚Add Note button anytime to start composing a private Note (text " |
1264 | "post) to your Shaarli" | 1334 | "post) to your Shaarli" |
1265 | msgstr "" | 1335 | msgstr "" |
1266 | "Puis cliquer sur ✚Add Note pour commencer à rédiger une Note sur Shaarli" | 1336 | "Puis cliquer sur ✚Add Note pour commencer à rédiger une Note sur Shaarli" |
1267 | 1337 | ||
1268 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:117 | 1338 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:127 |
1269 | msgid "Add Note" | 1339 | msgid "Add Note" |
1270 | msgstr "Ajouter une Note" | 1340 | msgstr "Ajouter une Note" |
1271 | 1341 | ||
1272 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:129 | 1342 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:139 |
1273 | msgid "" | 1343 | msgid "" |
1274 | "You need to browse your Shaarli over <strong>HTTPS</strong> to use this " | 1344 | "You need to browse your Shaarli over <strong>HTTPS</strong> to use this " |
1275 | "functionality." | 1345 | "functionality." |
@@ -1277,25 +1347,25 @@ msgstr "" | |||
1277 | "Vous devez utiliser Shaarli en <strong>HTTPS</strong> pour utiliser cette " | 1347 | "Vous devez utiliser Shaarli en <strong>HTTPS</strong> pour utiliser cette " |
1278 | "fonctionalité." | 1348 | "fonctionalité." |
1279 | 1349 | ||
1280 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:134 | 1350 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:144 |
1281 | msgid "Add to" | 1351 | msgid "Add to" |
1282 | msgstr "Ajouter à " | 1352 | msgstr "Ajouter à " |
1283 | 1353 | ||
1284 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:145 | 1354 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:155 |
1285 | msgid "3rd party" | 1355 | msgid "3rd party" |
1286 | msgstr "Applications tierces" | 1356 | msgstr "Applications tierces" |
1287 | 1357 | ||
1288 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:147 | 1358 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:157 |
1289 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:153 | 1359 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:163 |
1290 | msgid "Plugin" | 1360 | msgid "Plugin" |
1291 | msgstr "Extension" | 1361 | msgstr "Extension" |
1292 | 1362 | ||
1293 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:148 | 1363 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:158 |
1294 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:154 | 1364 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:164 |
1295 | msgid "plugin" | 1365 | msgid "plugin" |
1296 | msgstr "extension" | 1366 | msgstr "extension" |
1297 | 1367 | ||
1298 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:175 | 1368 | #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:191 |
1299 | msgid "" | 1369 | msgid "" |
1300 | "Drag this link to your bookmarks toolbar, or right-click it and choose " | 1370 | "Drag this link to your bookmarks toolbar, or right-click it and choose " |
1301 | "Bookmark This Link" | 1371 | "Bookmark This Link" |
@@ -1304,6 +1374,26 @@ msgstr "" | |||
1304 | "Ajouter aux favoris »" | 1374 | "Ajouter aux favoris »" |
1305 | 1375 | ||
1306 | #, fuzzy | 1376 | #, fuzzy |
1377 | #~| msgid "Enable thumbnails" | ||
1378 | #~ msgid "Synchonize thumbnails" | ||
1379 | #~ msgstr "Activer les miniatures" | ||
1380 | |||
1381 | #~ msgid "Warning: " | ||
1382 | #~ msgstr "Attention : " | ||
1383 | |||
1384 | #~ msgid "" | ||
1385 | #~ "It's recommended to visit the picture wall after enabling this feature." | ||
1386 | #~ msgstr "" | ||
1387 | #~ "Il est recommandé de visiter le Mur d'images après avoir activé cette " | ||
1388 | #~ "fonctionnalité." | ||
1389 | |||
1390 | #~ msgid "" | ||
1391 | #~ "If you have a large database, the first retrieval may take a few minutes." | ||
1392 | #~ msgstr "" | ||
1393 | #~ "Si vous avez beaucoup de liens, la première récupération peut prendre " | ||
1394 | #~ "plusieurs minutes." | ||
1395 | |||
1396 | #, fuzzy | ||
1307 | #~| msgid "Change" | 1397 | #~| msgid "Change" |
1308 | #~ msgid "range" | 1398 | #~ msgid "range" |
1309 | #~ msgstr "Changer" | 1399 | #~ msgstr "Changer" |
diff --git a/inc/web-thumbnailer.json b/inc/web-thumbnailer.json new file mode 100644 index 00000000..dcaa149e --- /dev/null +++ b/inc/web-thumbnailer.json | |||
@@ -0,0 +1,13 @@ | |||
1 | { | ||
2 | "settings": { | ||
3 | "default": { | ||
4 | "download_mode": "DOWNLOAD", | ||
5 | "_comment": "infinite cache", | ||
6 | "cache_duration": -1, | ||
7 | "timeout": 10 | ||
8 | }, | ||
9 | "path": { | ||
10 | "cache": "cache/" | ||
11 | } | ||
12 | } | ||
13 | } | ||
@@ -75,11 +75,12 @@ require_once 'application/Utils.php'; | |||
75 | require_once 'application/PluginManager.php'; | 75 | require_once 'application/PluginManager.php'; |
76 | require_once 'application/Router.php'; | 76 | require_once 'application/Router.php'; |
77 | require_once 'application/Updater.php'; | 77 | require_once 'application/Updater.php'; |
78 | use \Shaarli\Languages; | ||
79 | use \Shaarli\ThemeUtils; | ||
80 | use \Shaarli\Config\ConfigManager; | 78 | use \Shaarli\Config\ConfigManager; |
79 | use \Shaarli\Languages; | ||
81 | use \Shaarli\Security\LoginManager; | 80 | use \Shaarli\Security\LoginManager; |
82 | use \Shaarli\Security\SessionManager; | 81 | use \Shaarli\Security\SessionManager; |
82 | use \Shaarli\ThemeUtils; | ||
83 | use \Shaarli\Thumbnailer; | ||
83 | 84 | ||
84 | // Ensure the PHP version is supported | 85 | // Ensure the PHP version is supported |
85 | try { | 86 | try { |
@@ -513,7 +514,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, | |||
513 | read_updates_file($conf->get('resource.updates')), | 514 | read_updates_file($conf->get('resource.updates')), |
514 | $LINKSDB, | 515 | $LINKSDB, |
515 | $conf, | 516 | $conf, |
516 | $loginManager->isLoggedIn() | 517 | $loginManager->isLoggedIn(), |
518 | $_SESSION | ||
517 | ); | 519 | ); |
518 | try { | 520 | try { |
519 | $newUpdates = $updater->update(); | 521 | $newUpdates = $updater->update(); |
@@ -528,7 +530,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, | |||
528 | die($e->getMessage()); | 530 | die($e->getMessage()); |
529 | } | 531 | } |
530 | 532 | ||
531 | $PAGE = new PageBuilder($conf, $LINKSDB, $sessionManager->generateToken(), $loginManager->isLoggedIn()); | 533 | $PAGE = new PageBuilder($conf, $_SESSION, $LINKSDB, $sessionManager->generateToken(), $loginManager->isLoggedIn()); |
532 | $PAGE->assign('linkcount', count($LINKSDB)); | 534 | $PAGE->assign('linkcount', count($LINKSDB)); |
533 | $PAGE->assign('privateLinkcount', count_private($LINKSDB)); | 535 | $PAGE->assign('privateLinkcount', count_private($LINKSDB)); |
534 | $PAGE->assign('plugin_errors', $pluginManager->getErrors()); | 536 | $PAGE->assign('plugin_errors', $pluginManager->getErrors()); |
@@ -601,19 +603,23 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, | |||
601 | // -------- Picture wall | 603 | // -------- Picture wall |
602 | if ($targetPage == Router::$PAGE_PICWALL) | 604 | if ($targetPage == Router::$PAGE_PICWALL) |
603 | { | 605 | { |
606 | $PAGE->assign('pagetitle', t('Picture wall') .' - '. $conf->get('general.title', 'Shaarli')); | ||
607 | if (! $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) === Thumbnailer::MODE_NONE) { | ||
608 | $PAGE->assign('linksToDisplay', []); | ||
609 | $PAGE->renderPage('picwall'); | ||
610 | exit; | ||
611 | } | ||
612 | |||
604 | // Optionally filter the results: | 613 | // Optionally filter the results: |
605 | $links = $LINKSDB->filterSearch($_GET); | 614 | $links = $LINKSDB->filterSearch($_GET); |
606 | $linksToDisplay = array(); | 615 | $linksToDisplay = array(); |
607 | 616 | ||
608 | // Get only links which have a thumbnail. | 617 | // Get only links which have a thumbnail. |
609 | foreach($links as $link) | 618 | // Note: we do not retrieve thumbnails here, the request is too heavy. |
619 | foreach($links as $key => $link) | ||
610 | { | 620 | { |
611 | $permalink='?'.$link['shorturl']; | 621 | if (isset($link['thumbnail']) && $link['thumbnail'] !== false) { |
612 | $thumb=lazyThumbnail($conf, $link['url'],$permalink); | 622 | $linksToDisplay[] = $link; // Add to array. |
613 | if ($thumb!='') // Only output links which have a thumbnail. | ||
614 | { | ||
615 | $link['thumbnail']=$thumb; // Thumbnail HTML code. | ||
616 | $linksToDisplay[]=$link; // Add to array. | ||
617 | } | 623 | } |
618 | } | 624 | } |
619 | 625 | ||
@@ -626,7 +632,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, | |||
626 | $PAGE->assign($key, $value); | 632 | $PAGE->assign($key, $value); |
627 | } | 633 | } |
628 | 634 | ||
629 | $PAGE->assign('pagetitle', t('Picture wall') .' - '. $conf->get('general.title', 'Shaarli')); | 635 | |
630 | $PAGE->renderPage('picwall'); | 636 | $PAGE->renderPage('picwall'); |
631 | exit; | 637 | exit; |
632 | } | 638 | } |
@@ -1009,6 +1015,16 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, | |||
1009 | $conf->set('api.secret', escape($_POST['apiSecret'])); | 1015 | $conf->set('api.secret', escape($_POST['apiSecret'])); |
1010 | $conf->set('translation.language', escape($_POST['language'])); | 1016 | $conf->set('translation.language', escape($_POST['language'])); |
1011 | 1017 | ||
1018 | $thumbnailsMode = extension_loaded('gd') ? $_POST['enableThumbnails'] : Thumbnailer::MODE_NONE; | ||
1019 | if ($thumbnailsMode !== Thumbnailer::MODE_NONE | ||
1020 | && $thumbnailsMode !== $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) | ||
1021 | ) { | ||
1022 | $_SESSION['warnings'][] = t( | ||
1023 | 'You have enabled or changed thumbnails mode. <a href="?do=thumbs_update">Please synchronize them</a>.' | ||
1024 | ); | ||
1025 | } | ||
1026 | $conf->set('thumbnails.mode', $thumbnailsMode); | ||
1027 | |||
1012 | try { | 1028 | try { |
1013 | $conf->write($loginManager->isLoggedIn()); | 1029 | $conf->write($loginManager->isLoggedIn()); |
1014 | $history->updateSettings(); | 1030 | $history->updateSettings(); |
@@ -1047,6 +1063,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, | |||
1047 | $PAGE->assign('api_secret', $conf->get('api.secret')); | 1063 | $PAGE->assign('api_secret', $conf->get('api.secret')); |
1048 | $PAGE->assign('languages', Languages::getAvailableLanguages()); | 1064 | $PAGE->assign('languages', Languages::getAvailableLanguages()); |
1049 | $PAGE->assign('language', $conf->get('translation.language')); | 1065 | $PAGE->assign('language', $conf->get('translation.language')); |
1066 | $PAGE->assign('gd_enabled', extension_loaded('gd')); | ||
1067 | $PAGE->assign('thumbnails_mode', $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE)); | ||
1050 | $PAGE->assign('pagetitle', t('Configure') .' - '. $conf->get('general.title', 'Shaarli')); | 1068 | $PAGE->assign('pagetitle', t('Configure') .' - '. $conf->get('general.title', 'Shaarli')); |
1051 | $PAGE->renderPage('configure'); | 1069 | $PAGE->renderPage('configure'); |
1052 | exit; | 1070 | exit; |
@@ -1148,6 +1166,11 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, | |||
1148 | $link['title'] = $link['url']; | 1166 | $link['title'] = $link['url']; |
1149 | } | 1167 | } |
1150 | 1168 | ||
1169 | if ($conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE) { | ||
1170 | $thumbnailer = new Thumbnailer($conf); | ||
1171 | $link['thumbnail'] = $thumbnailer->get($url); | ||
1172 | } | ||
1173 | |||
1151 | $pluginManager->executeHooks('save_link', $link); | 1174 | $pluginManager->executeHooks('save_link', $link); |
1152 | 1175 | ||
1153 | $LINKSDB[$id] = $link; | 1176 | $LINKSDB[$id] = $link; |
@@ -1486,6 +1509,43 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, | |||
1486 | exit; | 1509 | exit; |
1487 | } | 1510 | } |
1488 | 1511 | ||
1512 | // -------- Thumbnails Update | ||
1513 | if ($targetPage == Router::$PAGE_THUMBS_UPDATE) { | ||
1514 | $ids = []; | ||
1515 | foreach ($LINKSDB as $link) { | ||
1516 | // A note or not HTTP(S) | ||
1517 | if ($link['url'][0] === '?' || ! startsWith(strtolower($link['url']), 'http')) { | ||
1518 | continue; | ||
1519 | } | ||
1520 | $ids[] = $link['id']; | ||
1521 | } | ||
1522 | $PAGE->assign('ids', $ids); | ||
1523 | $PAGE->assign('pagetitle', t('Thumbnails update') .' - '. $conf->get('general.title', 'Shaarli')); | ||
1524 | $PAGE->renderPage('thumbnails'); | ||
1525 | exit; | ||
1526 | } | ||
1527 | |||
1528 | // -------- Single Thumbnail Update | ||
1529 | if ($targetPage == Router::$AJAX_THUMB_UPDATE) { | ||
1530 | if (! isset($_POST['id']) || ! ctype_digit($_POST['id'])) { | ||
1531 | http_response_code(400); | ||
1532 | exit; | ||
1533 | } | ||
1534 | $id = (int) $_POST['id']; | ||
1535 | if (empty($LINKSDB[$id])) { | ||
1536 | http_response_code(404); | ||
1537 | exit; | ||
1538 | } | ||
1539 | $thumbnailer = new Thumbnailer($conf); | ||
1540 | $link = $LINKSDB[$id]; | ||
1541 | $link['thumbnail'] = $thumbnailer->get($link['url']); | ||
1542 | $LINKSDB[$id] = $link; | ||
1543 | $LINKSDB->save($conf->get('resource.page_cache')); | ||
1544 | |||
1545 | echo json_encode($link); | ||
1546 | exit; | ||
1547 | } | ||
1548 | |||
1489 | // -------- Otherwise, simply display search form and links: | 1549 | // -------- Otherwise, simply display search form and links: |
1490 | showLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager); | 1550 | showLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager); |
1491 | exit; | 1551 | exit; |
@@ -1549,6 +1609,12 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager) | |||
1549 | // Start index. | 1609 | // Start index. |
1550 | $i = ($page-1) * $_SESSION['LINKS_PER_PAGE']; | 1610 | $i = ($page-1) * $_SESSION['LINKS_PER_PAGE']; |
1551 | $end = $i + $_SESSION['LINKS_PER_PAGE']; | 1611 | $end = $i + $_SESSION['LINKS_PER_PAGE']; |
1612 | |||
1613 | $thumbnailsEnabled = $conf->get('thumbnails.mode', Thumbnailer::MODE_NONE) !== Thumbnailer::MODE_NONE; | ||
1614 | if ($thumbnailsEnabled) { | ||
1615 | $thumbnailer = new Thumbnailer($conf); | ||
1616 | } | ||
1617 | |||
1552 | $linkDisp = array(); | 1618 | $linkDisp = array(); |
1553 | while ($i<$end && $i<count($keys)) | 1619 | while ($i<$end && $i<count($keys)) |
1554 | { | 1620 | { |
@@ -1569,9 +1635,21 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager) | |||
1569 | $taglist = preg_split('/\s+/', $link['tags'], -1, PREG_SPLIT_NO_EMPTY); | 1635 | $taglist = preg_split('/\s+/', $link['tags'], -1, PREG_SPLIT_NO_EMPTY); |
1570 | uasort($taglist, 'strcasecmp'); | 1636 | uasort($taglist, 'strcasecmp'); |
1571 | $link['taglist'] = $taglist; | 1637 | $link['taglist'] = $taglist; |
1638 | |||
1639 | // Thumbnails enabled, not a note, | ||
1640 | // and (never retrieved yet or no valid cache file) | ||
1641 | if ($thumbnailsEnabled && $link['url'][0] != '?' | ||
1642 | && (! isset($link['thumbnail']) || ($link['thumbnail'] !== false && ! is_file($link['thumbnail']))) | ||
1643 | ) { | ||
1644 | $elem = $LINKSDB[$keys[$i]]; | ||
1645 | $elem['thumbnail'] = $thumbnailer->get($link['url']); | ||
1646 | $LINKSDB[$keys[$i]] = $elem; | ||
1647 | $updateDB = true; | ||
1648 | $link['thumbnail'] = $elem['thumbnail']; | ||
1649 | } | ||
1650 | |||
1572 | // Check for both signs of a note: starting with ? and 7 chars long. | 1651 | // Check for both signs of a note: starting with ? and 7 chars long. |
1573 | if ($link['url'][0] === '?' && | 1652 | if ($link['url'][0] === '?' && strlen($link['url']) === 7) { |
1574 | strlen($link['url']) === 7) { | ||
1575 | $link['url'] = index_url($_SERVER) . $link['url']; | 1653 | $link['url'] = index_url($_SERVER) . $link['url']; |
1576 | } | 1654 | } |
1577 | 1655 | ||
@@ -1579,6 +1657,11 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager) | |||
1579 | $i++; | 1657 | $i++; |
1580 | } | 1658 | } |
1581 | 1659 | ||
1660 | // If we retrieved new thumbnails, we update the database. | ||
1661 | if (!empty($updateDB)) { | ||
1662 | $LINKSDB->save($conf->get('resource.page_cache')); | ||
1663 | } | ||
1664 | |||
1582 | // Compute paging navigation | 1665 | // Compute paging navigation |
1583 | $searchtagsUrl = $searchtags === '' ? '' : '&searchtags=' . urlencode($searchtags); | 1666 | $searchtagsUrl = $searchtags === '' ? '' : '&searchtags=' . urlencode($searchtags); |
1584 | $searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm); | 1667 | $searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm); |
@@ -1630,194 +1713,6 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager) | |||
1630 | } | 1713 | } |
1631 | 1714 | ||
1632 | /** | 1715 | /** |
1633 | * Compute the thumbnail for a link. | ||
1634 | * | ||
1635 | * With a link to the original URL. | ||
1636 | * Understands various services (youtube.com...) | ||
1637 | * Input: $url = URL for which the thumbnail must be found. | ||
1638 | * $href = if provided, this URL will be followed instead of $url | ||
1639 | * Returns an associative array with thumbnail attributes (src,href,width,height,style,alt) | ||
1640 | * Some of them may be missing. | ||
1641 | * Return an empty array if no thumbnail available. | ||
1642 | * | ||
1643 | * @param ConfigManager $conf Configuration Manager instance. | ||
1644 | * @param string $url | ||
1645 | * @param string|bool $href | ||
1646 | * | ||
1647 | * @return array | ||
1648 | */ | ||
1649 | function computeThumbnail($conf, $url, $href = false) | ||
1650 | { | ||
1651 | if (!$conf->get('thumbnail.enable_thumbnails')) return array(); | ||
1652 | if ($href==false) $href=$url; | ||
1653 | |||
1654 | // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link. | ||
1655 | // (e.g. http://www.youtube.com/watch?v=spVypYk4kto ---> http://img.youtube.com/vi/spVypYk4kto/default.jpg ) | ||
1656 | // ^^^^^^^^^^^ ^^^^^^^^^^^ | ||
1657 | $domain = parse_url($url,PHP_URL_HOST); | ||
1658 | if ($domain=='youtube.com' || $domain=='www.youtube.com') | ||
1659 | { | ||
1660 | parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract video ID and get thumbnail | ||
1661 | if (!empty($params['v'])) return array('src'=>'https://img.youtube.com/vi/'.$params['v'].'/default.jpg', | ||
1662 | 'href'=>$href,'width'=>'120','height'=>'90','alt'=>'YouTube thumbnail'); | ||
1663 | } | ||
1664 | if ($domain=='youtu.be') // Youtube short links | ||
1665 | { | ||
1666 | $path = parse_url($url,PHP_URL_PATH); | ||
1667 | return array('src'=>'https://img.youtube.com/vi'.$path.'/default.jpg', | ||
1668 | 'href'=>$href,'width'=>'120','height'=>'90','alt'=>'YouTube thumbnail'); | ||
1669 | } | ||
1670 | if ($domain=='pix.toile-libre.org') // pix.toile-libre.org image hosting | ||
1671 | { | ||
1672 | parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract image filename. | ||
1673 | if (!empty($params) && !empty($params['img'])) return array('src'=>'http://pix.toile-libre.org/upload/thumb/'.urlencode($params['img']), | ||
1674 | 'href'=>$href,'style'=>'max-width:120px; max-height:150px','alt'=>'pix.toile-libre.org thumbnail'); | ||
1675 | } | ||
1676 | |||
1677 | if ($domain=='imgur.com') | ||
1678 | { | ||
1679 | $path = parse_url($url,PHP_URL_PATH); | ||
1680 | if (startsWith($path,'/a/')) return array(); // Thumbnails for albums are not available. | ||
1681 | if (startsWith($path,'/r/')) return array('src'=>'https://i.imgur.com/'.basename($path).'s.jpg', | ||
1682 | 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail'); | ||
1683 | if (startsWith($path,'/gallery/')) return array('src'=>'https://i.imgur.com'.substr($path,8).'s.jpg', | ||
1684 | 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail'); | ||
1685 | |||
1686 | if (substr_count($path,'/')==1) return array('src'=>'https://i.imgur.com/'.substr($path,1).'s.jpg', | ||
1687 | 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail'); | ||
1688 | } | ||
1689 | if ($domain=='i.imgur.com') | ||
1690 | { | ||
1691 | $pi = pathinfo(parse_url($url,PHP_URL_PATH)); | ||
1692 | if (!empty($pi['filename'])) return array('src'=>'https://i.imgur.com/'.$pi['filename'].'s.jpg', | ||
1693 | 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail'); | ||
1694 | } | ||
1695 | if ($domain=='dailymotion.com' || $domain=='www.dailymotion.com') | ||
1696 | { | ||
1697 | if (strpos($url,'dailymotion.com/video/')!==false) | ||
1698 | { | ||
1699 | $thumburl=str_replace('dailymotion.com/video/','dailymotion.com/thumbnail/video/',$url); | ||
1700 | return array('src'=>$thumburl, | ||
1701 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'DailyMotion thumbnail'); | ||
1702 | } | ||
1703 | } | ||
1704 | if (endsWith($domain,'.imageshack.us')) | ||
1705 | { | ||
1706 | $ext=strtolower(pathinfo($url,PATHINFO_EXTENSION)); | ||
1707 | if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') | ||
1708 | { | ||
1709 | $thumburl = substr($url,0,strlen($url)-strlen($ext)).'th.'.$ext; | ||
1710 | return array('src'=>$thumburl, | ||
1711 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'imageshack.us thumbnail'); | ||
1712 | } | ||
1713 | } | ||
1714 | |||
1715 | // Some other hosts are SLOW AS HELL and usually require an extra HTTP request to get the thumbnail URL. | ||
1716 | // So we deport the thumbnail generation in order not to slow down page generation | ||
1717 | // (and we also cache the thumbnail) | ||
1718 | |||
1719 | if (! $conf->get('thumbnail.enable_localcache')) return array(); // If local cache is disabled, no thumbnails for services which require the use a local cache. | ||
1720 | |||
1721 | if ($domain=='flickr.com' || endsWith($domain,'.flickr.com') | ||
1722 | || $domain=='vimeo.com' | ||
1723 | || $domain=='ted.com' || endsWith($domain,'.ted.com') | ||
1724 | || $domain=='xkcd.com' || endsWith($domain,'.xkcd.com') | ||
1725 | ) | ||
1726 | { | ||
1727 | if ($domain=='vimeo.com') | ||
1728 | { // Make sure this vimeo URL points to a video (/xxx... where xxx is numeric) | ||
1729 | $path = parse_url($url,PHP_URL_PATH); | ||
1730 | if (!preg_match('!/\d+.+?!',$path)) return array(); // This is not a single video URL. | ||
1731 | } | ||
1732 | if ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com')) | ||
1733 | { // Make sure this URL points to a single comic (/xxx... where xxx is numeric) | ||
1734 | $path = parse_url($url,PHP_URL_PATH); | ||
1735 | if (!preg_match('!/\d+.+?!',$path)) return array(); | ||
1736 | } | ||
1737 | if ($domain=='ted.com' || endsWith($domain,'.ted.com')) | ||
1738 | { // Make sure this TED URL points to a video (/talks/...) | ||
1739 | $path = parse_url($url,PHP_URL_PATH); | ||
1740 | if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL. | ||
1741 | } | ||
1742 | $sign = hash_hmac('sha256', $url, $conf->get('credentials.salt')); // We use the salt to sign data (it's random, secret, and specific to each installation) | ||
1743 | return array('src'=>index_url($_SERVER).'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url), | ||
1744 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); | ||
1745 | } | ||
1746 | |||
1747 | // For all other, we try to make a thumbnail of links ending with .jpg/jpeg/png/gif | ||
1748 | // Technically speaking, we should download ALL links and check their Content-Type to see if they are images. | ||
1749 | // But using the extension will do. | ||
1750 | $ext=strtolower(pathinfo($url,PATHINFO_EXTENSION)); | ||
1751 | if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') | ||
1752 | { | ||
1753 | $sign = hash_hmac('sha256', $url, $conf->get('credentials.salt')); // We use the salt to sign data (it's random, secret, and specific to each installation) | ||
1754 | return array('src'=>index_url($_SERVER).'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url), | ||
1755 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); | ||
1756 | } | ||
1757 | return array(); // No thumbnail. | ||
1758 | |||
1759 | } | ||
1760 | |||
1761 | |||
1762 | // Returns the HTML code to display a thumbnail for a link | ||
1763 | // with a link to the original URL. | ||
1764 | // Understands various services (youtube.com...) | ||
1765 | // Input: $url = URL for which the thumbnail must be found. | ||
1766 | // $href = if provided, this URL will be followed instead of $url | ||
1767 | // Returns '' if no thumbnail available. | ||
1768 | function thumbnail($url,$href=false) | ||
1769 | { | ||
1770 | // FIXME! | ||
1771 | global $conf; | ||
1772 | $t = computeThumbnail($conf, $url,$href); | ||
1773 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. | ||
1774 | |||
1775 | $html='<a href="'.escape($t['href']).'"><img src="'.escape($t['src']).'"'; | ||
1776 | if (!empty($t['width'])) $html.=' width="'.escape($t['width']).'"'; | ||
1777 | if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"'; | ||
1778 | if (!empty($t['style'])) $html.=' style="'.escape($t['style']).'"'; | ||
1779 | if (!empty($t['alt'])) $html.=' alt="'.escape($t['alt']).'"'; | ||
1780 | $html.='></a>'; | ||
1781 | return $html; | ||
1782 | } | ||
1783 | |||
1784 | // Returns the HTML code to display a thumbnail for a link | ||
1785 | // for the picture wall (using lazy image loading) | ||
1786 | // Understands various services (youtube.com...) | ||
1787 | // Input: $url = URL for which the thumbnail must be found. | ||
1788 | // $href = if provided, this URL will be followed instead of $url | ||
1789 | // Returns '' if no thumbnail available. | ||
1790 | function lazyThumbnail($conf, $url,$href=false) | ||
1791 | { | ||
1792 | // FIXME! | ||
1793 | global $conf; | ||
1794 | $t = computeThumbnail($conf, $url,$href); | ||
1795 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. | ||
1796 | |||
1797 | $html='<a href="'.escape($t['href']).'">'; | ||
1798 | |||
1799 | // Lazy image | ||
1800 | $html.='<img class="b-lazy" src="#" data-src="'.escape($t['src']).'"'; | ||
1801 | |||
1802 | if (!empty($t['width'])) $html.=' width="'.escape($t['width']).'"'; | ||
1803 | if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"'; | ||
1804 | if (!empty($t['style'])) $html.=' style="'.escape($t['style']).'"'; | ||
1805 | if (!empty($t['alt'])) $html.=' alt="'.escape($t['alt']).'"'; | ||
1806 | $html.='>'; | ||
1807 | |||
1808 | // No-JavaScript fallback. | ||
1809 | $html.='<noscript><img src="'.escape($t['src']).'"'; | ||
1810 | if (!empty($t['width'])) $html.=' width="'.escape($t['width']).'"'; | ||
1811 | if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"'; | ||
1812 | if (!empty($t['style'])) $html.=' style="'.escape($t['style']).'"'; | ||
1813 | if (!empty($t['alt'])) $html.=' alt="'.escape($t['alt']).'"'; | ||
1814 | $html.='></noscript></a>'; | ||
1815 | |||
1816 | return $html; | ||
1817 | } | ||
1818 | |||
1819 | |||
1820 | /** | ||
1821 | * Installation | 1716 | * Installation |
1822 | * This function should NEVER be called if the file data/config.php exists. | 1717 | * This function should NEVER be called if the file data/config.php exists. |
1823 | * | 1718 | * |
@@ -1908,7 +1803,7 @@ function install($conf, $sessionManager, $loginManager) { | |||
1908 | exit; | 1803 | exit; |
1909 | } | 1804 | } |
1910 | 1805 | ||
1911 | $PAGE = new PageBuilder($conf, null, $sessionManager->generateToken()); | 1806 | $PAGE = new PageBuilder($conf, $_SESSION, null, $sessionManager->generateToken()); |
1912 | list($continents, $cities) = generateTimeZoneData(timezone_identifiers_list(), date_default_timezone_get()); | 1807 | list($continents, $cities) = generateTimeZoneData(timezone_identifiers_list(), date_default_timezone_get()); |
1913 | $PAGE->assign('continents', $continents); | 1808 | $PAGE->assign('continents', $continents); |
1914 | $PAGE->assign('cities', $cities); | 1809 | $PAGE->assign('cities', $cities); |
@@ -1917,232 +1812,6 @@ function install($conf, $sessionManager, $loginManager) { | |||
1917 | exit; | 1812 | exit; |
1918 | } | 1813 | } |
1919 | 1814 | ||
1920 | /** | ||
1921 | * Because some f*cking services like flickr require an extra HTTP request to get the thumbnail URL, | ||
1922 | * I have deported the thumbnail URL code generation here, otherwise this would slow down page generation. | ||
1923 | * The following function takes the URL a link (e.g. a flickr page) and return the proper thumbnail. | ||
1924 | * This function is called by passing the URL: | ||
1925 | * http://mywebsite.com/shaarli/?do=genthumbnail&hmac=[HMAC]&url=[URL] | ||
1926 | * [URL] is the URL of the link (e.g. a flickr page) | ||
1927 | * [HMAC] is the signature for the [URL] (so that these URL cannot be forged). | ||
1928 | * The function below will fetch the image from the webservice and store it in the cache. | ||
1929 | * | ||
1930 | * @param ConfigManager $conf Configuration Manager instance, | ||
1931 | */ | ||
1932 | function genThumbnail($conf) | ||
1933 | { | ||
1934 | // Make sure the parameters in the URL were generated by us. | ||
1935 | $sign = hash_hmac('sha256', $_GET['url'], $conf->get('credentials.salt')); | ||
1936 | if ($sign!=$_GET['hmac']) die('Naughty boy!'); | ||
1937 | |||
1938 | $cacheDir = $conf->get('resource.thumbnails_cache', 'cache'); | ||
1939 | // Let's see if we don't already have the image for this URL in the cache. | ||
1940 | $thumbname=hash('sha1',$_GET['url']).'.jpg'; | ||
1941 | if (is_file($cacheDir .'/'. $thumbname)) | ||
1942 | { // We have the thumbnail, just serve it: | ||
1943 | header('Content-Type: image/jpeg'); | ||
1944 | echo file_get_contents($cacheDir .'/'. $thumbname); | ||
1945 | return; | ||
1946 | } | ||
1947 | // We may also serve a blank image (if service did not respond) | ||
1948 | $blankname=hash('sha1',$_GET['url']).'.gif'; | ||
1949 | if (is_file($cacheDir .'/'. $blankname)) | ||
1950 | { | ||
1951 | header('Content-Type: image/gif'); | ||
1952 | echo file_get_contents($cacheDir .'/'. $blankname); | ||
1953 | return; | ||
1954 | } | ||
1955 | |||
1956 | // Otherwise, generate the thumbnail. | ||
1957 | $url = $_GET['url']; | ||
1958 | $domain = parse_url($url,PHP_URL_HOST); | ||
1959 | |||
1960 | if ($domain=='flickr.com' || endsWith($domain,'.flickr.com')) | ||
1961 | { | ||
1962 | // Crude replacement to handle new flickr domain policy (They prefer www. now) | ||
1963 | $url = str_replace('http://flickr.com/','http://www.flickr.com/',$url); | ||
1964 | |||
1965 | // Is this a link to an image, or to a flickr page ? | ||
1966 | $imageurl=''; | ||
1967 | if (endsWith(parse_url($url, PHP_URL_PATH), '.jpg')) | ||
1968 | { // This is a direct link to an image. e.g. http://farm1.staticflickr.com/5/5921913_ac83ed27bd_o.jpg | ||
1969 | preg_match('!(http://farm\d+\.staticflickr\.com/\d+/\d+_\w+_)\w.jpg!',$url,$matches); | ||
1970 | if (!empty($matches[1])) $imageurl=$matches[1].'m.jpg'; | ||
1971 | } | ||
1972 | else // This is a flickr page (html) | ||
1973 | { | ||
1974 | // Get the flickr html page. | ||
1975 | list($headers, $content) = get_http_response($url, 20); | ||
1976 | if (strpos($headers[0], '200 OK') !== false) | ||
1977 | { | ||
1978 | // flickr now nicely provides the URL of the thumbnail in each flickr page. | ||
1979 | preg_match('!<link rel=\"image_src\" href=\"(.+?)\"!', $content, $matches); | ||
1980 | if (!empty($matches[1])) $imageurl=$matches[1]; | ||
1981 | |||
1982 | // In albums (and some other pages), the link rel="image_src" is not provided, | ||
1983 | // but flickr provides: | ||
1984 | // <meta property="og:image" content="http://farm4.staticflickr.com/3398/3239339068_25d13535ff_z.jpg" /> | ||
1985 | if ($imageurl=='') | ||
1986 | { | ||
1987 | preg_match('!<meta property=\"og:image\" content=\"(.+?)\"!', $content, $matches); | ||
1988 | if (!empty($matches[1])) $imageurl=$matches[1]; | ||
1989 | } | ||
1990 | } | ||
1991 | } | ||
1992 | |||
1993 | if ($imageurl!='') | ||
1994 | { // Let's download the image. | ||
1995 | // Image is 240x120, so 10 seconds to download should be enough. | ||
1996 | list($headers, $content) = get_http_response($imageurl, 10); | ||
1997 | if (strpos($headers[0], '200 OK') !== false) { | ||
1998 | // Save image to cache. | ||
1999 | file_put_contents($cacheDir .'/'. $thumbname, $content); | ||
2000 | header('Content-Type: image/jpeg'); | ||
2001 | echo $content; | ||
2002 | return; | ||
2003 | } | ||
2004 | } | ||
2005 | } | ||
2006 | |||
2007 | elseif ($domain=='vimeo.com' ) | ||
2008 | { | ||
2009 | // This is more complex: we have to perform a HTTP request, then parse the result. | ||
2010 | // Maybe we should deport this to JavaScript ? Example: http://stackoverflow.com/questions/1361149/get-img-thumbnails-from-vimeo/4285098#4285098 | ||
2011 | $vid = substr(parse_url($url,PHP_URL_PATH),1); | ||
2012 | list($headers, $content) = get_http_response('https://vimeo.com/api/v2/video/'.escape($vid).'.php', 5); | ||
2013 | if (strpos($headers[0], '200 OK') !== false) { | ||
2014 | $t = unserialize($content); | ||
2015 | $imageurl = $t[0]['thumbnail_medium']; | ||
2016 | // Then we download the image and serve it to our client. | ||
2017 | list($headers, $content) = get_http_response($imageurl, 10); | ||
2018 | if (strpos($headers[0], '200 OK') !== false) { | ||
2019 | // Save image to cache. | ||
2020 | file_put_contents($cacheDir .'/'. $thumbname, $content); | ||
2021 | header('Content-Type: image/jpeg'); | ||
2022 | echo $content; | ||
2023 | return; | ||
2024 | } | ||
2025 | } | ||
2026 | } | ||
2027 | |||
2028 | elseif ($domain=='ted.com' || endsWith($domain,'.ted.com')) | ||
2029 | { | ||
2030 | // The thumbnail for TED talks is located in the <link rel="image_src" [...]> tag on that page | ||
2031 | // http://www.ted.com/talks/mikko_hypponen_fighting_viruses_defending_the_net.html | ||
2032 | // <link rel="image_src" href="http://images.ted.com/images/ted/28bced335898ba54d4441809c5b1112ffaf36781_389x292.jpg" /> | ||
2033 | list($headers, $content) = get_http_response($url, 5); | ||
2034 | if (strpos($headers[0], '200 OK') !== false) { | ||
2035 | // Extract the link to the thumbnail | ||
2036 | preg_match('!link rel="image_src" href="(http://images.ted.com/images/ted/.+_\d+x\d+\.jpg)"!', $content, $matches); | ||
2037 | if (!empty($matches[1])) | ||
2038 | { // Let's download the image. | ||
2039 | $imageurl=$matches[1]; | ||
2040 | // No control on image size, so wait long enough | ||
2041 | list($headers, $content) = get_http_response($imageurl, 20); | ||
2042 | if (strpos($headers[0], '200 OK') !== false) { | ||
2043 | $filepath = $cacheDir .'/'. $thumbname; | ||
2044 | file_put_contents($filepath, $content); // Save image to cache. | ||
2045 | if (resizeImage($filepath)) | ||
2046 | { | ||
2047 | header('Content-Type: image/jpeg'); | ||
2048 | echo file_get_contents($filepath); | ||
2049 | return; | ||
2050 | } | ||
2051 | } | ||
2052 | } | ||
2053 | } | ||
2054 | } | ||
2055 | |||
2056 | elseif ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com')) | ||
2057 | { | ||
2058 | // There is no thumbnail available for xkcd comics, so download the whole image and resize it. | ||
2059 | // http://xkcd.com/327/ | ||
2060 | // <img src="http://imgs.xkcd.com/comics/exploits_of_a_mom.png" title="<BLABLA>" alt="<BLABLA>" /> | ||
2061 | list($headers, $content) = get_http_response($url, 5); | ||
2062 | if (strpos($headers[0], '200 OK') !== false) { | ||
2063 | // Extract the link to the thumbnail | ||
2064 | preg_match('!<img src="(http://imgs.xkcd.com/comics/.*)" title="[^s]!', $content, $matches); | ||
2065 | if (!empty($matches[1])) | ||
2066 | { // Let's download the image. | ||
2067 | $imageurl=$matches[1]; | ||
2068 | // No control on image size, so wait long enough | ||
2069 | list($headers, $content) = get_http_response($imageurl, 20); | ||
2070 | if (strpos($headers[0], '200 OK') !== false) { | ||
2071 | $filepath = $cacheDir.'/'.$thumbname; | ||
2072 | // Save image to cache. | ||
2073 | file_put_contents($filepath, $content); | ||
2074 | if (resizeImage($filepath)) | ||
2075 | { | ||
2076 | header('Content-Type: image/jpeg'); | ||
2077 | echo file_get_contents($filepath); | ||
2078 | return; | ||
2079 | } | ||
2080 | } | ||
2081 | } | ||
2082 | } | ||
2083 | } | ||
2084 | |||
2085 | else | ||
2086 | { | ||
2087 | // For all other domains, we try to download the image and make a thumbnail. | ||
2088 | // We allow 30 seconds max to download (and downloads are limited to 4 Mb) | ||
2089 | list($headers, $content) = get_http_response($url, 30); | ||
2090 | if (strpos($headers[0], '200 OK') !== false) { | ||
2091 | $filepath = $cacheDir .'/'.$thumbname; | ||
2092 | // Save image to cache. | ||
2093 | file_put_contents($filepath, $content); | ||
2094 | if (resizeImage($filepath)) | ||
2095 | { | ||
2096 | header('Content-Type: image/jpeg'); | ||
2097 | echo file_get_contents($filepath); | ||
2098 | return; | ||
2099 | } | ||
2100 | } | ||
2101 | } | ||
2102 | |||
2103 | |||
2104 | // Otherwise, return an empty image (8x8 transparent gif) | ||
2105 | $blankgif = base64_decode('R0lGODlhCAAIAIAAAP///////yH5BAEKAAEALAAAAAAIAAgAAAIHjI+py+1dAAA7'); | ||
2106 | // Also put something in cache so that this URL is not requested twice. | ||
2107 | file_put_contents($cacheDir .'/'. $blankname, $blankgif); | ||
2108 | header('Content-Type: image/gif'); | ||
2109 | echo $blankgif; | ||
2110 | } | ||
2111 | |||
2112 | // Make a thumbnail of the image (to width: 120 pixels) | ||
2113 | // Returns true if success, false otherwise. | ||
2114 | function resizeImage($filepath) | ||
2115 | { | ||
2116 | if (!function_exists('imagecreatefromjpeg')) return false; // GD not present: no thumbnail possible. | ||
2117 | |||
2118 | // Trick: some stupid people rename GIF as JPEG... or else. | ||
2119 | // So we really try to open each image type whatever the extension is. | ||
2120 | $header=file_get_contents($filepath,false,NULL,0,256); // Read first 256 bytes and try to sniff file type. | ||
2121 | $im=false; | ||
2122 | $i=strpos($header,'GIF8'); if (($i!==false) && ($i==0)) $im = imagecreatefromgif($filepath); // Well this is crude, but it should be enough. | ||
2123 | $i=strpos($header,'PNG'); if (($i!==false) && ($i==1)) $im = imagecreatefrompng($filepath); | ||
2124 | $i=strpos($header,'JFIF'); if ($i!==false) $im = imagecreatefromjpeg($filepath); | ||
2125 | if (!$im) return false; // Unable to open image (corrupted or not an image) | ||
2126 | $w = imagesx($im); | ||
2127 | $h = imagesy($im); | ||
2128 | $ystart = 0; $yheight=$h; | ||
2129 | if ($h>$w) { $ystart= ($h/2)-($w/2); $yheight=$w/2; } | ||
2130 | $nw = 120; // Desired width | ||
2131 | $nh = min(floor(($h*$nw)/$w),120); // Compute new width/height, but maximum 120 pixels height. | ||
2132 | // Resize image: | ||
2133 | $im2 = imagecreatetruecolor($nw,$nh); | ||
2134 | imagecopyresampled($im2, $im, 0, 0, 0, $ystart, $nw, $nh, $w, $yheight); | ||
2135 | imageinterlace($im2,true); // For progressive JPEG. | ||
2136 | $tempname=$filepath.'_TEMP.jpg'; | ||
2137 | imagejpeg($im2, $tempname, 90); | ||
2138 | imagedestroy($im); | ||
2139 | imagedestroy($im2); | ||
2140 | unlink($filepath); | ||
2141 | rename($tempname,$filepath); // Overwrite original picture with thumbnail. | ||
2142 | return true; | ||
2143 | } | ||
2144 | |||
2145 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=genthumbnail')) { genThumbnail($conf); exit; } // Thumbnail generation/cache does not need the link database. | ||
2146 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=dailyrss')) { showDailyRSS($conf); exit; } | 1815 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=dailyrss')) { showDailyRSS($conf); exit; } |
2147 | if (!isset($_SESSION['LINKS_PER_PAGE'])) { | 1816 | if (!isset($_SESSION['LINKS_PER_PAGE'])) { |
2148 | $_SESSION['LINKS_PER_PAGE'] = $conf->get('general.links_per_page', 20); | 1817 | $_SESSION['LINKS_PER_PAGE'] = $conf->get('general.links_per_page', 20); |
@@ -39,6 +39,7 @@ pages: | |||
39 | - Continuous integration tools: Continuous-integration-tools.md | 39 | - Continuous integration tools: Continuous-integration-tools.md |
40 | - GnuPG signature: GnuPG-signature.md | 40 | - GnuPG signature: GnuPG-signature.md |
41 | - Directory structure: Directory-structure.md | 41 | - Directory structure: Directory-structure.md |
42 | - Link Structure: Link-structure.md | ||
42 | - 3rd party libraries: 3rd-party-libraries.md | 43 | - 3rd party libraries: 3rd-party-libraries.md |
43 | - Plugin System: Plugin-System.md | 44 | - Plugin System: Plugin-System.md |
44 | - Release Shaarli: Release-Shaarli.md | 45 | - Release Shaarli: Release-Shaarli.md |
diff --git a/tests/ThumbnailerTest.php b/tests/ThumbnailerTest.php new file mode 100644 index 00000000..08311545 --- /dev/null +++ b/tests/ThumbnailerTest.php | |||
@@ -0,0 +1,114 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Shaarli; | ||
4 | |||
5 | use PHPUnit\Framework\TestCase; | ||
6 | use Shaarli\Config\ConfigManager; | ||
7 | use WebThumbnailer\Application\ConfigManager as WTConfigManager; | ||
8 | |||
9 | /** | ||
10 | * Class ThumbnailerTest | ||
11 | * | ||
12 | * We only make 1 thumb test because: | ||
13 | * | ||
14 | * 1. the thumbnailer library is itself tested | ||
15 | * 2. we don't want to make too many external requests during the tests | ||
16 | */ | ||
17 | class ThumbnailerTest extends TestCase | ||
18 | { | ||
19 | const WIDTH = 190; | ||
20 | |||
21 | const HEIGHT = 210; | ||
22 | |||
23 | /** | ||
24 | * @var Thumbnailer; | ||
25 | */ | ||
26 | protected $thumbnailer; | ||
27 | |||
28 | /** | ||
29 | * @var ConfigManager | ||
30 | */ | ||
31 | protected $conf; | ||
32 | |||
33 | public function setUp() | ||
34 | { | ||
35 | $this->conf = new ConfigManager('tests/utils/config/configJson'); | ||
36 | $this->conf->set('thumbnails.mode', Thumbnailer::MODE_ALL); | ||
37 | $this->conf->set('thumbnails.width', self::WIDTH); | ||
38 | $this->conf->set('thumbnails.height', self::HEIGHT); | ||
39 | $this->conf->set('dev.debug', true); | ||
40 | |||
41 | $this->thumbnailer = new Thumbnailer($this->conf); | ||
42 | // cache files in the sandbox | ||
43 | WTConfigManager::addFile('tests/utils/config/wt.json'); | ||
44 | } | ||
45 | |||
46 | public function tearDown() | ||
47 | { | ||
48 | $this->rrmdirContent('sandbox/'); | ||
49 | } | ||
50 | |||
51 | /** | ||
52 | * Test a thumbnail with a custom size in 'all' mode. | ||
53 | */ | ||
54 | public function testThumbnailAllValid() | ||
55 | { | ||
56 | $thumb = $this->thumbnailer->get('https://github.com/shaarli/Shaarli/'); | ||
57 | $this->assertNotFalse($thumb); | ||
58 | $image = imagecreatefromstring(file_get_contents($thumb)); | ||
59 | $this->assertEquals(self::WIDTH, imagesx($image)); | ||
60 | $this->assertEquals(self::HEIGHT, imagesy($image)); | ||
61 | } | ||
62 | |||
63 | /** | ||
64 | * Test a thumbnail with a custom size in 'common' mode. | ||
65 | */ | ||
66 | public function testThumbnailCommonValid() | ||
67 | { | ||
68 | $this->conf->set('thumbnails.mode', Thumbnailer::MODE_COMMON); | ||
69 | $thumb = $this->thumbnailer->get('https://imgur.com/jlFgGpe'); | ||
70 | $this->assertNotFalse($thumb); | ||
71 | $image = imagecreatefromstring(file_get_contents($thumb)); | ||
72 | $this->assertEquals(self::WIDTH, imagesx($image)); | ||
73 | $this->assertEquals(self::HEIGHT, imagesy($image)); | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * Test a thumbnail in 'common' mode which isn't include in common websites. | ||
78 | */ | ||
79 | public function testThumbnailCommonInvalid() | ||
80 | { | ||
81 | $this->conf->set('thumbnails.mode', Thumbnailer::MODE_COMMON); | ||
82 | $thumb = $this->thumbnailer->get('https://github.com/shaarli/Shaarli/'); | ||
83 | $this->assertFalse($thumb); | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * Test a thumbnail that can't be retrieved. | ||
88 | */ | ||
89 | public function testThumbnailNotValid() | ||
90 | { | ||
91 | $oldlog = ini_get('error_log'); | ||
92 | ini_set('error_log', '/dev/null'); | ||
93 | |||
94 | $thumbnailer = new Thumbnailer(new ConfigManager()); | ||
95 | $thumb = $thumbnailer->get('nope'); | ||
96 | $this->assertFalse($thumb); | ||
97 | |||
98 | ini_set('error_log', $oldlog); | ||
99 | } | ||
100 | |||
101 | protected function rrmdirContent($dir) { | ||
102 | if (is_dir($dir)) { | ||
103 | $objects = scandir($dir); | ||
104 | foreach ($objects as $object) { | ||
105 | if ($object != "." && $object != "..") { | ||
106 | if (is_dir($dir."/".$object)) | ||
107 | $this->rrmdirContent($dir."/".$object); | ||
108 | else | ||
109 | unlink($dir."/".$object); | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | } | ||
diff --git a/tests/Updater/UpdaterTest.php b/tests/Updater/UpdaterTest.php index 94e3c7d3..cacee2d2 100644 --- a/tests/Updater/UpdaterTest.php +++ b/tests/Updater/UpdaterTest.php | |||
@@ -2,6 +2,7 @@ | |||
2 | use Shaarli\Config\ConfigJson; | 2 | use Shaarli\Config\ConfigJson; |
3 | use Shaarli\Config\ConfigManager; | 3 | use Shaarli\Config\ConfigManager; |
4 | use Shaarli\Config\ConfigPhp; | 4 | use Shaarli\Config\ConfigPhp; |
5 | use Shaarli\Thumbnailer; | ||
5 | 6 | ||
6 | require_once 'tests/Updater/DummyUpdater.php'; | 7 | require_once 'tests/Updater/DummyUpdater.php'; |
7 | require_once 'inc/rain.tpl.class.php'; | 8 | require_once 'inc/rain.tpl.class.php'; |
@@ -20,7 +21,7 @@ class UpdaterTest extends PHPUnit_Framework_TestCase | |||
20 | /** | 21 | /** |
21 | * @var string Config file path (without extension). | 22 | * @var string Config file path (without extension). |
22 | */ | 23 | */ |
23 | protected static $configFile = 'tests/utils/config/configJson'; | 24 | protected static $configFile = 'sandbox/config'; |
24 | 25 | ||
25 | /** | 26 | /** |
26 | * @var ConfigManager | 27 | * @var ConfigManager |
@@ -32,6 +33,7 @@ class UpdaterTest extends PHPUnit_Framework_TestCase | |||
32 | */ | 33 | */ |
33 | public function setUp() | 34 | public function setUp() |
34 | { | 35 | { |
36 | copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php'); | ||
35 | $this->conf = new ConfigManager(self::$configFile); | 37 | $this->conf = new ConfigManager(self::$configFile); |
36 | } | 38 | } |
37 | 39 | ||
@@ -684,4 +686,50 @@ $GLOBALS[\'privateLinkByDefault\'] = true;'; | |||
684 | $this->assertEquals(4194304, $this->conf->get('general.download_max_size')); | 686 | $this->assertEquals(4194304, $this->conf->get('general.download_max_size')); |
685 | $this->assertEquals(3, $this->conf->get('general.download_timeout')); | 687 | $this->assertEquals(3, $this->conf->get('general.download_timeout')); |
686 | } | 688 | } |
689 | |||
690 | /** | ||
691 | * Test updateMethodWebThumbnailer with thumbnails enabled. | ||
692 | */ | ||
693 | public function testUpdateMethodWebThumbnailerEnabled() | ||
694 | { | ||
695 | $this->conf->remove('thumbnails'); | ||
696 | $this->conf->set('thumbnail.enable_thumbnails', true); | ||
697 | $updater = new Updater([], [], $this->conf, true, $_SESSION); | ||
698 | $this->assertTrue($updater->updateMethodWebThumbnailer()); | ||
699 | $this->assertFalse($this->conf->exists('thumbnail')); | ||
700 | $this->assertEquals(\Shaarli\Thumbnailer::MODE_ALL, $this->conf->get('thumbnails.mode')); | ||
701 | $this->assertEquals(125, $this->conf->get('thumbnails.width')); | ||
702 | $this->assertEquals(90, $this->conf->get('thumbnails.height')); | ||
703 | $this->assertContains('You have enabled or changed thumbnails', $_SESSION['warnings'][0]); | ||
704 | } | ||
705 | |||
706 | /** | ||
707 | * Test updateMethodWebThumbnailer with thumbnails disabled. | ||
708 | */ | ||
709 | public function testUpdateMethodWebThumbnailerDisabled() | ||
710 | { | ||
711 | $this->conf->remove('thumbnails'); | ||
712 | $this->conf->set('thumbnail.enable_thumbnails', false); | ||
713 | $updater = new Updater([], [], $this->conf, true, $_SESSION); | ||
714 | $this->assertTrue($updater->updateMethodWebThumbnailer()); | ||
715 | $this->assertFalse($this->conf->exists('thumbnail')); | ||
716 | $this->assertEquals(Thumbnailer::MODE_NONE, $this->conf->get('thumbnails.mode')); | ||
717 | $this->assertEquals(125, $this->conf->get('thumbnails.width')); | ||
718 | $this->assertEquals(90, $this->conf->get('thumbnails.height')); | ||
719 | $this->assertTrue(empty($_SESSION['warnings'])); | ||
720 | } | ||
721 | |||
722 | /** | ||
723 | * Test updateMethodWebThumbnailer with thumbnails disabled. | ||
724 | */ | ||
725 | public function testUpdateMethodWebThumbnailerNothingToDo() | ||
726 | { | ||
727 | $updater = new Updater([], [], $this->conf, true, $_SESSION); | ||
728 | $this->assertTrue($updater->updateMethodWebThumbnailer()); | ||
729 | $this->assertFalse($this->conf->exists('thumbnail')); | ||
730 | $this->assertEquals(Thumbnailer::MODE_COMMON, $this->conf->get('thumbnails.mode')); | ||
731 | $this->assertEquals(90, $this->conf->get('thumbnails.width')); | ||
732 | $this->assertEquals(53, $this->conf->get('thumbnails.height')); | ||
733 | $this->assertTrue(empty($_SESSION['warnings'])); | ||
734 | } | ||
687 | } | 735 | } |
diff --git a/tests/config/ConfigManagerTest.php b/tests/config/ConfigManagerTest.php index 1ec447b2..4a4e94ac 100644 --- a/tests/config/ConfigManagerTest.php +++ b/tests/config/ConfigManagerTest.php | |||
@@ -81,6 +81,18 @@ class ConfigManagerTest extends \PHPUnit_Framework_TestCase | |||
81 | $this->assertEquals('testSetWriteGetNested', $this->conf->get('foo.bar.key.stuff')); | 81 | $this->assertEquals('testSetWriteGetNested', $this->conf->get('foo.bar.key.stuff')); |
82 | } | 82 | } |
83 | 83 | ||
84 | public function testSetDeleteNested() | ||
85 | { | ||
86 | $this->conf->set('foo.bar.key.stuff', 'testSetDeleteNested'); | ||
87 | $this->assertTrue($this->conf->exists('foo.bar')); | ||
88 | $this->assertTrue($this->conf->exists('foo.bar.key.stuff')); | ||
89 | $this->assertEquals('testSetDeleteNested', $this->conf->get('foo.bar.key.stuff')); | ||
90 | |||
91 | $this->conf->remove('foo.bar'); | ||
92 | $this->assertFalse($this->conf->exists('foo.bar.key.stuff')); | ||
93 | $this->assertFalse($this->conf->exists('foo.bar')); | ||
94 | } | ||
95 | |||
84 | /** | 96 | /** |
85 | * Set with an empty key. | 97 | * Set with an empty key. |
86 | * | 98 | * |
@@ -104,6 +116,17 @@ class ConfigManagerTest extends \PHPUnit_Framework_TestCase | |||
104 | } | 116 | } |
105 | 117 | ||
106 | /** | 118 | /** |
119 | * Remove with an empty key. | ||
120 | * | ||
121 | * @expectedException \Exception | ||
122 | * @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*# | ||
123 | */ | ||
124 | public function testRmoveEmptyKey() | ||
125 | { | ||
126 | $this->conf->remove(''); | ||
127 | } | ||
128 | |||
129 | /** | ||
107 | * Try to write the config without mandatory parameter (e.g. 'login'). | 130 | * Try to write the config without mandatory parameter (e.g. 'login'). |
108 | * | 131 | * |
109 | * @expectedException Shaarli\Config\Exception\MissingFieldConfigException | 132 | * @expectedException Shaarli\Config\Exception\MissingFieldConfigException |
diff --git a/tests/utils/config/configJson.json.php b/tests/utils/config/configJson.json.php index 9c9288f3..1549ddfc 100644 --- a/tests/utils/config/configJson.json.php +++ b/tests/utils/config/configJson.json.php | |||
@@ -1,35 +1,84 @@ | |||
1 | <?php /* | 1 | <?php /* |
2 | { | 2 | { |
3 | "credentials": { | 3 | "credentials": { |
4 | "login":"root", | 4 | "login": "root", |
5 | "hash":"hash", | 5 | "hash": "hash", |
6 | "salt":"salt" | 6 | "salt": "salt" |
7 | }, | 7 | }, |
8 | "security": { | 8 | "security": { |
9 | "session_protection_disabled":false | 9 | "session_protection_disabled": false, |
10 | "ban_after": 4, | ||
11 | "ban_duration": 1800, | ||
12 | "open_shaarli": false, | ||
13 | "allowed_protocols": [ | ||
14 | "ftp", | ||
15 | "ftps", | ||
16 | "magnet" | ||
17 | ] | ||
10 | }, | 18 | }, |
11 | "general": { | 19 | "general": { |
12 | "timezone":"Europe\/Paris", | 20 | "timezone": "Europe\/Paris", |
13 | "title": "Shaarli", | 21 | "title": "Shaarli", |
14 | "header_link": "?" | 22 | "header_link": "?", |
23 | "links_per_page": 20, | ||
24 | "enabled_plugins": [ | ||
25 | "qrcode" | ||
26 | ], | ||
27 | "default_note_title": "Note: " | ||
15 | }, | 28 | }, |
16 | "privacy": { | 29 | "privacy": { |
17 | "default_private_links":true | 30 | "default_private_links": true, |
31 | "hide_public_links": false, | ||
32 | "force_login": false, | ||
33 | "hide_timestamps": false, | ||
34 | "remember_user_default": true | ||
18 | }, | 35 | }, |
19 | "redirector": { | 36 | "redirector": { |
20 | "url":"lala" | 37 | "url": "lala", |
38 | "encode_url": true | ||
21 | }, | 39 | }, |
22 | "config": { | 40 | "config": { |
23 | "foo": "bar" | 41 | "foo": "bar" |
24 | }, | 42 | }, |
25 | "resource": { | 43 | "resource": { |
26 | "datastore": "tests\/utils\/config\/datastore.php", | 44 | "datastore": "tests\/utils\/config\/datastore.php", |
27 | "data_dir": "sandbox/", | 45 | "data_dir": "sandbox\/", |
28 | "raintpl_tpl": "tpl/" | 46 | "raintpl_tpl": "tpl\/", |
47 | "config": "data\/config.php", | ||
48 | "ban_file": "data\/ipbans.php", | ||
49 | "updates": "data\/updates.txt", | ||
50 | "log": "data\/log.txt", | ||
51 | "update_check": "data\/lastupdatecheck.txt", | ||
52 | "history": "data\/history.php", | ||
53 | "theme": "default", | ||
54 | "raintpl_tmp": "tmp\/", | ||
55 | "thumbnails_cache": "cache", | ||
56 | "page_cache": "pagecache" | ||
29 | }, | 57 | }, |
30 | "plugins": { | 58 | "plugins": { |
31 | "WALLABAG_VERSION": 1 | 59 | "WALLABAG_VERSION": 1 |
60 | }, | ||
61 | "dev": { | ||
62 | "debug": true | ||
63 | }, | ||
64 | "updates": { | ||
65 | "check_updates": false, | ||
66 | "check_updates_branch": "stable", | ||
67 | "check_updates_interval": 86400 | ||
68 | }, | ||
69 | "feed": { | ||
70 | "rss_permalinks": true, | ||
71 | "show_atom": true | ||
72 | }, | ||
73 | "translation": { | ||
74 | "language": "auto", | ||
75 | "mode": "php", | ||
76 | "extensions": [] | ||
77 | }, | ||
78 | "thumbnails": { | ||
79 | "mode": "common", | ||
80 | "width": 90, | ||
81 | "height": 53 | ||
32 | } | 82 | } |
33 | } | 83 | } |
34 | */ ?> | 84 | */ ?> |
35 | |||
diff --git a/tests/utils/config/wt.json b/tests/utils/config/wt.json new file mode 100644 index 00000000..69ce49a6 --- /dev/null +++ b/tests/utils/config/wt.json | |||
@@ -0,0 +1,12 @@ | |||
1 | { | ||
2 | "settings": { | ||
3 | "default": { | ||
4 | "_comment": "infinite cache", | ||
5 | "cache_duration": -1, | ||
6 | "timeout": 10 | ||
7 | }, | ||
8 | "path": { | ||
9 | "cache": "sandbox/" | ||
10 | } | ||
11 | } | ||
12 | } \ No newline at end of file | ||
diff --git a/tpl/default/configure.html b/tpl/default/configure.html index a63c7ad3..42e32230 100644 --- a/tpl/default/configure.html +++ b/tpl/default/configure.html | |||
@@ -242,6 +242,37 @@ | |||
242 | </div> | 242 | </div> |
243 | </div> | 243 | </div> |
244 | </div> | 244 | </div> |
245 | <div class="pure-g"> | ||
246 | <div class="pure-u-lg-{$ratioLabel} pure-u-{$ratioLabelMobile}"> | ||
247 | <div class="form-label"> | ||
248 | <label for="enableThumbnails"> | ||
249 | <span class="label-name">{'Enable thumbnails'|t}</span><br> | ||
250 | <span class="label-desc"> | ||
251 | {if="! $gd_enabled"} | ||
252 | {'You need to enable the extension <code>php-gd</code> to use thumbnails.'|t} | ||
253 | {elseif="$thumbnails_enabled"} | ||
254 | <a href="?do=thumbs_update">{'Synchronize thumbnails'|t}</a> | ||
255 | {/if} | ||
256 | </span> | ||
257 | </label> | ||
258 | </div> | ||
259 | </div> | ||
260 | <div class="pure-u-lg-{$ratioInput} pure-u-{$ratioInputMobile}"> | ||
261 | <div class="form-input"> | ||
262 | <select name="enableThumbnails" id="enableThumbnails" class="align"> | ||
263 | <option value="all" {if="$thumbnails_mode=='all'"}selected{/if}> | ||
264 | {'All'|t} | ||
265 | </option> | ||
266 | <option value="common" {if="$thumbnails_mode=='common'"}selected{/if}> | ||
267 | {'Only common media hosts'|t} | ||
268 | </option> | ||
269 | <option value="none" {if="$thumbnails_mode=='none'"}selected{/if}> | ||
270 | {'None'|t} | ||
271 | </option> | ||
272 | </select> | ||
273 | </div> | ||
274 | </div> | ||
275 | </div> | ||
245 | <div class="center"> | 276 | <div class="center"> |
246 | <input type="submit" value="{'Save'|t}" name="save"> | 277 | <input type="submit" value="{'Save'|t}" name="save"> |
247 | </div> | 278 | </div> |
diff --git a/tpl/default/linklist.html b/tpl/default/linklist.html index 322cddd5..8ea2ce66 100644 --- a/tpl/default/linklist.html +++ b/tpl/default/linklist.html | |||
@@ -131,9 +131,17 @@ | |||
131 | 131 | ||
132 | <div class="linklist-item linklist-item{if="$value.class"} {$value.class}{/if}" data-id="{$value.id}"> | 132 | <div class="linklist-item linklist-item{if="$value.class"} {$value.class}{/if}" data-id="{$value.id}"> |
133 | <div class="linklist-item-title"> | 133 | <div class="linklist-item-title"> |
134 | {$thumb=thumbnail($value.url)} | 134 | {if="$thumbnails_enabled && !empty($value.thumbnail)"} |
135 | {if="$thumb!=false"} | 135 | <div class="linklist-item-thumbnail" style="width:{$thumbnails_width}px;height:{$thumbnails_height}px;"> |
136 | <div class="linklist-item-thumbnail">{$thumb}</div> | 136 | <div class="thumbnail"> |
137 | <a href="{$value.real_url}"> | ||
138 | {ignore}RainTPL hack: put the 2 src on two different line to avoid path replace bug{/ignore} | ||
139 | <img data-src="{$value.thumbnail}#" class="b-lazy" | ||
140 | src="#" | ||
141 | alt="thumbnail" width="{$thumbnails_width}" height="{$thumbnails_height}" /> | ||
142 | </a> | ||
143 | </div> | ||
144 | </div> | ||
137 | {/if} | 145 | {/if} |
138 | 146 | ||
139 | {if="$is_logged_in"} | 147 | {if="$is_logged_in"} |
@@ -268,5 +276,6 @@ | |||
268 | </div> | 276 | </div> |
269 | 277 | ||
270 | {include="page.footer"} | 278 | {include="page.footer"} |
279 | <script src="js/thumbnails.min.js?v={$version_hash}"></script> | ||
271 | </body> | 280 | </body> |
272 | </html> | 281 | </html> |
diff --git a/tpl/default/page.header.html b/tpl/default/page.header.html index 82568d63..fc03404e 100644 --- a/tpl/default/page.header.html +++ b/tpl/default/page.header.html | |||
@@ -30,9 +30,11 @@ | |||
30 | <li class="pure-menu-item" id="shaarli-menu-tags"> | 30 | <li class="pure-menu-item" id="shaarli-menu-tags"> |
31 | <a href="?do=tagcloud" class="pure-menu-link">{'Tag cloud'|t}</a> | 31 | <a href="?do=tagcloud" class="pure-menu-link">{'Tag cloud'|t}</a> |
32 | </li> | 32 | </li> |
33 | <li class="pure-menu-item" id="shaarli-menu-picwall"> | 33 | {if="$thumbnails_enabled"} |
34 | <a href="?do=picwall{$searchcrits}" class="pure-menu-link">{'Picture wall'|t}</a> | 34 | <li class="pure-menu-item" id="shaarli-menu-picwall"> |
35 | </li> | 35 | <a href="?do=picwall{$searchcrits}" class="pure-menu-link">{'Picture wall'|t}</a> |
36 | </li> | ||
37 | {/if} | ||
36 | <li class="pure-menu-item" id="shaarli-menu-daily"> | 38 | <li class="pure-menu-item" id="shaarli-menu-daily"> |
37 | <a href="?do=daily" class="pure-menu-link">{'Daily'|t}</a> | 39 | <a href="?do=daily" class="pure-menu-link">{'Daily'|t}</a> |
38 | </li> | 40 | </li> |
@@ -169,4 +171,18 @@ | |||
169 | </div> | 171 | </div> |
170 | {/if} | 172 | {/if} |
171 | 173 | ||
174 | {if="!empty($global_warnings) && $is_logged_in"} | ||
175 | <div class="pure-g pure-alert pure-alert-warning pure-alert-closable" id="shaarli-warnings-alert"> | ||
176 | <div class="pure-u-2-24"></div> | ||
177 | <div class="pure-u-20-24"> | ||
178 | {loop="global_warnings"} | ||
179 | <p>{$value}</p> | ||
180 | {/loop} | ||
181 | </div> | ||
182 | <div class="pure-u-2-24"> | ||
183 | <i class="fa fa-times pure-alert-close"></i> | ||
184 | </div> | ||
185 | </div> | ||
186 | {/if} | ||
187 | |||
172 | <div class="clear"></div> | 188 | <div class="clear"></div> |
diff --git a/tpl/default/picwall.html b/tpl/default/picwall.html index 2f7e03dc..9a0b10dc 100644 --- a/tpl/default/picwall.html +++ b/tpl/default/picwall.html | |||
@@ -5,41 +5,61 @@ | |||
5 | </head> | 5 | </head> |
6 | <body> | 6 | <body> |
7 | {include="page.header"} | 7 | {include="page.header"} |
8 | {if="!$thumbnails_enabled"} | ||
9 | <div class="pure-g pure-alert pure-alert-warning page-single-alert"> | ||
10 | <div class="pure-u-1 center"> | ||
11 | {'Picture wall unavailable (thumbnails are disabled).'|t} | ||
12 | </div> | ||
13 | </div> | ||
14 | {else} | ||
15 | {if="count($linksToDisplay)===0 && $is_logged_in"} | ||
16 | <div class="pure-g pure-alert pure-alert-warning page-single-alert"> | ||
17 | <div class="pure-u-1 center"> | ||
18 | {'There is no cached thumbnail. Try to <a href="?do=thumbs_update">synchronize them</a>.'|t} | ||
19 | </div> | ||
20 | </div> | ||
21 | {/if} | ||
8 | 22 | ||
9 | <div class="pure-g"> | 23 | <div class="pure-g"> |
10 | <div class="pure-u-lg-1-6 pure-u-1-24"></div> | 24 | <div class="pure-u-lg-1-6 pure-u-1-24"></div> |
11 | <div class="pure-u-lg-2-3 pure-u-22-24 page-form page-visitor"> | 25 | <div class="pure-u-lg-2-3 pure-u-22-24 page-form page-visitor"> |
12 | {$countPics=count($linksToDisplay)} | 26 | {$countPics=count($linksToDisplay)} |
13 | <h2 class="window-title">{'Picture Wall'|t} - {$countPics} {'pics'|t}</h2> | 27 | <h2 class="window-title">{'Picture Wall'|t} - {$countPics} {'pics'|t}</h2> |
14 | 28 | ||
15 | <div id="plugin_zone_start_picwall" class="plugin_zone"> | 29 | <div id="plugin_zone_start_picwall" class="plugin_zone"> |
16 | {loop="$plugin_start_zone"} | 30 | {loop="$plugin_start_zone"} |
17 | {$value} | 31 | {$value} |
18 | {/loop} | 32 | {/loop} |
19 | </div> | 33 | </div> |
20 | 34 | ||
21 | <div id="picwall_container" class="picwall-container"> | 35 | <div id="picwall-container" class="picwall-container"> |
22 | {loop="$linksToDisplay"} | 36 | {loop="$linksToDisplay"} |
23 | <div class="picwall-pictureframe"> | 37 | <div class="picwall-pictureframe"> |
24 | {$value.thumbnail}<a href="{$value.real_url}"><span class="info">{$value.title}</span></a> | 38 | {ignore}RainTPL hack: put the 2 src on two different line to avoid path replace bug{/ignore} |
25 | {loop="$value.picwall_plugin"} | 39 | <img data-src="{$value.thumbnail}#" class="b-lazy" |
26 | {$value} | 40 | src="#" |
27 | {/loop} | 41 | alt="thumbnail" width="{$thumbnails_width}" height="{$thumbnails_height}" /> |
28 | </div> | 42 | <a href="{$value.real_url}"><span class="info">{$value.title}</span></a> |
29 | {/loop} | 43 | {loop="$value.picwall_plugin"} |
30 | <div class="clear"></div> | 44 | {$value} |
31 | </div> | 45 | {/loop} |
46 | </div> | ||
47 | {/loop} | ||
48 | <div class="clear"></div> | ||
49 | </div> | ||
32 | 50 | ||
33 | <div id="plugin_zone_end_picwall" class="plugin_zone"> | 51 | <div id="plugin_zone_end_picwall" class="plugin_zone"> |
34 | {loop="$plugin_end_zone"} | 52 | {loop="$plugin_end_zone"} |
35 | {$value} | 53 | {$value} |
36 | {/loop} | 54 | {/loop} |
55 | </div> | ||
37 | </div> | 56 | </div> |
57 | <div class="pure-u-lg-1-6 pure-u-1-24"></div> | ||
38 | </div> | 58 | </div> |
39 | </div> | 59 | {/if} |
40 | 60 | ||
41 | {include="page.footer"} | 61 | {include="page.footer"} |
42 | <script src="js/picwall.min.js?v={$version_hash}"></script> | 62 | <script src="js/thumbnails.min.js?v={$version_hash}"></script> |
43 | </body> | 63 | </body> |
44 | </html> | 64 | </html> |
45 | 65 | ||
diff --git a/tpl/default/thumbnails.html b/tpl/default/thumbnails.html new file mode 100644 index 00000000..a8cf904e --- /dev/null +++ b/tpl/default/thumbnails.html | |||
@@ -0,0 +1,48 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <html> | ||
3 | <head> | ||
4 | {include="includes"} | ||
5 | </head> | ||
6 | <body> | ||
7 | {include="page.header"} | ||
8 | |||
9 | <div class="pure-g thumbnails-page-container"> | ||
10 | <div class="pure-u-lg-1-3 pure-u-1-24"></div> | ||
11 | <div class="pure-u-lg-1-3 pure-u-22-24 page-form page-form-light"> | ||
12 | <h2 class="window-title">{'Thumbnails update'|t}</h2> | ||
13 | |||
14 | <div class="pure-g"> | ||
15 | <div class="pure-u-lg-1-3 pure-u-1-24"></div> | ||
16 | <div class="pure-u-lg-1-3 pure-u-22-24"> | ||
17 | <div class="thumbnail-placeholder" style="width: {$thumbnails_width}px; height: {$thumbnails_height}px;"></div> | ||
18 | </div> | ||
19 | </div> | ||
20 | |||
21 | <div class="pure-g"> | ||
22 | <div class="pure-u-1-12"></div> | ||
23 | <div class="pure-u-5-6"> | ||
24 | <div class="thumbnail-link-title"></div> | ||
25 | |||
26 | <div class="progressbar"> | ||
27 | <div></div> | ||
28 | </div> | ||
29 | </div> | ||
30 | </div> | ||
31 | |||
32 | <div class="pure-g"> | ||
33 | <div class="pure-u-lg-1-3 pure-u-1-24"></div> | ||
34 | <div class="pure-u-lg-1-3 pure-u-22-24"> | ||
35 | <div class="progress-counter"> | ||
36 | <span class="progress-current">0</span> / <span class="progress-total">{$ids|count}</span> | ||
37 | </div> | ||
38 | </div> | ||
39 | </div> | ||
40 | |||
41 | <input type="hidden" name="ids" value="{function="implode($ids, ',')"}" /> | ||
42 | </div> | ||
43 | </div> | ||
44 | |||
45 | {include="page.footer"} | ||
46 | <script src="js/thumbnails_update.min.js?v={$version_hash}"></script> | ||
47 | </body> | ||
48 | </html> | ||
diff --git a/tpl/default/tools.html b/tpl/default/tools.html index ece66884..20060994 100644 --- a/tpl/default/tools.html +++ b/tpl/default/tools.html | |||
@@ -45,6 +45,14 @@ | |||
45 | </a> | 45 | </a> |
46 | </div> | 46 | </div> |
47 | 47 | ||
48 | {if="$thumbnails_enabled"} | ||
49 | <div class="tools-item"> | ||
50 | <a href="?do=thumbs_update" title="{'Synchronize all link thumbnails'|t}"> | ||
51 | <span class="pure-button pure-u-lg-2-3 pure-u-3-4">{'Synchronize thumbnails'|t}</span> | ||
52 | </a> | ||
53 | </div> | ||
54 | {/if} | ||
55 | |||
48 | {loop="$tools_plugin"} | 56 | {loop="$tools_plugin"} |
49 | <div class="tools-item"> | 57 | <div class="tools-item"> |
50 | {$value} | 58 | {$value} |
diff --git a/tpl/vintage/configure.html b/tpl/vintage/configure.html index 479284eb..9466c235 100644 --- a/tpl/vintage/configure.html +++ b/tpl/vintage/configure.html | |||
@@ -128,6 +128,29 @@ | |||
128 | <input type="text" name="apiSecret" id="apiSecret" size="50" value="{$api_secret}" /> | 128 | <input type="text" name="apiSecret" id="apiSecret" size="50" value="{$api_secret}" /> |
129 | </td> | 129 | </td> |
130 | </tr> | 130 | </tr> |
131 | <tr> | ||
132 | <td valign="top"><b>Enable thumbnails</b></td> | ||
133 | <td> | ||
134 | <select name="enableThumbnails" id="enableThumbnails" class="align"> | ||
135 | <option value="all" {if="$thumbnails_mode=='all'"}selected{/if}> | ||
136 | {'All'|t} | ||
137 | </option> | ||
138 | <option value="common" {if="$thumbnails_mode=='common'"}selected{/if}> | ||
139 | {'Only common media hosts'|t} | ||
140 | </option> | ||
141 | <option value="none" {if="$thumbnails_mode=='none'"}selected{/if}> | ||
142 | {'None'|t} | ||
143 | </option> | ||
144 | </select> | ||
145 | <label for="enableThumbnails"> | ||
146 | {if="! $gd_enabled"} | ||
147 | {'You need to enable the extension <code>php-gd</code> to use thumbnails.'|t} | ||
148 | {elseif="$thumbnails_enabled"} | ||
149 | <a href="?do=thumbs_update">{'Synchonize thumbnails'|t}</a> | ||
150 | {/if} | ||
151 | </label> | ||
152 | </td> | ||
153 | </tr> | ||
131 | 154 | ||
132 | <tr> | 155 | <tr> |
133 | <td></td> | 156 | <td></td> |
diff --git a/tpl/vintage/linklist.html b/tpl/vintage/linklist.html index 1ca51be3..3f202849 100644 --- a/tpl/vintage/linklist.html +++ b/tpl/vintage/linklist.html | |||
@@ -80,7 +80,16 @@ | |||
80 | {loop="$links"} | 80 | {loop="$links"} |
81 | <li{if="$value.class"} class="{$value.class}"{/if}> | 81 | <li{if="$value.class"} class="{$value.class}"{/if}> |
82 | <a id="{$value.shorturl}"></a> | 82 | <a id="{$value.shorturl}"></a> |
83 | <div class="thumbnail">{$value.url|thumbnail}</div> | 83 | {if="$thumbnails_enabled && !empty($value.thumbnail)"} |
84 | <div class="thumbnail"> | ||
85 | <a href="{$value.real_url}"> | ||
86 | {ignore}RainTPL hack: put the 2 src on two different line to avoid path replace bug{/ignore} | ||
87 | <img data-src="{$value.thumbnail}#" class="b-lazy" | ||
88 | src="#" | ||
89 | alt="thumbnail" width="{$thumbnails_width}" height="{$thumbnails_height}" /> | ||
90 | </a> | ||
91 | </div> | ||
92 | {/if} | ||
84 | <div class="linkcontainer"> | 93 | <div class="linkcontainer"> |
85 | {if="$is_logged_in"} | 94 | {if="$is_logged_in"} |
86 | <div class="linkeditbuttons"> | 95 | <div class="linkeditbuttons"> |
@@ -145,6 +154,7 @@ | |||
145 | </div> | 154 | </div> |
146 | 155 | ||
147 | {include="page.footer"} | 156 | {include="page.footer"} |
157 | <script src="js/thumbnails.min.js"></script> | ||
148 | 158 | ||
149 | </body> | 159 | </body> |
150 | </html> | 160 | </html> |
diff --git a/tpl/vintage/picwall.html b/tpl/vintage/picwall.html index 29688914..5f1d266e 100644 --- a/tpl/vintage/picwall.html +++ b/tpl/vintage/picwall.html | |||
@@ -15,7 +15,11 @@ | |||
15 | <div id="picwall_container"> | 15 | <div id="picwall_container"> |
16 | {loop="$linksToDisplay"} | 16 | {loop="$linksToDisplay"} |
17 | <div class="picwall_pictureframe"> | 17 | <div class="picwall_pictureframe"> |
18 | {$value.thumbnail}<a href="{$value.real_url}"><span class="info">{$value.title}</span></a> | 18 | {ignore}RainTPL hack: put the 2 src on two different line to avoid path replace bug{/ignore} |
19 | <img data-src="{$value.thumbnail}#" class="b-lazy" | ||
20 | src="#" | ||
21 | alt="thumbnail" width="{$thumbnails_width}" height="{$thumbnails_height}" /> | ||
22 | <a href="{$value.real_url}"><span class="info">{$value.title}</span></a> | ||
19 | {loop="$value.picwall_plugin"} | 23 | {loop="$value.picwall_plugin"} |
20 | {$value} | 24 | {$value} |
21 | {/loop} | 25 | {/loop} |
@@ -34,6 +38,6 @@ | |||
34 | 38 | ||
35 | {include="page.footer"} | 39 | {include="page.footer"} |
36 | 40 | ||
37 | <script src="js/picwall.min.js"></script> | 41 | <script src="js/thumbnails.min.js"></script> |
38 | </body> | 42 | </body> |
39 | </html> | 43 | </html> |
diff --git a/tpl/vintage/thumbnails.html b/tpl/vintage/thumbnails.html new file mode 100644 index 00000000..79aebf8d --- /dev/null +++ b/tpl/vintage/thumbnails.html | |||
@@ -0,0 +1,28 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <html> | ||
3 | <head>{include="includes"}</head> | ||
4 | <body> | ||
5 | <div id="pageheader"> | ||
6 | {include="page.header"} | ||
7 | </div> | ||
8 | |||
9 | <div class="center thumbnails-update-container"> | ||
10 | <div class="thumbnail-placeholder" style="width: {$thumbnails_width}px; height: {$thumbnails_height}px;"></div> | ||
11 | |||
12 | <div class="thumbnail-link-title"></div> | ||
13 | |||
14 | <div class="progressbar"> | ||
15 | <div></div> | ||
16 | </div> | ||
17 | |||
18 | <div class="progress-counter"> | ||
19 | <span class="progress-current">0</span> / <span class="progress-total">{$ids|count}</span> | ||
20 | </div> | ||
21 | </div> | ||
22 | |||
23 | <input type="hidden" name="ids" value="{function="implode($ids, ',')"}" /> | ||
24 | |||
25 | {include="page.footer"} | ||
26 | <script src="js/thumbnails_update.min.js?v={$version_hash}"></script> | ||
27 | </body> | ||
28 | </html> | ||
diff --git a/webpack.config.js b/webpack.config.js index 94b7aa70..ed548c73 100644 --- a/webpack.config.js +++ b/webpack.config.js | |||
@@ -23,7 +23,8 @@ const extractCssVintage = new ExtractTextPlugin({ | |||
23 | module.exports = [ | 23 | module.exports = [ |
24 | { | 24 | { |
25 | entry: { | 25 | entry: { |
26 | picwall: './assets/common/js/picwall.js', | 26 | thumbnails: './assets/common/js/thumbnails.js', |
27 | thumbnails_update: './assets/common/js/thumbnails-update.js', | ||
27 | pluginsadmin: './assets/default/js/plugins-admin.js', | 28 | pluginsadmin: './assets/default/js/plugins-admin.js', |
28 | shaarli: [ | 29 | shaarli: [ |
29 | './assets/default/js/base.js', | 30 | './assets/default/js/base.js', |
@@ -96,7 +97,8 @@ module.exports = [ | |||
96 | './assets/vintage/css/reset.css', | 97 | './assets/vintage/css/reset.css', |
97 | './assets/vintage/css/shaarli.css', | 98 | './assets/vintage/css/shaarli.css', |
98 | ].concat(glob.sync('./assets/vintage/img/*')), | 99 | ].concat(glob.sync('./assets/vintage/img/*')), |
99 | picwall: './assets/common/js/picwall.js', | 100 | thumbnails: './assets/common/js/thumbnails.js', |
101 | thumbnails_update: './assets/common/js/thumbnails-update.js', | ||
100 | }, | 102 | }, |
101 | output: { | 103 | output: { |
102 | filename: '[name].min.js', | 104 | filename: '[name].min.js', |