diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | application/LinkDB.php | 40 | ||||
-rw-r--r-- | application/LinkFilter.php | 41 | ||||
-rw-r--r-- | application/PageBuilder.php | 1 | ||||
-rw-r--r-- | index.php | 74 | ||||
-rw-r--r-- | tests/LinkDBTest.php | 55 | ||||
-rw-r--r-- | tests/LinkFilterTest.php | 3 | ||||
-rw-r--r-- | tpl/default/css/shaarli.css | 45 | ||||
-rw-r--r-- | tpl/default/linklist.html | 50 | ||||
-rw-r--r-- | tpl/default/linklist.paging.html | 11 | ||||
-rw-r--r-- | tpl/default/page.header.html | 39 |
11 files changed, 218 insertions, 143 deletions
@@ -1,4 +1,4 @@ | |||
1 | ![Shaarli logo](doc/images/doc-logo.png) | 1 | ![Shaarli logo](doc/md/images/doc-logo.png) |
2 | 2 | ||
3 | The personal, minimalist, super-fast, database free, bookmarking service. | 3 | The personal, minimalist, super-fast, database free, bookmarking service. |
4 | 4 | ||
diff --git a/application/LinkDB.php b/application/LinkDB.php index 8ca0fab3..9308164a 100644 --- a/application/LinkDB.php +++ b/application/LinkDB.php | |||
@@ -417,21 +417,22 @@ You use the community supported version of the original Shaarli project, by Seba | |||
417 | * - searchterm: term search | 417 | * - searchterm: term search |
418 | * @param bool $casesensitive Optional: Perform case sensitive filter | 418 | * @param bool $casesensitive Optional: Perform case sensitive filter |
419 | * @param string $visibility return only all/private/public links | 419 | * @param string $visibility return only all/private/public links |
420 | * @param string $untaggedonly return only untagged links | ||
420 | * | 421 | * |
421 | * @return array filtered links, all links if no suitable filter was provided. | 422 | * @return array filtered links, all links if no suitable filter was provided. |
422 | */ | 423 | */ |
423 | public function filterSearch($filterRequest = array(), $casesensitive = false, $visibility = 'all') | 424 | public function filterSearch($filterRequest = array(), $casesensitive = false, $visibility = 'all', $untaggedonly = false) |
424 | { | 425 | { |
425 | // Filter link database according to parameters. | 426 | // Filter link database according to parameters. |
426 | $searchtags = isset($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : ''; | 427 | $searchtags = isset($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : ''; |
427 | $searchterm = isset($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : ''; | 428 | $searchterm = isset($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : ''; |
428 | 429 | ||
429 | // Search tags + fullsearch - blank string parameter will return all links. | 430 | // Search tags + fullsearch - blank string parameter will return all links. |
430 | $type = LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT; | 431 | $type = LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT; // == "vuotext" |
431 | $request = [$searchtags, $searchterm]; | 432 | $request = [$searchtags, $searchterm]; |
432 | 433 | ||
433 | $linkFilter = new LinkFilter($this); | 434 | $linkFilter = new LinkFilter($this); |
434 | return $linkFilter->filter($type, $request, $casesensitive, $visibility); | 435 | return $linkFilter->filter($type, $request, $casesensitive, $visibility, $untaggedonly); |
435 | } | 436 | } |
436 | 437 | ||
437 | /** | 438 | /** |
@@ -464,6 +465,39 @@ You use the community supported version of the original Shaarli project, by Seba | |||
464 | } | 465 | } |
465 | 466 | ||
466 | /** | 467 | /** |
468 | * Rename or delete a tag across all links. | ||
469 | * | ||
470 | * @param string $from Tag to rename | ||
471 | * @param string $to New tag. If none is provided, the from tag will be deleted | ||
472 | * | ||
473 | * @return array|bool List of altered links or false on error | ||
474 | */ | ||
475 | public function renameTag($from, $to) | ||
476 | { | ||
477 | if (empty($from)) { | ||
478 | return false; | ||
479 | } | ||
480 | $delete = empty($to); | ||
481 | // True for case-sensitive tag search. | ||
482 | $linksToAlter = $this->filterSearch(['searchtags' => $from], true); | ||
483 | foreach($linksToAlter as $key => &$value) | ||
484 | { | ||
485 | $tags = preg_split('/\s+/', trim($value['tags'])); | ||
486 | if (($pos = array_search($from, $tags)) !== false) { | ||
487 | if ($delete) { | ||
488 | unset($tags[$pos]); // Remove tag. | ||
489 | } else { | ||
490 | $tags[$pos] = trim($to); | ||
491 | } | ||
492 | $value['tags'] = trim(implode(' ', array_unique($tags))); | ||
493 | $this[$value['id']] = $value; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | return $linksToAlter; | ||
498 | } | ||
499 | |||
500 | /** | ||
467 | * Returns the list of days containing articles (oldest first) | 501 | * Returns the list of days containing articles (oldest first) |
468 | * Output: An array containing days (in format YYYYMMDD). | 502 | * Output: An array containing days (in format YYYYMMDD). |
469 | */ | 503 | */ |
diff --git a/application/LinkFilter.php b/application/LinkFilter.php index 0e887d38..95519528 100644 --- a/application/LinkFilter.php +++ b/application/LinkFilter.php | |||
@@ -52,10 +52,11 @@ class LinkFilter | |||
52 | * @param mixed $request Filter content. | 52 | * @param mixed $request Filter content. |
53 | * @param bool $casesensitive Optional: Perform case sensitive filter if true. | 53 | * @param bool $casesensitive Optional: Perform case sensitive filter if true. |
54 | * @param string $visibility Optional: return only all/private/public links | 54 | * @param string $visibility Optional: return only all/private/public links |
55 | * @param string $untaggedonly Optional: return only untagged links. Applies only if $type includes FILTER_TAG | ||
55 | * | 56 | * |
56 | * @return array filtered link list. | 57 | * @return array filtered link list. |
57 | */ | 58 | */ |
58 | public function filter($type, $request, $casesensitive = false, $visibility = 'all') | 59 | public function filter($type, $request, $casesensitive = false, $visibility = 'all', $untaggedonly = false) |
59 | { | 60 | { |
60 | if (! in_array($visibility, ['all', 'public', 'private'])) { | 61 | if (! in_array($visibility, ['all', 'public', 'private'])) { |
61 | $visibility = 'all'; | 62 | $visibility = 'all'; |
@@ -64,23 +65,34 @@ class LinkFilter | |||
64 | switch($type) { | 65 | switch($type) { |
65 | case self::$FILTER_HASH: | 66 | case self::$FILTER_HASH: |
66 | return $this->filterSmallHash($request); | 67 | return $this->filterSmallHash($request); |
67 | case self::$FILTER_TAG | self::$FILTER_TEXT: | 68 | case self::$FILTER_TAG | self::$FILTER_TEXT: // == "vuotext" |
68 | if (!empty($request)) { | 69 | $noRequest = empty($request) || (empty($request[0]) && empty($request[1])); |
69 | $filtered = $this->links; | 70 | if ($noRequest) { |
70 | if (isset($request[0])) { | 71 | if ($untaggedonly) { |
71 | $filtered = $this->filterTags($request[0], $casesensitive, $visibility); | 72 | return $this->filterUntagged($visibility); |
72 | } | ||
73 | if (isset($request[1])) { | ||
74 | $lf = new LinkFilter($filtered); | ||
75 | $filtered = $lf->filterFulltext($request[1], $visibility); | ||
76 | } | 73 | } |
77 | return $filtered; | 74 | return $this->noFilter($visibility); |
78 | } | 75 | } |
79 | return $this->noFilter($visibility); | 76 | if ($untaggedonly) { |
77 | $filtered = $this->filterUntagged($visibility); | ||
78 | } else { | ||
79 | $filtered = $this->links; | ||
80 | } | ||
81 | if (!empty($request[0])) { | ||
82 | $filtered = (new LinkFilter($filtered))->filterTags($request[0], $casesensitive, $visibility); | ||
83 | } | ||
84 | if (!empty($request[1])) { | ||
85 | $filtered = (new LinkFilter($filtered))->filterFulltext($request[1], $visibility); | ||
86 | } | ||
87 | return $filtered; | ||
80 | case self::$FILTER_TEXT: | 88 | case self::$FILTER_TEXT: |
81 | return $this->filterFulltext($request, $visibility); | 89 | return $this->filterFulltext($request, $visibility); |
82 | case self::$FILTER_TAG: | 90 | case self::$FILTER_TAG: |
83 | return $this->filterTags($request, $casesensitive, $visibility); | 91 | if ($untaggedonly) { |
92 | return $this->filterUntagged($visibility); | ||
93 | } else { | ||
94 | return $this->filterTags($request, $casesensitive, $visibility); | ||
95 | } | ||
84 | case self::$FILTER_DAY: | 96 | case self::$FILTER_DAY: |
85 | return $this->filterDay($request); | 97 | return $this->filterDay($request); |
86 | default: | 98 | default: |
@@ -253,9 +265,6 @@ class LinkFilter | |||
253 | { | 265 | { |
254 | // Implode if array for clean up. | 266 | // Implode if array for clean up. |
255 | $tags = is_array($tags) ? trim(implode(' ', $tags)) : $tags; | 267 | $tags = is_array($tags) ? trim(implode(' ', $tags)) : $tags; |
256 | if ($tags === false) { | ||
257 | return $this->filterUntagged($visibility); | ||
258 | } | ||
259 | if (empty($tags)) { | 268 | if (empty($tags)) { |
260 | return $this->noFilter($visibility); | 269 | return $this->noFilter($visibility); |
261 | } | 270 | } |
diff --git a/application/PageBuilder.php b/application/PageBuilder.php index c86621a2..7a42400d 100644 --- a/application/PageBuilder.php +++ b/application/PageBuilder.php | |||
@@ -78,6 +78,7 @@ class PageBuilder | |||
78 | $this->tpl->assign('version', shaarli_version); | 78 | $this->tpl->assign('version', shaarli_version); |
79 | $this->tpl->assign('scripturl', index_url($_SERVER)); | 79 | $this->tpl->assign('scripturl', index_url($_SERVER)); |
80 | $this->tpl->assign('privateonly', !empty($_SESSION['privateonly'])); // Show only private links? | 80 | $this->tpl->assign('privateonly', !empty($_SESSION['privateonly'])); // Show only private links? |
81 | $this->tpl->assign('untaggedonly', !empty($_SESSION['untaggedonly'])); | ||
81 | $this->tpl->assign('pagetitle', $this->conf->get('general.title', 'Shaarli')); | 82 | $this->tpl->assign('pagetitle', $this->conf->get('general.title', 'Shaarli')); |
82 | if ($this->conf->exists('general.header_link')) { | 83 | if ($this->conf->exists('general.header_link')) { |
83 | $this->tpl->assign('titleLink', $this->conf->get('general.header_link')); | 84 | $this->tpl->assign('titleLink', $this->conf->get('general.header_link')); |
@@ -287,6 +287,7 @@ function logout() { | |||
287 | unset($_SESSION['ip']); | 287 | unset($_SESSION['ip']); |
288 | unset($_SESSION['username']); | 288 | unset($_SESSION['username']); |
289 | unset($_SESSION['privateonly']); | 289 | unset($_SESSION['privateonly']); |
290 | unset($_SESSION['untaggedonly']); | ||
290 | } | 291 | } |
291 | setcookie('shaarli_staySignedIn', FALSE, 0, WEB_PATH); | 292 | setcookie('shaarli_staySignedIn', FALSE, 0, WEB_PATH); |
292 | } | 293 | } |
@@ -685,6 +686,7 @@ function showLinkList($PAGE, $LINKSDB, $conf, $pluginManager) { | |||
685 | * @param ConfigManager $conf Configuration Manager instance. | 686 | * @param ConfigManager $conf Configuration Manager instance. |
686 | * @param PluginManager $pluginManager Plugin Manager instance, | 687 | * @param PluginManager $pluginManager Plugin Manager instance, |
687 | * @param LinkDB $LINKSDB | 688 | * @param LinkDB $LINKSDB |
689 | * @param History $history instance | ||
688 | */ | 690 | */ |
689 | function renderPage($conf, $pluginManager, $LINKSDB, $history) | 691 | function renderPage($conf, $pluginManager, $LINKSDB, $history) |
690 | { | 692 | { |
@@ -1017,6 +1019,19 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1017 | exit; | 1019 | exit; |
1018 | } | 1020 | } |
1019 | 1021 | ||
1022 | // -------- User wants to see only untagged links (toggle) | ||
1023 | if (isset($_GET['untaggedonly'])) { | ||
1024 | $_SESSION['untaggedonly'] = !$_SESSION['untaggedonly']; | ||
1025 | |||
1026 | if (! empty($_SERVER['HTTP_REFERER'])) { | ||
1027 | $location = generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('untaggedonly')); | ||
1028 | } else { | ||
1029 | $location = '?'; | ||
1030 | } | ||
1031 | header('Location: '. $location); | ||
1032 | exit; | ||
1033 | } | ||
1034 | |||
1020 | // -------- Handle other actions allowed for non-logged in users: | 1035 | // -------- Handle other actions allowed for non-logged in users: |
1021 | if (!isLoggedIn()) | 1036 | if (!isLoggedIn()) |
1022 | { | 1037 | { |
@@ -1184,41 +1199,18 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history) | |||
1184 | die('Wrong token.'); | 1199 | die('Wrong token.'); |
1185 | } | 1200 | } |
1186 | 1201 | ||
1187 | // Delete a tag: | 1202 | $alteredLinks = $LINKSDB->renameTag(escape($_POST['fromtag']), escape($_POST['totag'])); |
1188 | if (isset($_POST['deletetag']) && !empty($_POST['fromtag'])) { | 1203 | $LINKSDB->save($conf->get('resource.page_cache')); |
1189 | $needle = trim($_POST['fromtag']); | 1204 | foreach ($alteredLinks as $link) { |
1190 | // True for case-sensitive tag search. | 1205 | $history->updateLink($link); |
1191 | $linksToAlter = $LINKSDB->filterSearch(array('searchtags' => $needle), true); | ||
1192 | foreach($linksToAlter as $key=>$value) | ||
1193 | { | ||
1194 | $tags = explode(' ',trim($value['tags'])); | ||
1195 | unset($tags[array_search($needle,$tags)]); // Remove tag. | ||
1196 | $value['tags']=trim(implode(' ',$tags)); | ||
1197 | $LINKSDB[$key]=$value; | ||
1198 | $history->updateLink($LINKSDB[$key]); | ||
1199 | } | ||
1200 | $LINKSDB->save($conf->get('resource.page_cache')); | ||
1201 | echo '<script>alert("Tag was removed from '.count($linksToAlter).' links.");document.location=\'?do=changetag\';</script>'; | ||
1202 | exit; | ||
1203 | } | ||
1204 | |||
1205 | // Rename a tag: | ||
1206 | if (isset($_POST['renametag']) && !empty($_POST['fromtag']) && !empty($_POST['totag'])) { | ||
1207 | $needle = trim($_POST['fromtag']); | ||
1208 | // True for case-sensitive tag search. | ||
1209 | $linksToAlter = $LINKSDB->filterSearch(array('searchtags' => $needle), true); | ||
1210 | foreach($linksToAlter as $key=>$value) { | ||
1211 | $tags = preg_split('/\s+/', trim($value['tags'])); | ||
1212 | // Replace tags value. | ||
1213 | $tags[array_search($needle, $tags)] = trim($_POST['totag']); | ||
1214 | $value['tags'] = implode(' ', array_unique($tags)); | ||
1215 | $LINKSDB[$key] = $value; | ||
1216 | $history->updateLink($LINKSDB[$key]); | ||
1217 | } | ||
1218 | $LINKSDB->save($conf->get('resource.page_cache')); // Save to disk. | ||
1219 | echo '<script>alert("Tag was renamed in '.count($linksToAlter).' links.");document.location=\'?searchtags='.urlencode(escape($_POST['totag'])).'\';</script>'; | ||
1220 | exit; | ||
1221 | } | 1206 | } |
1207 | $delete = empty($_POST['totag']); | ||
1208 | $redirect = $delete ? 'do=changetag' : 'searchtags='. urlencode(escape($_POST['totag'])); | ||
1209 | $alert = $delete | ||
1210 | ? sprintf(t('The tag was removed from %d links.'), count($alteredLinks)) | ||
1211 | : sprintf(t('The tag was renamed in %d links.'), count($alteredLinks)); | ||
1212 | echo '<script>alert("'. $alert .'");document.location=\'?'. $redirect .'\';</script>'; | ||
1213 | exit; | ||
1222 | } | 1214 | } |
1223 | 1215 | ||
1224 | // -------- User wants to add a link without using the bookmarklet: Show form. | 1216 | // -------- User wants to add a link without using the bookmarklet: Show form. |
@@ -1651,7 +1643,7 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | |||
1651 | 'searchtags' => $searchtags, | 1643 | 'searchtags' => $searchtags, |
1652 | 'searchterm' => $searchterm, | 1644 | 'searchterm' => $searchterm, |
1653 | ]; | 1645 | ]; |
1654 | $linksToDisplay = $LINKSDB->filterSearch($request, false, $visibility); | 1646 | $linksToDisplay = $LINKSDB->filterSearch($request, false, $visibility, !empty($_SESSION['untaggedonly'])); |
1655 | } | 1647 | } |
1656 | 1648 | ||
1657 | // ---- Handle paging. | 1649 | // ---- Handle paging. |
@@ -2245,6 +2237,12 @@ if (!isset($_SESSION['LINKS_PER_PAGE'])) { | |||
2245 | $_SESSION['LINKS_PER_PAGE'] = $conf->get('general.links_per_page', 20); | 2237 | $_SESSION['LINKS_PER_PAGE'] = $conf->get('general.links_per_page', 20); |
2246 | } | 2238 | } |
2247 | 2239 | ||
2240 | try { | ||
2241 | $history = new History($conf->get('resource.history')); | ||
2242 | } catch(Exception $e) { | ||
2243 | die($e->getMessage()); | ||
2244 | } | ||
2245 | |||
2248 | $linkDb = new LinkDB( | 2246 | $linkDb = new LinkDB( |
2249 | $conf->get('resource.datastore'), | 2247 | $conf->get('resource.datastore'), |
2250 | isLoggedIn(), | 2248 | isLoggedIn(), |
@@ -2253,12 +2251,6 @@ $linkDb = new LinkDB( | |||
2253 | $conf->get('redirector.encode_url') | 2251 | $conf->get('redirector.encode_url') |
2254 | ); | 2252 | ); |
2255 | 2253 | ||
2256 | try { | ||
2257 | $history = new History($conf->get('resource.history')); | ||
2258 | } catch(Exception $e) { | ||
2259 | die($e->getMessage()); | ||
2260 | } | ||
2261 | |||
2262 | $container = new \Slim\Container(); | 2254 | $container = new \Slim\Container(); |
2263 | $container['conf'] = $conf; | 2255 | $container['conf'] = $conf; |
2264 | $container['plugins'] = $pluginManager; | 2256 | $container['plugins'] = $pluginManager; |
diff --git a/tests/LinkDBTest.php b/tests/LinkDBTest.php index 25438277..5b2f3667 100644 --- a/tests/LinkDBTest.php +++ b/tests/LinkDBTest.php | |||
@@ -487,4 +487,59 @@ class LinkDBTest extends PHPUnit_Framework_TestCase | |||
487 | $this->assertEquals($linkIds[$cpt++], $key); | 487 | $this->assertEquals($linkIds[$cpt++], $key); |
488 | } | 488 | } |
489 | } | 489 | } |
490 | |||
491 | /** | ||
492 | * Test rename tag with a valid value present in multiple links | ||
493 | */ | ||
494 | public function testRenameTagMultiple() | ||
495 | { | ||
496 | self::$refDB->write(self::$testDatastore); | ||
497 | $linkDB = new LinkDB(self::$testDatastore, true, false); | ||
498 | |||
499 | $res = $linkDB->renameTag('cartoon', 'Taz'); | ||
500 | $this->assertEquals(3, count($res)); | ||
501 | $this->assertContains(' Taz ', $linkDB[4]['tags']); | ||
502 | $this->assertContains(' Taz ', $linkDB[1]['tags']); | ||
503 | $this->assertContains(' Taz ', $linkDB[0]['tags']); | ||
504 | } | ||
505 | |||
506 | /** | ||
507 | * Test rename tag with a valid value | ||
508 | */ | ||
509 | public function testRenameTagCaseSensitive() | ||
510 | { | ||
511 | self::$refDB->write(self::$testDatastore); | ||
512 | $linkDB = new LinkDB(self::$testDatastore, true, false, ''); | ||
513 | |||
514 | $res = $linkDB->renameTag('sTuff', 'Taz'); | ||
515 | $this->assertEquals(1, count($res)); | ||
516 | $this->assertEquals('Taz', $linkDB[41]['tags']); | ||
517 | } | ||
518 | |||
519 | /** | ||
520 | * Test rename tag with invalid values | ||
521 | */ | ||
522 | public function testRenameTagInvalid() | ||
523 | { | ||
524 | $linkDB = new LinkDB(self::$testDatastore, false, false); | ||
525 | |||
526 | $this->assertFalse($linkDB->renameTag('', 'test')); | ||
527 | $this->assertFalse($linkDB->renameTag('', '')); | ||
528 | // tag non existent | ||
529 | $this->assertEquals([], $linkDB->renameTag('test', '')); | ||
530 | $this->assertEquals([], $linkDB->renameTag('test', 'retest')); | ||
531 | } | ||
532 | |||
533 | /** | ||
534 | * Test delete tag with a valid value | ||
535 | */ | ||
536 | public function testDeleteTag() | ||
537 | { | ||
538 | self::$refDB->write(self::$testDatastore); | ||
539 | $linkDB = new LinkDB(self::$testDatastore, true, false); | ||
540 | |||
541 | $res = $linkDB->renameTag('cartoon', null); | ||
542 | $this->assertEquals(3, count($res)); | ||
543 | $this->assertNotContains('cartoon', $linkDB[4]['tags']); | ||
544 | } | ||
490 | } | 545 | } |
diff --git a/tests/LinkFilterTest.php b/tests/LinkFilterTest.php index 74162358..d796d3a3 100644 --- a/tests/LinkFilterTest.php +++ b/tests/LinkFilterTest.php | |||
@@ -63,10 +63,9 @@ class LinkFilterTest extends PHPUnit_Framework_TestCase | |||
63 | count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '')) | 63 | count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, '')) |
64 | ); | 64 | ); |
65 | 65 | ||
66 | // Untagged only | ||
67 | $this->assertEquals( | 66 | $this->assertEquals( |
68 | self::$refDB->countUntaggedLinks(), | 67 | self::$refDB->countUntaggedLinks(), |
69 | count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, false)) | 68 | count(self::$linkFilter->filter(LinkFilter::$FILTER_TAG, /*$request=*/'', /*$casesensitive=*/false, /*$visibility=*/'all', /*$untaggedonly=*/true)) |
70 | ); | 69 | ); |
71 | 70 | ||
72 | $this->assertEquals( | 71 | $this->assertEquals( |
diff --git a/tpl/default/css/shaarli.css b/tpl/default/css/shaarli.css index 39bbd0a3..e1868c59 100644 --- a/tpl/default/css/shaarli.css +++ b/tpl/default/css/shaarli.css | |||
@@ -226,6 +226,12 @@ body, .pure-g [class*="pure-u"] { | |||
226 | border-radius: 2px; | 226 | border-radius: 2px; |
227 | color: #252525; | 227 | color: #252525; |
228 | } | 228 | } |
229 | @media screen and (max-width: 64em) { | ||
230 | .searchform { | ||
231 | max-width: 260px; | ||
232 | margin: 0 auto; | ||
233 | } | ||
234 | } | ||
229 | 235 | ||
230 | /* because chrome */ | 236 | /* because chrome */ |
231 | #search input[type="text"]::-webkit-input-placeholder, | 237 | #search input[type="text"]::-webkit-input-placeholder, |
@@ -236,43 +242,37 @@ body, .pure-g [class*="pure-u"] { | |||
236 | #search button, | 242 | #search button, |
237 | #search-tagcloud button, | 243 | #search-tagcloud button, |
238 | #search-linklist button { | 244 | #search-linklist button { |
239 | background: transparent; | 245 | padding: 4px 8px 6px 8px; |
246 | background-color: #1B926C; | ||
247 | color: #f5f5f5; | ||
240 | border: none; | 248 | border: none; |
249 | border-radius: 2px; | ||
241 | } | 250 | } |
242 | 251 | ||
243 | #search button { | 252 | #search-tagcloud button { |
244 | color: #f5f5f5; | 253 | width: 90%; |
245 | } | 254 | } |
246 | 255 | ||
247 | #search-linklist button { | 256 | @media screen and (max-width: 64em) { |
248 | color: #252525; | 257 | #search-linklist button { |
258 | width: 100%; | ||
259 | } | ||
260 | #search-linklist .awesomplete { | ||
261 | margin: 5px 0; | ||
262 | } | ||
249 | } | 263 | } |
250 | 264 | ||
251 | #search button:hover, | 265 | #search button:hover, |
252 | #search-linklist button:hover { | 266 | #search-linklist button:hover, |
253 | color: #fff; | ||
254 | } | ||
255 | #search-tagcloud button:hover { | 267 | #search-tagcloud button:hover { |
256 | color: #d0d0d0; | 268 | color: #d0d0d0; |
257 | } | 269 | } |
258 | 270 | ||
271 | #search, | ||
259 | #search-linklist { | 272 | #search-linklist { |
260 | padding: 5px 0; | 273 | padding: 6px 0; |
261 | } | 274 | } |
262 | 275 | ||
263 | @media screen and (min-width: 64em) { | ||
264 | #search .searchform, | ||
265 | #search-linklist .searchform { | ||
266 | margin-right: 25px; | ||
267 | text-align: right; | ||
268 | } | ||
269 | |||
270 | #search .tagfilter, | ||
271 | #search-linklist .tagfilter { | ||
272 | margin-left: 25px; | ||
273 | text-align: left; | ||
274 | } | ||
275 | } | ||
276 | @media screen and (max-width: 64em) { | 276 | @media screen and (max-width: 64em) { |
277 | #search, #search * { | 277 | #search, #search * { |
278 | visibility: hidden; | 278 | visibility: hidden; |
@@ -321,7 +321,6 @@ body, .pure-g [class*="pure-u"] { | |||
321 | } | 321 | } |
322 | 322 | ||
323 | .subheader-form input[type="text"], .subheader-form input[type="password"], .subheader-form .remember-me { | 323 | .subheader-form input[type="text"], .subheader-form input[type="password"], .subheader-form .remember-me { |
324 | margin: 0 0 5px 0; | ||
325 | padding: 5px 5px 3px 15px; | 324 | padding: 5px 5px 3px 15px; |
326 | height: 20px; | 325 | height: 20px; |
327 | width: 20%; | 326 | width: 20%; |
diff --git a/tpl/default/linklist.html b/tpl/default/linklist.html index 2568a5d6..685821e3 100644 --- a/tpl/default/linklist.html +++ b/tpl/default/linklist.html | |||
@@ -19,30 +19,21 @@ | |||
19 | 19 | ||
20 | <div id="search-linklist"> | 20 | <div id="search-linklist"> |
21 | 21 | ||
22 | <div class="pure-g"> | 22 | <form method="GET" class="pure-form searchform" name="searchform"> |
23 | <div class="pure-u-1 pure-u-lg-1-2"> | 23 | <input type="text" tabindex="1" name="searchterm" class="searchterm" placeholder="{'Search text'|t}" |
24 | <form method="GET" class="searchform" name="searchform"> | 24 | {if="!empty($search_term)"} |
25 | <input type="text" tabindex="1" name="searchterm" placeholder="{'Search text'|t}" | 25 | value="{$search_term}" |
26 | {if="!empty($search_term)"} | 26 | {/if} |
27 | value="{$search_term}" | 27 | > |
28 | {/if} | 28 | <input type="text" tabindex="2" name="searchtags" class="searchtags" placeholder="{'Filter by tag'|t}" |
29 | > | 29 | {if="!empty($search_tags)"} |
30 | <button type="submit" class="search-button"><i class="fa fa-search"></i></button> | 30 | value="{$search_tags}" |
31 | </form> | 31 | {/if} |
32 | </div> | 32 | autocomplete="off" data-multiple data-autofirst data-minChars="1" |
33 | <div class="pure-u-1 pure-u-lg-1-2"> | 33 | data-list="{loop="$tags"}{$key}, {/loop}" |
34 | <form method="GET" class="tagfilter" name="tagfilter"> | 34 | > |
35 | <input type="text" tabindex="2" name="searchtags" placeholder="{'Filter by tag'|t}" | 35 | <button type="submit" class="search-button"><i class="fa fa-search"></i></button> |
36 | {if="!empty($search_tags)"} | 36 | </form> |
37 | value="{$search_tags}" | ||
38 | {/if} | ||
39 | autocomplete="off" data-multiple data-autofirst data-minChars="1" | ||
40 | data-list="{loop="$tags"}{$key}, {/loop}" | ||
41 | > | ||
42 | <button type="submit" class="search-button"><i class="fa fa-search"></i></button> | ||
43 | </form> | ||
44 | </div> | ||
45 | </div> | ||
46 | </div> | 37 | </div> |
47 | 38 | ||
48 | {loop="$plugins_header.fields_toolbar"} | 39 | {loop="$plugins_header.fields_toolbar"} |
@@ -91,7 +82,7 @@ | |||
91 | <div id="searchcriteria">{'Nothing found.'|t}</div> | 82 | <div id="searchcriteria">{'Nothing found.'|t}</div> |
92 | </div> | 83 | </div> |
93 | </div> | 84 | </div> |
94 | {elseif="!empty($search_term) or $search_tags !== '' or !empty($visibility)"} | 85 | {elseif="!empty($search_term) or $search_tags !== '' or !empty($visibility) or $untaggedonly"} |
95 | <div class="pure-g pure-alert pure-alert-success search-result"> | 86 | <div class="pure-g pure-alert pure-alert-success search-result"> |
96 | <div class="pure-u-2-24"></div> | 87 | <div class="pure-u-2-24"></div> |
97 | <div class="pure-u-20-24"> | 88 | <div class="pure-u-20-24"> |
@@ -107,10 +98,6 @@ | |||
107 | <a href="?removetag={function="urlencode($value)"}">{$value}<span class="remove"><i class="fa fa-times"></i></span></a> | 98 | <a href="?removetag={function="urlencode($value)"}">{$value}<span class="remove"><i class="fa fa-times"></i></span></a> |
108 | </span> | 99 | </span> |
109 | {/loop} | 100 | {/loop} |
110 | {elseif="$search_tags === false"} | ||
111 | <span class="label label-tag" title="{'Remove tag'|t}"> | ||
112 | <a href="?">{'untagged'|t}<span class="remove"><i class="fa fa-times"></i></span></a> | ||
113 | </span> | ||
114 | {/if} | 101 | {/if} |
115 | {if="!empty($visibility)"} | 102 | {if="!empty($visibility)"} |
116 | {'with status'|t} | 103 | {'with status'|t} |
@@ -118,6 +105,11 @@ | |||
118 | {$visibility|t} | 105 | {$visibility|t} |
119 | </span> | 106 | </span> |
120 | {/if} | 107 | {/if} |
108 | {if="$untaggedonly"} | ||
109 | <span class="label label-private"> | ||
110 | {'without any tag'|t} | ||
111 | </span> | ||
112 | {/if} | ||
121 | </div> | 113 | </div> |
122 | </div> | 114 | </div> |
123 | {/if} | 115 | {/if} |
diff --git a/tpl/default/linklist.paging.html b/tpl/default/linklist.paging.html index d8c1e76e..41e9fa34 100644 --- a/tpl/default/linklist.paging.html +++ b/tpl/default/linklist.paging.html | |||
@@ -6,10 +6,13 @@ | |||
6 | {'Filters'|t} | 6 | {'Filters'|t} |
7 | </span> | 7 | </span> |
8 | {if="isLoggedIn()"} | 8 | {if="isLoggedIn()"} |
9 | <a href="?privateonly" title="{'Filter private links'|t}" | 9 | <a href="?privateonly" title="{'Filter private links'|t}" |
10 | class={if="$privateonly"}"filter-on"{else}"filter-off"{/if} | 10 | class={if="$privateonly"}"filter-on"{else}"filter-off"{/if} |
11 | ><i class="fa fa-key"></i></a> | 11 | ><i class="fa fa-key"></i></a> |
12 | {/if} | 12 | {/if} |
13 | <a href="?untaggedonly" title="{'Filter untagged links'|t}" | ||
14 | class={if="$untaggedonly"}"filter-on"{else}"filter-off"{/if} | ||
15 | ><i class="fa fa-tag"></i></a> | ||
13 | <a href="#" class="filter-off fold-all pure-u-lg-0" title="Fold all"> | 16 | <a href="#" class="filter-off fold-all pure-u-lg-0" title="Fold all"> |
14 | <i class="fa fa-chevron-up"></i> | 17 | <i class="fa fa-chevron-up"></i> |
15 | </a> | 18 | </a> |
@@ -55,4 +58,4 @@ | |||
55 | </a> | 58 | </a> |
56 | </div> | 59 | </div> |
57 | </div> | 60 | </div> |
58 | </div> \ No newline at end of file | 61 | </div> |
diff --git a/tpl/default/page.header.html b/tpl/default/page.header.html index 6c71a718..2411703c 100644 --- a/tpl/default/page.header.html +++ b/tpl/default/page.header.html | |||
@@ -97,30 +97,21 @@ | |||
97 | 97 | ||
98 | <div id="content"> | 98 | <div id="content"> |
99 | <div id="search" class="subheader-form"> | 99 | <div id="search" class="subheader-form"> |
100 | <div class="pure-g"> | 100 | <form method="GET" class="pure-form searchform" name="searchform"> |
101 | <div class="pure-u-1 pure-u-lg-1-2"> | 101 | <input type="text" tabindex="1" id="searchform_value" name="searchterm" placeholder="{'Search text'|t}" |
102 | <form method="GET" class="searchform" name="searchform"> | 102 | {if="!empty($search_term)"} |
103 | <input type="text" tabindex="1" id="searchform_value" name="searchterm" placeholder="{'Search text'|t}" | 103 | value="{$search_term}" |
104 | {if="!empty($search_term)"} | 104 | {/if} |
105 | value="{$search_term}" | 105 | > |
106 | {/if} | 106 | <input type="text" tabindex="2" name="searchtags" id="tagfilter_value" placeholder="{'Filter by tag'|t}" |
107 | > | 107 | {if="!empty($search_tags)"} |
108 | <button type="submit" class="search-button"><i class="fa fa-search"></i></button> | 108 | value="{$search_tags}" |
109 | </form> | 109 | {/if} |
110 | </div> | 110 | autocomplete="off" data-multiple data-autofirst data-minChars="1" |
111 | <div class="pure-u-1 pure-u-lg-1-2"> | 111 | data-list="{loop="$tags"}{$key}, {/loop}" |
112 | <form method="GET" class="tagfilter" name="tagfilter"> | 112 | > |
113 | <input type="text" tabindex="2" name="searchtags" id="tagfilter_value" placeholder="{'Filter by tag'|t}" | 113 | <button type="submit" class="search-button"><i class="fa fa-search"></i></button> |
114 | {if="!empty($search_tags)"} | 114 | </form> |
115 | value="{$search_tags}" | ||
116 | {/if} | ||
117 | autocomplete="off" data-multiple data-autofirst data-minChars="1" | ||
118 | data-list="{loop="$tags"}{$key}, {/loop}" | ||
119 | > | ||
120 | <button type="submit" class="search-button"><i class="fa fa-search"></i></button> | ||
121 | </form> | ||
122 | </div> | ||
123 | </div> | ||
124 | </div> | 115 | </div> |
125 | <div id="actions" class="subheader-form"> | 116 | <div id="actions" class="subheader-form"> |
126 | <div class="pure-g"> | 117 | <div class="pure-g"> |