diff --git a/application/Utils.php b/application/Utils.php index 952378ab..c5cd884b 100644 --- a/application/Utils.php +++ b/application/Utils.php @@ -323,6 +323,7 @@ function format_date($date, $time = true, $intl = true) IntlDateFormatter::LONG, $time ? IntlDateFormatter::LONG : IntlDateFormatter::NONE ); + $formatter->setTimeZone($date->getTimezone()); return $formatter->format($date); } diff --git a/application/api/ApiMiddleware.php b/application/api/ApiMiddleware.php index 9fb88358..cc7af18e 100644 --- a/application/api/ApiMiddleware.php +++ b/application/api/ApiMiddleware.php @@ -145,6 +145,7 @@ protected function setLinkDb($conf) { $linkDb = new BookmarkFileService( $conf, + $this->container->get('pluginManager'), $this->container->get('history'), new FlockMutex(fopen(SHAARLI_MUTEX_FILE, 'r'), 2), true diff --git a/application/api/controllers/Links.php b/application/api/controllers/Links.php index b83b2260..fe4bdc9f 100644 --- a/application/api/controllers/Links.php +++ b/application/api/controllers/Links.php @@ -36,13 +36,6 @@ class Links extends ApiController public function getLinks($request, $response) { $private = $request->getParam('visibility'); - $bookmarks = $this->bookmarkService->search( - [ - 'searchtags' => $request->getParam('searchtags', ''), - 'searchterm' => $request->getParam('searchterm', ''), - ], - $private - ); // Return bookmarks from the {offset}th link, starting from 0. $offset = $request->getParam('offset'); @@ -50,9 +43,6 @@ public function getLinks($request, $response) throw new ApiBadParametersException('Invalid offset'); } $offset = ! empty($offset) ? intval($offset) : 0; - if ($offset > count($bookmarks)) { - return $response->withJson([], 200, $this->jsonStyle); - } // limit parameter is either a number of bookmarks or 'all' for everything. $limit = $request->getParam('limit'); @@ -61,23 +51,33 @@ public function getLinks($request, $response) } elseif (ctype_digit($limit)) { $limit = intval($limit); } elseif ($limit === 'all') { - $limit = count($bookmarks); + $limit = null; } else { throw new ApiBadParametersException('Invalid limit'); } + $searchResult = $this->bookmarkService->search( + [ + 'searchtags' => $request->getParam('searchtags', ''), + 'searchterm' => $request->getParam('searchterm', ''), + ], + $private, + false, + false, + false, + [ + 'limit' => $limit, + 'offset' => $offset, + 'allowOutOfBounds' => true, + ] + ); + // 'environment' is set by Slim and encapsulate $_SERVER. $indexUrl = index_url($this->ci['environment']); $out = []; - $index = 0; - foreach ($bookmarks as $bookmark) { - if (count($out) >= $limit) { - break; - } - if ($index++ >= $offset) { - $out[] = ApiUtils::formatLink($bookmark, $indexUrl); - } + foreach ($searchResult->getBookmarks() as $bookmark) { + $out[] = ApiUtils::formatLink($bookmark, $indexUrl); } return $response->withJson($out, 200, $this->jsonStyle); diff --git a/application/api/controllers/Tags.php b/application/api/controllers/Tags.php index e60e00a7..5a23f6db 100644 --- a/application/api/controllers/Tags.php +++ b/application/api/controllers/Tags.php @@ -122,12 +122,12 @@ public function putTag($request, $response, $args) throw new ApiBadParametersException('New tag name is required in the request body'); } - $bookmarks = $this->bookmarkService->search( + $searchResult = $this->bookmarkService->search( ['searchtags' => $args['tagName']], BookmarkFilter::$ALL, true ); - foreach ($bookmarks as $bookmark) { + foreach ($searchResult->getBookmarks() as $bookmark) { $bookmark->renameTag($args['tagName'], $data['name']); $this->bookmarkService->set($bookmark, false); $this->history->updateLink($bookmark); @@ -157,12 +157,12 @@ public function deleteTag($request, $response, $args) throw new ApiTagNotFoundException(); } - $bookmarks = $this->bookmarkService->search( + $searchResult = $this->bookmarkService->search( ['searchtags' => $args['tagName']], BookmarkFilter::$ALL, true ); - foreach ($bookmarks as $bookmark) { + foreach ($searchResult->getBookmarks() as $bookmark) { $bookmark->deleteTag($args['tagName']); $this->bookmarkService->set($bookmark, false); $this->history->updateLink($bookmark); diff --git a/application/bookmark/BookmarkFileService.php b/application/bookmark/BookmarkFileService.php index 6666a251..9faf1c3b 100644 --- a/application/bookmark/BookmarkFileService.php +++ b/application/bookmark/BookmarkFileService.php @@ -15,6 +15,7 @@ use Shaarli\History; use Shaarli\Legacy\LegacyLinkDB; use Shaarli\Legacy\LegacyUpdater; +use Shaarli\Plugin\PluginManager; use Shaarli\Render\PageCacheManager; use Shaarli\Updater\UpdaterUtils; @@ -40,6 +41,9 @@ class BookmarkFileService implements BookmarkServiceInterface /** @var ConfigManager instance */ protected $conf; + /** @var PluginManager */ + protected $pluginManager; + /** @var History instance */ protected $history; @@ -55,8 +59,13 @@ class BookmarkFileService implements BookmarkServiceInterface /** * @inheritDoc */ - public function __construct(ConfigManager $conf, History $history, Mutex $mutex, bool $isLoggedIn) - { + public function __construct( + ConfigManager $conf, + PluginManager $pluginManager, + History $history, + Mutex $mutex, + bool $isLoggedIn + ) { $this->conf = $conf; $this->history = $history; $this->mutex = $mutex; @@ -65,7 +74,7 @@ public function __construct(ConfigManager $conf, History $history, Mutex $mutex, $this->isLoggedIn = $isLoggedIn; if (!$this->isLoggedIn && $this->conf->get('privacy.hide_public_links', false)) { - $this->bookmarks = []; + $this->bookmarks = new BookmarkArray(); } else { try { $this->bookmarks = $this->bookmarksIO->read(); @@ -91,7 +100,8 @@ public function __construct(ConfigManager $conf, History $history, Mutex $mutex, } } - $this->bookmarkFilter = new BookmarkFilter($this->bookmarks, $this->conf); + $this->pluginManager = $pluginManager; + $this->bookmarkFilter = new BookmarkFilter($this->bookmarks, $this->conf, $this->pluginManager); } /** @@ -129,8 +139,9 @@ public function search( string $visibility = null, bool $caseSensitive = false, bool $untaggedOnly = false, - bool $ignoreSticky = false - ) { + bool $ignoreSticky = false, + array $pagination = [] + ): SearchResult { if ($visibility === null) { $visibility = $this->isLoggedIn ? BookmarkFilter::$ALL : BookmarkFilter::$PUBLIC; } @@ -143,13 +154,20 @@ public function search( $this->bookmarks->reorder('DESC', true); } - return $this->bookmarkFilter->filter( + $bookmarks = $this->bookmarkFilter->filter( BookmarkFilter::$FILTER_TAG | BookmarkFilter::$FILTER_TEXT, [$searchTags, $searchTerm], $caseSensitive, $visibility, $untaggedOnly ); + + return SearchResult::getSearchResult( + $bookmarks, + $pagination['offset'] ?? 0, + $pagination['limit'] ?? null, + $pagination['allowOutOfBounds'] ?? false + ); } /** @@ -282,7 +300,7 @@ public function exists(int $id, string $visibility = null): bool */ public function count(string $visibility = null): int { - return count($this->search([], $visibility)); + return $this->search([], $visibility)->getResultCount(); } /** @@ -305,10 +323,10 @@ public function save(): void */ public function bookmarksCountPerTag(array $filteringTags = [], string $visibility = null): array { - $bookmarks = $this->search(['searchtags' => $filteringTags], $visibility); + $searchResult = $this->search(['searchtags' => $filteringTags], $visibility); $tags = []; $caseMapping = []; - foreach ($bookmarks as $bookmark) { + foreach ($searchResult->getBookmarks() as $bookmark) { foreach ($bookmark->getTags() as $tag) { if ( empty($tag) @@ -357,7 +375,7 @@ public function findByDate( $previous = null; $next = null; - foreach ($this->search([], null, false, false, true) as $bookmark) { + foreach ($this->search([], null, false, false, true)->getBookmarks() as $bookmark) { if ($to < $bookmark->getCreated()) { $next = $bookmark->getCreated(); } elseif ($from < $bookmark->getCreated() && $to > $bookmark->getCreated()) { @@ -378,7 +396,7 @@ public function findByDate( */ public function getLatest(): ?Bookmark { - foreach ($this->search([], null, false, false, true) as $bookmark) { + foreach ($this->search([], null, false, false, true)->getBookmarks() as $bookmark) { return $bookmark; } diff --git a/application/bookmark/BookmarkFilter.php b/application/bookmark/BookmarkFilter.php index db83c51c..8b41dbb8 100644 --- a/application/bookmark/BookmarkFilter.php +++ b/application/bookmark/BookmarkFilter.php @@ -4,9 +4,9 @@ namespace Shaarli\Bookmark; -use Exception; use Shaarli\Bookmark\Exception\BookmarkNotFoundException; use Shaarli\Config\ConfigManager; +use Shaarli\Plugin\PluginManager; /** * Class LinkFilter. @@ -30,11 +30,6 @@ class BookmarkFilter */ public static $FILTER_TAG = 'tags'; - /** - * @var string filter by day. - */ - public static $FILTER_DAY = 'FILTER_DAY'; - /** * @var string filter by day. */ @@ -62,13 +57,17 @@ class BookmarkFilter /** @var ConfigManager */ protected $conf; + /** @var PluginManager */ + protected $pluginManager; + /** * @param Bookmark[] $bookmarks initialization. */ - public function __construct($bookmarks, ConfigManager $conf) + public function __construct($bookmarks, ConfigManager $conf, PluginManager $pluginManager) { $this->bookmarks = $bookmarks; $this->conf = $conf; + $this->pluginManager = $pluginManager; } /** @@ -112,12 +111,12 @@ public function filter( $filtered = $this->bookmarks; } if (!empty($request[0])) { - $filtered = (new BookmarkFilter($filtered, $this->conf)) + $filtered = (new BookmarkFilter($filtered, $this->conf, $this->pluginManager)) ->filterTags($request[0], $casesensitive, $visibility) ; } if (!empty($request[1])) { - $filtered = (new BookmarkFilter($filtered, $this->conf)) + $filtered = (new BookmarkFilter($filtered, $this->conf, $this->pluginManager)) ->filterFulltext($request[1], $visibility) ; } @@ -130,8 +129,6 @@ public function filter( } else { return $this->filterTags($request, $casesensitive, $visibility); } - case self::$FILTER_DAY: - return $this->filterDay($request, $visibility); default: return $this->noFilter($visibility); } @@ -146,13 +143,20 @@ public function filter( */ private function noFilter(string $visibility = 'all') { - if ($visibility === 'all') { - return $this->bookmarks; - } - $out = []; foreach ($this->bookmarks as $key => $value) { - if ($value->isPrivate() && $visibility === 'private') { + if ( + !$this->pluginManager->filterSearchEntry( + $value, + ['source' => 'no_filter', 'visibility' => $visibility] + ) + ) { + continue; + } + + if ($visibility === 'all') { + $out[$key] = $value; + } elseif ($value->isPrivate() && $visibility === 'private') { $out[$key] = $value; } elseif (!$value->isPrivate() && $visibility === 'public') { $out[$key] = $value; @@ -233,18 +237,34 @@ private function filterFulltext(string $searchterms, string $visibility = 'all') } // Iterate over every stored link. - foreach ($this->bookmarks as $id => $link) { + foreach ($this->bookmarks as $id => $bookmark) { + if ( + !$this->pluginManager->filterSearchEntry( + $bookmark, + [ + 'source' => 'fulltext', + 'searchterms' => $searchterms, + 'andSearch' => $andSearch, + 'exactSearch' => $exactSearch, + 'excludeSearch' => $excludeSearch, + 'visibility' => $visibility + ] + ) + ) { + continue; + } + // ignore non private bookmarks when 'privatonly' is on. if ($visibility !== 'all') { - if (!$link->isPrivate() && $visibility === 'private') { + if (!$bookmark->isPrivate() && $visibility === 'private') { continue; - } elseif ($link->isPrivate() && $visibility === 'public') { + } elseif ($bookmark->isPrivate() && $visibility === 'public') { continue; } } $lengths = []; - $content = $this->buildFullTextSearchableLink($link, $lengths); + $content = $this->buildFullTextSearchableLink($bookmark, $lengths); // Be optimistic $found = true; @@ -270,68 +290,18 @@ private function filterFulltext(string $searchterms, string $visibility = 'all') } if ($found !== false) { - $link->addAdditionalContentEntry( + $bookmark->addAdditionalContentEntry( 'search_highlight', $this->postProcessFoundPositions($lengths, $foundPositions) ); - $filtered[$id] = $link; + $filtered[$id] = $bookmark; } } return $filtered; } - /** - * generate a regex fragment out of a tag - * - * @param string $tag to to generate regexs from. may start with '-' to negate, contain '*' as wildcard - * - * @return string generated regex fragment - */ - protected function tag2regex(string $tag): string - { - $tagsSeparator = $this->conf->get('general.tags_separator', ' '); - $len = strlen($tag); - if (!$len || $tag === "-" || $tag === "*") { - // nothing to search, return empty regex - return ''; - } - if ($tag[0] === "-") { - // query is negated - $i = 1; // use offset to start after '-' character - $regex = '(?!'; // create negative lookahead - } else { - $i = 0; // start at first character - $regex = '(?='; // use positive lookahead - } - // before tag may only be the separator or the beginning - $regex .= '.*(?:^|' . $tagsSeparator . ')'; - // iterate over string, separating it into placeholder and content - for (; $i < $len; $i++) { - if ($tag[$i] === '*') { - // placeholder found - $regex .= '[^' . $tagsSeparator . ']*?'; - } else { - // regular characters - $offset = strpos($tag, '*', $i); - if ($offset === false) { - // no placeholder found, set offset to end of string - $offset = $len; - } - // subtract one, as we want to get before the placeholder or end of string - $offset -= 1; - // we got a tag name that we want to search for. escape any regex characters to prevent conflicts. - $regex .= preg_quote(substr($tag, $i, $offset - $i + 1), '/'); - // move $i on - $i = $offset; - } - } - // after the tag may only be the separator or the end - $regex .= '(?:$|' . $tagsSeparator . '))'; - return $regex; - } - /** * Returns the list of bookmarks associated with a given list of tags * @@ -381,25 +351,39 @@ public function filterTags($tags, bool $casesensitive = false, string $visibilit $filtered = []; // iterate over each link - foreach ($this->bookmarks as $key => $link) { + foreach ($this->bookmarks as $key => $bookmark) { + if ( + !$this->pluginManager->filterSearchEntry( + $bookmark, + [ + 'source' => 'tags', + 'tags' => $tags, + 'casesensitive' => $casesensitive, + 'visibility' => $visibility + ] + ) + ) { + continue; + } + // check level of visibility // ignore non private bookmarks when 'privateonly' is on. if ($visibility !== 'all') { - if (!$link->isPrivate() && $visibility === 'private') { + if (!$bookmark->isPrivate() && $visibility === 'private') { continue; - } elseif ($link->isPrivate() && $visibility === 'public') { + } elseif ($bookmark->isPrivate() && $visibility === 'public') { continue; } } // build search string, start with tags of current link - $search = $link->getTagsString($tagsSeparator); - if (strlen(trim($link->getDescription())) && strpos($link->getDescription(), '#') !== false) { + $search = $bookmark->getTagsString($tagsSeparator); + if (strlen(trim($bookmark->getDescription())) && strpos($bookmark->getDescription(), '#') !== false) { // description given and at least one possible tag found $descTags = []; // find all tags in the form of #tag in the description preg_match_all( '/(?getDescription(), + $bookmark->getDescription(), $descTags ); if (count($descTags[1])) { @@ -412,8 +396,9 @@ public function filterTags($tags, bool $casesensitive = false, string $visibilit // this entry does _not_ match our regex continue; } - $filtered[$key] = $link; + $filtered[$key] = $bookmark; } + return $filtered; } @@ -427,55 +412,30 @@ public function filterTags($tags, bool $casesensitive = false, string $visibilit public function filterUntagged(string $visibility) { $filtered = []; - foreach ($this->bookmarks as $key => $link) { + foreach ($this->bookmarks as $key => $bookmark) { + if ( + !$this->pluginManager->filterSearchEntry( + $bookmark, + ['source' => 'untagged', 'visibility' => $visibility] + ) + ) { + continue; + } + if ($visibility !== 'all') { - if (!$link->isPrivate() && $visibility === 'private') { + if (!$bookmark->isPrivate() && $visibility === 'private') { continue; - } elseif ($link->isPrivate() && $visibility === 'public') { + } elseif ($bookmark->isPrivate() && $visibility === 'public') { continue; } } - if (empty($link->getTags())) { - $filtered[$key] = $link; - } - } - - return $filtered; - } - - /** - * Returns the list of articles for a given day, chronologically sorted - * - * Day must be in the form 'YYYYMMDD' (e.g. '20120125'), e.g. - * print_r($mydb->filterDay('20120125')); - * - * @param string $day day to filter. - * @param string $visibility return only all/private/public bookmarks. - - * @return Bookmark[] all link matching given day. - * - * @throws Exception if date format is invalid. - */ - public function filterDay(string $day, string $visibility) - { - if (!checkDateFormat('Ymd', $day)) { - throw new Exception('Invalid date format'); - } - - $filtered = []; - foreach ($this->bookmarks as $key => $bookmark) { - if ($visibility === static::$PUBLIC && $bookmark->isPrivate()) { - continue; - } - - if ($bookmark->getCreated()->format('Ymd') == $day) { + if (empty($bookmark->getTags())) { $filtered[$key] = $bookmark; } } - // sort by date ASC - return array_reverse($filtered, true); + return $filtered; } /** @@ -497,6 +457,56 @@ public static function tagsStrToArray(string $tags, bool $casesensitive): array return preg_split('/\s+/', $tagsOut, -1, PREG_SPLIT_NO_EMPTY); } + /** + * generate a regex fragment out of a tag + * + * @param string $tag to to generate regexs from. may start with '-' to negate, contain '*' as wildcard + * + * @return string generated regex fragment + */ + protected function tag2regex(string $tag): string + { + $tagsSeparator = $this->conf->get('general.tags_separator', ' '); + $len = strlen($tag); + if (!$len || $tag === "-" || $tag === "*") { + // nothing to search, return empty regex + return ''; + } + if ($tag[0] === "-") { + // query is negated + $i = 1; // use offset to start after '-' character + $regex = '(?!'; // create negative lookahead + } else { + $i = 0; // start at first character + $regex = '(?='; // use positive lookahead + } + // before tag may only be the separator or the beginning + $regex .= '.*(?:^|' . $tagsSeparator . ')'; + // iterate over string, separating it into placeholder and content + for (; $i < $len; $i++) { + if ($tag[$i] === '*') { + // placeholder found + $regex .= '[^' . $tagsSeparator . ']*?'; + } else { + // regular characters + $offset = strpos($tag, '*', $i); + if ($offset === false) { + // no placeholder found, set offset to end of string + $offset = $len; + } + // subtract one, as we want to get before the placeholder or end of string + $offset -= 1; + // we got a tag name that we want to search for. escape any regex characters to prevent conflicts. + $regex .= preg_quote(substr($tag, $i, $offset - $i + 1), '/'); + // move $i on + $i = $offset; + } + } + // after the tag may only be the separator or the end + $regex .= '(?:$|' . $tagsSeparator . '))'; + return $regex; + } + /** * This method finalize the content of the foundPositions array, * by associated all search results to their associated bookmark field, diff --git a/application/bookmark/BookmarkServiceInterface.php b/application/bookmark/BookmarkServiceInterface.php index 08cdbb4e..4b1f0daa 100644 --- a/application/bookmark/BookmarkServiceInterface.php +++ b/application/bookmark/BookmarkServiceInterface.php @@ -44,16 +44,18 @@ public function findByUrl(string $url): ?Bookmark; * @param bool $caseSensitive * @param bool $untaggedOnly * @param bool $ignoreSticky + * @param array $pagination This array can contain the following keys for pagination: limit, offset. * - * @return Bookmark[] + * @return SearchResult */ public function search( array $request = [], string $visibility = null, bool $caseSensitive = false, bool $untaggedOnly = false, - bool $ignoreSticky = false - ); + bool $ignoreSticky = false, + array $pagination = [] + ): SearchResult; /** * Get a single bookmark by its ID. diff --git a/application/bookmark/LinkUtils.php b/application/bookmark/LinkUtils.php index 0ab2d213..8fa2953a 100644 --- a/application/bookmark/LinkUtils.php +++ b/application/bookmark/LinkUtils.php @@ -1,6 +1,7 @@ $1', $text); + $format = function (array $match): string { + return '' . $match[1] . '' + ; + }; + + return preg_replace_callback($regex, $format, $text); } /** @@ -111,6 +123,9 @@ function text2clickable($text) */ function hashtag_autolink($description, $indexUrl = '') { + $tokens = '(?:' . BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_OPEN . ')' . + '(?:' . BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_CLOSE . ')' + ; /* * To support unicode: http://stackoverflow.com/a/35498078/1484919 * \p{Pc} - to match underscore @@ -118,9 +133,20 @@ function hashtag_autolink($description, $indexUrl = '') * \p{L} - letter from any language * \p{Mn} - any non marking space (accents, umlauts, etc) */ - $regex = '/(^|\s)#([\p{Pc}\p{N}\p{L}\p{Mn}]+)/mui'; - $replacement = '$1#$2'; - return preg_replace($regex, $replacement, $description); + $regex = '/(^|\s)#([\p{Pc}\p{N}\p{L}\p{Mn}' . $tokens . ']+)/mui'; + $format = function (array $match) use ($indexUrl): string { + $cleanMatch = str_replace( + BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_OPEN, + '', + str_replace(BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_CLOSE, '', $match[2]) + ); + return $match[1] . '' . + '#' . $match[2] . + ''; + }; + + return preg_replace_callback($regex, $format, $description); } /** diff --git a/application/bookmark/SearchResult.php b/application/bookmark/SearchResult.php new file mode 100644 index 00000000..c0bce311 --- /dev/null +++ b/application/bookmark/SearchResult.php @@ -0,0 +1,136 @@ +bookmarks = $bookmarks; + $this->resultCount = count($bookmarks); + $this->totalCount = $totalCount; + $this->limit = $limit; + $this->offset = $offset; + } + + /** + * Build a SearchResult from provided full result set and pagination settings. + * + * @param Bookmark[] $bookmarks Full set of result which will be filtered + * @param int $offset Start recording results from $offset + * @param int|null $limit End recording results after $limit bookmarks is reached + * @param bool $allowOutOfBounds Set to false to display the last page if the offset is out of bound, + * return empty result set otherwise (default: false) + * + * @return SearchResult + */ + public static function getSearchResult( + $bookmarks, + int $offset = 0, + ?int $limit = null, + bool $allowOutOfBounds = false + ): self { + $totalCount = count($bookmarks); + if (!$allowOutOfBounds && $offset > $totalCount) { + $offset = $limit === null ? 0 : $limit * -1; + } + + if ($bookmarks instanceof BookmarkArray) { + $buffer = []; + foreach ($bookmarks as $key => $value) { + $buffer[$key] = $value; + } + $bookmarks = $buffer; + } + + return new static( + array_slice($bookmarks, $offset, $limit, true), + $totalCount, + $offset, + $limit + ); + } + + /** @return Bookmark[] List of result bookmarks with pagination applied */ + public function getBookmarks(): array + { + return $this->bookmarks; + } + + /** @return int number of Bookmarks found, with pagination applied */ + public function getResultCount(): int + { + return $this->resultCount; + } + + /** @return int total number of result found */ + public function getTotalCount(): int + { + return $this->totalCount; + } + + /** @return int pagination: limit number of result bookmarks */ + public function getLimit(): ?int + { + return $this->limit; + } + + /** @return int pagination: offset to apply to complete result list */ + public function getOffset(): int + { + return $this->offset; + } + + /** @return int Current page of result set in complete results */ + public function getPage(): int + { + if (empty($this->limit)) { + return $this->offset === 0 ? 1 : 2; + } + $base = $this->offset >= 0 ? $this->offset : $this->totalCount + $this->offset; + + return (int) ceil($base / $this->limit) + 1; + } + + /** @return int Get the # of the last page */ + public function getLastPage(): int + { + if (empty($this->limit)) { + return $this->offset === 0 ? 1 : 2; + } + + return (int) ceil($this->totalCount / $this->limit); + } + + /** @return bool Either the current page is the last one or not */ + public function isLastPage(): bool + { + return $this->getPage() === $this->getLastPage(); + } + + /** @return bool Either the current page is the first one or not */ + public function isFirstPage(): bool + { + return $this->offset === 0; + } +} diff --git a/application/container/ContainerBuilder.php b/application/container/ContainerBuilder.php index 6d69a880..f66d75bd 100644 --- a/application/container/ContainerBuilder.php +++ b/application/container/ContainerBuilder.php @@ -95,6 +95,7 @@ public function build(): ShaarliContainer $container['bookmarkService'] = function (ShaarliContainer $container): BookmarkServiceInterface { return new BookmarkFileService( $container->conf, + $container->pluginManager, $container->history, new FlockMutex(fopen(SHAARLI_MUTEX_FILE, 'r'), 2), $container->loginManager->isLoggedIn() diff --git a/application/feed/FeedBuilder.php b/application/feed/FeedBuilder.php index ed62af26..d5d74fd1 100644 --- a/application/feed/FeedBuilder.php +++ b/application/feed/FeedBuilder.php @@ -102,22 +102,16 @@ public function buildData(string $feedType, ?array $userInput) $userInput['searchtags'] = false; } + $limit = $this->getLimit($userInput); + // Optionally filter the results: - $linksToDisplay = $this->linkDB->search($userInput ?? [], null, false, false, true); - - $nblinksToDisplay = $this->getNbLinks(count($linksToDisplay), $userInput); - - // Can't use array_keys() because $link is a LinkDB instance and not a real array. - $keys = []; - foreach ($linksToDisplay as $key => $value) { - $keys[] = $key; - } + $searchResult = $this->linkDB->search($userInput ?? [], null, false, false, true, ['limit' => $limit]); $pageaddr = escape(index_url($this->serverInfo)); $this->formatter->addContextData('index_url', $pageaddr); - $linkDisplayed = []; - for ($i = 0; $i < $nblinksToDisplay && $i < count($keys); $i++) { - $linkDisplayed[$keys[$i]] = $this->buildItem($feedType, $linksToDisplay[$keys[$i]], $pageaddr); + $links = []; + foreach ($searchResult->getBookmarks() as $key => $bookmark) { + $links[$key] = $this->buildItem($feedType, $bookmark, $pageaddr); } $data['language'] = $this->getTypeLanguage($feedType); @@ -128,7 +122,7 @@ public function buildData(string $feedType, ?array $userInput) $data['self_link'] = $pageaddr . $requestUri; $data['index_url'] = $pageaddr; $data['usepermalinks'] = $this->usePermalinks === true; - $data['links'] = $linkDisplayed; + $data['links'] = $links; return $data; } @@ -268,19 +262,18 @@ protected function getIsoDate(string $feedType, DateTime $date, $format = false) * If 'nb' not set or invalid, default value: $DEFAULT_NB_LINKS. * If 'nb' is set to 'all', display all filtered bookmarks (max parameter). * - * @param int $max maximum number of bookmarks to display. * @param array $userInput $_GET. * * @return int number of bookmarks to display. */ - protected function getNbLinks($max, ?array $userInput) + protected function getLimit(?array $userInput) { if (empty($userInput['nb'])) { return self::$DEFAULT_NB_LINKS; } if ($userInput['nb'] == 'all') { - return $max; + return null; } $intNb = intval($userInput['nb']); diff --git a/application/formatter/BookmarkDefaultFormatter.php b/application/formatter/BookmarkDefaultFormatter.php index 7e0afafc..7e93bf71 100644 --- a/application/formatter/BookmarkDefaultFormatter.php +++ b/application/formatter/BookmarkDefaultFormatter.php @@ -12,8 +12,8 @@ */ class BookmarkDefaultFormatter extends BookmarkFormatter { - protected const SEARCH_HIGHLIGHT_OPEN = '|@@HIGHLIGHT'; - protected const SEARCH_HIGHLIGHT_CLOSE = 'HIGHLIGHT@@|'; + public const SEARCH_HIGHLIGHT_OPEN = '||O_HIGHLIGHT'; + public const SEARCH_HIGHLIGHT_CLOSE = '||C_HIGHLIGHT'; /** * @inheritdoc diff --git a/application/formatter/BookmarkMarkdownExtraFormatter.php b/application/formatter/BookmarkMarkdownExtraFormatter.php index 0694b23f..da539bfd 100644 --- a/application/formatter/BookmarkMarkdownExtraFormatter.php +++ b/application/formatter/BookmarkMarkdownExtraFormatter.php @@ -3,6 +3,7 @@ namespace Shaarli\Formatter; use Shaarli\Config\ConfigManager; +use Shaarli\Formatter\Parsedown\ShaarliParsedownExtra; /** * Class BookmarkMarkdownExtraFormatter @@ -18,7 +19,6 @@ class BookmarkMarkdownExtraFormatter extends BookmarkMarkdownFormatter public function __construct(ConfigManager $conf, bool $isLoggedIn) { parent::__construct($conf, $isLoggedIn); - - $this->parsedown = new \ParsedownExtra(); + $this->parsedown = new ShaarliParsedownExtra(); } } diff --git a/application/formatter/BookmarkMarkdownFormatter.php b/application/formatter/BookmarkMarkdownFormatter.php index ee4e8dca..d4dccee6 100644 --- a/application/formatter/BookmarkMarkdownFormatter.php +++ b/application/formatter/BookmarkMarkdownFormatter.php @@ -3,6 +3,7 @@ namespace Shaarli\Formatter; use Shaarli\Config\ConfigManager; +use Shaarli\Formatter\Parsedown\ShaarliParsedown; /** * Class BookmarkMarkdownFormatter @@ -42,7 +43,7 @@ public function __construct(ConfigManager $conf, bool $isLoggedIn) { parent::__construct($conf, $isLoggedIn); - $this->parsedown = new \Parsedown(); + $this->parsedown = new ShaarliParsedown(); $this->escape = $conf->get('security.markdown_escape', true); $this->allowedProtocols = $conf->get('security.allowed_protocols', []); } @@ -128,6 +129,9 @@ function ($match) use ($allowedProtocols, $indexUrl) { protected function formatHashTags($description) { $indexUrl = ! empty($this->contextData['index_url']) ? $this->contextData['index_url'] : ''; + $tokens = '(?:' . BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_OPEN . ')' . + '(?:' . BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_CLOSE . ')' + ; /* * To support unicode: http://stackoverflow.com/a/35498078/1484919 @@ -136,8 +140,15 @@ protected function formatHashTags($description) * \p{L} - letter from any language * \p{Mn} - any non marking space (accents, umlauts, etc) */ - $regex = '/(^|\s)#([\p{Pc}\p{N}\p{L}\p{Mn}]+)/mui'; - $replacement = '$1[#$2](' . $indexUrl . './add-tag/$2)'; + $regex = '/(^|\s)#([\p{Pc}\p{N}\p{L}\p{Mn}' . $tokens . ']+)/mui'; + $replacement = function (array $match) use ($indexUrl): string { + $cleanMatch = str_replace( + BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_OPEN, + '', + str_replace(BookmarkDefaultFormatter::SEARCH_HIGHLIGHT_CLOSE, '', $match[2]) + ); + return $match[1] . '[#' . $match[2] . '](' . $indexUrl . './add-tag/' . $cleanMatch . ')'; + }; $descriptionLines = explode(PHP_EOL, $description); $descriptionOut = ''; @@ -156,7 +167,7 @@ protected function formatHashTags($description) } if (!$codeBlockOn && !$codeLineOn) { - $descriptionLine = preg_replace($regex, $replacement, $descriptionLine); + $descriptionLine = preg_replace_callback($regex, $replacement, $descriptionLine); } $descriptionOut .= $descriptionLine; diff --git a/application/formatter/Parsedown/ShaarliParsedown.php b/application/formatter/Parsedown/ShaarliParsedown.php new file mode 100644 index 00000000..8eb48fda --- /dev/null +++ b/application/formatter/Parsedown/ShaarliParsedown.php @@ -0,0 +1,15 @@ +shaarliFormatLink(parent::inlineLink($excerpt), true); + } + + /** + * @inheritDoc + */ + protected function inlineUrl($excerpt) + { + return $this->shaarliFormatLink(parent::inlineUrl($excerpt), false); + } + + /** + * Properly format markdown link: + * - remove highlight tags from HREF attribute + * - (optional) add highlight tags to link caption + * + * @param array|null $link Parsedown formatted link array. + * It can be empty. + * @param bool $fullWrap Add highlight tags the whole link caption + * + * @return array|null + */ + protected function shaarliFormatLink(?array $link, bool $fullWrap): ?array + { + // If open and clean search tokens are found in the link, process. + if ( + is_array($link) + && strpos($link['element']['attributes']['href'] ?? '', Formatter::SEARCH_HIGHLIGHT_OPEN) !== false + && strpos($link['element']['attributes']['href'] ?? '', Formatter::SEARCH_HIGHLIGHT_CLOSE) !== false + ) { + $link['element']['attributes']['href'] = $this->shaarliRemoveSearchTokens( + $link['element']['attributes']['href'] + ); + + if ($fullWrap) { + $link['element']['text'] = Formatter::SEARCH_HIGHLIGHT_OPEN . + $link['element']['text'] . + Formatter::SEARCH_HIGHLIGHT_CLOSE + ; + } + } + + return $link; + } + + /** + * Remove open and close tags from provided string. + * + * @param string $entry input + * + * @return string Striped input + */ + protected function shaarliRemoveSearchTokens(string $entry): string + { + $entry = str_replace(Formatter::SEARCH_HIGHLIGHT_OPEN, '', $entry); + $entry = str_replace(Formatter::SEARCH_HIGHLIGHT_CLOSE, '', $entry); + + return $entry; + } +} diff --git a/application/front/controller/admin/ManageTagController.php b/application/front/controller/admin/ManageTagController.php index 8675a0c5..1333cce7 100644 --- a/application/front/controller/admin/ManageTagController.php +++ b/application/front/controller/admin/ManageTagController.php @@ -57,9 +57,12 @@ public function save(Request $request, Response $response): Response } // TODO: move this to bookmark service - $count = 0; - $bookmarks = $this->container->bookmarkService->search(['searchtags' => $fromTag], BookmarkFilter::$ALL, true); - foreach ($bookmarks as $bookmark) { + $searchResult = $this->container->bookmarkService->search( + ['searchtags' => $fromTag], + BookmarkFilter::$ALL, + true + ); + foreach ($searchResult->getBookmarks() as $bookmark) { if (false === $isDelete) { $bookmark->renameTag($fromTag, $toTag); } else { @@ -68,11 +71,11 @@ public function save(Request $request, Response $response): Response $this->container->bookmarkService->set($bookmark, false); $this->container->history->updateLink($bookmark); - $count++; } $this->container->bookmarkService->save(); + $count = $searchResult->getResultCount(); if (true === $isDelete) { $alert = sprintf( t('The tag was removed from %d bookmark.', 'The tag was removed from %d bookmarks.', $count), diff --git a/application/front/controller/admin/ShaareManageController.php b/application/front/controller/admin/ShaareManageController.php index 35837baa..9633cd51 100644 --- a/application/front/controller/admin/ShaareManageController.php +++ b/application/front/controller/admin/ShaareManageController.php @@ -66,6 +66,10 @@ public function deleteBookmark(Request $request, Response $response): Response return $response->write(''); } + if ($request->getParam('source') === 'batch') { + return $response->withStatus(204); + } + // Don't redirect to permalink after deletion. return $this->redirectFromReferer($request, $response, ['shaare/']); } diff --git a/application/front/controller/admin/ThumbnailsController.php b/application/front/controller/admin/ThumbnailsController.php index 94d97d4b..5dfea096 100644 --- a/application/front/controller/admin/ThumbnailsController.php +++ b/application/front/controller/admin/ThumbnailsController.php @@ -22,7 +22,7 @@ class ThumbnailsController extends ShaarliAdminController public function index(Request $request, Response $response): Response { $ids = []; - foreach ($this->container->bookmarkService->search() as $bookmark) { + foreach ($this->container->bookmarkService->search()->getBookmarks() as $bookmark) { // A note or not HTTP(S) if ($bookmark->isNote() || !startsWith(strtolower($bookmark->getUrl()), 'http')) { continue; diff --git a/application/front/controller/visitor/BookmarkListController.php b/application/front/controller/visitor/BookmarkListController.php index fe8231be..4aae2652 100644 --- a/application/front/controller/visitor/BookmarkListController.php +++ b/application/front/controller/visitor/BookmarkListController.php @@ -33,10 +33,10 @@ public function index(Request $request, Response $response): Response $formatter = $this->container->formatterFactory->getFormatter(); $formatter->addContextData('base_path', $this->container->basePath); + $formatter->addContextData('index_url', index_url($this->container->environment)); $searchTags = normalize_spaces($request->getParam('searchtags') ?? ''); $searchTerm = escape(normalize_spaces($request->getParam('searchterm') ?? '')); - ; // Filter bookmarks according search parameters. $visibility = $this->container->sessionManager->getSessionParameter('visibility'); @@ -44,39 +44,26 @@ public function index(Request $request, Response $response): Response 'searchtags' => $searchTags, 'searchterm' => $searchTerm, ]; - $linksToDisplay = $this->container->bookmarkService->search( + + // Select articles according to paging. + $page = (int) ($request->getParam('page') ?? 1); + $page = $page < 1 ? 1 : $page; + $linksPerPage = $this->container->sessionManager->getSessionParameter('LINKS_PER_PAGE', 20) ?: 20; + + $searchResult = $this->container->bookmarkService->search( $search, $visibility, false, - !!$this->container->sessionManager->getSessionParameter('untaggedonly') + !!$this->container->sessionManager->getSessionParameter('untaggedonly'), + false, + ['offset' => $linksPerPage * ($page - 1), 'limit' => $linksPerPage] ) ?? []; - // ---- Handle paging. - $keys = []; - foreach ($linksToDisplay as $key => $value) { - $keys[] = $key; - } - - $linksPerPage = $this->container->sessionManager->getSessionParameter('LINKS_PER_PAGE', 20) ?: 20; - - // Select articles according to paging. - $pageCount = (int) ceil(count($keys) / $linksPerPage) ?: 1; - $page = (int) $request->getParam('page') ?? 1; - $page = $page < 1 ? 1 : $page; - $page = $page > $pageCount ? $pageCount : $page; - - // Start index. - $i = ($page - 1) * $linksPerPage; - $end = $i + $linksPerPage; - - $linkDisp = []; $save = false; - while ($i < $end && $i < count($keys)) { - $save = $this->updateThumbnail($linksToDisplay[$keys[$i]], false) || $save; - $link = $formatter->format($linksToDisplay[$keys[$i]]); - - $linkDisp[$keys[$i]] = $link; - $i++; + $links = []; + foreach ($searchResult->getBookmarks() as $key => $bookmark) { + $save = $this->updateThumbnail($bookmark, false) || $save; + $links[$key] = $formatter->format($bookmark); } if ($save) { @@ -86,15 +73,10 @@ public function index(Request $request, Response $response): Response // Compute paging navigation $searchtagsUrl = $searchTags === '' ? '' : '&searchtags=' . urlencode($searchTags); $searchtermUrl = $searchTerm === '' ? '' : '&searchterm=' . urlencode($searchTerm); + $page = $searchResult->getPage(); - $previous_page_url = ''; - if ($i !== count($keys)) { - $previous_page_url = '?page=' . ($page + 1) . $searchtermUrl . $searchtagsUrl; - } - $next_page_url = ''; - if ($page > 1) { - $next_page_url = '?page=' . ($page - 1) . $searchtermUrl . $searchtagsUrl; - } + $previousPageUrl = !$searchResult->isLastPage() ? '?page=' . ($page + 1) . $searchtermUrl . $searchtagsUrl : ''; + $nextPageUrl = !$searchResult->isFirstPage() ? '?page=' . ($page - 1) . $searchtermUrl . $searchtagsUrl : ''; $tagsSeparator = $this->container->conf->get('general.tags_separator', ' '); $searchTagsUrlEncoded = array_map('urlencode', tags_str2array($searchTags, $tagsSeparator)); @@ -104,16 +86,16 @@ public function index(Request $request, Response $response): Response $data = array_merge( $this->initializeTemplateVars(), [ - 'previous_page_url' => $previous_page_url, - 'next_page_url' => $next_page_url, + 'previous_page_url' => $previousPageUrl, + 'next_page_url' => $nextPageUrl, 'page_current' => $page, - 'page_max' => $pageCount, - 'result_count' => count($linksToDisplay), + 'page_max' => $searchResult->getLastPage(), + 'result_count' => $searchResult->getTotalCount(), 'search_term' => escape($searchTerm), 'search_tags' => escape($searchTags), 'search_tags_url' => $searchTagsUrlEncoded, 'visibility' => $visibility, - 'links' => $linkDisp, + 'links' => $links, ] ); @@ -157,6 +139,7 @@ public function permalink(Request $request, Response $response, array $args): Re $formatter = $this->container->formatterFactory->getFormatter(); $formatter->addContextData('base_path', $this->container->basePath); + $formatter->addContextData('index_url', index_url($this->container->environment)); $data = array_merge( $this->initializeTemplateVars(), diff --git a/application/front/controller/visitor/DailyController.php b/application/front/controller/visitor/DailyController.php index 29492a5f..3739ec16 100644 --- a/application/front/controller/visitor/DailyController.php +++ b/application/front/controller/visitor/DailyController.php @@ -100,7 +100,7 @@ public function rss(Request $request, Response $response): Response $days = []; $format = DailyPageHelper::getFormatByType($type); $length = DailyPageHelper::getRssLengthByType($type); - foreach ($this->container->bookmarkService->search() as $bookmark) { + foreach ($this->container->bookmarkService->search()->getBookmarks() as $bookmark) { $day = $bookmark->getCreated()->format($format); // Stop iterating after DAILY_RSS_NB_DAYS entries diff --git a/application/front/controller/visitor/PictureWallController.php b/application/front/controller/visitor/PictureWallController.php index 23553ee6..9c8f07d7 100644 --- a/application/front/controller/visitor/PictureWallController.php +++ b/application/front/controller/visitor/PictureWallController.php @@ -30,19 +30,19 @@ public function index(Request $request, Response $response): Response ); // Optionally filter the results: - $links = $this->container->bookmarkService->search($request->getQueryParams()); - $linksToDisplay = []; + $bookmarks = $this->container->bookmarkService->search($request->getQueryParams())->getBookmarks(); + $links = []; // Get only bookmarks which have a thumbnail. // Note: we do not retrieve thumbnails here, the request is too heavy. $formatter = $this->container->formatterFactory->getFormatter('raw'); - foreach ($links as $key => $link) { - if (!empty($link->getThumbnail())) { - $linksToDisplay[] = $formatter->format($link); + foreach ($bookmarks as $key => $bookmark) { + if (!empty($bookmark->getThumbnail())) { + $links[] = $formatter->format($bookmark); } } - $data = ['linksToDisplay' => $linksToDisplay]; + $data = ['linksToDisplay' => $links]; $this->executePageHooks('render_picwall', $data, TemplatePage::PICTURE_WALL); foreach ($data as $key => $value) { diff --git a/application/front/controller/visitor/ShaarliVisitorController.php b/application/front/controller/visitor/ShaarliVisitorController.php index ae946c59..d3f28f2f 100644 --- a/application/front/controller/visitor/ShaarliVisitorController.php +++ b/application/front/controller/visitor/ShaarliVisitorController.php @@ -56,6 +56,10 @@ protected function assignAllView(array $data): self protected function render(string $template): string { + // Legacy key that used to be injected by PluginManager + $this->assignView('_PAGE_', $template); + $this->assignView('template', $template); + $this->assignView('linkcount', $this->container->bookmarkService->count(BookmarkFilter::$ALL)); $this->assignView('privateLinkcount', $this->container->bookmarkService->count(BookmarkFilter::$PRIVATE)); diff --git a/application/helper/ApplicationUtils.php b/application/helper/ApplicationUtils.php index a6c03aae..f79998b5 100644 --- a/application/helper/ApplicationUtils.php +++ b/application/helper/ApplicationUtils.php @@ -37,7 +37,7 @@ public static function getLatestGitVersionCode($url, $timeout = 2) { list($headers, $data) = get_http_response($url, $timeout); - if (strpos($headers[0], '200 OK') === false) { + if (preg_match('#HTTP/[\d\.]+ 200(?: OK)?#', $headers[0]) !== 1) { error_log('Failed to retrieve ' . $url); return false; } diff --git a/application/netscape/NetscapeBookmarkUtils.php b/application/netscape/NetscapeBookmarkUtils.php index 2d97b4c8..20715bd0 100644 --- a/application/netscape/NetscapeBookmarkUtils.php +++ b/application/netscape/NetscapeBookmarkUtils.php @@ -64,7 +64,7 @@ public function filterAndFormat( } $bookmarkLinks = []; - foreach ($this->bookmarkService->search([], $selection) as $bookmark) { + foreach ($this->bookmarkService->search([], $selection)->getBookmarks() as $bookmark) { $link = $formatter->format($bookmark); $link['taglist'] = implode(',', $bookmark->getTags()); if ($bookmark->isNote() && $prependNoteUrl) { diff --git a/application/plugin/PluginManager.php b/application/plugin/PluginManager.php index 7fc0cb04..939db1ea 100644 --- a/application/plugin/PluginManager.php +++ b/application/plugin/PluginManager.php @@ -2,6 +2,7 @@ namespace Shaarli\Plugin; +use Shaarli\Bookmark\Bookmark; use Shaarli\Config\ConfigManager; use Shaarli\Plugin\Exception\PluginFileNotFoundException; use Shaarli\Plugin\Exception\PluginInvalidRouteException; @@ -45,6 +46,9 @@ class PluginManager */ protected $errors; + /** @var callable[]|null Preloaded list of hook function for filterSearchEntry() */ + protected $filterSearchEntryHooks = null; + /** * Plugins subdirectory. * @@ -273,6 +277,14 @@ public function getRegisteredRoutes(): array return $this->registeredRoutes; } + /** + * @return array List of registered filter_search_entry hooks + */ + public function getFilterSearchEntryHooks(): ?array + { + return $this->filterSearchEntryHooks; + } + /** * Return the list of encountered errors. * @@ -283,6 +295,50 @@ public function getErrors() return $this->errors; } + /** + * Apply additional filter on every search result of BookmarkFilter calling plugins hooks. + * + * @param Bookmark $bookmark To check. + * @param array $context Additional info about search context, depends on the search source. + * + * @return bool True if the result must be kept in search results, false otherwise. + */ + public function filterSearchEntry(Bookmark $bookmark, array $context): bool + { + if ($this->filterSearchEntryHooks === null) { + $this->loadFilterSearchEntryHooks(); + } + + if ($this->filterSearchEntryHooks === []) { + return true; + } + + foreach ($this->filterSearchEntryHooks as $filterSearchEntryHook) { + if ($filterSearchEntryHook($bookmark, $context) === false) { + return false; + } + } + + return true; + } + + /** + * filterSearchEntry() method will be called for every search result, + * so for performances we preload existing functions to invoke them directly. + */ + protected function loadFilterSearchEntryHooks(): void + { + $this->filterSearchEntryHooks = []; + + foreach ($this->loadedPlugins as $plugin) { + $hookFunction = $this->buildHookName('filter_search_entry', $plugin); + + if (function_exists($hookFunction)) { + $this->filterSearchEntryHooks[] = $hookFunction; + } + } + } + /** * Checks whether provided input is valid to register a new route. * It must contain keys `method`, `route`, `callable` (all strings). diff --git a/application/updater/Updater.php b/application/updater/Updater.php index 4f557d0f..11b6c051 100644 --- a/application/updater/Updater.php +++ b/application/updater/Updater.php @@ -152,7 +152,7 @@ public function updateMethodMigrateExistingNotesUrl(): bool { $updated = false; - foreach ($this->bookmarkService->search() as $bookmark) { + foreach ($this->bookmarkService->search()->getBookmarks() as $bookmark) { if ( $bookmark->isNote() && startsWith($bookmark->getUrl(), '?') diff --git a/assets/common/js/shaare-batch.js b/assets/common/js/shaare-batch.js index 557325ee..6fc16faf 100644 --- a/assets/common/js/shaare-batch.js +++ b/assets/common/js/shaare-batch.js @@ -4,7 +4,11 @@ const sendBookmarkForm = (basePath, formElement) => { const formData = new FormData(); [...inputs].forEach((input) => { - formData.append(input.getAttribute('name'), input.value); + if (input.getAttribute('type') === 'checkbox') { + formData.append(input.getAttribute('name'), input.checked); + } else { + formData.append(input.getAttribute('name'), input.value); + } }); return new Promise((resolve, reject) => { @@ -26,9 +30,9 @@ const sendBookmarkForm = (basePath, formElement) => { const sendBookmarkDelete = (buttonElement, formElement) => ( new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); - xhr.open('GET', buttonElement.href); + xhr.open('GET', `${buttonElement.href}&source=batch`); xhr.onload = () => { - if (xhr.status !== 200) { + if (xhr.status !== 204) { alert(`An error occurred. Return code: ${xhr.status}`); reject(); } else { @@ -100,7 +104,7 @@ const redirectIfEmptyBatch = (basePath, formElements, path) => { }); Promise.all(promises).then(() => { - window.location.href = basePath || '/'; + window.location.href = `${basePath}/`; }); }); }); diff --git a/composer.lock b/composer.lock index 0023df88..f2f9c7f1 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "arthurhoaro/web-thumbnailer", - "version": "v2.0.3", + "version": "v2.0.4", "source": { "type": "git", "url": "https://github.com/ArthurHoaro/web-thumbnailer.git", - "reference": "39bfd4f3136d9e6096496b9720e877326cfe4775" + "reference": "7780ddc0f44fccdce6cddb86d1db0354810290d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ArthurHoaro/web-thumbnailer/zipball/39bfd4f3136d9e6096496b9720e877326cfe4775", - "reference": "39bfd4f3136d9e6096496b9720e877326cfe4775", + "url": "https://api.github.com/repos/ArthurHoaro/web-thumbnailer/zipball/7780ddc0f44fccdce6cddb86d1db0354810290d0", + "reference": "7780ddc0f44fccdce6cddb86d1db0354810290d0", "shasum": "" }, "require": { @@ -53,9 +53,9 @@ "description": "PHP library which will retrieve a thumbnail for any given URL", "support": { "issues": "https://github.com/ArthurHoaro/web-thumbnailer/issues", - "source": "https://github.com/ArthurHoaro/web-thumbnailer/tree/v2.0.3" + "source": "https://github.com/ArthurHoaro/web-thumbnailer/tree/v2.0.4" }, - "time": "2020-09-29T15:51:03+00:00" + "time": "2021-02-22T10:43:01+00:00" }, { "name": "erusev/parsedown", diff --git a/doc/md/Docker.md b/doc/md/Docker.md index fc406c00..64c42d77 100644 --- a/doc/md/Docker.md +++ b/doc/md/Docker.md @@ -194,7 +194,7 @@ $ docker logs -f # delete unused images to free up disk space $ docker system prune --images # delete unused volumes to free up disk space (CAUTION all data in unused volumes will be lost) -$ docker system prunt --volumes +$ docker system prune --volumes # delete unused containers $ docker system prune ``` diff --git a/doc/md/Server-configuration.md b/doc/md/Server-configuration.md index a49b6033..e4086dca 100644 --- a/doc/md/Server-configuration.md +++ b/doc/md/Server-configuration.md @@ -199,6 +199,8 @@ sudo nano /etc/apache2/sites-available/shaarli.mydomain.org.conf Require all denied + DirectoryIndex index.php + Require all granted diff --git a/doc/md/dev/Plugin-system.md b/doc/md/dev/Plugin-system.md index 79654011..0ada57ea 100644 --- a/doc/md/dev/Plugin-system.md +++ b/doc/md/dev/Plugin-system.md @@ -27,7 +27,6 @@ You should have the following tree view: | |---| demo_plugin.php ``` - ### Plugin initialization At the beginning of Shaarli execution, all enabled plugins are loaded. At this point, the plugin system looks for an `init()` function in the .php to execute and run it if it exists. This function must be named this way, and takes the `ConfigManager` as parameter. @@ -209,6 +208,7 @@ If it's still not working, please [open an issue](https://github.com/shaarli/Sha | [save_link](#save_link) | Allow to alter the link being saved in the datastore. | | [delete_link](#delete_link) | Allow to do an action before a link is deleted from the datastore. | | [save_plugin_parameters](#save_plugin_parameters) | Allow to manipulate plugin parameters before they're saved. | +| [filter_search_entry](#filter_search_entry) | Add custom filters to Shaarli search engine | #### render_header @@ -565,6 +565,23 @@ the array will contain an entry with `MYPLUGIN_PARAMETER` as a key. Also [special data](#special-data). +#### filter_search_entry + +Triggered for *every* bookmark when Shaarli's BookmarkService method `search()` is used. +Any custom filter can be added to filter out bookmarks from search results. + +The hook **must** return either: + - `true` to keep bookmark entry in search result set + - `false` to discard bookmark entry in result set + +> Note: custom filters are called *before* default filters are applied. + +##### Parameters + +- `Shaarli\Bookmark\Bookmark` object: entry to evaluate +- $context `array`: additional information provided depending on what search is currently used, +the user request, etc. + ## Guide for template designers ### Plugin administration diff --git a/inc/languages/de/LC_MESSAGES/shaarli.po b/inc/languages/de/LC_MESSAGES/shaarli.po index 34d29ce8..26249b72 100644 --- a/inc/languages/de/LC_MESSAGES/shaarli.po +++ b/inc/languages/de/LC_MESSAGES/shaarli.po @@ -2,15 +2,15 @@ msgid "" msgstr "" "Project-Id-Version: Shaarli\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-31 09:09+0200\n" -"PO-Revision-Date: 2018-03-31 09:12+0200\n" +"POT-Creation-Date: 2021-01-23 23:57+0100\n" +"PO-Revision-Date: 2021-01-24 00:37+0100\n" "Last-Translator: \n" "Language-Team: Shaarli\n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.0.6\n" +"X-Generator: Poedit 2.4.2\n" "X-Poedit-Basepath: ../../../..\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SourceCharset: UTF-8\n" @@ -19,7 +19,614 @@ msgstr "" "X-Poedit-SearchPathExcluded-0: node_modules\n" "X-Poedit-SearchPathExcluded-1: vendor\n" -#: application/ApplicationUtils.php:153 +#: application/History.php:181 +msgid "History file isn't readable or writable" +msgstr "Protokolldatei nicht lesbar oder beschreibbar" + +#: application/History.php:192 +msgid "Could not parse history file" +msgstr "Protokolldatei konnte nicht analysiert werden" + +#: application/Languages.php:184 +msgid "Automatic" +msgstr "Automatisch" + +#: application/Languages.php:185 +msgid "German" +msgstr "Deutsch" + +#: application/Languages.php:186 +msgid "English" +msgstr "Englisch" + +#: application/Languages.php:187 +msgid "French" +msgstr "Französisch" + +#: application/Languages.php:188 +msgid "Japanese" +msgstr "Japanisch" + +#: application/Languages.php:189 +msgid "Russian" +msgstr "Russisch" + +#: application/Thumbnailer.php:62 +msgid "" +"php-gd extension must be loaded to use thumbnails. Thumbnails are now " +"disabled. Please reload the page." +msgstr "" +"Die Erweiterung php-gd muss geladen werden, um Miniaturansichten " +"(Thumbnails) verwenden zu können. Thumbnails sind jetzt deaktiviert. Bitte " +"lade die Seite neu." + +#: application/Utils.php:405 tests/UtilsTest.php:327 +msgid "Setting not set" +msgstr "Einstellung nicht gesetzt" + +#: application/Utils.php:412 tests/UtilsTest.php:325 tests/UtilsTest.php:326 +msgid "Unlimited" +msgstr "Unbegrenzt" + +#: application/Utils.php:415 tests/UtilsTest.php:322 tests/UtilsTest.php:323 +#: tests/UtilsTest.php:337 +msgid "B" +msgstr "B" + +#: application/Utils.php:415 tests/UtilsTest.php:316 tests/UtilsTest.php:317 +#: tests/UtilsTest.php:324 +msgid "kiB" +msgstr "kiB" + +#: application/Utils.php:415 tests/UtilsTest.php:318 tests/UtilsTest.php:319 +#: tests/UtilsTest.php:335 tests/UtilsTest.php:336 +msgid "MiB" +msgstr "MiB" + +#: application/Utils.php:415 tests/UtilsTest.php:320 tests/UtilsTest.php:321 +msgid "GiB" +msgstr "GiB" + +#: application/bookmark/BookmarkFileService.php:185 +#: application/bookmark/BookmarkFileService.php:207 +#: application/bookmark/BookmarkFileService.php:229 +#: application/bookmark/BookmarkFileService.php:243 +msgid "You're not authorized to alter the datastore" +msgstr "Du bist nicht berechtigt, den Datenspeicher zu ändern" + +#: application/bookmark/BookmarkFileService.php:210 +msgid "This bookmarks already exists" +msgstr "Diese Lesezeichen sind bereits vorhanden" + +#: application/bookmark/BookmarkInitializer.php:42 +msgid "(private bookmark with thumbnail demo)" +msgstr "(privates Lesezeichen mit Thumbnail-Demo)" + +#: application/bookmark/BookmarkInitializer.php:45 +msgid "" +"Shaarli will automatically pick up the thumbnail for links to a variety of " +"websites.\n" +"\n" +"Explore your new Shaarli instance by trying out controls and menus.\n" +"Visit the project on [Github](https://github.com/shaarli/Shaarli) or [the " +"documentation](https://shaarli.readthedocs.io/en/master/) to learn more " +"about Shaarli.\n" +"\n" +"Now you can edit or delete the default shaares.\n" +msgstr "" +"Shaarli holt sich automatisch das Miniaturbild (Thumbnail) für Links zu " +"verschiedenen Websites.\n" +"\n" +"Erkunde Deine neue Shaarli-Instanz, indem Du Steuerelemente und Menüs " +"ausprobierst.\n" +"Besuche das Projekt auf [Github](https://github.com/shaarli/Shaarli) oder " +"[die Dokumentation](https://shaarli.readthedocs.io/en/master/), um mehr über " +"Shaarli zu erfahren.\n" +"\n" +"Jetzt kannst Du die Standard-Shaares bearbeiten oder löschen.\n" + +#: application/bookmark/BookmarkInitializer.php:58 +msgid "Note: Shaare descriptions" +msgstr "Hinweis: Shaare Beschreibungen" + +#: application/bookmark/BookmarkInitializer.php:60 +msgid "" +"Adding a shaare without entering a URL creates a text-only \"note\" post " +"such as this one.\n" +"This note is private, so you are the only one able to see it while logged " +"in.\n" +"\n" +"You can use this to keep notes, post articles, code snippets, and much " +"more.\n" +"\n" +"The Markdown formatting setting allows you to format your notes and bookmark " +"description:\n" +"\n" +"### Title headings\n" +"\n" +"#### Multiple headings levels\n" +" * bullet lists\n" +" * _italic_ text\n" +" * **bold** text\n" +" * ~~strike through~~ text\n" +" * `code` blocks\n" +" * images\n" +" * [links](https://en.wikipedia.org/wiki/Markdown)\n" +"\n" +"Markdown also supports tables:\n" +"\n" +"| Name | Type | Color | Qty |\n" +"| ------- | --------- | ------ | ----- |\n" +"| Orange | Fruit | Orange | 126 |\n" +"| Apple | Fruit | Any | 62 |\n" +"| Lemon | Fruit | Yellow | 30 |\n" +"| Carrot | Vegetable | Red | 14 |\n" +msgstr "" +"Durch Hinzufügen eines Shaare ohne Eingabe einer URL wird ein Nur-Text-" +"Notizbeitrag wie dieser erstellt.\n" +"Diese Notiz ist privat, sodass Du sie als einziger sehen kannst, während Du " +"angemeldet bist.\n" +"\n" +"Du kannst dies nutzen, um Notizen zu machen, Artikel, Codefragmente und " +"vieles mehr zu veröffentlichen.\n" +"\n" +"Mit der Markdown-Formatierungseinstellung kannst Du Deine Notizen und die " +"Lesezeichenbeschreibung formatieren:\n" +"\n" +"### Titel-Überschrift\n" +"\n" +"#### Mehrere Überschriftenebenen\n" +" * bullet lists\n" +" * _kursiver_ Text\n" +" * **fetter** Text\n" +" * ~~durchgestrichener~~ Text\n" +" * `Code` Blöcke\n" +" * Bilder\n" +" * [Links](https://en.wikipedia.org/wiki/Markdown)\n" +"\n" +"Markdown unterstützt auch Tabellen:\n" +"\n" +"| Name | Typ | Farbe | Menge |\n" +"| ------- | --------- | ------ | ----- |\n" +"| Orange | Frucht | orange | 126 |\n" +"| Apfel | Frucht | verschiedene | 62 |\n" +"| Lemon | Frucht | gelb | 30 |\n" +"| Karotte | Gemüse | rot | 14 |\n" + +#: application/bookmark/BookmarkInitializer.php:94 +#: application/legacy/LegacyLinkDB.php:246 +#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:15 +#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48 +#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:15 +#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:48 +msgid "" +"The personal, minimalist, super-fast, database free, bookmarking service" +msgstr "" +"Der persönliche, minimalistische, superschnelle, datenbankfreie " +"Lesezeichenservice" + +#: application/bookmark/BookmarkInitializer.php:97 +msgid "" +"Welcome to Shaarli!\n" +"\n" +"Shaarli allows you to bookmark your favorite pages, and share them with " +"others or store them privately.\n" +"You can add a description to your bookmarks, such as this one, and tag " +"them.\n" +"\n" +"Create a new shaare by clicking the `+Shaare` button, or using any of the " +"recommended tools (browser extension, mobile app, bookmarklet, REST API, " +"etc.).\n" +"\n" +"You can easily retrieve your links, even with thousands of them, using the " +"internal search engine, or search through tags (e.g. this Shaare is tagged " +"with `shaarli` and `help`).\n" +"Hashtags such as #shaarli #help are also supported.\n" +"You can also filter the available [RSS feed](/feed/atom) and picture wall by " +"tag or plaintext search.\n" +"\n" +"We hope that you will enjoy using Shaarli, maintained with ❤️ by the " +"community!\n" +"Feel free to open [an issue](https://github.com/shaarli/Shaarli/issues) if " +"you have a suggestion or encounter an issue.\n" +msgstr "" +"Willkommen bei Shaarli!\n" +"\n" +"Mit Shaarli kannst Du Lesezeichen für Deine Lieblingsseiten anlegen und mit " +"anderen teilen oder privat speichern.\n" +"Du kannst Lesezeichen wie diesem eine Beschreibung hinzufügen und sie mit " +"Tags versehen.\n" +"\n" +"Erstelle eine neue Shaare, indem Du auf die Schaltfläche \"+ Shaare\" " +"klickst oder eines der empfohlenen Tools (Browsererweiterung, mobile App, " +"Lesezeichen, REST-API usw.) verwendest.\n" +"\n" +"Du kannst Deine Links - auch mit Tausenden von ihnen- einfach über die " +"interne Suchmaschine abrufen oder Tags durchsuchen (z. B. ist diese Shaare " +"mit \"shaarli\" und \"help\" gekennzeichnet).\n" +"Hashtags wie #shaarli #help werden ebenfalls unterstützt.\n" +"Du kannst den verfügbaren [RSS-Feed] (/feed/atom) und die Bilderwand auch " +"nach Tag- oder Klartextsuche filtern.\n" +"\n" +"Wir hoffen, dass Du Shaarli schätzen wirst, das von der Community mit ❤️ " +"gepflegt wird!\n" +"Du kannst gerne [ein Problem] (https://github.com/shaarli/Shaarli/issues) " +"öffnen, wenn Du einen Vorschlag hast oder auf ein Problem stößt.\n" + +#: application/bookmark/exception/BookmarkNotFoundException.php:14 +msgid "The link you are trying to reach does not exist or has been deleted." +msgstr "" +"Den Link, den du versucht zu erreichen, existiert nicht oder wurde gelöscht." + +#: application/config/ConfigJson.php:52 application/config/ConfigPhp.php:131 +msgid "" +"Shaarli could not create the config file. Please make sure Shaarli has the " +"right to write in the folder is it installed in." +msgstr "" +"Shaarli konnte die Konfigurationsdatei nicht erstellen. Bitte stelle sicher, " +"dass Shaarli das Recht hat, in den Ordner zu schreiben, in dem es " +"installiert ist." + +#: application/config/ConfigManager.php:137 +#: application/config/ConfigManager.php:164 +msgid "Invalid setting key parameter. String expected, got: " +msgstr "" +"Ungültiger Parameter für den Einstellungsschlüssel. Zeichenfolge erwartet, " +"erhalten: " + +#: application/config/exception/MissingFieldConfigException.php:20 +#, php-format +msgid "Configuration value is required for %s" +msgstr "Konfigurationswert erforderlich für %s" + +#: application/config/exception/PluginConfigOrderException.php:15 +msgid "An error occurred while trying to save plugins loading order." +msgstr "" +"Beim Versuch, die Ladereihenfolge der Plugins zu speichern, ist ein Fehler " +"aufgetreten." + +#: application/config/exception/UnauthorizedConfigException.php:15 +msgid "You are not authorized to alter config." +msgstr "Du bist nicht berechtigt, die Konfiguration zu ändern." + +#: application/exceptions/IOException.php:23 +msgid "Error accessing" +msgstr "Fehler beim Zugriff" + +#: application/feed/FeedBuilder.php:180 +msgid "Direct link" +msgstr "Direct Link" + +#: application/feed/FeedBuilder.php:182 +#: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:103 +#: tmp/dailyrss.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:179 +msgid "Permalink" +msgstr "Permalink" + +#: application/front/controller/admin/ConfigureController.php:56 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:24 +msgid "Configure" +msgstr "Konfigurieren" + +#: application/front/controller/admin/ConfigureController.php:106 +#: application/legacy/LegacyUpdater.php:539 +msgid "You have enabled or changed thumbnails mode." +msgstr "Du hast den Miniaturansichten-Modus aktiviert oder geändert." + +#: application/front/controller/admin/ConfigureController.php:108 +#: application/front/controller/admin/ServerController.php:81 +#: application/legacy/LegacyUpdater.php:540 +msgid "Please synchronize them." +msgstr "Bitte synchronisiere sie." + +#: application/front/controller/admin/ConfigureController.php:119 +#: application/front/controller/visitor/InstallController.php:154 +msgid "Error while writing config file after configuration update." +msgstr "" +"Fehler beim Schreiben der Einstellungsdatei nach der " +"Konfigurationsaktualisierung." + +#: application/front/controller/admin/ConfigureController.php:128 +msgid "Configuration was saved." +msgstr "Konfiguration wurde gespeichert." + +#: application/front/controller/admin/ExportController.php:26 +#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:64 +msgid "Export" +msgstr "Exportieren" + +#: application/front/controller/admin/ExportController.php:42 +msgid "Please select an export mode." +msgstr "Bitte wähle einen Export-Modus." + +#: application/front/controller/admin/ImportController.php:41 +#: tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:83 +msgid "Import" +msgstr "Importieren" + +#: application/front/controller/admin/ImportController.php:55 +msgid "No import file provided." +msgstr "Keine Import-Datei übergeben." + +#: application/front/controller/admin/ImportController.php:66 +#, php-format +msgid "" +"The file you are trying to upload is probably bigger than what this " +"webserver can accept (%s). Please upload in smaller chunks." +msgstr "" +"Die Datei, die du hochladen möchtest, ist wahrscheinlich größer als das, was " +"dieser Webserver akzeptieren kann (%s). Bitte lade in kleineren Blöcken hoch." + +#: application/front/controller/admin/ManageTagController.php:30 +msgid "whitespace" +msgstr "Leerzeichen" + +#: application/front/controller/admin/ManageTagController.php:35 +#: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 +msgid "Manage tags" +msgstr "Tags verwalten" + +#: application/front/controller/admin/ManageTagController.php:54 +msgid "Invalid tags provided." +msgstr "Ungültige Tags übergeben." + +#: application/front/controller/admin/ManageTagController.php:78 +#, php-format +msgid "The tag was removed from %d bookmark." +msgid_plural "The tag was removed from %d bookmarks." +msgstr[0] "Der Tag wurde aus dem Lesezeichen %d entfernt." +msgstr[1] "Der Tag wurde aus den Lesezeichen %d entfernt." + +#: application/front/controller/admin/ManageTagController.php:83 +#, php-format +msgid "The tag was renamed in %d bookmark." +msgid_plural "The tag was renamed in %d bookmarks." +msgstr[0] "Der Tag wurde im Lesezeichen %d umbenannt." +msgstr[1] "Der Tag wurde in den Lesezeichen %d umbenannt." + +#: application/front/controller/admin/ManageTagController.php:105 +msgid "Tags separator must be a single character." +msgstr "Tags müssen durch ein einzelnen Zeichen getrennt werden." + +#: application/front/controller/admin/ManageTagController.php:111 +msgid "These characters are reserved and can't be used as tags separator: " +msgstr "" +"Diese Zeichen sind reserviert und können nicht als Tag-Trennzeichen genutzt " +"werden: " + +#: application/front/controller/admin/PasswordController.php:28 +#: tmp/changepassword.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:35 +msgid "Change password" +msgstr "Passwort ändern" + +#: application/front/controller/admin/PasswordController.php:55 +msgid "You must provide the current and new password to change it." +msgstr "Du musst das aktuelle und das neue Passwort angeben zur Änderung." + +#: application/front/controller/admin/PasswordController.php:71 +msgid "The old password is not correct." +msgstr "Das alte Passwort ist nicht korrekt." + +#: application/front/controller/admin/PasswordController.php:97 +msgid "Your password has been changed" +msgstr "Dein Passwort wurde geändert" + +#: application/front/controller/admin/PluginsController.php:45 +msgid "Plugin Administration" +msgstr "Plugin Administration" + +#: application/front/controller/admin/PluginsController.php:76 +msgid "Setting successfully saved." +msgstr "Einstellung wurde erfolgreich gespeichert." + +#: application/front/controller/admin/PluginsController.php:79 +msgid "Error while saving plugin configuration: " +msgstr "Fehler beim Speichern der Plugin-Konfiguration: " + +#: application/front/controller/admin/ServerController.php:35 +msgid "Check disabled" +msgstr "Prüfung deaktiviert" + +#: application/front/controller/admin/ServerController.php:62 +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28 +msgid "Server administration" +msgstr "Server-Administration" + +#: application/front/controller/admin/ServerController.php:79 +msgid "Thumbnails cache has been cleared." +msgstr "Zwischenspeicher der Miniaturansichten wurde geleert." + +#: application/front/controller/admin/ServerController.php:90 +msgid "Shaarli's cache folder has been cleared!" +msgstr "Der Zwischenspeicher-Ordner von Shaarli wurde geleert!" + +#: application/front/controller/admin/ShaareAddController.php:26 +#: tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 +msgid "Shaare a new link" +msgstr "Teile einen neuen Link" + +#: application/front/controller/admin/ShaareManageController.php:35 +#: application/front/controller/admin/ShaareManageController.php:93 +msgid "Invalid bookmark ID provided." +msgstr "Ungültige Lesezeichen-ID bereitgestellt." + +#: application/front/controller/admin/ShaareManageController.php:47 +#: application/front/controller/admin/ShaareManageController.php:116 +#: application/front/controller/admin/ShaareManageController.php:156 +#: application/front/controller/admin/ShaarePublishController.php:82 +#, php-format +msgid "Bookmark with identifier %s could not be found." +msgstr "Lesezeichen mit der ID %s konnte nicht gefunden werden." + +#: application/front/controller/admin/ShaareManageController.php:101 +msgid "Invalid visibility provided." +msgstr "Ungültige Sichtbarkeit angegeben." + +#: application/front/controller/admin/ShaarePublishController.php:173 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:171 +msgid "Edit" +msgstr "Bearbeiten" + +#: application/front/controller/admin/ShaarePublishController.php:176 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:28 +msgid "Shaare" +msgstr "Teilen" + +#: application/front/controller/admin/ShaarePublishController.php:208 +msgid "Note: " +msgstr "Notiz: " + +#: application/front/controller/admin/ThumbnailsController.php:37 +#: tmp/thumbnails.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 +msgid "Thumbnails update" +msgstr "Thumbnail-Aktualisierung" + +#: application/front/controller/admin/ToolsController.php:31 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:33 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:33 +msgid "Tools" +msgstr "Tools" + +#: application/front/controller/visitor/BookmarkListController.php:121 +msgid "Search: " +msgstr "Suche: " + +#: application/front/controller/visitor/DailyController.php:201 +msgid "day" +msgstr "Tag" + +#: application/front/controller/visitor/DailyController.php:201 +#: application/front/controller/visitor/DailyController.php:204 +#: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:48 +msgid "Daily" +msgstr "Täglich" + +#: application/front/controller/visitor/DailyController.php:202 +msgid "week" +msgstr "Woche" + +#: application/front/controller/visitor/DailyController.php:202 +#: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 +msgid "Weekly" +msgstr "Wöchentlich" + +#: application/front/controller/visitor/DailyController.php:203 +msgid "month" +msgstr "Monat" + +#: application/front/controller/visitor/DailyController.php:203 +#: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:15 +msgid "Monthly" +msgstr "Monatlich" + +#: application/front/controller/visitor/ErrorController.php:30 +msgid "Error: " +msgstr "Fehler: " + +#: application/front/controller/visitor/ErrorController.php:34 +msgid "Please report it on Github." +msgstr "Bitte berichte es bei Github." + +#: application/front/controller/visitor/ErrorController.php:39 +msgid "An unexpected error occurred." +msgstr "Ein unerwarteter Fehler ist aufgetreten." + +#: application/front/controller/visitor/ErrorNotFoundController.php:25 +msgid "Requested page could not be found." +msgstr "Angefragte Seite kann nicht gefunden werden." + +#: application/front/controller/visitor/InstallController.php:70 +#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:22 +msgid "Install Shaarli" +msgstr "Installiere Shaarli" + +#: application/front/controller/visitor/InstallController.php:90 +#, php-format +msgid "" +"
Sessions do not seem to work correctly on your server.
Make sure the " +"variable \"session.save_path\" is set correctly in your PHP config, and that " +"you have write access to it.
It currently points to %s.
On some " +"browsers, accessing your server via a hostname like 'localhost' or any " +"custom hostname without a dot causes cookie storage to fail. We recommend " +"accessing your server via it's IP address or Fully Qualified Domain Name.
" +msgstr "" +"
Sessions scheinen auf deinem Server nicht korrekt zu funktionieren. "
+"
Stelle sicher, dass die Variable \"session.save_path\" in deiner PHP-" +"Konfiguration richtig eingestellt ist und dass du Schreibzugriff darauf hast." +"
Es verweist aktuell auf %s.
Bei einigen Browsern führt der Zugriff " +"auf deinen Server über einen Hostnamen wie \"localhost\" oder einen " +"beliebigen benutzerdefinierten Hostnamen ohne Punkt dazu, dass der Cookie-" +"Speicher fehlschlägt. Wir empfehlen den Zugriff auf deinen Server über die " +"IP-Adresse oder den Fully Qualified Domain Namen.
" + +#: application/front/controller/visitor/InstallController.php:162 +msgid "" +"Shaarli is now configured. Please login and start shaaring your bookmarks!" +msgstr "" +"Shaarli ist nun konfiguriert. Bitte melden Dich an und teile Deine " +"Lesezeichen!" + +#: application/front/controller/visitor/InstallController.php:176 +msgid "Insufficient permissions:" +msgstr "Unzureichende Berechtigungen:" + +#: application/front/controller/visitor/LoginController.php:46 +#: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 +#: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:77 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:101 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:77 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:101 +msgid "Login" +msgstr "Einloggen" + +#: application/front/controller/visitor/LoginController.php:78 +msgid "Wrong login/password." +msgstr "Falscher Loging/Passwort." + +#: application/front/controller/visitor/PictureWallController.php:29 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:43 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:43 +msgid "Picture wall" +msgstr "Bildwand" + +#: application/front/controller/visitor/TagCloudController.php:90 +msgid "Tag " +msgstr "Tag Liste " + +#: application/front/exceptions/AlreadyInstalledException.php:11 +msgid "Shaarli has already been installed. Login to edit the configuration." +msgstr "" +"Shaarlie wurde bereits installiert. Melde Dich an zum Ändern der " +"Konfiguration." + +#: application/front/exceptions/LoginBannedException.php:11 +msgid "" +"You have been banned after too many failed login attempts. Try again later." +msgstr "" +"Du wurdest nach zu vielen fehlgeschlagenen Anmeldeversuchen gesperrt. " +"Versuche es später noch einmal." + +#: application/front/exceptions/OpenShaarliPasswordException.php:16 +msgid "You are not supposed to change a password on an Open Shaarli." +msgstr "Du darfst kein Passwort für ein offenes Shaarli ändern." + +#: application/front/exceptions/ThumbnailsDisabledException.php:11 +msgid "Picture wall unavailable (thumbnails are disabled)." +msgstr "Bildwand ist nicht verfügbar (Miniaturansichten sind deaktiviert)." + +#: application/front/exceptions/WrongTokenException.php:16 +msgid "Wrong token." +msgstr "Falsches Zeichen." + +#: application/helper/ApplicationUtils.php:165 #, php-format msgid "" "Your PHP version is obsolete! Shaarli requires at least PHP %s, and thus " @@ -30,89 +637,100 @@ msgstr "" "daher nicht laufen. Deine PHP-Version hat bekannte Sicherheitslücken und " "sollte so bald wie möglich aktualisiert werden." -#: application/ApplicationUtils.php:183 application/ApplicationUtils.php:195 +#: application/helper/ApplicationUtils.php:200 +#: application/helper/ApplicationUtils.php:220 msgid "directory is not readable" msgstr "Verzeichnis ist nicht lesbar" -#: application/ApplicationUtils.php:198 +#: application/helper/ApplicationUtils.php:223 msgid "directory is not writable" msgstr "Verzeichnis ist nicht beschreibbar" -#: application/ApplicationUtils.php:216 +#: application/helper/ApplicationUtils.php:247 msgid "file is not readable" msgstr "Datei ist nicht lesbar" -#: application/ApplicationUtils.php:219 +#: application/helper/ApplicationUtils.php:250 msgid "file is not writable" msgstr "Datei ist nicht beschreibbar" -#: application/Cache.php:16 -#, php-format -msgid "Cannot purge %s: no directory" -msgstr "Kann nicht löschen, %s ist kein Verzeichnis" +#: application/helper/ApplicationUtils.php:265 +msgid "" +"Lock can not be acquired on the datastore. You might encounter concurrent " +"access issues." +msgstr "" +"Der Datenspeicher kann nicht gesperrt werden. Möglicherweise treten Probleme " +"beim gleichzeitigen Zugriff auf." -#: application/FeedBuilder.php:151 -msgid "Direct link" -msgstr "Direct Link" +#: application/helper/ApplicationUtils.php:298 +msgid "Configuration parsing" +msgstr "Konfigurationsanalyse" -#: application/FeedBuilder.php:153 -#: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:88 -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:178 -msgid "Permalink" -msgstr "Permalink" +#: application/helper/ApplicationUtils.php:299 +msgid "Slim Framework (routing, etc.)" +msgstr "Slim Framework (Routing usw.)" -#: application/History.php:174 -msgid "History file isn't readable or writable" -msgstr "Protokolldatei nicht lesbar oder beschreibbar" +#: application/helper/ApplicationUtils.php:300 +msgid "Multibyte (Unicode) string support" +msgstr "Unterstützung für Multibyte-Zeichenfolgen (Unicode)" -#: application/History.php:185 -msgid "Could not parse history file" -msgstr "Protokolldatei konnte nicht analysiert werden" +#: application/helper/ApplicationUtils.php:301 +msgid "Required to use thumbnails" +msgstr "Erforderlich, um Miniaturansichten (Thumbnails) zu verwenden" -#: application/Languages.php:177 -msgid "Automatic" -msgstr "Automatisch" +#: application/helper/ApplicationUtils.php:302 +msgid "Localized text sorting (e.g. e->è->f)" +msgstr "Lokalisierte Textsortierung (z. B. e->è->f)" -#: application/Languages.php:178 -msgid "English" -msgstr "Englisch" +#: application/helper/ApplicationUtils.php:303 +msgid "Better retrieval of bookmark metadata and thumbnail" +msgstr "Besserer Abruf von Lesezeichen-Metadaten und Miniaturansichten" -#: application/Languages.php:179 -msgid "French" -msgstr "Französisch" +#: application/helper/ApplicationUtils.php:304 +msgid "Use the translation system in gettext mode" +msgstr "Verwende das Übersetzungssystem im gettext-Modus" -#: application/Languages.php:180 -msgid "German" -msgstr "Deutsch" +#: application/helper/ApplicationUtils.php:305 +msgid "Login using LDAP server" +msgstr "Anmeldung mittels LDAP-Server" -#: application/LinkDB.php:136 +#: application/helper/DailyPageHelper.php:179 +msgid "Week" +msgstr "Woche" + +#: application/helper/DailyPageHelper.php:183 +msgid "Today" +msgstr "Heute" + +#: application/helper/DailyPageHelper.php:185 +msgid "Yesterday" +msgstr "Gestern" + +#: application/helper/FileUtils.php:100 +msgid "Provided path is not a directory." +msgstr "Der angegebene Pfad ist kein Verzeichnis." + +#: application/helper/FileUtils.php:104 +msgid "Trying to delete a folder outside of Shaarli path." +msgstr "Versuch, einen Ordner außerhalb des Shaarli-Pfads zu löschen." + +#: application/legacy/LegacyLinkDB.php:131 msgid "You are not authorized to add a link." msgstr "Du bist nicht berechtigt einen Link hinzuzufügen." -#: application/LinkDB.php:139 +#: application/legacy/LegacyLinkDB.php:134 msgid "Internal Error: A link should always have an id and URL." msgstr "Interner Fehler: Ein Link sollte immer eine ID und URL haben." -#: application/LinkDB.php:142 +#: application/legacy/LegacyLinkDB.php:137 msgid "You must specify an integer as a key." msgstr "Du musst eine Ganzzahl als Schlüssel angeben." -#: application/LinkDB.php:145 +#: application/legacy/LegacyLinkDB.php:140 msgid "Array offset and link ID must be equal." msgstr "Array-Offset und Link-ID müssen gleich sein." -#: application/LinkDB.php:251 -#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 -#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48 -#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:14 -#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:48 -msgid "" -"The personal, minimalist, super-fast, database free, bookmarking service" -msgstr "" -"Der persönliche, minimalistische, superschnelle, datenbankfreie " -"Lesezeichenservice" - -#: application/LinkDB.php:253 +#: application/legacy/LegacyLinkDB.php:249 msgid "" "Welcome to Shaarli! This is your first public bookmark. To edit or delete " "me, you must first login.\n" @@ -132,326 +750,115 @@ msgstr "" "Du verwendest die von der Community unterstützte Version des ursprünglichen " "Shaarli-Projekts von Sebastien Sauvage." -#: application/LinkDB.php:267 +#: application/legacy/LegacyLinkDB.php:266 msgid "My secret stuff... - Pastebin.com" msgstr "Meine geheimen Sachen... - Pastebin.com" -#: application/LinkDB.php:269 +#: application/legacy/LegacyLinkDB.php:268 msgid "Shhhh! I'm a private link only YOU can see. You can delete me too." msgstr "" "Pssst Ich bin ein privater Link, den nur du sehen kannst. Du kannst mich " "auch löschen." -#: application/LinkFilter.php:452 -msgid "The link you are trying to reach does not exist or has been deleted." -msgstr "" -"Den Link, den du versucht zu erreichen, existiert nicht oder wurde gelöscht." +#: application/legacy/LegacyUpdater.php:104 +msgid "Couldn't retrieve updater class methods." +msgstr "Die Updater-Klassenmethoden konnten nicht abgerufen werden." -#: application/NetscapeBookmarkUtils.php:35 +#: application/legacy/LegacyUpdater.php:540 +msgid "" +msgstr "" + +#: application/netscape/NetscapeBookmarkUtils.php:63 msgid "Invalid export selection:" msgstr "Ungültige Exportauswahl:" -#: application/NetscapeBookmarkUtils.php:81 +#: application/netscape/NetscapeBookmarkUtils.php:215 #, php-format msgid "File %s (%d bytes) " msgstr "Datei %s (%d bytes) " -#: application/NetscapeBookmarkUtils.php:83 +#: application/netscape/NetscapeBookmarkUtils.php:217 msgid "has an unknown file format. Nothing was imported." msgstr "hat ein unbekanntes Dateiformat. Es wurde nichts importiert." -#: application/NetscapeBookmarkUtils.php:86 +#: application/netscape/NetscapeBookmarkUtils.php:221 #, php-format msgid "" -"was successfully processed in %d seconds: %d links imported, %d links " -"overwritten, %d links skipped." +"was successfully processed in %d seconds: %d bookmarks imported, %d " +"bookmarks overwritten, %d bookmarks skipped." msgstr "" -"wurde erfolgreich in %d Sekunden verarbeitet: %d Links importiert, %d Links " -"überschrieben, %d Links übersprungen." +"wurde erfolgreich in %d Sekunden verarbeitet: %d Lesezeichen importiert, %d " +"Lesezeichen überschrieben, %d Lesezeichen übersprungen." -#: application/PageBuilder.php:168 -msgid "The page you are trying to reach does not exist or has been deleted." -msgstr "" -"Die Seite, die du erreichen möchtest, existiert nicht oder wurde gelöscht." +#: application/plugin/PluginManager.php:99 +#: application/plugin/PluginManager.php:137 +msgid " [plugin incompatibility]: " +msgstr " [Plugin-Inkompatibiliät]: " -#: application/PageBuilder.php:170 -msgid "404 Not Found" -msgstr "404 Nicht gefunden" - -#: application/PluginManager.php:243 +#: application/plugin/exception/PluginFileNotFoundException.php:22 #, php-format msgid "Plugin \"%s\" files not found." msgstr "Plugin \"%s\" Dateien nicht gefunden." -#: application/Updater.php:76 -msgid "Couldn't retrieve Updater class methods." -msgstr "Die Updater-Klassenmethoden konnten nicht abgerufen werden." +#: application/render/PageCacheManager.php:33 +#, php-format +msgid "Cannot purge %s: no directory" +msgstr "Kann nicht löschen, %s ist kein Verzeichnis" -#: application/Updater.php:532 +#: application/updater/exception/UpdaterException.php:51 msgid "An error occurred while running the update " msgstr "Beim Ausführen des Updates ist ein Fehler aufgetreten " -#: application/Updater.php:572 -msgid "Updates file path is not set, can't write updates." -msgstr "" -"Der Update-Dateipfad ist nicht festgelegt, es können keine Updates " -"geschrieben werden." +#: index.php:82 +msgid "Shared bookmarks on " +msgstr "Geteilte Lesezeichen auf " -#: application/Updater.php:577 -msgid "Unable to write updates in " -msgstr "Es ist nicht möglich Updates zu schreiben in " - -#: application/Utils.php:376 tests/UtilsTest.php:340 -msgid "Setting not set" -msgstr "Einstellung nicht gesetzt" - -#: application/Utils.php:383 tests/UtilsTest.php:338 tests/UtilsTest.php:339 -msgid "Unlimited" -msgstr "Unbegrenzt" - -#: application/Utils.php:386 tests/UtilsTest.php:335 tests/UtilsTest.php:336 -#: tests/UtilsTest.php:350 -msgid "B" -msgstr "B" - -#: application/Utils.php:386 tests/UtilsTest.php:329 tests/UtilsTest.php:330 -#: tests/UtilsTest.php:337 -msgid "kiB" -msgstr "kiB" - -#: application/Utils.php:386 tests/UtilsTest.php:331 tests/UtilsTest.php:332 -#: tests/UtilsTest.php:348 tests/UtilsTest.php:349 -msgid "MiB" -msgstr "MiB" - -#: application/Utils.php:386 tests/UtilsTest.php:333 tests/UtilsTest.php:334 -msgid "GiB" -msgstr "GiB" - -#: application/config/ConfigJson.php:52 application/config/ConfigPhp.php:121 -msgid "" -"Shaarli could not create the config file. Please make sure Shaarli has the " -"right to write in the folder is it installed in." -msgstr "" -"Shaarli konnte die Konfigurationsdatei nicht erstellen. Bitte stelle sicher, " -"dass Shaarli das Recht hat, in den Ordner zu schreiben, in dem es " -"installiert ist." - -#: application/config/ConfigManager.php:135 -msgid "Invalid setting key parameter. String expected, got: " -msgstr "" -"Ungültiger Parameter für den Einstellungsschlüssel. Zeichenfolge erwartet, " -"erhalten: " - -#: application/config/exception/MissingFieldConfigException.php:21 -#, php-format -msgid "Configuration value is required for %s" -msgstr "Konfigurationswert erforderlich für %s" - -#: application/config/exception/PluginConfigOrderException.php:15 -msgid "An error occurred while trying to save plugins loading order." -msgstr "" -"Beim Versuch, die Ladereihenfolge der Plugins zu speichern, ist ein Fehler " -"aufgetreten." - -#: application/config/exception/UnauthorizedConfigException.php:16 -msgid "You are not authorized to alter config." -msgstr "Du bist nicht berechtigt, die Konfiguration zu ändern." - -#: application/exceptions/IOException.php:19 -msgid "Error accessing" -msgstr "Fehler beim Zugriff" - -#: index.php:142 -msgid "Shared links on " -msgstr "Geteilte Links auf " - -#: index.php:164 -msgid "Insufficient permissions:" -msgstr "Unzureichende Berechtigungen:" - -#: index.php:303 -msgid "I said: NO. You are banned for the moment. Go away." -msgstr "Ich sagte NEIN. Du bist für den Moment gesperrt. Verschwinde." - -#: index.php:368 -msgid "Wrong login/password." -msgstr "Falscher Loging/Passwort." - -#: index.php:576 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:42 -msgid "Daily" -msgstr "Täglich" - -#: index.php:681 tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28 -#: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:44 -#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:71 -#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:95 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:71 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:95 -msgid "Login" -msgstr "Einloggen" - -#: index.php:722 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:39 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:39 -msgid "Picture wall" -msgstr "Bildwand" - -#: index.php:770 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:36 -#: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 -msgid "Tag cloud" -msgstr "Tag Cloud" - -#: index.php:803 tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 -msgid "Tag list" -msgstr "Tag Liste" - -#: index.php:1028 tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:31 -msgid "Tools" -msgstr "Tools" - -#: index.php:1037 -msgid "You are not supposed to change a password on an Open Shaarli." -msgstr "Du darfst kein Passwort für ein offenes Shaarli ändern." - -#: index.php:1042 index.php:1084 index.php:1160 index.php:1191 index.php:1291 -msgid "Wrong token." -msgstr "Falsches Zeichen." - -#: index.php:1047 -msgid "The old password is not correct." -msgstr "Das alte Passwort ist nicht korrekt." - -#: index.php:1067 -msgid "Your password has been changed" -msgstr "Dein Passwort wurde geändert" - -#: index.php:1072 -#: tmp/changepassword.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29 -msgid "Change password" -msgstr "Passwort ändern" - -#: index.php:1120 -msgid "Configuration was saved." -msgstr "Konfiguration wurde gespeichert." - -#: index.php:1143 tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:24 -msgid "Configure" -msgstr "Konfigurieren" - -#: index.php:1154 tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 -msgid "Manage tags" -msgstr "Tags verwalten" - -#: index.php:1172 -#, php-format -msgid "The tag was removed from %d link." -msgid_plural "The tag was removed from %d links." -msgstr[0] "Der Tag wurde aus dem Link %d entfernt." -msgstr[1] "Der Tag wurde aus den Links %d entfernt." - -#: index.php:1173 -#, php-format -msgid "The tag was renamed in %d link." -msgid_plural "The tag was renamed in %d links." -msgstr[0] "Der Tag wurde im Link %d umbenannt." -msgstr[1] "Der Tag wurde in den Links %d umbenannt." - -#: index.php:1181 tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 -msgid "Shaare a new link" -msgstr "Teile einen neuen Link" - -#: index.php:1351 tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:170 -msgid "Edit" -msgstr "Bearbeiten" - -#: index.php:1351 index.php:1421 -#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 -#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:26 -msgid "Shaare" -msgstr "Teilen" - -#: index.php:1390 -msgid "Note: " -msgstr "Notiz: " - -#: index.php:1430 tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:65 -msgid "Export" -msgstr "Exportieren" - -#: index.php:1492 tmp/import.b91ef64efc3688266305ea9b42e5017e.rtpl.php:83 -msgid "Import" -msgstr "Importieren" - -#: index.php:1502 -#, php-format -msgid "" -"The file you are trying to upload is probably bigger than what this " -"webserver can accept (%s). Please upload in smaller chunks." -msgstr "" -"Die Datei, die du hochladen möchtest, ist wahrscheinlich größer als das, was " -"dieser Webserver akzeptieren kann (%s). Bitte lade in kleineren Blöcken hoch." - -#: index.php:1541 tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:22 -msgid "Plugin administration" -msgstr "Plugin Adminstration" - -#: index.php:1706 -msgid "Search: " -msgstr "Suche: " - -#: index.php:1933 -#, php-format -msgid "" -"
Sessions do not seem to work correctly on your server.
Make sure the " -"variable \"session.save_path\" is set correctly in your PHP config, and that " -"you have write access to it.
It currently points to %s.
On some " -"browsers, accessing your server via a hostname like 'localhost' or any " -"custom hostname without a dot causes cookie storage to fail. We recommend " -"accessing your server via it's IP address or Fully Qualified Domain Name.
" -msgstr "" -"
Sessions scheinen auf deinem Server nicht korrekt zu funktionieren. "
-"
Stelle sicher, dass die Variable \"session.save_path\" in deiner PHP-" -"Konfiguration richtig eingestellt ist und dass du Schreibzugriff darauf hast." -"
Es verweist aktuell auf %s.
Bei einigen Browsern führt der Zugriff " -"auf deinen Server über einen Hostnamen wie \"localhost\" oder einen " -"beliebigen benutzerdefinierten Hostnamen ohne Punkt dazu, dass der Cookie-" -"Speicher fehlschlägt. Wir empfehlen den Zugriff auf deinen Server über die " -"IP-Adresse oder den Fully Qualified Domain Namen.
" - -#: index.php:1943 -msgid "Click to try again." -msgstr "Klicke um es erneut zu versuchen." - -#: plugins/addlink_toolbar/addlink_toolbar.php:29 +#: plugins/addlink_toolbar/addlink_toolbar.php:31 msgid "URI" msgstr "URI" -#: plugins/addlink_toolbar/addlink_toolbar.php:33 -#: tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 +#: plugins/addlink_toolbar/addlink_toolbar.php:35 +#: tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:20 msgid "Add link" msgstr "Link hinzufügen" -#: plugins/addlink_toolbar/addlink_toolbar.php:50 +#: plugins/addlink_toolbar/addlink_toolbar.php:52 msgid "Adds the addlink input on the linklist page." msgstr "Fügt die Link-hinzufügen-Eingabe auf der Linkliste hinzu." -#: plugins/archiveorg/archiveorg.php:23 +#: plugins/archiveorg/archiveorg.php:29 msgid "View on archive.org" msgstr "Auf archive.org ansehen" -#: plugins/archiveorg/archiveorg.php:36 +#: plugins/archiveorg/archiveorg.php:42 msgid "For each link, add an Archive.org icon." msgstr "Füge für jeden Link ein Archive.org Symbol hinzu." -#: plugins/demo_plugin/demo_plugin.php:465 +#: plugins/default_colors/default_colors.php:38 +msgid "" +"Default colors plugin error: This plugin is active and no custom color is " +"configured." +msgstr "" +"Fehler beim Plugin für Standardfarben: Dieses Plugin ist aktiv und es ist " +"keine benutzerdefinierte Farbe konfiguriert." + +#: plugins/default_colors/default_colors.php:127 +msgid "Override default theme colors. Use any CSS valid color." +msgstr "Überschreibe Standard-Thema-Farben. Benutze jede gültige CSS Farbe." + +#: plugins/default_colors/default_colors.php:128 +msgid "Main color (navbar green)" +msgstr "Haupt-Farbe (navbar grün)" + +#: plugins/default_colors/default_colors.php:129 +msgid "Background color (light grey)" +msgstr "Hintergrund-Farbe (hellgrau)" + +#: plugins/default_colors/default_colors.php:130 +msgid "Dark main color (e.g. visited links)" +msgstr "Dunkle Haupt-Farbe (z. B. besuchte Links)" + +#: plugins/demo_plugin/demo_plugin.php:495 msgid "" "A demo plugin covering all use cases for template designers and plugin " "developers." @@ -459,7 +866,16 @@ msgstr "" "Ein Demo-Plugin, das alle Anwendungsfälle für Template-Designer und Plugin-" "Entwickler abdeckt." -#: plugins/isso/isso.php:20 +#: plugins/demo_plugin/demo_plugin.php:496 +msgid "This is a parameter dedicated to the demo plugin. It'll be suffixed." +msgstr "" +"Dies ist ein Parameter, der dem Demo-Plugin gewidmet ist. Es wird angehängt." + +#: plugins/demo_plugin/demo_plugin.php:497 +msgid "Other demo parameter" +msgstr "Andere Demo-Parameter" + +#: plugins/isso/isso.php:22 msgid "" "Isso plugin error: Please define the \"ISSO_SERVER\" setting in the plugin " "administration page." @@ -467,47 +883,17 @@ msgstr "" "Isso Plugin Fehler: Bitte definiere die Einstellung \"ISSO_SERVER\" auf der " "Plugin-Administrationsseite." -#: plugins/isso/isso.php:63 +#: plugins/isso/isso.php:92 msgid "Let visitor comment your shaares on permalinks with Isso." msgstr "" "Lassen Sie Besucher ihre geteilten Links auf Permalinks mit Isso " "kommentieren." -#: plugins/isso/isso.php:64 +#: plugins/isso/isso.php:93 msgid "Isso server URL (without 'http://')" msgstr "Isso Server URL (ohne 'http://')" -#: plugins/markdown/markdown.php:158 -msgid "Description will be rendered with" -msgstr "Die Beschreibung wird dargestellt mit" - -#: plugins/markdown/markdown.php:159 -msgid "Markdown syntax documentation" -msgstr "Markdown Syntax Dokumentation" - -#: plugins/markdown/markdown.php:160 -msgid "Markdown syntax" -msgstr "Markdown Syntax" - -#: plugins/markdown/markdown.php:339 -msgid "" -"Render shaare description with Markdown syntax.
Warning:\n" -"If your shaared descriptions contained HTML tags before enabling the " -"markdown plugin,\n" -"enabling it might break your page.\n" -"See the
README." -msgstr "" -"Übertrage Teilen Beschreibung mit Markdown-Syntax.
Warnung:\n" -"Wenn deine Teilen Beschreibungen HTML-Tags enthielten, bevor das Markdown-" -"Plugin aktiviert wurde,\n" -"kann es deine Seite beschädigen, solltest du es aktivieren.\n" -"Weitere Informationen findest du in der README." - -#: plugins/piwik/piwik.php:21 +#: plugins/piwik/piwik.php:24 msgid "" "Piwik plugin error: Please define PIWIK_URL and PIWIK_SITEID in the plugin " "administration page." @@ -515,28 +901,28 @@ msgstr "" "Piwik-Plugin-Fehler: Bitte definiere die PIWIK_URL und PIWIK_SITEID auf der " "Plugin-Administrationsseite." -#: plugins/piwik/piwik.php:70 +#: plugins/piwik/piwik.php:73 msgid "A plugin that adds Piwik tracking code to Shaarli pages." msgstr "" "Ein Plugin, das einen Piwik-Tracking-Code auf Shaarli-Seiten hinzufügt." -#: plugins/piwik/piwik.php:71 +#: plugins/piwik/piwik.php:74 msgid "Piwik URL" msgstr "Piwik URL" -#: plugins/piwik/piwik.php:72 +#: plugins/piwik/piwik.php:75 msgid "Piwik site ID" msgstr "Piwik site ID" -#: plugins/playvideos/playvideos.php:22 +#: plugins/playvideos/playvideos.php:26 msgid "Video player" msgstr "Videoplayer" -#: plugins/playvideos/playvideos.php:25 +#: plugins/playvideos/playvideos.php:29 msgid "Play Videos" msgstr "Videos abspielen" -#: plugins/playvideos/playvideos.php:56 +#: plugins/playvideos/playvideos.php:60 msgid "Add a button in the toolbar allowing to watch all videos." msgstr "" "Fügt eine Schaltfläche in der Symbolleiste hinzu, mit der man alle Videos " @@ -546,30 +932,30 @@ msgstr "" msgid "plugins/playvideos/jquery-1.11.2.min.js" msgstr "plugins/playvideos/jquery-1.11.2.min.js" -#: plugins/pubsubhubbub/pubsubhubbub.php:69 +#: plugins/pubsubhubbub/pubsubhubbub.php:72 #, php-format msgid "Could not publish to PubSubHubbub: %s" msgstr "Veröffentlichung auf PubSubHubbub nicht möglich: %s" -#: plugins/pubsubhubbub/pubsubhubbub.php:95 +#: plugins/pubsubhubbub/pubsubhubbub.php:99 #, php-format msgid "Could not post to %s" msgstr "Kann nicht posten auf %s" -#: plugins/pubsubhubbub/pubsubhubbub.php:99 +#: plugins/pubsubhubbub/pubsubhubbub.php:103 #, php-format msgid "Bad response from the hub %s" msgstr "Ungültige Antwort vom Hub %s" -#: plugins/pubsubhubbub/pubsubhubbub.php:110 +#: plugins/pubsubhubbub/pubsubhubbub.php:114 msgid "Enable PubSubHubbub feed publishing." msgstr "Aktiviere PubSubHubbub Feed Veröffentlichung." -#: plugins/qrcode/qrcode.php:69 plugins/wallabag/wallabag.php:68 +#: plugins/qrcode/qrcode.php:74 plugins/wallabag/wallabag.php:72 msgid "For each link, add a QRCode icon." msgstr "Für jeden Link, füge eine QRCode Icon hinzu." -#: plugins/wallabag/wallabag.php:21 +#: plugins/wallabag/wallabag.php:22 msgid "" "Wallabag plugin error: Please define the \"WALLABAG_URL\" setting in the " "plugin administration page." @@ -577,23 +963,28 @@ msgstr "" "Wallabag Plugin Fehler: Bitte definiere die Einstellung \"WALLABAG_URL\" auf " "der Plugin Administrationsseite." -#: plugins/wallabag/wallabag.php:47 +#: plugins/wallabag/wallabag.php:49 msgid "Save to wallabag" msgstr "Auf Wallabag speichern" -#: plugins/wallabag/wallabag.php:69 +#: plugins/wallabag/wallabag.php:73 msgid "Wallabag API URL" msgstr "Wallabag API URL" -#: plugins/wallabag/wallabag.php:70 +#: plugins/wallabag/wallabag.php:74 msgid "Wallabag API version (1 or 2)" msgstr "Wallabag API version (1 oder 2)" #: tests/LanguagesTest.php:214 tests/LanguagesTest.php:227 -#: tests/languages/fr/LanguagesFrTest.php:160 -#: tests/languages/fr/LanguagesFrTest.php:173 -#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:81 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:81 +#: tests/languages/fr/LanguagesFrTest.php:159 +#: tests/languages/fr/LanguagesFrTest.php:172 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:46 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:87 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:139 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:87 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:139 +#: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:46 +#: tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:45 msgid "Search" msgid_plural "Search" msgstr[0] "Suche" @@ -607,6 +998,48 @@ msgstr "Entschuldige, hier gibt es nichts zu sehen." msgid "URL or leave empty to post a note" msgstr "URL oder leer lassen um eine Notiz hinzuzufügen" +#: tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29 +msgid "BULK CREATION" +msgstr "Mehrfach-Erstellung" + +#: tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:40 +msgid "Metadata asynchronous retrieval is disabled." +msgstr "Der asynchrone Metadatenabruf ist deaktiviert." + +#: tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 +msgid "" +"We recommend that you enable the setting general > " +"enable_async_metadata in your configuration file to use bulk link " +"creation." +msgstr "" +"Es wird empfohlen, dass Du die Einstellung \"allgemein > " +"enable_async_metadata in Deiner Konfigurationsdatei aktivierst, um die " +"Massen-Linkerstellung verwenden zu können." + +#: tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:56 +msgid "Shaare multiple new links" +msgstr "Shaare mehrere neuen Links" + +#: tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:59 +msgid "Add one URL per line to create multiple bookmarks." +msgstr "Füge eine URL pro Zeile hinzu, um mehrere Lesezeichen zu erstellen." + +#: tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:63 +#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:67 +msgid "Tags" +msgstr "Tags" + +#: tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:73 +#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:83 +#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:35 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:169 +msgid "Private" +msgstr "Privat" + +#: tmp/addlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:78 +msgid "Add links" +msgstr "Links hinzufügen" + #: tmp/changepassword.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 msgid "Current password" msgstr "Aktuelles Passwort" @@ -633,23 +1066,48 @@ msgid "Case sensitive" msgstr "Groß- / Kleinschreibung-unterscheidend" #: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:34 -msgid "Rename" -msgstr "Umbenennen" +#: tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:68 +msgid "Rename tag" +msgstr "Tag umbenennen" #: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:35 -#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:79 -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:172 -msgid "Delete" -msgstr "Löschen" +msgid "Delete tag" +msgstr "Lösche Tag" -#: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:39 +#: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:40 msgid "You can also edit tags in the" msgstr "Du kannst auch Tags bearbeiten in der" -#: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:39 +#: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:40 msgid "tag list" msgstr "Tag Liste" +#: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:47 +msgid "Change tags separator" +msgstr "Tags-Trennzeichen ändern" + +#: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:50 +msgid "Your current tag separator is" +msgstr "Ihr aktuelles Tag-Trennzeichen ist" + +#: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:53 +msgid "New separator" +msgstr "Neues Trennzeichen" + +#: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:58 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:355 +#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:121 +#: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:139 +#: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:199 +msgid "Save" +msgstr "Speichern" + +#: tmp/changetag.b91ef64efc3688266305ea9b42e5017e.rtpl.php:61 +msgid "Note that hashtags won't fully work with a non-whitespace separator." +msgstr "" +"Beachten Sie, dass Hashtags nicht vollständig mit einem Nicht-" +"Leerraumtrennzeichen funktionieren." + #: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29 msgid "title" msgstr "Titel" @@ -666,128 +1124,177 @@ msgstr "Standardwert" msgid "Theme" msgstr "Thema" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:87 -#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:78 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:85 +msgid "Description formatter" +msgstr "Beschreibungsformatierer" + +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:114 +#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:77 msgid "Language" msgstr "Sprache" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:116 -#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:102 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:143 +#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:101 msgid "Timezone" msgstr "Zeitzone" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:117 -#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:103 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:144 +#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:102 msgid "Continent" msgstr "Kontinent" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:117 -#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:103 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:144 +#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:102 msgid "City" msgstr "Stadt" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:164 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:191 msgid "Disable session cookie hijacking protection" msgstr "Deaktiviere Session Cookie Hijacking Schutz" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:166 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:193 msgid "Check this if you get disconnected or if your IP address changes often" msgstr "" "Überprüfe dies, wenn die Verbindung getrennt wird oder wenn sich deine IP-" "Adresse häufig ändert" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:183 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:210 msgid "Private links by default" msgstr "Standardmäßig Private Links" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:184 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:211 msgid "All new links are private by default" msgstr "Alle neuen Links sind standardmäßig privat" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:199 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:226 msgid "RSS direct links" msgstr "RSS Direkt Links" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:200 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:227 msgid "Check this to use direct URL instead of permalink in feeds" msgstr "" "Aktivieren diese Option, um direkte URLs anstelle von Permalinks in Feeds zu " "verwenden" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:215 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:242 msgid "Hide public links" msgstr "Verstecke öffentliche Links" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:216 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:243 msgid "Do not show any links if the user is not logged in" msgstr "Zeige keine Links, wenn der Benutzer nicht angemeldet ist" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:231 -#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:150 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:258 +#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:149 msgid "Check updates" msgstr "Auf Updates prüfen" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:232 -#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:152 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:259 +#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:151 msgid "Notify me when a new release is ready" msgstr "Benachrichtige mich, wenn eine neue Version zur Verfügung steht" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:247 -#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:169 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:274 +msgid "Automatically retrieve description for new bookmarks" +msgstr "Automatisches Abrufen der Beschreibung für neue Lesezeichen" + +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:275 +msgid "Shaarli will try to retrieve the description from meta HTML headers" +msgstr "Shaarli versucht, die Beschreibung aus Meta-HTML-Headern abzurufen" + +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:290 +#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:168 msgid "Enable REST API" msgstr "Aktiviere REST API" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:248 -#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:170 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:291 +#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:169 msgid "Allow third party software to use Shaarli such as mobile application" msgstr "" "Erlaube Software von Drittanbietern für Shaarli, wie z.B. die mobile " "Anwendung" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:263 +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:306 msgid "API secret" -msgstr "API secret" +msgstr "API-Geheimnis" -#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:274 -#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:74 -#: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:139 -#: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:199 -msgid "Save" -msgstr "Speichern" +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:320 +msgid "Enable thumbnails" +msgstr "Aktivierte Thunbnails" -#: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:15 -msgid "The Daily Shaarli" -msgstr "Der tägliche Shaarli" +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:324 +msgid "You need to enable the extension php-gd to use thumbnails." +msgstr "" +"Sie müssen die Erweiterung php-gd aktivieren, um " +"Miniaturansichten zu verwenden." -#: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:17 -msgid "1 RSS entry per day" -msgstr "1 RSS Eintrag pro Tag" +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:328 +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:122 +msgid "Synchronize thumbnails" +msgstr "Thumbnails synchronisieren" -#: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:37 -msgid "Previous day" -msgstr "Vorheriger Tag" +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:339 +#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:30 +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:102 +msgid "All" +msgstr "Alle" -#: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:44 -msgid "All links of one day in a single page." -msgstr "Alle Links eines Tages auf einer Seite." +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:343 +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:106 +msgid "Only common media hosts" +msgstr "Nur gängige Medienhosts" -#: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:51 -msgid "Next day" -msgstr "Nächster Tag" +#: tmp/configure.b91ef64efc3688266305ea9b42e5017e.rtpl.php:347 +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:110 +msgid "None" +msgstr "Keine" -#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:25 +#: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 +msgid "1 RSS entry per :type" +msgid_plural "" +msgstr[0] "1 RSS Eintrag pro :type" +msgstr[1] "1 RSS Eintrag pro :type" + +#: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:49 +msgid "Previous :type" +msgid_plural "" +msgstr[0] "Vorheriger :type" +msgstr[1] "Vorherige :type" + +#: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:56 +#: tmp/dailyrss.b91ef64efc3688266305ea9b42e5017e.rtpl.php:7 +msgid "All links of one :type in a single page." +msgid_plural "" +msgstr[0] "Alle Links eines :type auf einer Seite." +msgstr[1] "Alle Links aller :type auf einer Seite." + +#: tmp/daily.b91ef64efc3688266305ea9b42e5017e.rtpl.php:63 +msgid "Next :type" +msgid_plural "" +msgstr[0] "Nächster :type" +msgstr[1] "Nächste :type" + +#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:30 +msgid "Edit Shaare" +msgstr "Bearbeite Shaare" + +#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:30 +msgid "New Shaare" +msgstr "Neue Shaare" + +#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:38 msgid "Created:" msgstr "Erstellt:" -#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28 +#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 msgid "URL" msgstr "URL" -#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:34 +#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:47 msgid "Title" msgstr "Titel" -#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:40 +#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:58 #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:75 #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:99 @@ -795,41 +1302,56 @@ msgstr "Titel" msgid "Description" msgstr "Beschreibung" -#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:46 -msgid "Tags" -msgstr "Tags" +#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:89 +msgid "Description will be rendered with" +msgstr "Beschreibung wird dargestellt mit" -#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:59 -#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:168 -msgid "Private" -msgstr "Privat" +#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:91 +msgid "Markdown syntax documentation" +msgstr "Dokumentation der Markdown-Syntax" -#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:74 +#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:92 +msgid "Markdown syntax" +msgstr "Markdown-Syntax" + +#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:115 +msgid "Cancel" +msgstr "Abbruch" + +#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:121 msgid "Apply Changes" msgstr "Änderungen übernehmen" +#: tmp/editlink.b91ef64efc3688266305ea9b42e5017e.rtpl.php:126 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:173 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:147 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:147 +#: tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:67 +msgid "Delete" +msgstr "Löschen" + +#: tmp/editlink.batch.b91ef64efc3688266305ea9b42e5017e.rtpl.php:21 +#: tmp/editlink.batch.b91ef64efc3688266305ea9b42e5017e.rtpl.php:32 +msgid "Save all" +msgstr "Speichere alles" + #: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 msgid "Export Database" msgstr "Exportiere Datenbank" -#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:24 +#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:23 msgid "Selection" msgstr "Beschreibung" -#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31 -msgid "All" -msgstr "Alle" - -#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 +#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:40 msgid "Public" msgstr "Öffentlich" -#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:52 +#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:51 msgid "Prepend note permalinks with this Shaarli instance's URL" msgstr "Voranstellen von Notizen-Permalinks mit der URL dieser Shaarli-Instanz" -#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:53 +#: tmp/export.b91ef64efc3688266305ea9b42e5017e.rtpl.php:52 msgid "Useful to import bookmarks in a web browser" msgstr "Sinnvoll Lesezeichen im Browser zu importieren" @@ -869,224 +1391,269 @@ msgstr "Duplikate basierend auf URL" msgid "Add default tags" msgstr "Standard-Tag hinzufügen" -#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:22 -msgid "Install Shaarli" -msgstr "Installiere Shaarli" - #: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:25 msgid "It looks like it's the first time you run Shaarli. Please configure it." msgstr "" "Es sieht so aus, als ob du Shaarli das erste mal verwendest. Bitte " "konfiguriere es." -#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:33 -#: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:30 -#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:147 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:147 +#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:32 +#: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:167 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:167 msgid "Username" msgstr "Benutzername" -#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48 -#: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:34 -#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:148 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:148 +#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:47 +#: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:20 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:168 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:168 msgid "Password" msgstr "Passwort" -#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:63 +#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:62 msgid "Shaarli title" msgstr "Shaarli Titel" -#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:69 +#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:68 msgid "My links" msgstr "Meine Links" -#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:182 +#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:181 msgid "Install" msgstr "Installiere" +#: tmp/install.b91ef64efc3688266305ea9b42e5017e.rtpl.php:190 +msgid "Server requirements" +msgstr "Server-Anforderungen" + #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:80 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:79 msgid "shaare" msgid_plural "shaares" msgstr[0] "Teile" msgstr[1] "Teilen" #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:18 -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:84 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:83 msgid "private link" msgid_plural "private links" msgstr[0] "Privater Link" msgstr[1] "Private Links" -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:31 -#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:117 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:117 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:30 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:123 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:123 msgid "Search text" msgstr "Text durchsuchen" -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:38 -#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:124 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:124 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:37 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:130 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:130 #: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 -#: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:64 +#: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:65 #: tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 #: tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:74 msgid "Filter by tag" msgstr "Nach Tag filtern" -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:111 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:110 msgid "Nothing found." msgstr "Nichts gefunden." -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:119 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:118 #, php-format msgid "%s result" msgid_plural "%s results" msgstr[0] "%s Ergebnis" msgstr[1] "%s Ergebnisse" -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:123 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:122 msgid "for" msgstr "für" -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:130 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:129 msgid "tagged" msgstr "markiert" +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:133 #: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:134 msgid "Remove tag" msgstr "Tag entfernen" -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:143 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:144 msgid "with status" msgstr "mit Status" -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:154 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:155 msgid "without any tag" msgstr "ohne irgendeinen Tag" -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:174 -#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 -#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:42 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:175 +#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 +#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:41 msgid "Fold" -msgstr "Ablegen" +msgstr "Einklappen" -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:176 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:177 msgid "Edited: " msgstr "Bearbeitet: " -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:180 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:181 msgid "permalink" msgstr "Permalink" -#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:182 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:183 msgid "Add tag" msgstr "Tag hinzufügen" -#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:7 -#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:7 +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:185 +msgid "Toggle sticky" +msgstr "Anheften umschalten" + +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:187 +msgid "Sticky" +msgstr "Angeheftet" + +#: tmp/linklist.b91ef64efc3688266305ea9b42e5017e.rtpl.php:189 +msgid "Share a private link" +msgstr "Teile einen privaten Link" + +#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:5 +#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:5 msgid "Filters" msgstr "Filter" -#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:12 -#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:12 +#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:10 +#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:10 msgid "Only display private links" msgstr "Zeige nur private Links" -#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:15 -#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:15 +#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13 +#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:13 msgid "Only display public links" msgstr "Zeige nur öffentliche Links" -#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:20 -#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:20 +#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:18 +#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:18 msgid "Filter untagged links" msgstr "Unmarkierte Tags filtern" #: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:24 -#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:76 #: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:24 -#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:76 -#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:43 -#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:43 -msgid "Fold all" -msgstr "Alles ablegen" +msgid "Select all" +msgstr "Alle selektieren" -#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:69 -#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:69 +#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29 +#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:89 +#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:29 +#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:89 +#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 +#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:42 +msgid "Fold all" +msgstr "Alles einklappen" + +#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:76 +#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:76 msgid "Links per page" msgstr "Links pro Seite" -#: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:15 -msgid "" -"You have been banned after too many failed login attempts. Try again later." -msgstr "" -"Du wurdest nach zu vielen fehlgeschlagenen Anmeldeversuchen gesperrt. " -"Versuche es später noch einmal." - -#: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 -#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:151 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:151 +#: tmp/loginform.b91ef64efc3688266305ea9b42e5017e.rtpl.php:25 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:171 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:171 msgid "Remember me" msgstr "Erinnere dich an mich" -#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:14 +#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:15 #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48 -#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:14 +#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:15 #: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:48 msgid "by the Shaarli community" msgstr "von der Shaarli Community" -#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:15 -#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:15 +#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 +#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:16 msgid "Documentation" msgstr "Dokumentation" -#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:44 -#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:44 +#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:43 +#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:43 msgid "Expand" msgstr "Erweitern" -#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:45 -#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:45 +#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:44 +#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:44 msgid "Expand all" msgstr "Alles erweitern" -#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:46 -#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:46 +#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:45 +#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:45 msgid "Are you sure you want to delete this link?" msgstr "Bist du sicher das du diesen Link löschen möchtest?" -#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:61 -#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:86 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:61 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:86 +#: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:46 +#: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:46 +msgid "Are you sure you want to delete this tag?" +msgstr "Bist du sicher das du diesen Tag löschen möchtest?" + +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:11 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:11 +msgid "Menu" +msgstr "Menü" + +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:38 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:38 +#: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 +msgid "Tag cloud" +msgstr "Tag-Cloud" + +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:67 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:92 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:67 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:92 msgid "RSS Feed" msgstr "RSS Feed" -#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:66 -#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:102 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:66 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:102 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:72 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:108 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:72 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:108 msgid "Logout" msgstr "Ausloggen" -#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:169 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:169 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:152 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:152 +msgid "Set public" +msgstr "Setze Status auf Öffentlich" + +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:157 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:157 +msgid "Set private" +msgstr "Setze Status auf Privat" + +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:189 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:189 msgid "is available" msgstr "ist verfügbar" -#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:176 -#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:176 +#: tmp/page.header.b91ef64efc3688266305ea9b42e5017e.rtpl.php:196 +#: tmp/page.header.cedf684561d925457130839629000a81.rtpl.php:196 msgid "Error" msgstr "Fehler" -#: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 +#: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:15 +msgid "There is no cached thumbnail." +msgstr "Es gibt keine zwischengespeicherte Miniaturansicht / Thumbnail." + +#: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:17 +msgid "Try to synchronize them." +msgstr "Versuche sie zu synchronisieren." + +#: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28 msgid "Picture Wall" msgstr "Bildwand" -#: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 +#: tmp/picwall.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28 msgid "pics" msgstr "Bilder" @@ -1095,6 +1662,11 @@ msgid "You need to enable Javascript to change plugin loading order." msgstr "" "Du musst Javascript aktivieren um die Ladereihenfolge der Plugins zu ändern." +#: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:26 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:22 +msgid "Plugin administration" +msgstr "Plugin-Administration" + #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29 msgid "Enabled Plugins" msgstr "Aktivierte Plugins" @@ -1144,12 +1716,138 @@ msgstr "In der Dokumentation" #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:150 msgid "Plugin configuration" -msgstr "Plugin Konfiguration" +msgstr "Plugin-Konfiguration" #: tmp/pluginsadmin.b91ef64efc3688266305ea9b42e5017e.rtpl.php:195 msgid "No parameter available." msgstr "Kein Parameter verfügbar." +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:16 +msgid "General" +msgstr "Allgemein" + +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:20 +msgid "Index URL" +msgstr "Index-URL" + +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28 +msgid "Base path" +msgstr "Basispfad" + +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 +msgid "Client IP" +msgstr "Client-IP" + +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:44 +msgid "Trusted reverse proxies" +msgstr "Vertrauenswürdige Reverse-Proxies" + +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:58 +msgid "N/A" +msgstr "n. a." + +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:67 +msgid "Version" +msgstr "Version" + +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:71 +msgid "Current version" +msgstr "Aktuelle Version" + +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:80 +msgid "Latest release" +msgstr "Letzte Veröffentlichung" + +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:84 +msgid "Visit releases page on Github" +msgstr "Besuche die Releases-/Veröffentlichungs-Seite bei Github" + +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:92 +msgid "Thumbnails" +msgstr "Thumbnails / Miniaturbilder" + +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:96 +msgid "Thumbnails status" +msgstr "Thumbnails-Status" + +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:121 +msgid "Synchronize all link thumbnails" +msgstr "Synchronisiere alle Link-Thumbnails" + +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:128 +msgid "Cache" +msgstr "Zwischenspeicher" + +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:132 +msgid "Clear main cache" +msgstr "Haupt-Zwischenspeicher leeren" + +#: tmp/server.b91ef64efc3688266305ea9b42e5017e.rtpl.php:138 +msgid "Clear thumbnails cache" +msgstr "Leere Thumbnail-Zwischenspeicher" + +#: tmp/server.requirements.b91ef64efc3688266305ea9b42e5017e.rtpl.php:2 +#: tmp/server.requirements.cedf684561d925457130839629000a81.rtpl.php:2 +msgid "Permissions" +msgstr "Berechtigungen" + +#: tmp/server.requirements.b91ef64efc3688266305ea9b42e5017e.rtpl.php:8 +#: tmp/server.requirements.cedf684561d925457130839629000a81.rtpl.php:8 +msgid "There are permissions that need to be fixed." +msgstr "Es gibt Berechtigungen, die korrigiert werden müssen." + +#: tmp/server.requirements.b91ef64efc3688266305ea9b42e5017e.rtpl.php:23 +#: tmp/server.requirements.cedf684561d925457130839629000a81.rtpl.php:23 +msgid "All read/write permissions are properly set." +msgstr "Alle Lese-/Schreib-Berechtigungen sind richtig gesetzt." + +#: tmp/server.requirements.b91ef64efc3688266305ea9b42e5017e.rtpl.php:32 +#: tmp/server.requirements.cedf684561d925457130839629000a81.rtpl.php:32 +msgid "Running PHP" +msgstr "Laufendes PHP" + +#: tmp/server.requirements.b91ef64efc3688266305ea9b42e5017e.rtpl.php:36 +#: tmp/server.requirements.cedf684561d925457130839629000a81.rtpl.php:36 +msgid "End of life: " +msgstr "Abgekündigt: " + +#: tmp/server.requirements.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48 +#: tmp/server.requirements.cedf684561d925457130839629000a81.rtpl.php:48 +msgid "Extension" +msgstr "Erweiterung" + +#: tmp/server.requirements.b91ef64efc3688266305ea9b42e5017e.rtpl.php:49 +#: tmp/server.requirements.cedf684561d925457130839629000a81.rtpl.php:49 +msgid "Usage" +msgstr "Benutzung" + +#: tmp/server.requirements.b91ef64efc3688266305ea9b42e5017e.rtpl.php:50 +#: tmp/server.requirements.cedf684561d925457130839629000a81.rtpl.php:50 +msgid "Status" +msgstr "Status" + +#: tmp/server.requirements.b91ef64efc3688266305ea9b42e5017e.rtpl.php:51 +#: tmp/server.requirements.b91ef64efc3688266305ea9b42e5017e.rtpl.php:66 +#: tmp/server.requirements.cedf684561d925457130839629000a81.rtpl.php:51 +#: tmp/server.requirements.cedf684561d925457130839629000a81.rtpl.php:66 +msgid "Loaded" +msgstr "Geladen" + +#: tmp/server.requirements.b91ef64efc3688266305ea9b42e5017e.rtpl.php:60 +#: tmp/server.requirements.cedf684561d925457130839629000a81.rtpl.php:60 +msgid "Required" +msgstr "Erforderlich" + +#: tmp/server.requirements.b91ef64efc3688266305ea9b42e5017e.rtpl.php:60 +#: tmp/server.requirements.cedf684561d925457130839629000a81.rtpl.php:60 +msgid "Optional" +msgstr "optional" + +#: tmp/server.requirements.b91ef64efc3688266305ea9b42e5017e.rtpl.php:70 +#: tmp/server.requirements.cedf684561d925457130839629000a81.rtpl.php:70 +msgid "Not loaded" +msgstr "Nicht geladen" + #: tmp/tag.cloud.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 #: tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 msgid "tags" @@ -1160,6 +1858,10 @@ msgstr "Tags" msgid "List all links with those tags" msgstr "Zeige alle Links mit diesen Tags" +#: tmp/tag.list.b91ef64efc3688266305ea9b42e5017e.rtpl.php:19 +msgid "Tag list" +msgstr "Tag Liste" + #: tmp/tag.sort.b91ef64efc3688266305ea9b42e5017e.rtpl.php:3 #: tmp/tag.sort.cedf684561d925457130839629000a81.rtpl.php:3 msgid "Sort by:" @@ -1196,15 +1898,19 @@ msgstr "Shaarli konfigurieren" msgid "Enable, disable and configure plugins" msgstr "Plugins aktivieren, deaktivieren und konfigurieren" -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:28 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:27 +msgid "Check instance's server configuration" +msgstr "Überprüfe die Server-Konfiguration dieser Instanz" + +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:34 msgid "Change your password" msgstr "Ändere dein Passwort" -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:35 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 msgid "Rename or delete a tag in all links" msgstr "Umbenennen oder löschen eines Tags in allen Links" -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:47 msgid "" "Import Netscape HTML bookmarks (as exported from Firefox, Chrome, Opera, " "delicious...)" @@ -1212,11 +1918,11 @@ msgstr "" "Importiere Netscape Lesezeichen (wie aus Firefox exportiert, Chrome, Opera, " "delicious...)" -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48 msgid "Import links" msgstr "Importiere Links" -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:47 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:53 msgid "" "Export Netscape HTML bookmarks (which can be imported in Firefox, Chrome, " "Opera, delicious...)" @@ -1224,11 +1930,11 @@ msgstr "" "Exportiere Netscape HTML Lesezeichen (welche in Firefox importiert werden " "können, Chrome, Opera, delicious...)" -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:54 msgid "Export database" msgstr "Exportiere Datenbank" -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:71 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:77 msgid "" "Drag one of these button to your bookmarks toolbar or right-click it and " "\"Bookmark This Link\"" @@ -1237,13 +1943,13 @@ msgstr "" "klicke mit der rechten Maustaste darauf und \"Speichere diesen Link als " "Lesezeichen\"" -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:72 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:78 msgid "then click on the bookmarklet in any page you want to share." msgstr "" "Klicke dann auf das Bookmarklet auf jeder Seite, welches du teilen möchtest." -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:76 -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:100 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:82 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:106 msgid "" "Drag this link to your bookmarks toolbar or right-click it and Bookmark This " "Link" @@ -1251,22 +1957,22 @@ msgstr "" "Ziehe diese Link in deine Lesezeichen-Symbolleiste oder klicke mit der " "rechten Maustaste darauf und \"Speichere diesen Link als Lesezeichen\"" -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:77 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:83 msgid "then click ✚Shaare link button in any page you want to share" msgstr "" "klicke dann auf die Schaltfläche ✚Teilen auf jeder Seite, die du teilen " "möchtest" -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:86 -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:108 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:92 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:114 msgid "The selected text is too long, it will be truncated." msgstr "Der ausgewählte Text ist zu lang, er wird gekürzt." -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:96 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:102 msgid "Shaare link" msgstr "Teile Link" -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:101 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:107 msgid "" "Then click ✚Add Note button anytime to start composing a private Note (text " "post) to your Shaarli" @@ -1274,40 +1980,42 @@ msgstr "" "Klicke auf ✚Notiz hinzufügen um eine private Notiz (Textnachricht) zu " "Shaarli hinzuzufügen" -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:117 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:123 msgid "Add Note" msgstr "Notiz hinzufügen" -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:129 -msgid "" -"You need to browse your Shaarli over HTTPS to use this " -"functionality." -msgstr "" -"Um diese Funktion nutzen zu können, musst du Shaarli über HTTPS aufrufen." - -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:134 -msgid "Add to" -msgstr "Hinzufügen zu" - -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:145 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:132 msgid "3rd party" msgstr "Von Dritten" -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:147 -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:153 -msgid "Plugin" -msgstr "Plugin" - -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:148 -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:154 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:135 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:140 msgid "plugin" msgstr "Plugin" -#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:175 +#: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:165 msgid "" "Drag this link to your bookmarks toolbar, or right-click it and choose " "Bookmark This Link" msgstr "" "Ziehe diesen Link in deine Lesezeichen-Symbolleiste oder klicke mit der " "rechten Maustaste darauf und wähle \"Speichere diesen Link als Lesezeichen\"" + +#~ msgid "Rename" +#~ msgstr "Umbenennen" + +#~ msgid "The Daily Shaarli" +#~ msgstr "Der tägliche Shaarli" + +#~ msgid "" +#~ "You need to browse your Shaarli over HTTPS to use this " +#~ "functionality." +#~ msgstr "" +#~ "Um diese Funktion nutzen zu können, musst du Shaarli über HTTPS aufrufen." + +#~ msgid "Add to" +#~ msgstr "Hinzufügen zu" + +#~ msgid "Plugin" +#~ msgstr "Plugin" diff --git a/plugins/demo_plugin/demo_plugin.php b/plugins/demo_plugin/demo_plugin.php index 15cfc2c5..d89765cf 100644 --- a/plugins/demo_plugin/demo_plugin.php +++ b/plugins/demo_plugin/demo_plugin.php @@ -17,6 +17,7 @@ * and check user status with _LOGGEDIN_. */ +use Shaarli\Bookmark\Bookmark; use Shaarli\Config\ConfigManager; use Shaarli\Plugin\PluginManager; use Shaarli\Render\TemplatePage; @@ -263,6 +264,17 @@ function hook_demo_plugin_render_linklist($data) } $data['action_plugin'][] = $action; + // Action to trigger custom filter hiding bookmarks not containing 'e' letter in their description + $action = [ + 'attr' => [ + 'href' => '?e', + 'title' => 'Hide bookmarks without "e" in their description.', + ], + 'html' => 'e', + 'on' => isset($_GET['e']) + ]; + $data['action_plugin'][] = $action; + // link_plugin (for each link) foreach ($data['links'] as &$value) { $value['link_plugin'][] = ' DEMO \o/'; @@ -486,6 +498,27 @@ function hook_demo_plugin_save_plugin_parameters($data) return $data; } +/** + * This hook is called when a search is performed, on every search entry. + * It allows to add custom filters, and filter out additional link. + * + * For exemple here, we hide all bookmarks not containing the letter 'e' in their description. + * + * @param Bookmark $bookmark Search entry. Note that this is a Bookmark object, and not a link array. + * It should NOT be altered. + * @param array $context Additional info on the search performed. + * + * @return bool True if the bookmark should be kept in the search result, false to discard it. + */ +function hook_demo_plugin_filter_search_entry(Bookmark $bookmark, array $context): bool +{ + if (isset($_GET['e'])) { + return strpos($bookmark->getDescription(), 'e') !== false; + } + + return true; +} + /** * This function is never called, but contains translation calls for GNU gettext extraction. */ diff --git a/tests/PluginManagerTest.php b/tests/PluginManagerTest.php index 8947f679..75b3ae00 100644 --- a/tests/PluginManagerTest.php +++ b/tests/PluginManagerTest.php @@ -2,6 +2,7 @@ namespace Shaarli\Plugin; +use Shaarli\Bookmark\Bookmark; use Shaarli\Config\ConfigManager; /** @@ -159,4 +160,19 @@ public function testRegisteredRoutesInvalid(): void $errors = $this->pluginManager->getErrors(); static::assertSame(['test_route_invalid [plugin incompatibility]: trying to register invalid route.'], $errors); } + + public function testSearchFilterPlugin(): void + { + PluginManager::$PLUGINS_PATH = self::$pluginPath; + $this->pluginManager->load([self::$pluginName]); + + static::assertNull($this->pluginManager->getFilterSearchEntryHooks()); + + static::assertTrue($this->pluginManager->filterSearchEntry(new Bookmark(), ['_result' => true])); + + static::assertCount(1, $this->pluginManager->getFilterSearchEntryHooks()); + static::assertSame('hook_test_filter_search_entry', $this->pluginManager->getFilterSearchEntryHooks()[0]); + + static::assertFalse($this->pluginManager->filterSearchEntry(new Bookmark(), ['_result' => false])); + } } diff --git a/tests/api/ApiMiddlewareTest.php b/tests/api/ApiMiddlewareTest.php index 86700840..2afac28b 100644 --- a/tests/api/ApiMiddlewareTest.php +++ b/tests/api/ApiMiddlewareTest.php @@ -3,6 +3,7 @@ use Shaarli\Config\ConfigManager; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Slim\Container; use Slim\Http\Environment; use Slim\Http\Request; @@ -56,6 +57,7 @@ protected function setUp(): void $this->container = new Container(); $this->container['conf'] = $this->conf; $this->container['history'] = $history; + $this->container['pluginManager'] = new PluginManager($this->conf); } /** diff --git a/tests/api/controllers/info/InfoTest.php b/tests/api/controllers/info/InfoTest.php index 10b29ab2..2428ca43 100644 --- a/tests/api/controllers/info/InfoTest.php +++ b/tests/api/controllers/info/InfoTest.php @@ -5,6 +5,7 @@ use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Config\ConfigManager; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Shaarli\TestCase; use Slim\Container; use Slim\Http\Environment; @@ -55,12 +56,18 @@ protected function setUp(): void $this->conf->set('resource.datastore', self::$testDatastore); $this->refDB = new \ReferenceLinkDB(); $this->refDB->write(self::$testDatastore); - + $this->pluginManager = new PluginManager($this->conf); $history = new History('sandbox/history.php'); $this->container = new Container(); $this->container['conf'] = $this->conf; - $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true); + $this->container['db'] = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $history, + $mutex, + true + ); $this->container['history'] = null; $this->controller = new Info($this->container); diff --git a/tests/api/controllers/links/DeleteLinkTest.php b/tests/api/controllers/links/DeleteLinkTest.php index 805c9be3..dc2cf917 100644 --- a/tests/api/controllers/links/DeleteLinkTest.php +++ b/tests/api/controllers/links/DeleteLinkTest.php @@ -7,6 +7,7 @@ use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Config\ConfigManager; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Slim\Container; use Slim\Http\Environment; use Slim\Http\Request; @@ -57,6 +58,9 @@ class DeleteLinkTest extends \Shaarli\TestCase /** @var NoMutex */ protected $mutex; + /** @var PluginManager */ + protected $pluginManager; + /** * Before each test, instantiate a new Api with its config, plugins and bookmarks. */ @@ -70,7 +74,14 @@ protected function setUp(): void $refHistory = new \ReferenceHistory(); $refHistory->write(self::$testHistory); $this->history = new History(self::$testHistory); - $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->pluginManager = new PluginManager($this->conf); + $this->bookmarkService = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $this->container = new Container(); $this->container['conf'] = $this->conf; @@ -105,7 +116,13 @@ public function testDeleteLinkValid() $this->assertEquals(204, $response->getStatusCode()); $this->assertEmpty((string) $response->getBody()); - $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->bookmarkService = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $this->assertFalse($this->bookmarkService->exists($id)); $historyEntry = $this->history->getHistory()[0]; diff --git a/tests/api/controllers/links/GetLinkIdTest.php b/tests/api/controllers/links/GetLinkIdTest.php index 1ec56ef3..c93a3b4b 100644 --- a/tests/api/controllers/links/GetLinkIdTest.php +++ b/tests/api/controllers/links/GetLinkIdTest.php @@ -7,6 +7,7 @@ use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Config\ConfigManager; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Slim\Container; use Slim\Http\Environment; use Slim\Http\Request; @@ -67,7 +68,14 @@ protected function setUp(): void $this->container = new Container(); $this->container['conf'] = $this->conf; - $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true); + $pluginManager = new PluginManager($this->conf); + $this->container['db'] = new BookmarkFileService( + $this->conf, + $pluginManager, + $history, + $mutex, + true + ); $this->container['history'] = null; $this->controller = new Links($this->container); diff --git a/tests/api/controllers/links/GetLinksTest.php b/tests/api/controllers/links/GetLinksTest.php index b1c46ee2..3c966732 100644 --- a/tests/api/controllers/links/GetLinksTest.php +++ b/tests/api/controllers/links/GetLinksTest.php @@ -7,6 +7,7 @@ use Shaarli\Bookmark\LinkDB; use Shaarli\Config\ConfigManager; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Slim\Container; use Slim\Http\Environment; use Slim\Http\Request; @@ -67,7 +68,14 @@ protected function setUp(): void $this->container = new Container(); $this->container['conf'] = $this->conf; - $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true); + $pluginManager = new PluginManager($this->conf); + $this->container['db'] = new BookmarkFileService( + $this->conf, + $pluginManager, + $history, + $mutex, + true + ); $this->container['history'] = null; $this->controller = new Links($this->container); diff --git a/tests/api/controllers/links/PostLinkTest.php b/tests/api/controllers/links/PostLinkTest.php index f755e2d2..a54e4a16 100644 --- a/tests/api/controllers/links/PostLinkTest.php +++ b/tests/api/controllers/links/PostLinkTest.php @@ -7,6 +7,7 @@ use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Config\ConfigManager; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Shaarli\TestCase; use Slim\Container; use Slim\Http\Environment; @@ -81,8 +82,14 @@ protected function setUp(): void $refHistory = new \ReferenceHistory(); $refHistory->write(self::$testHistory); $this->history = new History(self::$testHistory); - $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true); - + $pluginManager = new PluginManager($this->conf); + $this->bookmarkService = new BookmarkFileService( + $this->conf, + $pluginManager, + $this->history, + $mutex, + true + ); $this->container = new Container(); $this->container['conf'] = $this->conf; $this->container['db'] = $this->bookmarkService; diff --git a/tests/api/controllers/links/PutLinkTest.php b/tests/api/controllers/links/PutLinkTest.php index fe24f2eb..ed14d5f8 100644 --- a/tests/api/controllers/links/PutLinkTest.php +++ b/tests/api/controllers/links/PutLinkTest.php @@ -8,6 +8,7 @@ use Shaarli\Bookmark\BookmarkFileService; use Shaarli\Config\ConfigManager; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Slim\Container; use Slim\Http\Environment; use Slim\Http\Request; @@ -73,8 +74,14 @@ protected function setUp(): void $refHistory = new \ReferenceHistory(); $refHistory->write(self::$testHistory); $this->history = new History(self::$testHistory); - $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true); - + $pluginManager = new PluginManager($this->conf); + $this->bookmarkService = new BookmarkFileService( + $this->conf, + $pluginManager, + $this->history, + $mutex, + true + ); $this->container = new Container(); $this->container['conf'] = $this->conf; $this->container['db'] = $this->bookmarkService; diff --git a/tests/api/controllers/tags/DeleteTagTest.php b/tests/api/controllers/tags/DeleteTagTest.php index 37f07229..c0f8a6a9 100644 --- a/tests/api/controllers/tags/DeleteTagTest.php +++ b/tests/api/controllers/tags/DeleteTagTest.php @@ -8,6 +8,7 @@ use Shaarli\Bookmark\LinkDB; use Shaarli\Config\ConfigManager; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Slim\Container; use Slim\Http\Environment; use Slim\Http\Request; @@ -55,6 +56,9 @@ class DeleteTagTest extends \Shaarli\TestCase */ protected $controller; + /** @var PluginManager */ + protected $pluginManager; + /** @var NoMutex */ protected $mutex; @@ -71,7 +75,14 @@ protected function setUp(): void $refHistory = new \ReferenceHistory(); $refHistory->write(self::$testHistory); $this->history = new History(self::$testHistory); - $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->pluginManager = new PluginManager($this->conf); + $this->bookmarkService = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $this->container = new Container(); $this->container['conf'] = $this->conf; @@ -107,7 +118,13 @@ public function testDeleteTagValid() $this->assertEquals(204, $response->getStatusCode()); $this->assertEmpty((string) $response->getBody()); - $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->bookmarkService = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $tags = $this->bookmarkService->bookmarksCountPerTag(); $this->assertFalse(isset($tags[$tagName])); @@ -141,7 +158,13 @@ public function testDeleteTagCaseSensitivity() $this->assertEquals(204, $response->getStatusCode()); $this->assertEmpty((string) $response->getBody()); - $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->bookmarkService = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $tags = $this->bookmarkService->bookmarksCountPerTag(); $this->assertFalse(isset($tags[$tagName])); $this->assertTrue($tags[strtolower($tagName)] > 0); diff --git a/tests/api/controllers/tags/GetTagNameTest.php b/tests/api/controllers/tags/GetTagNameTest.php index 878de5a4..0ad71495 100644 --- a/tests/api/controllers/tags/GetTagNameTest.php +++ b/tests/api/controllers/tags/GetTagNameTest.php @@ -7,6 +7,7 @@ use Shaarli\Bookmark\LinkDB; use Shaarli\Config\ConfigManager; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Slim\Container; use Slim\Http\Environment; use Slim\Http\Request; @@ -46,6 +47,9 @@ class GetTagNameTest extends \Shaarli\TestCase */ protected $controller; + /** @var PluginManager */ + protected $pluginManager; + /** * Number of JSON fields per link. */ @@ -65,7 +69,14 @@ protected function setUp(): void $this->container = new Container(); $this->container['conf'] = $this->conf; - $this->container['db'] = new BookmarkFileService($this->conf, $history, $mutex, true); + $this->pluginManager = new PluginManager($this->conf); + $this->container['db'] = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $history, + $mutex, + true + ); $this->container['history'] = null; $this->controller = new Tags($this->container); diff --git a/tests/api/controllers/tags/GetTagsTest.php b/tests/api/controllers/tags/GetTagsTest.php index b565a8c4..a4b62c51 100644 --- a/tests/api/controllers/tags/GetTagsTest.php +++ b/tests/api/controllers/tags/GetTagsTest.php @@ -6,6 +6,7 @@ use Shaarli\Bookmark\LinkDB; use Shaarli\Config\ConfigManager; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Slim\Container; use Slim\Http\Environment; use Slim\Http\Request; @@ -50,6 +51,9 @@ class GetTagsTest extends \Shaarli\TestCase */ protected $controller; + /** @var PluginManager */ + protected $pluginManager; + /** * Number of JSON field per link. */ @@ -66,9 +70,14 @@ protected function setUp(): void $this->refDB = new \ReferenceLinkDB(); $this->refDB->write(self::$testDatastore); $history = new History('sandbox/history.php'); - - $this->bookmarkService = new BookmarkFileService($this->conf, $history, $mutex, true); - + $this->pluginManager = new PluginManager($this->conf); + $this->bookmarkService = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $history, + $mutex, + true + ); $this->container = new Container(); $this->container['conf'] = $this->conf; $this->container['db'] = $this->bookmarkService; diff --git a/tests/api/controllers/tags/PutTagTest.php b/tests/api/controllers/tags/PutTagTest.php index c73f6d3b..045473e6 100644 --- a/tests/api/controllers/tags/PutTagTest.php +++ b/tests/api/controllers/tags/PutTagTest.php @@ -8,6 +8,7 @@ use Shaarli\Bookmark\LinkDB; use Shaarli\Config\ConfigManager; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Slim\Container; use Slim\Http\Environment; use Slim\Http\Request; @@ -55,6 +56,9 @@ class PutTagTest extends \Shaarli\TestCase */ protected $controller; + /** @var PluginManager */ + protected $pluginManager; + /** * Number of JSON field per link. */ @@ -73,7 +77,14 @@ protected function setUp(): void $refHistory = new \ReferenceHistory(); $refHistory->write(self::$testHistory); $this->history = new History(self::$testHistory); - $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true); + $this->pluginManager = new PluginManager($this->conf); + $this->bookmarkService = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $mutex, + true + ); $this->container = new Container(); $this->container['conf'] = $this->conf; diff --git a/tests/bookmark/BookmarkFileServiceTest.php b/tests/bookmark/BookmarkFileServiceTest.php index f619aff3..1d250719 100644 --- a/tests/bookmark/BookmarkFileServiceTest.php +++ b/tests/bookmark/BookmarkFileServiceTest.php @@ -14,6 +14,7 @@ use Shaarli\Config\ConfigManager; use Shaarli\Formatter\BookmarkMarkdownFormatter; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Shaarli\TestCase; /** @@ -56,6 +57,9 @@ class BookmarkFileServiceTest extends TestCase /** @var NoMutex */ protected $mutex; + /** @var PluginManager */ + protected $pluginManager; + /** * Instantiates public and private LinkDBs with test data * @@ -93,8 +97,21 @@ protected function setUp(): void $this->refDB = new \ReferenceLinkDB(); $this->refDB->write(self::$testDatastore); $this->history = new History('sandbox/history.php'); - $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false); - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->pluginManager = new PluginManager($this->conf); + $this->publicLinkDB = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + false + ); + $this->privateLinkDB = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); } /** @@ -111,7 +128,13 @@ public function testDatabaseMigration() $db = self::getMethod('migrate'); $db->invokeArgs($this->privateLinkDB, []); - $db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, true); + $db = new \FakeBookmarkService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks()); $this->assertEquals($this->refDB->countLinks(), $db->count()); } @@ -180,7 +203,13 @@ public function testAddFull() $this->assertEquals($updated, $bookmark->getUpdated()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->privateLinkDB = new \FakeBookmarkService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $bookmark = $this->privateLinkDB->get(43); $this->assertEquals(43, $bookmark->getId()); @@ -218,7 +247,13 @@ public function testAddMinimal() $this->assertNull($bookmark->getUpdated()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->privateLinkDB = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $bookmark = $this->privateLinkDB->get(43); $this->assertEquals(43, $bookmark->getId()); @@ -248,7 +283,13 @@ public function testAddMinimalNoWrite() $this->assertEquals(43, $bookmark->getId()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->privateLinkDB = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $this->privateLinkDB->get(43); } @@ -309,7 +350,13 @@ public function testSetFull() $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->privateLinkDB = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $bookmark = $this->privateLinkDB->get(42); $this->assertEquals(42, $bookmark->getId()); @@ -350,7 +397,13 @@ public function testSetMinimal() $this->assertTrue(new \DateTime('5 seconds ago') < $bookmark->getUpdated()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->privateLinkDB = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $bookmark = $this->privateLinkDB->get(42); $this->assertEquals(42, $bookmark->getId()); @@ -383,7 +436,13 @@ public function testSetMinimalNoWrite() $this->assertEquals($title, $bookmark->getTitle()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->privateLinkDB = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $bookmark = $this->privateLinkDB->get(42); $this->assertEquals(42, $bookmark->getId()); @@ -436,7 +495,13 @@ public function testAddOrSetNew() $this->assertEquals(43, $bookmark->getId()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->privateLinkDB = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $bookmark = $this->privateLinkDB->get(43); $this->assertEquals(43, $bookmark->getId()); @@ -456,7 +521,13 @@ public function testAddOrSetExisting() $this->assertEquals($title, $bookmark->getTitle()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->privateLinkDB = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $bookmark = $this->privateLinkDB->get(42); $this->assertEquals(42, $bookmark->getId()); @@ -488,7 +559,13 @@ public function testAddOrSetMinimalNoWrite() $this->assertEquals($title, $bookmark->getTitle()); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->privateLinkDB = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $bookmark = $this->privateLinkDB->get(42); $this->assertEquals(42, $bookmark->getId()); @@ -514,7 +591,13 @@ public function testRemoveExisting() $this->assertInstanceOf(BookmarkNotFoundException::class, $exception); // reload from file - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->privateLinkDB = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $this->privateLinkDB->get(42); } @@ -607,7 +690,7 @@ public function testConstructDatastoreNotWriteable() $conf = new ConfigManager('tests/utils/config/configJson'); $conf->set('resource.datastore', 'null/store.db'); - new BookmarkFileService($conf, $this->history, $this->mutex, true); + new BookmarkFileService($conf, $this->pluginManager, $this->history, $this->mutex, true); } /** @@ -617,7 +700,7 @@ public function testCheckDBNewLoggedIn() { unlink(self::$testDatastore); $this->assertFileNotExists(self::$testDatastore); - new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + new BookmarkFileService($this->conf, $this->pluginManager, $this->history, $this->mutex, true); $this->assertFileExists(self::$testDatastore); // ensure the correct data has been written @@ -631,7 +714,7 @@ public function testCheckDBNewLoggedOut() { unlink(self::$testDatastore); $this->assertFileNotExists(self::$testDatastore); - $db = new \FakeBookmarkService($this->conf, $this->history, $this->mutex, false); + $db = new \FakeBookmarkService($this->conf, $this->pluginManager, $this->history, $this->mutex, false); $this->assertFileNotExists(self::$testDatastore); $this->assertInstanceOf(BookmarkArray::class, $db->getBookmarks()); $this->assertCount(0, $db->getBookmarks()); @@ -664,13 +747,13 @@ public function testReadPrivateDB() */ public function testSave() { - $testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $testDB = new BookmarkFileService($this->conf, $this->pluginManager, $this->history, $this->mutex, true); $dbSize = $testDB->count(); $bookmark = new Bookmark(); $testDB->add($bookmark); - $testDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $testDB = new BookmarkFileService($this->conf, $this->pluginManager, $this->history, $this->mutex, true); $this->assertEquals($dbSize + 1, $testDB->count()); } @@ -680,7 +763,7 @@ public function testSave() public function testCountHiddenPublic() { $this->conf->set('privacy.hide_public_links', true); - $linkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false); + $linkDB = new BookmarkFileService($this->conf, $this->pluginManager, $this->history, $this->mutex, false); $this->assertEquals(0, $linkDB->count()); } @@ -807,7 +890,7 @@ public function testFilterString() $request = ['searchtags' => $tags]; $this->assertEquals( 2, - count($this->privateLinkDB->search($request, null, true)) + count($this->privateLinkDB->search($request, null, true)->getBookmarks()) ); } @@ -820,7 +903,7 @@ public function testFilterArray() $request = ['searchtags' => $tags]; $this->assertEquals( 2, - count($this->privateLinkDB->search($request, null, true)) + count($this->privateLinkDB->search($request, null, true)->getBookmarks()) ); } @@ -834,12 +917,12 @@ public function testHiddenTags() $request = ['searchtags' => $tags]; $this->assertEquals( 1, - count($this->privateLinkDB->search($request, 'all', true)) + count($this->privateLinkDB->search($request, 'all', true)->getBookmarks()) ); $this->assertEquals( 0, - count($this->publicLinkDB->search($request, 'public', true)) + count($this->publicLinkDB->search($request, 'public', true)->getBookmarks()) ); } @@ -906,7 +989,13 @@ public function testFilterHashWithPrivateKey() $bookmark->addAdditionalContentEntry('private_key', $privateKey); $this->privateLinkDB->save(); - $this->privateLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false); + $this->privateLinkDB = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + false + ); $bookmark = $this->privateLinkDB->findByHash($hash, $privateKey); static::assertSame(6, $bookmark->getId()); @@ -1152,7 +1241,13 @@ public function testGetLatestWithSticky(): void public function testGetLatestEmptyDatastore(): void { unlink($this->conf->get('resource.datastore')); - $this->publicLinkDB = new BookmarkFileService($this->conf, $this->history, $this->mutex, false); + $this->publicLinkDB = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + false + ); $bookmark = $this->publicLinkDB->getLatest(); diff --git a/tests/bookmark/BookmarkFilterTest.php b/tests/bookmark/BookmarkFilterTest.php index 835674f2..79be807d 100644 --- a/tests/bookmark/BookmarkFilterTest.php +++ b/tests/bookmark/BookmarkFilterTest.php @@ -6,6 +6,7 @@ use ReferenceLinkDB; use Shaarli\Config\ConfigManager; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Shaarli\TestCase; /** @@ -32,19 +33,24 @@ class BookmarkFilterTest extends TestCase */ protected static $bookmarkService; + /** @var PluginManager */ + protected static $pluginManager; + /** * Instantiate linkFilter with ReferenceLinkDB data. */ public static function setUpBeforeClass(): void { + $mutex = new NoMutex(); $conf = new ConfigManager('tests/utils/config/configJson'); $conf->set('resource.datastore', self::$testDatastore); + static::$pluginManager = new PluginManager($conf); self::$refDB = new \ReferenceLinkDB(); self::$refDB->write(self::$testDatastore); $history = new History('sandbox/history.php'); - self::$bookmarkService = new \FakeBookmarkService($conf, $history, $mutex, true); - self::$linkFilter = new BookmarkFilter(self::$bookmarkService->getBookmarks(), $conf); + self::$bookmarkService = new \FakeBookmarkService($conf, static::$pluginManager, $history, $mutex, true); + self::$linkFilter = new BookmarkFilter(self::$bookmarkService->getBookmarks(), $conf, static::$pluginManager); } /** @@ -178,61 +184,6 @@ public function testFilterUnknownTag() ); } - /** - * Return bookmarks for a given day - */ - public function testFilterDay() - { - $this->assertEquals( - 4, - count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20121206')) - ); - } - - /** - * Return bookmarks for a given day - */ - public function testFilterDayRestrictedVisibility(): void - { - $this->assertEquals( - 3, - count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20121206', false, BookmarkFilter::$PUBLIC)) - ); - } - - /** - * 404 - day not found - */ - public function testFilterUnknownDay() - { - $this->assertEquals( - 0, - count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '19700101')) - ); - } - - /** - * Use an invalid date format - */ - public function testFilterInvalidDayWithChars() - { - $this->expectException(\Exception::class); - $this->expectExceptionMessageRegExp('/Invalid date format/'); - - self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, 'Rainy day, dream away'); - } - - /** - * Use an invalid date format - */ - public function testFilterInvalidDayDigits() - { - $this->expectException(\Exception::class); - $this->expectExceptionMessageRegExp('/Invalid date format/'); - - self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20'); - } - /** * Retrieve a link entry with its hash */ diff --git a/tests/bookmark/BookmarkInitializerTest.php b/tests/bookmark/BookmarkInitializerTest.php index 0c8420ce..351807c1 100644 --- a/tests/bookmark/BookmarkInitializerTest.php +++ b/tests/bookmark/BookmarkInitializerTest.php @@ -5,6 +5,7 @@ use malkusch\lock\mutex\NoMutex; use Shaarli\Config\ConfigManager; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Shaarli\TestCase; /** @@ -38,6 +39,9 @@ class BookmarkInitializerTest extends TestCase /** @var NoMutex */ protected $mutex; + /** @var PluginManager */ + protected $pluginManager; + /** * Initialize an empty BookmarkFileService */ @@ -51,8 +55,15 @@ public function setUp(): void copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php'); $this->conf = new ConfigManager(self::$testConf); $this->conf->set('resource.datastore', self::$testDatastore); + $this->pluginManager = new PluginManager($this->conf); $this->history = new History('sandbox/history.php'); - $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->bookmarkService = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $this->initializer = new BookmarkInitializer($this->bookmarkService); } @@ -64,7 +75,13 @@ public function testInitializeNotEmptyDataStore(): void { $refDB = new \ReferenceLinkDB(); $refDB->write(self::$testDatastore); - $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->bookmarkService = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $this->initializer = new BookmarkInitializer($this->bookmarkService); $this->initializer->initialize(); @@ -95,7 +112,13 @@ public function testInitializeNotEmptyDataStore(): void $this->bookmarkService->save(); // Reload from file - $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->bookmarkService = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count()); $bookmark = $this->bookmarkService->get(43); @@ -126,7 +149,13 @@ public function testInitializeNotEmptyDataStore(): void public function testInitializeNonExistentDataStore(): void { $this->conf->set('resource.datastore', static::$testDatastore . '_empty'); - $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $this->mutex, true); + $this->bookmarkService = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $this->mutex, + true + ); $this->initializer->initialize(); diff --git a/tests/bookmark/SearchResultTest.php b/tests/bookmark/SearchResultTest.php new file mode 100644 index 00000000..12854c1f --- /dev/null +++ b/tests/bookmark/SearchResultTest.php @@ -0,0 +1,125 @@ +getBookmarks()); + static::assertSame(6, $searchResult->getResultCount()); + static::assertSame(6, $searchResult->getTotalCount()); + static::assertSame(null, $searchResult->getLimit()); + static::assertSame(0, $searchResult->getOffset()); + static::assertSame(1, $searchResult->getPage()); + static::assertSame(1, $searchResult->getLastPage()); + static::assertTrue($searchResult->isFirstPage()); + static::assertTrue($searchResult->isLastPage()); + } + + /** Create a SearchResult with only an offset parameter */ + public function testResultWithOffset(): void + { + $searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 2); + + static::assertSame([2 => 'c', 3 => 'd', 4 => 'e', 5 => 'f'], $searchResult->getBookmarks()); + static::assertSame(4, $searchResult->getResultCount()); + static::assertSame(6, $searchResult->getTotalCount()); + static::assertSame(null, $searchResult->getLimit()); + static::assertSame(2, $searchResult->getOffset()); + static::assertSame(2, $searchResult->getPage()); + static::assertSame(2, $searchResult->getLastPage()); + static::assertFalse($searchResult->isFirstPage()); + static::assertTrue($searchResult->isLastPage()); + } + + /** Create a SearchResult with only a limit parameter */ + public function testResultWithLimit(): void + { + $searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 0, 2); + + static::assertSame([0 => 'a', 1 => 'b'], $searchResult->getBookmarks()); + static::assertSame(2, $searchResult->getResultCount()); + static::assertSame(6, $searchResult->getTotalCount()); + static::assertSame(2, $searchResult->getLimit()); + static::assertSame(0, $searchResult->getOffset()); + static::assertSame(1, $searchResult->getPage()); + static::assertSame(3, $searchResult->getLastPage()); + static::assertTrue($searchResult->isFirstPage()); + static::assertFalse($searchResult->isLastPage()); + } + + /** Create a SearchResult with offset and limit parameters */ + public function testResultWithLimitAndOffset(): void + { + $searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 2, 2); + + static::assertSame([2 => 'c', 3 => 'd'], $searchResult->getBookmarks()); + static::assertSame(2, $searchResult->getResultCount()); + static::assertSame(6, $searchResult->getTotalCount()); + static::assertSame(2, $searchResult->getLimit()); + static::assertSame(2, $searchResult->getOffset()); + static::assertSame(2, $searchResult->getPage()); + static::assertSame(3, $searchResult->getLastPage()); + static::assertFalse($searchResult->isFirstPage()); + static::assertFalse($searchResult->isLastPage()); + } + + /** Create a SearchResult with offset and limit parameters displaying the last page */ + public function testResultWithLimitAndOffsetLastPage(): void + { + $searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 4, 2); + + static::assertSame([4 => 'e', 5 => 'f'], $searchResult->getBookmarks()); + static::assertSame(2, $searchResult->getResultCount()); + static::assertSame(6, $searchResult->getTotalCount()); + static::assertSame(2, $searchResult->getLimit()); + static::assertSame(4, $searchResult->getOffset()); + static::assertSame(3, $searchResult->getPage()); + static::assertSame(3, $searchResult->getLastPage()); + static::assertFalse($searchResult->isFirstPage()); + static::assertTrue($searchResult->isLastPage()); + } + + /** Create a SearchResult with offset and limit parameters out of bound (display the last page) */ + public function testResultWithLimitAndOffsetOutOfBounds(): void + { + $searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 12, 2); + + static::assertSame([4 => 'e', 5 => 'f'], $searchResult->getBookmarks()); + static::assertSame(2, $searchResult->getResultCount()); + static::assertSame(6, $searchResult->getTotalCount()); + static::assertSame(2, $searchResult->getLimit()); + static::assertSame(-2, $searchResult->getOffset()); + static::assertSame(3, $searchResult->getPage()); + static::assertSame(3, $searchResult->getLastPage()); + static::assertFalse($searchResult->isFirstPage()); + static::assertTrue($searchResult->isLastPage()); + } + + /** Create a SearchResult with offset and limit parameters out of bound (no result) */ + public function testResultWithLimitAndOffsetOutOfBoundsNoResult(): void + { + $searchResult = SearchResult::getSearchResult(['a', 'b', 'c', 'd', 'e', 'f'], 12, 2, true); + + static::assertSame([], $searchResult->getBookmarks()); + static::assertSame(0, $searchResult->getResultCount()); + static::assertSame(6, $searchResult->getTotalCount()); + static::assertSame(2, $searchResult->getLimit()); + static::assertSame(12, $searchResult->getOffset()); + static::assertSame(7, $searchResult->getPage()); + static::assertSame(3, $searchResult->getLastPage()); + static::assertFalse($searchResult->isFirstPage()); + static::assertFalse($searchResult->isLastPage()); + } +} diff --git a/tests/feed/FeedBuilderTest.php b/tests/feed/FeedBuilderTest.php index 6b9204eb..fe092f78 100644 --- a/tests/feed/FeedBuilderTest.php +++ b/tests/feed/FeedBuilderTest.php @@ -11,6 +11,7 @@ use Shaarli\Config\ConfigManager; use Shaarli\Formatter\FormatterFactory; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Shaarli\TestCase; /** @@ -55,8 +56,15 @@ public static function setUpBeforeClass(): void $refLinkDB->write(self::$testDatastore); $history = new History('sandbox/history.php'); $factory = new FormatterFactory($conf, true); + $pluginManager = new PluginManager($conf); self::$formatter = $factory->getFormatter(); - self::$bookmarkService = new BookmarkFileService($conf, $history, $mutex, true); + self::$bookmarkService = new BookmarkFileService( + $conf, + $pluginManager, + $history, + $mutex, + true + ); self::$serverInfo = array( 'HTTPS' => 'Off', diff --git a/tests/formatter/BookmarkDefaultFormatterTest.php b/tests/formatter/BookmarkDefaultFormatterTest.php index 4fcc5dd1..983960b6 100644 --- a/tests/formatter/BookmarkDefaultFormatterTest.php +++ b/tests/formatter/BookmarkDefaultFormatterTest.php @@ -211,13 +211,17 @@ public function testFormatDescriptionWithSearchHighlight(): void $this->formatter = new BookmarkDefaultFormatter($this->conf, false); $bookmark = new Bookmark(); - $bookmark->setDescription('This guide extends and expands on PSR-1, the basic coding standard.'); + $bookmark->setDescription( + 'This guide extends and expands on PSR-1, the basic coding standard.' . PHP_EOL . + 'https://www.php-fig.org/psr/psr-1/' + ); $bookmark->addAdditionalContentEntry( 'search_highlight', ['description' => [ ['start' => 0, 'end' => 10], // "This guide" ['start' => 45, 'end' => 50], // basic ['start' => 58, 'end' => 67], // standard. + ['start' => 84, 'end' => 87], // fig ]] ); @@ -226,7 +230,10 @@ public function testFormatDescriptionWithSearchHighlight(): void $this->assertSame( 'This guide extends and expands on PSR-1, the ' . 'basic coding ' . - 'standard.', + 'standard.
' . PHP_EOL . + '' . + 'https://www.php-fig.org/psr/psr-1/' . + '', $link['description'] ); } diff --git a/tests/formatter/BookmarkMarkdownFormatterTest.php b/tests/formatter/BookmarkMarkdownFormatterTest.php index ab6b4080..32f7b444 100644 --- a/tests/formatter/BookmarkMarkdownFormatterTest.php +++ b/tests/formatter/BookmarkMarkdownFormatterTest.php @@ -132,6 +132,49 @@ public function testFormatDescription() $this->assertEquals($description, $link['description']); } + /** + * Make sure that the description is properly formatted by the default formatter. + */ + public function testFormatDescriptionWithSearchHighlight() + { + $description = 'This a description'. PHP_EOL; + $description .= 'text https://sub.domain.tld?query=here&for=real#hash more text'. PHP_EOL; + $description .= 'Also, there is an #hashtag added'. PHP_EOL; + $description .= ' A N D KEEP SPACES ! '. PHP_EOL; + $description .= 'And [yet another link](https://other.domain.tld)'. PHP_EOL; + + $bookmark = new Bookmark(); + $bookmark->setDescription($description); + $bookmark->addAdditionalContentEntry( + 'search_highlight', + ['description' => [ + ['start' => 18, 'end' => 26], // cription + ['start' => 49, 'end' => 52], // sub + ['start' => 84, 'end' => 88], // hash + ['start' => 118, 'end' => 123], // hasht + ['start' => 203, 'end' => 215], // other.domain + ]] + ); + + $link = $this->formatter->format($bookmark); + + $description = '

'; + $description .= 'This a <strong>description</strong>
' . + PHP_EOL; + $url = 'https://sub.domain.tld?query=here&for=real#hash'; + $highlighted = 'https://sub.domain.tld'; + $highlighted .= '?query=here&for=real#hash'; + $description .= 'text '. $highlighted .' more text
'. PHP_EOL; + $description .= 'Also, there is an #hasht' . + 'ag added
'. PHP_EOL; + $description .= 'A N D KEEP SPACES !
' . PHP_EOL; + $description .= 'And ' . + 'yet another link'; + $description .= '

'; + + $this->assertEquals($description, $link['description']); + } + /** * Test formatting URL with an index_url set * It should prepend relative links. diff --git a/tests/front/controller/admin/ManageTagControllerTest.php b/tests/front/controller/admin/ManageTagControllerTest.php index af6f273f..56a64cbb 100644 --- a/tests/front/controller/admin/ManageTagControllerTest.php +++ b/tests/front/controller/admin/ManageTagControllerTest.php @@ -6,6 +6,7 @@ use Shaarli\Bookmark\Bookmark; use Shaarli\Bookmark\BookmarkFilter; +use Shaarli\Bookmark\SearchResult; use Shaarli\Config\ConfigManager; use Shaarli\Front\Exception\WrongTokenException; use Shaarli\Security\SessionManager; @@ -100,11 +101,11 @@ public function testSaveRenameTagValid(): void ->expects(static::once()) ->method('search') ->with(['searchtags' => 'old-tag'], BookmarkFilter::$ALL, true) - ->willReturnCallback(function () use ($bookmark1, $bookmark2): array { + ->willReturnCallback(function () use ($bookmark1, $bookmark2): SearchResult { $bookmark1->expects(static::once())->method('renameTag')->with('old-tag', 'new-tag'); $bookmark2->expects(static::once())->method('renameTag')->with('old-tag', 'new-tag'); - return [$bookmark1, $bookmark2]; + return SearchResult::getSearchResult([$bookmark1, $bookmark2]); }) ; $this->container->bookmarkService @@ -153,11 +154,11 @@ public function testSaveDeleteTagValid(): void ->expects(static::once()) ->method('search') ->with(['searchtags' => 'old-tag'], BookmarkFilter::$ALL, true) - ->willReturnCallback(function () use ($bookmark1, $bookmark2): array { + ->willReturnCallback(function () use ($bookmark1, $bookmark2): SearchResult { $bookmark1->expects(static::once())->method('deleteTag')->with('old-tag'); $bookmark2->expects(static::once())->method('deleteTag')->with('old-tag'); - return [$bookmark1, $bookmark2]; + return SearchResult::getSearchResult([$bookmark1, $bookmark2]); }) ; $this->container->bookmarkService diff --git a/tests/front/controller/admin/ShaareManageControllerTest/DeleteBookmarkTest.php b/tests/front/controller/admin/ShaareManageControllerTest/DeleteBookmarkTest.php index a276d988..42d0c0d6 100644 --- a/tests/front/controller/admin/ShaareManageControllerTest/DeleteBookmarkTest.php +++ b/tests/front/controller/admin/ShaareManageControllerTest/DeleteBookmarkTest.php @@ -363,6 +363,7 @@ public function testDeleteBookmarkFromBookmarklet(): void $this->container->bookmarkService->method('get')->with('123')->willReturn( (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123') ); + $this->container->bookmarkService->expects(static::once())->method('remove'); $this->container->formatterFactory = $this->createMock(FormatterFactory::class); $this->container->formatterFactory @@ -379,6 +380,48 @@ public function testDeleteBookmarkFromBookmarklet(): void $result = $this->controller->deleteBookmark($request, $response); static::assertSame(200, $result->getStatusCode()); - static::assertSame('', (string) $result->getBody('location')); + static::assertSame('', (string) $result->getBody()); + } + + /** + * Delete bookmark - from batch view + */ + public function testDeleteBookmarkFromBatch(): void + { + $parameters = [ + 'id' => '123', + 'source' => 'batch', + ]; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $this->container->bookmarkService->method('get')->with('123')->willReturn( + (new Bookmark())->setId(123)->setUrl('http://domain.tld')->setTitle('Title 123') + ); + $this->container->bookmarkService->expects(static::once())->method('remove'); + + $this->container->formatterFactory = $this->createMock(FormatterFactory::class); + $this->container->formatterFactory + ->expects(static::once()) + ->method('getFormatter') + ->willReturnCallback(function (): BookmarkFormatter { + $formatter = $this->createMock(BookmarkFormatter::class); + $formatter->method('format')->willReturn(['formatted']); + + return $formatter; + }) + ; + + $result = $this->controller->deleteBookmark($request, $response); + + static::assertSame(204, $result->getStatusCode()); + static::assertEmpty((string) $result->getBody()); } } diff --git a/tests/front/controller/admin/ThumbnailsControllerTest.php b/tests/front/controller/admin/ThumbnailsControllerTest.php index e5749654..0c9b63c3 100644 --- a/tests/front/controller/admin/ThumbnailsControllerTest.php +++ b/tests/front/controller/admin/ThumbnailsControllerTest.php @@ -6,6 +6,7 @@ use Shaarli\Bookmark\Bookmark; use Shaarli\Bookmark\Exception\BookmarkNotFoundException; +use Shaarli\Bookmark\SearchResult; use Shaarli\TestCase; use Shaarli\Thumbnailer; use Slim\Http\Request; @@ -40,12 +41,12 @@ public function testIndex(): void $this->container->bookmarkService ->expects(static::once()) ->method('search') - ->willReturn([ + ->willReturn(SearchResult::getSearchResult([ (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'), (new Bookmark())->setId(2)->setUrl('?abcdef')->setTitle('Note 1'), (new Bookmark())->setId(3)->setUrl('http://url2.tld')->setTitle('Title 2'), (new Bookmark())->setId(4)->setUrl('ftp://domain.tld', ['ftp'])->setTitle('FTP'), - ]) + ])) ; $result = $this->controller->index($request, $response); diff --git a/tests/front/controller/visitor/BookmarkListControllerTest.php b/tests/front/controller/visitor/BookmarkListControllerTest.php index dec938f2..0fbab9d4 100644 --- a/tests/front/controller/visitor/BookmarkListControllerTest.php +++ b/tests/front/controller/visitor/BookmarkListControllerTest.php @@ -6,6 +6,7 @@ use Shaarli\Bookmark\Bookmark; use Shaarli\Bookmark\Exception\BookmarkNotFoundException; +use Shaarli\Bookmark\SearchResult; use Shaarli\Config\ConfigManager; use Shaarli\Security\LoginManager; use Shaarli\TestCase; @@ -45,13 +46,15 @@ public function testIndexDefaultFirstPage(): void ['searchtags' => '', 'searchterm' => ''], null, false, - false + false, + false, + ['offset' => 0, 'limit' => 2] ) - ->willReturn([ + ->willReturn(SearchResult::getSearchResult([ (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'), (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'), (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'), - ] + ], 0, 2) ); $this->container->sessionManager @@ -119,13 +122,15 @@ public function testIndexDefaultSecondPage(): void ['searchtags' => '', 'searchterm' => ''], null, false, - false + false, + false, + ['offset' => 2, 'limit' => 2] ) - ->willReturn([ + ->willReturn(SearchResult::getSearchResult([ (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'), (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'), (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'), - ]) + ], 2, 2)) ; $this->container->sessionManager @@ -207,13 +212,15 @@ public function testIndexDefaultWithFilters(): void ['searchtags' => 'abc@def', 'searchterm' => 'ghi jkl'], 'private', false, - true + true, + false, + ['offset' => 0, 'limit' => 2] ) - ->willReturn([ + ->willReturn(SearchResult::getSearchResult([ (new Bookmark())->setId(1)->setUrl('http://url1.tld')->setTitle('Title 1'), (new Bookmark())->setId(2)->setUrl('http://url2.tld')->setTitle('Title 2'), (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setTitle('Title 3'), - ]) + ], 0, 2)) ; $result = $this->controller->index($request, $response); @@ -358,13 +365,13 @@ public function testThumbnailUpdateFromLinkList(): void $this->container->bookmarkService ->expects(static::once()) ->method('search') - ->willReturn([ + ->willReturn(SearchResult::getSearchResult([ (new Bookmark())->setId(1)->setUrl('https://url1.tld')->setTitle('Title 1')->setThumbnail(false), $b1 = (new Bookmark())->setId(2)->setUrl('https://url2.tld')->setTitle('Title 2'), (new Bookmark())->setId(3)->setUrl('https://url3.tld')->setTitle('Title 3')->setThumbnail(false), $b2 = (new Bookmark())->setId(2)->setUrl('https://url4.tld')->setTitle('Title 4'), (new Bookmark())->setId(2)->setUrl('ftp://url5.tld', ['ftp'])->setTitle('Title 5'), - ]) + ])) ; $this->container->bookmarkService ->expects(static::exactly(2)) diff --git a/tests/front/controller/visitor/DailyControllerTest.php b/tests/front/controller/visitor/DailyControllerTest.php index 70fbce54..821ba321 100644 --- a/tests/front/controller/visitor/DailyControllerTest.php +++ b/tests/front/controller/visitor/DailyControllerTest.php @@ -5,6 +5,7 @@ namespace Shaarli\Front\Controller\Visitor; use Shaarli\Bookmark\Bookmark; +use Shaarli\Bookmark\SearchResult; use Shaarli\Feed\CachedPage; use Shaarli\TestCase; use Slim\Http\Request; @@ -347,13 +348,15 @@ public function testValidRssControllerInvokeDefault(): void $request = $this->createMock(Request::class); $response = new Response(); - $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([ - (new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'), - (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'), - (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'), - (new Bookmark())->setId(4)->setCreated($dates[2])->setUrl('http://domain.tld/4'), - (new Bookmark())->setId(5)->setCreated($dates[3])->setUrl('http://domain.tld/5'), - ]); + $this->container->bookmarkService->expects(static::once())->method('search')->willReturn( + SearchResult::getSearchResult([ + (new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'), + (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'), + (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'), + (new Bookmark())->setId(4)->setCreated($dates[2])->setUrl('http://domain.tld/4'), + (new Bookmark())->setId(5)->setCreated($dates[3])->setUrl('http://domain.tld/5'), + ]) + ); $this->container->pageCacheManager ->expects(static::once()) @@ -454,7 +457,9 @@ public function testValidRssControllerInvokeNoBookmark(): void $request = $this->createMock(Request::class); $response = new Response(); - $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([]); + $this->container->bookmarkService + ->expects(static::once())->method('search') + ->willReturn(SearchResult::getSearchResult([])); // Save RainTPL assigned variables $assignedVariables = []; @@ -613,11 +618,13 @@ public function testSimpleRssWeekly(): void }); $response = new Response(); - $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([ - (new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'), - (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'), - (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'), - ]); + $this->container->bookmarkService->expects(static::once())->method('search')->willReturn( + SearchResult::getSearchResult([ + (new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'), + (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'), + (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'), + ]) + ); // Save RainTPL assigned variables $assignedVariables = []; @@ -674,11 +681,13 @@ public function testSimpleRssMonthly(): void }); $response = new Response(); - $this->container->bookmarkService->expects(static::once())->method('search')->willReturn([ - (new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'), - (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'), - (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'), - ]); + $this->container->bookmarkService->expects(static::once())->method('search')->willReturn( + SearchResult::getSearchResult([ + (new Bookmark())->setId(1)->setCreated($dates[0])->setUrl('http://domain.tld/1'), + (new Bookmark())->setId(2)->setCreated($dates[1])->setUrl('http://domain.tld/2'), + (new Bookmark())->setId(3)->setCreated($dates[1])->setUrl('http://domain.tld/3'), + ]) + ); // Save RainTPL assigned variables $assignedVariables = []; diff --git a/tests/front/controller/visitor/PictureWallControllerTest.php b/tests/front/controller/visitor/PictureWallControllerTest.php index b868231d..429e99a2 100644 --- a/tests/front/controller/visitor/PictureWallControllerTest.php +++ b/tests/front/controller/visitor/PictureWallControllerTest.php @@ -5,6 +5,7 @@ namespace Shaarli\Front\Controller\Visitor; use Shaarli\Bookmark\Bookmark; +use Shaarli\Bookmark\SearchResult; use Shaarli\Config\ConfigManager; use Shaarli\Front\Exception\ThumbnailsDisabledException; use Shaarli\TestCase; @@ -50,17 +51,17 @@ public function testValidControllerInvokeDefault(): void $this->container->bookmarkService ->expects(static::once()) ->method('search') - ->willReturnCallback(function (array $parameters, ?string $visibility): array { + ->willReturnCallback(function (array $parameters, ?string $visibility): SearchResult { // Visibility is set through the container, not the call static::assertNull($visibility); // No query parameters if (count($parameters) === 0) { - return [ + return SearchResult::getSearchResult([ (new Bookmark())->setId(1)->setUrl('http://url.tld')->setThumbnail('thumb1'), (new Bookmark())->setId(2)->setUrl('http://url2.tld'), (new Bookmark())->setId(3)->setUrl('http://url3.tld')->setThumbnail('thumb2'), - ]; + ]); } }) ; diff --git a/tests/front/controller/visitor/ShaarliVisitorControllerTest.php b/tests/front/controller/visitor/ShaarliVisitorControllerTest.php index 935ec24e..7676f14d 100644 --- a/tests/front/controller/visitor/ShaarliVisitorControllerTest.php +++ b/tests/front/controller/visitor/ShaarliVisitorControllerTest.php @@ -93,6 +93,9 @@ public function testRender(): void static::assertSame('templateName', $render); + static::assertSame('templateName', $this->assignedValues['_PAGE_']); + static::assertSame('templateName', $this->assignedValues['template']); + static::assertSame(10, $this->assignedValues['linkcount']); static::assertSame(5, $this->assignedValues['privateLinkcount']); static::assertSame(['error'], $this->assignedValues['plugin_errors']); diff --git a/tests/netscape/BookmarkExportTest.php b/tests/netscape/BookmarkExportTest.php index ad288f78..b8a88cd8 100644 --- a/tests/netscape/BookmarkExportTest.php +++ b/tests/netscape/BookmarkExportTest.php @@ -8,6 +8,7 @@ use Shaarli\Formatter\BookmarkFormatter; use Shaarli\Formatter\FormatterFactory; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Shaarli\TestCase; require_once 'tests/utils/ReferenceLinkDB.php'; @@ -47,6 +48,9 @@ class BookmarkExportTest extends TestCase */ protected static $history; + /** @var PluginManager */ + protected static $pluginManager; + /** * @var NetscapeBookmarkUtils */ @@ -63,7 +67,14 @@ public static function setUpBeforeClass(): void static::$refDb = new \ReferenceLinkDB(); static::$refDb->write(static::$testDatastore); static::$history = new History('sandbox/history.php'); - static::$bookmarkService = new BookmarkFileService(static::$conf, static::$history, $mutex, true); + static::$pluginManager = new PluginManager(static::$conf); + static::$bookmarkService = new BookmarkFileService( + static::$conf, + static::$pluginManager, + static::$history, + $mutex, + true + ); $factory = new FormatterFactory(static::$conf, true); static::$formatter = $factory->getFormatter('raw'); } diff --git a/tests/netscape/BookmarkImportTest.php b/tests/netscape/BookmarkImportTest.php index 6856ebca..ecd33ea1 100644 --- a/tests/netscape/BookmarkImportTest.php +++ b/tests/netscape/BookmarkImportTest.php @@ -10,6 +10,7 @@ use Shaarli\Bookmark\BookmarkFilter; use Shaarli\Config\ConfigManager; use Shaarli\History; +use Shaarli\Plugin\PluginManager; use Shaarli\TestCase; use Slim\Http\UploadedFile; @@ -71,6 +72,9 @@ class BookmarkImportTest extends TestCase */ protected $netscapeBookmarkUtils; + /** @var PluginManager */ + protected $pluginManager; + /** * @var string Save the current timezone. */ @@ -99,7 +103,14 @@ protected function setUp(): void $this->conf->set('resource.page_cache', $this->pagecache); $this->conf->set('resource.datastore', self::$testDatastore); $this->history = new History(self::$historyFilePath); - $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, $mutex, true); + $this->pluginManager = new PluginManager($this->conf); + $this->bookmarkService = new BookmarkFileService( + $this->conf, + $this->pluginManager, + $this->history, + $mutex, + true + ); $this->netscapeBookmarkUtils = new NetscapeBookmarkUtils($this->bookmarkService, $this->conf, $this->history); } diff --git a/tests/plugins/test/test.php b/tests/plugins/test/test.php index 34cd339e..8dbb3f94 100644 --- a/tests/plugins/test/test.php +++ b/tests/plugins/test/test.php @@ -1,5 +1,7 @@ conf = new ConfigManager(self::$configFile); - $this->bookmarkService = new BookmarkFileService($this->conf, $this->createMock(History::class), $mutex, true); + $this->bookmarkService = new BookmarkFileService( + $this->conf, + $this->createMock(PluginManager::class), + $this->createMock(History::class), + $mutex, + true + ); $this->updater = new Updater([], $this->bookmarkService, $this->conf, true); } diff --git a/tpl/default/editlink.batch.html b/tpl/default/editlink.batch.html index b1f8e5bd..973a5ccc 100644 --- a/tpl/default/editlink.batch.html +++ b/tpl/default/editlink.batch.html @@ -20,6 +20,7 @@ {loop="$links"} + {$batchId=$key} {include="editlink"} {/loop} diff --git a/tpl/default/editlink.html b/tpl/default/editlink.html index 83e541fd..a5828c75 100644 --- a/tpl/default/editlink.html +++ b/tpl/default/editlink.html @@ -1,3 +1,4 @@ +{$batchId=isset($batchId) ? $batchId : ''} {if="empty($batch_mode)"} @@ -10,7 +11,7 @@ {ignore}Lil hack: when included in a loop in batch mode, `$value` is assigned by RainTPL with template vars.{/ignore} {function="extract($value) ? '' : ''"} {/if} -