aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--application/bookmark/BookmarkArray.php9
-rw-r--r--application/bookmark/BookmarkFileService.php13
-rw-r--r--application/bookmark/BookmarkServiceInterface.php9
-rw-r--r--application/feed/FeedBuilder.php2
-rw-r--r--application/front/ShaarliMiddleware.php2
-rw-r--r--application/legacy/LegacyController.php32
-rw-r--r--application/security/SessionManager.php1
-rw-r--r--assets/default/js/base.js19
-rw-r--r--index.php2
-rw-r--r--tests/feed/FeedBuilderTest.php12
-rw-r--r--tests/legacy/LegacyControllerTest.php8
-rw-r--r--tests/security/SessionManagerTest.php13
-rw-r--r--tpl/default/linklist.paging.html44
-rw-r--r--yarn.lock31
14 files changed, 129 insertions, 68 deletions
diff --git a/application/bookmark/BookmarkArray.php b/application/bookmark/BookmarkArray.php
index d87d43b4..3bd5eb20 100644
--- a/application/bookmark/BookmarkArray.php
+++ b/application/bookmark/BookmarkArray.php
@@ -234,16 +234,17 @@ class BookmarkArray implements \Iterator, \Countable, \ArrayAccess
234 * 234 *
235 * Also update the urls and ids mapping arrays. 235 * Also update the urls and ids mapping arrays.
236 * 236 *
237 * @param string $order ASC|DESC 237 * @param string $order ASC|DESC
238 * @param bool $ignoreSticky If set to true, sticky bookmarks won't be first
238 */ 239 */
239 public function reorder($order = 'DESC') 240 public function reorder(string $order = 'DESC', bool $ignoreSticky = false): void
240 { 241 {
241 $order = $order === 'ASC' ? -1 : 1; 242 $order = $order === 'ASC' ? -1 : 1;
242 // Reorder array by dates. 243 // Reorder array by dates.
243 usort($this->bookmarks, function ($a, $b) use ($order) { 244 usort($this->bookmarks, function ($a, $b) use ($order, $ignoreSticky) {
244 /** @var $a Bookmark */ 245 /** @var $a Bookmark */
245 /** @var $b Bookmark */ 246 /** @var $b Bookmark */
246 if ($a->isSticky() !== $b->isSticky()) { 247 if (false === $ignoreSticky && $a->isSticky() !== $b->isSticky()) {
247 return $a->isSticky() ? -1 : 1; 248 return $a->isSticky() ? -1 : 1;
248 } 249 }
249 return $a->getCreated() < $b->getCreated() ? 1 * $order : -1 * $order; 250 return $a->getCreated() < $b->getCreated() ? 1 * $order : -1 * $order;
diff --git a/application/bookmark/BookmarkFileService.php b/application/bookmark/BookmarkFileService.php
index b3a90ed4..e3a61146 100644
--- a/application/bookmark/BookmarkFileService.php
+++ b/application/bookmark/BookmarkFileService.php
@@ -114,8 +114,13 @@ class BookmarkFileService implements BookmarkServiceInterface
114 /** 114 /**
115 * @inheritDoc 115 * @inheritDoc
116 */ 116 */
117 public function search($request = [], $visibility = null, $caseSensitive = false, $untaggedOnly = false) 117 public function search(
118 { 118 $request = [],
119 $visibility = null,
120 $caseSensitive = false,
121 $untaggedOnly = false,
122 bool $ignoreSticky = false
123 ) {
119 if ($visibility === null) { 124 if ($visibility === null) {
120 $visibility = $this->isLoggedIn ? BookmarkFilter::$ALL : BookmarkFilter::$PUBLIC; 125 $visibility = $this->isLoggedIn ? BookmarkFilter::$ALL : BookmarkFilter::$PUBLIC;
121 } 126 }
@@ -124,6 +129,10 @@ class BookmarkFileService implements BookmarkServiceInterface
124 $searchtags = isset($request['searchtags']) ? $request['searchtags'] : ''; 129 $searchtags = isset($request['searchtags']) ? $request['searchtags'] : '';
125 $searchterm = isset($request['searchterm']) ? $request['searchterm'] : ''; 130 $searchterm = isset($request['searchterm']) ? $request['searchterm'] : '';
126 131
132 if ($ignoreSticky) {
133 $this->bookmarks->reorder('DESC', true);
134 }
135
127 return $this->bookmarkFilter->filter( 136 return $this->bookmarkFilter->filter(
128 BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT, 137 BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT,
129 [$searchtags, $searchterm], 138 [$searchtags, $searchterm],
diff --git a/application/bookmark/BookmarkServiceInterface.php b/application/bookmark/BookmarkServiceInterface.php
index ce8bd912..b9b483eb 100644
--- a/application/bookmark/BookmarkServiceInterface.php
+++ b/application/bookmark/BookmarkServiceInterface.php
@@ -49,10 +49,17 @@ interface BookmarkServiceInterface
49 * @param string $visibility 49 * @param string $visibility
50 * @param bool $caseSensitive 50 * @param bool $caseSensitive
51 * @param bool $untaggedOnly 51 * @param bool $untaggedOnly
52 * @param bool $ignoreSticky
52 * 53 *
53 * @return Bookmark[] 54 * @return Bookmark[]
54 */ 55 */
55 public function search($request = [], $visibility = null, $caseSensitive = false, $untaggedOnly = false); 56 public function search(
57 $request = [],
58 $visibility = null,
59 $caseSensitive = false,
60 $untaggedOnly = false,
61 bool $ignoreSticky = false
62 );
56 63
57 /** 64 /**
58 * Get a single bookmark by its ID. 65 * Get a single bookmark by its ID.
diff --git a/application/feed/FeedBuilder.php b/application/feed/FeedBuilder.php
index 269ad877..3653c32f 100644
--- a/application/feed/FeedBuilder.php
+++ b/application/feed/FeedBuilder.php
@@ -102,7 +102,7 @@ class FeedBuilder
102 } 102 }
103 103
104 // Optionally filter the results: 104 // Optionally filter the results:
105 $linksToDisplay = $this->linkDB->search($userInput); 105 $linksToDisplay = $this->linkDB->search($userInput, null, false, false, true);
106 106
107 $nblinksToDisplay = $this->getNbLinks(count($linksToDisplay), $userInput); 107 $nblinksToDisplay = $this->getNbLinks(count($linksToDisplay), $userInput);
108 108
diff --git a/application/front/ShaarliMiddleware.php b/application/front/ShaarliMiddleware.php
index c015c0c6..d1aa1399 100644
--- a/application/front/ShaarliMiddleware.php
+++ b/application/front/ShaarliMiddleware.php
@@ -94,7 +94,7 @@ class ShaarliMiddleware
94 && $this->container->conf->get('privacy.force_login') 94 && $this->container->conf->get('privacy.force_login')
95 // and the current page isn't already the login page 95 // and the current page isn't already the login page
96 // and the user is not requesting a feed (which would lead to a different content-type as expected) 96 // and the user is not requesting a feed (which would lead to a different content-type as expected)
97 && !in_array($next->getName(), ['login', 'atom', 'rss'], true) 97 && !in_array($next->getName(), ['login', 'processLogin', 'atom', 'rss'], true)
98 ) { 98 ) {
99 throw new UnauthorizedException(); 99 throw new UnauthorizedException();
100 } 100 }
diff --git a/application/legacy/LegacyController.php b/application/legacy/LegacyController.php
index 26465d2c..e16dd0f4 100644
--- a/application/legacy/LegacyController.php
+++ b/application/legacy/LegacyController.php
@@ -40,28 +40,33 @@ class LegacyController extends ShaarliVisitorController
40 public function post(Request $request, Response $response): Response 40 public function post(Request $request, Response $response): Response
41 { 41 {
42 $parameters = count($request->getQueryParams()) > 0 ? '?' . http_build_query($request->getQueryParams()) : ''; 42 $parameters = count($request->getQueryParams()) > 0 ? '?' . http_build_query($request->getQueryParams()) : '';
43 $route = '/admin/shaare';
43 44
44 if (!$this->container->loginManager->isLoggedIn()) { 45 if (!$this->container->loginManager->isLoggedIn()) {
45 return $this->redirect($response, '/login' . $parameters); 46 return $this->redirect($response, '/login?returnurl='. $this->getBasePath() . $route . $parameters);
46 } 47 }
47 48
48 return $this->redirect($response, '/admin/shaare' . $parameters); 49 return $this->redirect($response, $route . $parameters);
49 } 50 }
50 51
51 /** Legacy route: ?addlink= */ 52 /** Legacy route: ?addlink= */
52 protected function addlink(Request $request, Response $response): Response 53 protected function addlink(Request $request, Response $response): Response
53 { 54 {
55 $route = '/admin/add-shaare';
56
54 if (!$this->container->loginManager->isLoggedIn()) { 57 if (!$this->container->loginManager->isLoggedIn()) {
55 return $this->redirect($response, '/login'); 58 return $this->redirect($response, '/login?returnurl=' . $this->getBasePath() . $route);
56 } 59 }
57 60
58 return $this->redirect($response, '/admin/add-shaare'); 61 return $this->redirect($response, $route);
59 } 62 }
60 63
61 /** Legacy route: ?do=login */ 64 /** Legacy route: ?do=login */
62 protected function login(Request $request, Response $response): Response 65 protected function login(Request $request, Response $response): Response
63 { 66 {
64 return $this->redirect($response, '/login'); 67 $returnUrl = $request->getQueryParam('returnurl');
68
69 return $this->redirect($response, '/login' . ($returnUrl ? '?returnurl=' . $returnUrl : ''));
65 } 70 }
66 71
67 /** Legacy route: ?do=logout */ 72 /** Legacy route: ?do=logout */
@@ -127,4 +132,21 @@ class LegacyController extends ShaarliVisitorController
127 132
128 return $this->redirect($response, '/feed/' . $feedType . $parameters); 133 return $this->redirect($response, '/feed/' . $feedType . $parameters);
129 } 134 }
135
136 /** Legacy route: ?do=configure */
137 protected function configure(Request $request, Response $response): Response
138 {
139 $route = '/admin/configure';
140
141 if (!$this->container->loginManager->isLoggedIn()) {
142 return $this->redirect($response, '/login?returnurl=' . $this->getBasePath() . $route);
143 }
144
145 return $this->redirect($response, $route);
146 }
147
148 protected function getBasePath(): string
149 {
150 return $this->container->basePath ?: '';
151 }
130} 152}
diff --git a/application/security/SessionManager.php b/application/security/SessionManager.php
index 76b0afe8..36df8c1c 100644
--- a/application/security/SessionManager.php
+++ b/application/security/SessionManager.php
@@ -183,7 +183,6 @@ class SessionManager
183 unset($this->session['expires_on']); 183 unset($this->session['expires_on']);
184 unset($this->session['username']); 184 unset($this->session['username']);
185 unset($this->session['visibility']); 185 unset($this->session['visibility']);
186 unset($this->session['untaggedonly']);
187 } 186 }
188 } 187 }
189 188
diff --git a/assets/default/js/base.js b/assets/default/js/base.js
index 0f29799d..27938823 100644
--- a/assets/default/js/base.js
+++ b/assets/default/js/base.js
@@ -25,16 +25,18 @@ function findParent(element, tagName, attributes) {
25/** 25/**
26 * Ajax request to refresh the CSRF token. 26 * Ajax request to refresh the CSRF token.
27 */ 27 */
28function refreshToken(basePath) { 28function refreshToken(basePath, callback) {
29 console.log('refresh');
30 const xhr = new XMLHttpRequest(); 29 const xhr = new XMLHttpRequest();
31 xhr.open('GET', `${basePath}/admin/token`); 30 xhr.open('GET', `${basePath}/admin/token`);
32 xhr.onload = () => { 31 xhr.onload = () => {
33 const elements = document.querySelectorAll('input[name="token"]'); 32 const elements = document.querySelectorAll('input[name="token"]');
34 [...elements].forEach((element) => { 33 [...elements].forEach((element) => {
35 console.log(element);
36 element.setAttribute('value', xhr.responseText); 34 element.setAttribute('value', xhr.responseText);
37 }); 35 });
36
37 if (callback) {
38 callback(xhr.response);
39 }
38 }; 40 };
39 xhr.send(); 41 xhr.send();
40} 42}
@@ -622,4 +624,15 @@ function init(description) {
622 [...autocompleteFields].forEach((autocompleteField) => { 624 [...autocompleteFields].forEach((autocompleteField) => {
623 awesomepletes.push(createAwesompleteInstance(autocompleteField)); 625 awesomepletes.push(createAwesompleteInstance(autocompleteField));
624 }); 626 });
627
628 const exportForm = document.querySelector('#exportform');
629 if (exportForm != null) {
630 exportForm.addEventListener('submit', (event) => {
631 event.preventDefault();
632
633 refreshToken(basePath, () => {
634 event.target.submit();
635 });
636 });
637 }
625})(); 638})();
diff --git a/index.php b/index.php
index e7471823..869f42de 100644
--- a/index.php
+++ b/index.php
@@ -95,7 +95,7 @@ $app->group('', function () {
95 $this->get('/add-tag/{newTag}', '\Shaarli\Front\Controller\Visitor\TagController:addTag'); 95 $this->get('/add-tag/{newTag}', '\Shaarli\Front\Controller\Visitor\TagController:addTag');
96 $this->get('/remove-tag/{tag}', '\Shaarli\Front\Controller\Visitor\TagController:removeTag'); 96 $this->get('/remove-tag/{tag}', '\Shaarli\Front\Controller\Visitor\TagController:removeTag');
97 $this->get('/links-per-page', '\Shaarli\Front\Controller\Visitor\PublicSessionFilterController:linksPerPage'); 97 $this->get('/links-per-page', '\Shaarli\Front\Controller\Visitor\PublicSessionFilterController:linksPerPage');
98 $this->get('/untagged-only', '\Shaarli\Front\Controller\Admin\PublicSessionFilterController:untaggedOnly'); 98 $this->get('/untagged-only', '\Shaarli\Front\Controller\Visitor\PublicSessionFilterController:untaggedOnly');
99})->add('\Shaarli\Front\ShaarliMiddleware'); 99})->add('\Shaarli\Front\ShaarliMiddleware');
100 100
101$app->group('/admin', function () { 101$app->group('/admin', function () {
diff --git a/tests/feed/FeedBuilderTest.php b/tests/feed/FeedBuilderTest.php
index 5c2aaedb..fe37d5f2 100644
--- a/tests/feed/FeedBuilderTest.php
+++ b/tests/feed/FeedBuilderTest.php
@@ -87,7 +87,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
87 $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); 87 $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
88 88
89 // Test first not pinned link (note link) 89 // Test first not pinned link (note link)
90 $link = $data['links'][array_keys($data['links'])[2]]; 90 $link = $data['links'][array_keys($data['links'])[0]];
91 $this->assertEquals(41, $link['id']); 91 $this->assertEquals(41, $link['id']);
92 $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); 92 $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']);
93 $this->assertEquals('http://host.tld/shaare/WDWyig', $link['guid']); 93 $this->assertEquals('http://host.tld/shaare/WDWyig', $link['guid']);
@@ -128,7 +128,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
128 $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null); 128 $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null);
129 $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); 129 $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
130 $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['last_update']); 130 $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['last_update']);
131 $link = $data['links'][array_keys($data['links'])[2]]; 131 $link = $data['links'][array_keys($data['links'])[0]];
132 $this->assertRegExp('/2015-03-10T11:46:51\+\d{2}:\d{2}/', $link['pub_iso_date']); 132 $this->assertRegExp('/2015-03-10T11:46:51\+\d{2}:\d{2}/', $link['pub_iso_date']);
133 $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['links'][8]['up_iso_date']); 133 $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['links'][8]['up_iso_date']);
134 } 134 }
@@ -173,7 +173,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
173 $feedBuilder->setLocale(self::$LOCALE); 173 $feedBuilder->setLocale(self::$LOCALE);
174 $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, $criteria); 174 $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, $criteria);
175 $this->assertEquals(3, count($data['links'])); 175 $this->assertEquals(3, count($data['links']));
176 $link = $data['links'][array_keys($data['links'])[2]]; 176 $link = $data['links'][array_keys($data['links'])[0]];
177 $this->assertEquals(41, $link['id']); 177 $this->assertEquals(41, $link['id']);
178 $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); 178 $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']);
179 } 179 }
@@ -195,7 +195,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
195 $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); 195 $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
196 $this->assertTrue($data['usepermalinks']); 196 $this->assertTrue($data['usepermalinks']);
197 // First link is a permalink 197 // First link is a permalink
198 $link = $data['links'][array_keys($data['links'])[2]]; 198 $link = $data['links'][array_keys($data['links'])[0]];
199 $this->assertEquals(41, $link['id']); 199 $this->assertEquals(41, $link['id']);
200 $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']); 200 $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']);
201 $this->assertEquals('http://host.tld/shaare/WDWyig', $link['guid']); 201 $this->assertEquals('http://host.tld/shaare/WDWyig', $link['guid']);
@@ -203,7 +203,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
203 $this->assertContains('Direct link', $link['description']); 203 $this->assertContains('Direct link', $link['description']);
204 $this->assertContains('http://host.tld/shaare/WDWyig', $link['description']); 204 $this->assertContains('http://host.tld/shaare/WDWyig', $link['description']);
205 // Second link is a direct link 205 // Second link is a direct link
206 $link = $data['links'][array_keys($data['links'])[3]]; 206 $link = $data['links'][array_keys($data['links'])[1]];
207 $this->assertEquals(8, $link['id']); 207 $this->assertEquals(8, $link['id']);
208 $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114633'), $link['created']); 208 $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114633'), $link['created']);
209 $this->assertEquals('http://host.tld/shaare/RttfEw', $link['guid']); 209 $this->assertEquals('http://host.tld/shaare/RttfEw', $link['guid']);
@@ -270,7 +270,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
270 ); 270 );
271 271
272 // Test first link (note link) 272 // Test first link (note link)
273 $link = $data['links'][array_keys($data['links'])[2]]; 273 $link = $data['links'][array_keys($data['links'])[0]];
274 $this->assertEquals('http://host.tld:8080/~user/shaarli/shaare/WDWyig', $link['guid']); 274 $this->assertEquals('http://host.tld:8080/~user/shaarli/shaare/WDWyig', $link['guid']);
275 $this->assertEquals('http://host.tld:8080/~user/shaarli/shaare/WDWyig', $link['url']); 275 $this->assertEquals('http://host.tld:8080/~user/shaarli/shaare/WDWyig', $link['url']);
276 $this->assertContains('http://host.tld:8080/~user/shaarli/./add-tag/hashtag', $link['description']); 276 $this->assertContains('http://host.tld:8080/~user/shaarli/./add-tag/hashtag', $link['description']);
diff --git a/tests/legacy/LegacyControllerTest.php b/tests/legacy/LegacyControllerTest.php
index 759a5b2a..4e52f3e1 100644
--- a/tests/legacy/LegacyControllerTest.php
+++ b/tests/legacy/LegacyControllerTest.php
@@ -66,11 +66,11 @@ class LegacyControllerTest extends TestCase
66 { 66 {
67 return [ 67 return [
68 ['post', [], '/admin/shaare', true], 68 ['post', [], '/admin/shaare', true],
69 ['post', [], '/login', false], 69 ['post', [], '/login?returnurl=/subfolder/admin/shaare', false],
70 ['post', ['title' => 'test'], '/admin/shaare?title=test', true], 70 ['post', ['title' => 'test'], '/admin/shaare?title=test', true],
71 ['post', ['title' => 'test'], '/login?title=test', false], 71 ['post', ['title' => 'test'], '/login?returnurl=/subfolder/admin/shaare?title=test', false],
72 ['addlink', [], '/admin/add-shaare', true], 72 ['addlink', [], '/admin/add-shaare', true],
73 ['addlink', [], '/login', false], 73 ['addlink', [], '/login?returnurl=/subfolder/admin/add-shaare', false],
74 ['login', [], '/login', true], 74 ['login', [], '/login', true],
75 ['login', [], '/login', false], 75 ['login', [], '/login', false],
76 ['logout', [], '/admin/logout', true], 76 ['logout', [], '/admin/logout', true],
@@ -94,6 +94,8 @@ class LegacyControllerTest extends TestCase
94 ['opensearch', [], '/open-search', true], 94 ['opensearch', [], '/open-search', true],
95 ['dailyrss', [], '/daily-rss', false], 95 ['dailyrss', [], '/daily-rss', false],
96 ['dailyrss', [], '/daily-rss', true], 96 ['dailyrss', [], '/daily-rss', true],
97 ['configure', [], '/login?returnurl=/subfolder/admin/configure', false],
98 ['configure', [], '/admin/configure', true],
97 ]; 99 ];
98 } 100 }
99} 101}
diff --git a/tests/security/SessionManagerTest.php b/tests/security/SessionManagerTest.php
index 60695dcf..11a59f9c 100644
--- a/tests/security/SessionManagerTest.php
+++ b/tests/security/SessionManagerTest.php
@@ -207,15 +207,16 @@ class SessionManagerTest extends TestCase
207 'expires_on' => time() + 1000, 207 'expires_on' => time() + 1000,
208 'username' => 'johndoe', 208 'username' => 'johndoe',
209 'visibility' => 'public', 209 'visibility' => 'public',
210 'untaggedonly' => false, 210 'untaggedonly' => true,
211 ]; 211 ];
212 $this->sessionManager->logout(); 212 $this->sessionManager->logout();
213 213
214 $this->assertFalse(isset($this->session['ip'])); 214 $this->assertArrayNotHasKey('ip', $this->session);
215 $this->assertFalse(isset($this->session['expires_on'])); 215 $this->assertArrayNotHasKey('expires_on', $this->session);
216 $this->assertFalse(isset($this->session['username'])); 216 $this->assertArrayNotHasKey('username', $this->session);
217 $this->assertFalse(isset($this->session['visibility'])); 217 $this->assertArrayNotHasKey('visibility', $this->session);
218 $this->assertFalse(isset($this->session['untaggedonly'])); 218 $this->assertArrayHasKey('untaggedonly', $this->session);
219 $this->assertTrue($this->session['untaggedonly']);
219 } 220 }
220 221
221 /** 222 /**
diff --git a/tpl/default/linklist.paging.html b/tpl/default/linklist.paging.html
index 009692b9..aa637868 100644
--- a/tpl/default/linklist.paging.html
+++ b/tpl/default/linklist.paging.html
@@ -1,27 +1,29 @@
1<div class="linklist-paging"> 1<div class="linklist-paging">
2 <div class="paging pure-g"> 2 <div class="paging pure-g">
3 <div class="linklist-filters pure-u-1-3"> 3 <div class="linklist-filters pure-u-1-3">
4 {if="$is_logged_in or !empty($action_plugin)"} 4 <span class="linklist-filters-text pure-u-0 pure-u-lg-visible">
5 <span class="linklist-filters-text pure-u-0 pure-u-lg-visible"> 5 {'Filters'|t}
6 {'Filters'|t} 6 </span>
7 </span> 7 {if="$is_logged_in"}
8 {if="$is_logged_in"} 8 <a href="{$base_path}/admin/visibility/private" aria-label="{'Only display private links'|t}" title="{'Only display private links'|t}"
9 <a href="{$base_path}/admin/visibility/private" aria-label="{'Only display private links'|t}" title="{'Only display private links'|t}" 9 class="{if="$visibility==='private'"}filter-on{else}filter-off{/if}"
10 class="{if="$visibility==='private'"}filter-on{else}filter-off{/if}" 10 ><i class="fa fa-user-secret" aria-hidden="true"></i></a>
11 ><i class="fa fa-user-secret" aria-hidden="true"></i></a> 11 <a href="{$base_path}/admin/visibility/public" aria-label="{'Only display public links'|t}" title="{'Only display public links'|t}"
12 <a href="{$base_path}/admin/visibility/public" aria-label="{'Only display public links'|t}" title="{'Only display public links'|t}" 12 class="{if="$visibility==='public'"}filter-on{else}filter-off{/if}"
13 class="{if="$visibility==='public'"}filter-on{else}filter-off{/if}" 13 ><i class="fa fa-globe" aria-hidden="true"></i></a>
14 ><i class="fa fa-globe" aria-hidden="true"></i></a> 14 {/if}
15 {/if} 15 <a href="{$base_path}/untagged-only" aria-label="{'Filter untagged links'|t}" title="{'Filter untagged links'|t}"
16 <a href="{$base_path}/untagged-only" aria-label="{'Filter untagged links'|t}" title="{'Filter untagged links'|t}" 16 class={if="$untaggedonly"}"filter-on"{else}"filter-off"{/if}
17 class={if="$untaggedonly"}"filter-on"{else}"filter-off"{/if} 17 ><i class="fa fa-tag" aria-hidden="true"></i></a>
18 ><i class="fa fa-tag" aria-hidden="true"></i></a> 18 {if="$is_logged_in"}
19 <a href="#" aria-label="{'Select all'|t}" title="{'Select all'|t}" 19 <a href="#" aria-label="{'Select all'|t}" title="{'Select all'|t}"
20 class="filter-off select-all-button pure-u-0 pure-u-lg-visible" 20 class="filter-off select-all-button pure-u-0 pure-u-lg-visible"
21 ><i class="fa fa-check-square-o" aria-hidden="true"></i></a> 21 ><i class="fa fa-check-square-o" aria-hidden="true"></i></a>
22 <a href="#" class="filter-off fold-all pure-u-lg-0" aria-label="{'Fold all'|t}" title="{'Fold all'|t}"> 22 {/if}
23 <i class="fa fa-chevron-up" aria-hidden="true"></i> 23 <a href="#" class="filter-off fold-all pure-u-lg-0" aria-label="{'Fold all'|t}" title="{'Fold all'|t}">
24 </a> 24 <i class="fa fa-chevron-up" aria-hidden="true"></i>
25 </a>
26 {if="!empty($action_plugin)"}
25 {loop="$action_plugin"} 27 {loop="$action_plugin"}
26 {$value.attr.class=isset($value.attr.class) ? $value.attr.class : ''} 28 {$value.attr.class=isset($value.attr.class) ? $value.attr.class : ''}
27 {$value.attr.class=!empty($value.on) ? $value.attr.class .' filter-on' : $value.attr.class .' filter-off'} 29 {$value.attr.class=!empty($value.on) ? $value.attr.class .' filter-on' : $value.attr.class .' filter-off'}
diff --git a/yarn.lock b/yarn.lock
index 96f854c1..df647950 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1065,9 +1065,9 @@ block-stream@*:
1065 inherits "~2.0.0" 1065 inherits "~2.0.0"
1066 1066
1067bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: 1067bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
1068 version "4.11.8" 1068 version "4.11.9"
1069 resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" 1069 resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828"
1070 integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== 1070 integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==
1071 1071
1072brace-expansion@^1.1.7: 1072brace-expansion@^1.1.7:
1073 version "1.1.11" 1073 version "1.1.11"
@@ -1886,9 +1886,9 @@ electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.47:
1886 integrity sha512-xXLNstRdVsisPF3pL3H9TVZo2XkMILfqtD6RiWIUmDK2sFX1Bjwqmd8LBp0Kuo2FgKO63JXPoEVGm8WyYdwP0Q== 1886 integrity sha512-xXLNstRdVsisPF3pL3H9TVZo2XkMILfqtD6RiWIUmDK2sFX1Bjwqmd8LBp0Kuo2FgKO63JXPoEVGm8WyYdwP0Q==
1887 1887
1888elliptic@^6.0.0: 1888elliptic@^6.0.0:
1889 version "6.4.1" 1889 version "6.5.3"
1890 resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" 1890 resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6"
1891 integrity sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ== 1891 integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==
1892 dependencies: 1892 dependencies:
1893 bn.js "^4.4.0" 1893 bn.js "^4.4.0"
1894 brorand "^1.0.1" 1894 brorand "^1.0.1"
@@ -2856,16 +2856,21 @@ inflight@^1.0.4:
2856 once "^1.3.0" 2856 once "^1.3.0"
2857 wrappy "1" 2857 wrappy "1"
2858 2858
2859inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: 2859inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
2860 version "2.0.3" 2860 version "2.0.4"
2861 resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 2861 resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
2862 integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 2862 integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
2863 2863
2864inherits@2.0.1: 2864inherits@2.0.1:
2865 version "2.0.1" 2865 version "2.0.1"
2866 resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" 2866 resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
2867 integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= 2867 integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=
2868 2868
2869inherits@2.0.3:
2870 version "2.0.3"
2871 resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
2872 integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
2873
2869ini@~1.3.0: 2874ini@~1.3.0:
2870 version "1.3.5" 2875 version "1.3.5"
2871 resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" 2876 resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
@@ -3428,9 +3433,9 @@ lodash.uniq@^4.5.0:
3428 integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= 3433 integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
3429 3434
3430lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.3.0, lodash@~4.17.10: 3435lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.3.0, lodash@~4.17.10:
3431 version "4.17.15" 3436 version "4.17.19"
3432 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" 3437 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
3433 integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== 3438 integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
3434 3439
3435longest@^1.0.1: 3440longest@^1.0.1:
3436 version "1.0.1" 3441 version "1.0.1"