diff options
Diffstat (limited to 'application/formatter')
-rw-r--r-- | application/formatter/BookmarkDefaultFormatter.php | 154 | ||||
-rw-r--r-- | application/formatter/BookmarkFormatter.php | 101 | ||||
-rw-r--r-- | application/formatter/BookmarkMarkdownExtraFormatter.php | 24 | ||||
-rw-r--r-- | application/formatter/BookmarkMarkdownFormatter.php | 10 | ||||
-rw-r--r-- | application/formatter/FormatterFactory.php | 2 |
5 files changed, 269 insertions, 22 deletions
diff --git a/application/formatter/BookmarkDefaultFormatter.php b/application/formatter/BookmarkDefaultFormatter.php index c6c59064..d58a5e39 100644 --- a/application/formatter/BookmarkDefaultFormatter.php +++ b/application/formatter/BookmarkDefaultFormatter.php | |||
@@ -12,10 +12,13 @@ namespace Shaarli\Formatter; | |||
12 | */ | 12 | */ |
13 | class BookmarkDefaultFormatter extends BookmarkFormatter | 13 | class BookmarkDefaultFormatter extends BookmarkFormatter |
14 | { | 14 | { |
15 | const SEARCH_HIGHLIGHT_OPEN = '|@@HIGHLIGHT'; | ||
16 | const SEARCH_HIGHLIGHT_CLOSE = 'HIGHLIGHT@@|'; | ||
17 | |||
15 | /** | 18 | /** |
16 | * @inheritdoc | 19 | * @inheritdoc |
17 | */ | 20 | */ |
18 | public function formatTitle($bookmark) | 21 | protected function formatTitle($bookmark) |
19 | { | 22 | { |
20 | return escape($bookmark->getTitle()); | 23 | return escape($bookmark->getTitle()); |
21 | } | 24 | } |
@@ -23,10 +26,28 @@ class BookmarkDefaultFormatter extends BookmarkFormatter | |||
23 | /** | 26 | /** |
24 | * @inheritdoc | 27 | * @inheritdoc |
25 | */ | 28 | */ |
26 | public function formatDescription($bookmark) | 29 | protected function formatTitleHtml($bookmark) |
30 | { | ||
31 | $title = $this->tokenizeSearchHighlightField( | ||
32 | $bookmark->getTitle() ?? '', | ||
33 | $bookmark->getAdditionalContentEntry('search_highlight')['title'] ?? [] | ||
34 | ); | ||
35 | |||
36 | return $this->replaceTokens(escape($title)); | ||
37 | } | ||
38 | |||
39 | /** | ||
40 | * @inheritdoc | ||
41 | */ | ||
42 | protected function formatDescription($bookmark) | ||
27 | { | 43 | { |
28 | $indexUrl = ! empty($this->contextData['index_url']) ? $this->contextData['index_url'] : ''; | 44 | $indexUrl = ! empty($this->contextData['index_url']) ? $this->contextData['index_url'] : ''; |
29 | return format_description(escape($bookmark->getDescription()), $indexUrl); | 45 | $description = $this->tokenizeSearchHighlightField( |
46 | $bookmark->getDescription() ?? '', | ||
47 | $bookmark->getAdditionalContentEntry('search_highlight')['description'] ?? [] | ||
48 | ); | ||
49 | |||
50 | return $this->replaceTokens(format_description(escape($description), $indexUrl)); | ||
30 | } | 51 | } |
31 | 52 | ||
32 | /** | 53 | /** |
@@ -40,7 +61,27 @@ class BookmarkDefaultFormatter extends BookmarkFormatter | |||
40 | /** | 61 | /** |
41 | * @inheritdoc | 62 | * @inheritdoc |
42 | */ | 63 | */ |
43 | public function formatTagString($bookmark) | 64 | protected function formatTagListHtml($bookmark) |
65 | { | ||
66 | if (empty($bookmark->getAdditionalContentEntry('search_highlight')['tags'])) { | ||
67 | return $this->formatTagList($bookmark); | ||
68 | } | ||
69 | |||
70 | $tags = $this->tokenizeSearchHighlightField( | ||
71 | $bookmark->getTagsString(), | ||
72 | $bookmark->getAdditionalContentEntry('search_highlight')['tags'] | ||
73 | ); | ||
74 | $tags = $this->filterTagList(explode(' ', $tags)); | ||
75 | $tags = escape($tags); | ||
76 | $tags = $this->replaceTokensArray($tags); | ||
77 | |||
78 | return $tags; | ||
79 | } | ||
80 | |||
81 | /** | ||
82 | * @inheritdoc | ||
83 | */ | ||
84 | protected function formatTagString($bookmark) | ||
44 | { | 85 | { |
45 | return implode(' ', $this->formatTagList($bookmark)); | 86 | return implode(' ', $this->formatTagList($bookmark)); |
46 | } | 87 | } |
@@ -48,13 +89,12 @@ class BookmarkDefaultFormatter extends BookmarkFormatter | |||
48 | /** | 89 | /** |
49 | * @inheritdoc | 90 | * @inheritdoc |
50 | */ | 91 | */ |
51 | public function formatUrl($bookmark) | 92 | protected function formatUrl($bookmark) |
52 | { | 93 | { |
53 | if (! empty($this->contextData['index_url']) && ( | 94 | if ($bookmark->isNote() && isset($this->contextData['index_url'])) { |
54 | startsWith($bookmark->getUrl(), '?') || startsWith($bookmark->getUrl(), '/') | 95 | return rtrim($this->contextData['index_url'], '/') . '/' . escape(ltrim($bookmark->getUrl(), '/')); |
55 | )) { | ||
56 | return $this->contextData['index_url'] . escape($bookmark->getUrl()); | ||
57 | } | 96 | } |
97 | |||
58 | return escape($bookmark->getUrl()); | 98 | return escape($bookmark->getUrl()); |
59 | } | 99 | } |
60 | 100 | ||
@@ -63,19 +103,107 @@ class BookmarkDefaultFormatter extends BookmarkFormatter | |||
63 | */ | 103 | */ |
64 | protected function formatRealUrl($bookmark) | 104 | protected function formatRealUrl($bookmark) |
65 | { | 105 | { |
66 | if (! empty($this->contextData['index_url']) && ( | 106 | if ($bookmark->isNote()) { |
67 | startsWith($bookmark->getUrl(), '?') || startsWith($bookmark->getUrl(), '/') | 107 | if (isset($this->contextData['index_url'])) { |
68 | )) { | 108 | $prefix = rtrim($this->contextData['index_url'], '/') . '/'; |
69 | return $this->contextData['index_url'] . escape($bookmark->getUrl()); | 109 | } |
110 | |||
111 | if (isset($this->contextData['base_path'])) { | ||
112 | $prefix = rtrim($this->contextData['base_path'], '/') . '/'; | ||
113 | } | ||
114 | |||
115 | return escape($prefix ?? '') . escape(ltrim($bookmark->getUrl(), '/')); | ||
70 | } | 116 | } |
117 | |||
71 | return escape($bookmark->getUrl()); | 118 | return escape($bookmark->getUrl()); |
72 | } | 119 | } |
73 | 120 | ||
74 | /** | 121 | /** |
75 | * @inheritdoc | 122 | * @inheritdoc |
76 | */ | 123 | */ |
124 | protected function formatUrlHtml($bookmark) | ||
125 | { | ||
126 | $url = $this->tokenizeSearchHighlightField( | ||
127 | $bookmark->getUrl() ?? '', | ||
128 | $bookmark->getAdditionalContentEntry('search_highlight')['url'] ?? [] | ||
129 | ); | ||
130 | |||
131 | return $this->replaceTokens(escape($url)); | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * @inheritdoc | ||
136 | */ | ||
77 | protected function formatThumbnail($bookmark) | 137 | protected function formatThumbnail($bookmark) |
78 | { | 138 | { |
79 | return escape($bookmark->getThumbnail()); | 139 | return escape($bookmark->getThumbnail()); |
80 | } | 140 | } |
141 | |||
142 | /** | ||
143 | * Insert search highlight token in provided field content based on a list of search result positions | ||
144 | * | ||
145 | * @param string $fieldContent | ||
146 | * @param array|null $positions List of of search results with 'start' and 'end' positions. | ||
147 | * | ||
148 | * @return string Updated $fieldContent. | ||
149 | */ | ||
150 | protected function tokenizeSearchHighlightField(string $fieldContent, ?array $positions): string | ||
151 | { | ||
152 | if (empty($positions)) { | ||
153 | return $fieldContent; | ||
154 | } | ||
155 | |||
156 | $insertedTokens = 0; | ||
157 | $tokenLength = strlen(static::SEARCH_HIGHLIGHT_OPEN); | ||
158 | foreach ($positions as $position) { | ||
159 | $position = [ | ||
160 | 'start' => $position['start'] + ($insertedTokens * $tokenLength), | ||
161 | 'end' => $position['end'] + ($insertedTokens * $tokenLength), | ||
162 | ]; | ||
163 | |||
164 | $content = mb_substr($fieldContent, 0, $position['start']); | ||
165 | $content .= static::SEARCH_HIGHLIGHT_OPEN; | ||
166 | $content .= mb_substr($fieldContent, $position['start'], $position['end'] - $position['start']); | ||
167 | $content .= static::SEARCH_HIGHLIGHT_CLOSE; | ||
168 | $content .= mb_substr($fieldContent, $position['end']); | ||
169 | |||
170 | $fieldContent = $content; | ||
171 | |||
172 | $insertedTokens += 2; | ||
173 | } | ||
174 | |||
175 | return $fieldContent; | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * Replace search highlight tokens with HTML highlighted span. | ||
180 | * | ||
181 | * @param string $fieldContent | ||
182 | * | ||
183 | * @return string updated content. | ||
184 | */ | ||
185 | protected function replaceTokens(string $fieldContent): string | ||
186 | { | ||
187 | return str_replace( | ||
188 | [static::SEARCH_HIGHLIGHT_OPEN, static::SEARCH_HIGHLIGHT_CLOSE], | ||
189 | ['<span class="search-highlight">', '</span>'], | ||
190 | $fieldContent | ||
191 | ); | ||
192 | } | ||
193 | |||
194 | /** | ||
195 | * Apply replaceTokens to an array of content strings. | ||
196 | * | ||
197 | * @param string[] $fieldContents | ||
198 | * | ||
199 | * @return array | ||
200 | */ | ||
201 | protected function replaceTokensArray(array $fieldContents): array | ||
202 | { | ||
203 | foreach ($fieldContents as &$entry) { | ||
204 | $entry = $this->replaceTokens($entry); | ||
205 | } | ||
206 | |||
207 | return $fieldContents; | ||
208 | } | ||
81 | } | 209 | } |
diff --git a/application/formatter/BookmarkFormatter.php b/application/formatter/BookmarkFormatter.php index a80d83fc..e1b7f705 100644 --- a/application/formatter/BookmarkFormatter.php +++ b/application/formatter/BookmarkFormatter.php | |||
@@ -2,15 +2,38 @@ | |||
2 | 2 | ||
3 | namespace Shaarli\Formatter; | 3 | namespace Shaarli\Formatter; |
4 | 4 | ||
5 | use DateTime; | 5 | use DateTimeInterface; |
6 | use Shaarli\Config\ConfigManager; | ||
7 | use Shaarli\Bookmark\Bookmark; | 6 | use Shaarli\Bookmark\Bookmark; |
7 | use Shaarli\Config\ConfigManager; | ||
8 | 8 | ||
9 | /** | 9 | /** |
10 | * Class BookmarkFormatter | 10 | * Class BookmarkFormatter |
11 | * | 11 | * |
12 | * Abstract class processing all bookmark attributes through methods designed to be overridden. | 12 | * Abstract class processing all bookmark attributes through methods designed to be overridden. |
13 | * | 13 | * |
14 | * List of available formatted fields: | ||
15 | * - id ID | ||
16 | * - shorturl Unique identifier, used in permalinks | ||
17 | * - url URL, can be altered in some way, e.g. passing through an HTTP reverse proxy | ||
18 | * - real_url (legacy) same as `url` | ||
19 | * - url_html URL to be displayed in HTML content (it can contain HTML tags) | ||
20 | * - title Title | ||
21 | * - title_html Title to be displayed in HTML content (it can contain HTML tags) | ||
22 | * - description Description content. It most likely contains HTML tags | ||
23 | * - thumbnail Thumbnail: path to local cache file, false if there is none, null if hasn't been retrieved | ||
24 | * - taglist List of tags (array) | ||
25 | * - taglist_urlencoded List of tags (array) URL encoded: it must be used to create a link to a URL containing a tag | ||
26 | * - taglist_html List of tags (array) to be displayed in HTML content (it can contain HTML tags) | ||
27 | * - tags Tags separated by a single whitespace | ||
28 | * - tags_urlencoded Tags separated by a single whitespace, URL encoded: must be used to create a link | ||
29 | * - sticky Is sticky (bool) | ||
30 | * - private Is private (bool) | ||
31 | * - class Additional CSS class | ||
32 | * - created Creation DateTime | ||
33 | * - updated Last edit DateTime | ||
34 | * - timestamp Creation timestamp | ||
35 | * - updated_timestamp Last edit timestamp | ||
36 | * | ||
14 | * @package Shaarli\Formatter | 37 | * @package Shaarli\Formatter |
15 | */ | 38 | */ |
16 | abstract class BookmarkFormatter | 39 | abstract class BookmarkFormatter |
@@ -55,11 +78,16 @@ abstract class BookmarkFormatter | |||
55 | $out['shorturl'] = $this->formatShortUrl($bookmark); | 78 | $out['shorturl'] = $this->formatShortUrl($bookmark); |
56 | $out['url'] = $this->formatUrl($bookmark); | 79 | $out['url'] = $this->formatUrl($bookmark); |
57 | $out['real_url'] = $this->formatRealUrl($bookmark); | 80 | $out['real_url'] = $this->formatRealUrl($bookmark); |
81 | $out['url_html'] = $this->formatUrlHtml($bookmark); | ||
58 | $out['title'] = $this->formatTitle($bookmark); | 82 | $out['title'] = $this->formatTitle($bookmark); |
83 | $out['title_html'] = $this->formatTitleHtml($bookmark); | ||
59 | $out['description'] = $this->formatDescription($bookmark); | 84 | $out['description'] = $this->formatDescription($bookmark); |
60 | $out['thumbnail'] = $this->formatThumbnail($bookmark); | 85 | $out['thumbnail'] = $this->formatThumbnail($bookmark); |
61 | $out['taglist'] = $this->formatTagList($bookmark); | 86 | $out['taglist'] = $this->formatTagList($bookmark); |
87 | $out['taglist_urlencoded'] = $this->formatTagListUrlEncoded($bookmark); | ||
88 | $out['taglist_html'] = $this->formatTagListHtml($bookmark); | ||
62 | $out['tags'] = $this->formatTagString($bookmark); | 89 | $out['tags'] = $this->formatTagString($bookmark); |
90 | $out['tags_urlencoded'] = $this->formatTagStringUrlEncoded($bookmark); | ||
63 | $out['sticky'] = $bookmark->isSticky(); | 91 | $out['sticky'] = $bookmark->isSticky(); |
64 | $out['private'] = $bookmark->isPrivate(); | 92 | $out['private'] = $bookmark->isPrivate(); |
65 | $out['class'] = $this->formatClass($bookmark); | 93 | $out['class'] = $this->formatClass($bookmark); |
@@ -67,6 +95,7 @@ abstract class BookmarkFormatter | |||
67 | $out['updated'] = $this->formatUpdated($bookmark); | 95 | $out['updated'] = $this->formatUpdated($bookmark); |
68 | $out['timestamp'] = $this->formatCreatedTimestamp($bookmark); | 96 | $out['timestamp'] = $this->formatCreatedTimestamp($bookmark); |
69 | $out['updated_timestamp'] = $this->formatUpdatedTimestamp($bookmark); | 97 | $out['updated_timestamp'] = $this->formatUpdatedTimestamp($bookmark); |
98 | |||
70 | return $out; | 99 | return $out; |
71 | } | 100 | } |
72 | 101 | ||
@@ -80,6 +109,8 @@ abstract class BookmarkFormatter | |||
80 | public function addContextData($key, $value) | 109 | public function addContextData($key, $value) |
81 | { | 110 | { |
82 | $this->contextData[$key] = $value; | 111 | $this->contextData[$key] = $value; |
112 | |||
113 | return $this; | ||
83 | } | 114 | } |
84 | 115 | ||
85 | /** | 116 | /** |
@@ -128,7 +159,19 @@ abstract class BookmarkFormatter | |||
128 | */ | 159 | */ |
129 | protected function formatRealUrl($bookmark) | 160 | protected function formatRealUrl($bookmark) |
130 | { | 161 | { |
131 | return $bookmark->getUrl(); | 162 | return $this->formatUrl($bookmark); |
163 | } | ||
164 | |||
165 | /** | ||
166 | * Format Url Html: to be displayed in HTML content, it can contains HTML tags. | ||
167 | * | ||
168 | * @param Bookmark $bookmark instance | ||
169 | * | ||
170 | * @return string formatted Url HTML | ||
171 | */ | ||
172 | protected function formatUrlHtml($bookmark) | ||
173 | { | ||
174 | return $this->formatUrl($bookmark); | ||
132 | } | 175 | } |
133 | 176 | ||
134 | /** | 177 | /** |
@@ -144,6 +187,18 @@ abstract class BookmarkFormatter | |||
144 | } | 187 | } |
145 | 188 | ||
146 | /** | 189 | /** |
190 | * Format Title HTML: to be displayed in HTML content, it can contains HTML tags. | ||
191 | * | ||
192 | * @param Bookmark $bookmark instance | ||
193 | * | ||
194 | * @return string formatted Title | ||
195 | */ | ||
196 | protected function formatTitleHtml($bookmark) | ||
197 | { | ||
198 | return $bookmark->getTitle(); | ||
199 | } | ||
200 | |||
201 | /** | ||
147 | * Format Description | 202 | * Format Description |
148 | * | 203 | * |
149 | * @param Bookmark $bookmark instance | 204 | * @param Bookmark $bookmark instance |
@@ -180,6 +235,30 @@ abstract class BookmarkFormatter | |||
180 | } | 235 | } |
181 | 236 | ||
182 | /** | 237 | /** |
238 | * Format Url Encoded Tags | ||
239 | * | ||
240 | * @param Bookmark $bookmark instance | ||
241 | * | ||
242 | * @return array formatted Tags | ||
243 | */ | ||
244 | protected function formatTagListUrlEncoded($bookmark) | ||
245 | { | ||
246 | return array_map('urlencode', $this->filterTagList($bookmark->getTags())); | ||
247 | } | ||
248 | |||
249 | /** | ||
250 | * Format Tags HTML: to be displayed in HTML content, it can contains HTML tags. | ||
251 | * | ||
252 | * @param Bookmark $bookmark instance | ||
253 | * | ||
254 | * @return array formatted Tags | ||
255 | */ | ||
256 | protected function formatTagListHtml($bookmark) | ||
257 | { | ||
258 | return $this->formatTagList($bookmark); | ||
259 | } | ||
260 | |||
261 | /** | ||
183 | * Format TagString | 262 | * Format TagString |
184 | * | 263 | * |
185 | * @param Bookmark $bookmark instance | 264 | * @param Bookmark $bookmark instance |
@@ -192,6 +271,18 @@ abstract class BookmarkFormatter | |||
192 | } | 271 | } |
193 | 272 | ||
194 | /** | 273 | /** |
274 | * Format TagString | ||
275 | * | ||
276 | * @param Bookmark $bookmark instance | ||
277 | * | ||
278 | * @return string formatted TagString | ||
279 | */ | ||
280 | protected function formatTagStringUrlEncoded($bookmark) | ||
281 | { | ||
282 | return implode(' ', $this->formatTagListUrlEncoded($bookmark)); | ||
283 | } | ||
284 | |||
285 | /** | ||
195 | * Format Class | 286 | * Format Class |
196 | * Used to add specific CSS class for a link | 287 | * Used to add specific CSS class for a link |
197 | * | 288 | * |
@@ -209,7 +300,7 @@ abstract class BookmarkFormatter | |||
209 | * | 300 | * |
210 | * @param Bookmark $bookmark instance | 301 | * @param Bookmark $bookmark instance |
211 | * | 302 | * |
212 | * @return DateTime instance | 303 | * @return DateTimeInterface instance |
213 | */ | 304 | */ |
214 | protected function formatCreated(Bookmark $bookmark) | 305 | protected function formatCreated(Bookmark $bookmark) |
215 | { | 306 | { |
@@ -221,7 +312,7 @@ abstract class BookmarkFormatter | |||
221 | * | 312 | * |
222 | * @param Bookmark $bookmark instance | 313 | * @param Bookmark $bookmark instance |
223 | * | 314 | * |
224 | * @return DateTime instance | 315 | * @return DateTimeInterface instance |
225 | */ | 316 | */ |
226 | protected function formatUpdated(Bookmark $bookmark) | 317 | protected function formatUpdated(Bookmark $bookmark) |
227 | { | 318 | { |
diff --git a/application/formatter/BookmarkMarkdownExtraFormatter.php b/application/formatter/BookmarkMarkdownExtraFormatter.php new file mode 100644 index 00000000..0694b23f --- /dev/null +++ b/application/formatter/BookmarkMarkdownExtraFormatter.php | |||
@@ -0,0 +1,24 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Shaarli\Formatter; | ||
4 | |||
5 | use Shaarli\Config\ConfigManager; | ||
6 | |||
7 | /** | ||
8 | * Class BookmarkMarkdownExtraFormatter | ||
9 | * | ||
10 | * Format bookmark description into MarkdownExtra format. | ||
11 | * | ||
12 | * @see https://michelf.ca/projects/php-markdown/extra/ | ||
13 | * | ||
14 | * @package Shaarli\Formatter | ||
15 | */ | ||
16 | class BookmarkMarkdownExtraFormatter extends BookmarkMarkdownFormatter | ||
17 | { | ||
18 | public function __construct(ConfigManager $conf, bool $isLoggedIn) | ||
19 | { | ||
20 | parent::__construct($conf, $isLoggedIn); | ||
21 | |||
22 | $this->parsedown = new \ParsedownExtra(); | ||
23 | } | ||
24 | } | ||
diff --git a/application/formatter/BookmarkMarkdownFormatter.php b/application/formatter/BookmarkMarkdownFormatter.php index 077e5312..f7714be9 100644 --- a/application/formatter/BookmarkMarkdownFormatter.php +++ b/application/formatter/BookmarkMarkdownFormatter.php | |||
@@ -56,7 +56,10 @@ class BookmarkMarkdownFormatter extends BookmarkDefaultFormatter | |||
56 | return parent::formatDescription($bookmark); | 56 | return parent::formatDescription($bookmark); |
57 | } | 57 | } |
58 | 58 | ||
59 | $processedDescription = $bookmark->getDescription(); | 59 | $processedDescription = $this->tokenizeSearchHighlightField( |
60 | $bookmark->getDescription() ?? '', | ||
61 | $bookmark->getAdditionalContentEntry('search_highlight')['description'] ?? [] | ||
62 | ); | ||
60 | $processedDescription = $this->filterProtocols($processedDescription); | 63 | $processedDescription = $this->filterProtocols($processedDescription); |
61 | $processedDescription = $this->formatHashTags($processedDescription); | 64 | $processedDescription = $this->formatHashTags($processedDescription); |
62 | $processedDescription = $this->reverseEscapedHtml($processedDescription); | 65 | $processedDescription = $this->reverseEscapedHtml($processedDescription); |
@@ -65,6 +68,7 @@ class BookmarkMarkdownFormatter extends BookmarkDefaultFormatter | |||
65 | ->setBreaksEnabled(true) | 68 | ->setBreaksEnabled(true) |
66 | ->text($processedDescription); | 69 | ->text($processedDescription); |
67 | $processedDescription = $this->sanitizeHtml($processedDescription); | 70 | $processedDescription = $this->sanitizeHtml($processedDescription); |
71 | $processedDescription = $this->replaceTokens($processedDescription); | ||
68 | 72 | ||
69 | if (!empty($processedDescription)) { | 73 | if (!empty($processedDescription)) { |
70 | $processedDescription = '<div class="markdown">'. $processedDescription . '</div>'; | 74 | $processedDescription = '<div class="markdown">'. $processedDescription . '</div>'; |
@@ -114,7 +118,7 @@ class BookmarkMarkdownFormatter extends BookmarkDefaultFormatter | |||
114 | 118 | ||
115 | /** | 119 | /** |
116 | * Replace hashtag in Markdown links format | 120 | * Replace hashtag in Markdown links format |
117 | * E.g. `#hashtag` becomes `[#hashtag](?addtag=hashtag)` | 121 | * E.g. `#hashtag` becomes `[#hashtag](./add-tag/hashtag)` |
118 | * It includes the index URL if specified. | 122 | * It includes the index URL if specified. |
119 | * | 123 | * |
120 | * @param string $description | 124 | * @param string $description |
@@ -133,7 +137,7 @@ class BookmarkMarkdownFormatter extends BookmarkDefaultFormatter | |||
133 | * \p{Mn} - any non marking space (accents, umlauts, etc) | 137 | * \p{Mn} - any non marking space (accents, umlauts, etc) |
134 | */ | 138 | */ |
135 | $regex = '/(^|\s)#([\p{Pc}\p{N}\p{L}\p{Mn}]+)/mui'; | 139 | $regex = '/(^|\s)#([\p{Pc}\p{N}\p{L}\p{Mn}]+)/mui'; |
136 | $replacement = '$1[#$2]('. $indexUrl .'?addtag=$2)'; | 140 | $replacement = '$1[#$2]('. $indexUrl .'./add-tag/$2)'; |
137 | 141 | ||
138 | $descriptionLines = explode(PHP_EOL, $description); | 142 | $descriptionLines = explode(PHP_EOL, $description); |
139 | $descriptionOut = ''; | 143 | $descriptionOut = ''; |
diff --git a/application/formatter/FormatterFactory.php b/application/formatter/FormatterFactory.php index 5f282f68..a029579f 100644 --- a/application/formatter/FormatterFactory.php +++ b/application/formatter/FormatterFactory.php | |||
@@ -38,7 +38,7 @@ class FormatterFactory | |||
38 | * | 38 | * |
39 | * @return BookmarkFormatter instance. | 39 | * @return BookmarkFormatter instance. |
40 | */ | 40 | */ |
41 | public function getFormatter(string $type = null) | 41 | public function getFormatter(string $type = null): BookmarkFormatter |
42 | { | 42 | { |
43 | $type = $type ? $type : $this->conf->get('formatter', 'default'); | 43 | $type = $type ? $type : $this->conf->get('formatter', 'default'); |
44 | $className = '\\Shaarli\\Formatter\\Bookmark'. ucfirst($type) .'Formatter'; | 44 | $className = '\\Shaarli\\Formatter\\Bookmark'. ucfirst($type) .'Formatter'; |