aboutsummaryrefslogtreecommitdiffhomepage
path: root/application/formatter/BookmarkDefaultFormatter.php
diff options
context:
space:
mode:
Diffstat (limited to 'application/formatter/BookmarkDefaultFormatter.php')
-rw-r--r--application/formatter/BookmarkDefaultFormatter.php140
1 files changed, 134 insertions, 6 deletions
diff --git a/application/formatter/BookmarkDefaultFormatter.php b/application/formatter/BookmarkDefaultFormatter.php
index 9d4a0fa0..7e0afafc 100644
--- a/application/formatter/BookmarkDefaultFormatter.php
+++ b/application/formatter/BookmarkDefaultFormatter.php
@@ -12,10 +12,13 @@ namespace Shaarli\Formatter;
12 */ 12 */
13class BookmarkDefaultFormatter extends BookmarkFormatter 13class BookmarkDefaultFormatter extends BookmarkFormatter
14{ 14{
15 protected const SEARCH_HIGHLIGHT_OPEN = '|@@HIGHLIGHT';
16 protected 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,33 @@ 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 $description = format_description(
50 escape($description),
51 $indexUrl,
52 $this->conf->get('formatter_settings.autolink', true)
53 );
54
55 return $this->replaceTokens($description);
30 } 56 }
31 57
32 /** 58 /**
@@ -40,15 +66,36 @@ class BookmarkDefaultFormatter extends BookmarkFormatter
40 /** 66 /**
41 * @inheritdoc 67 * @inheritdoc
42 */ 68 */
43 public function formatTagString($bookmark) 69 protected function formatTagListHtml($bookmark)
44 { 70 {
45 return implode(' ', $this->formatTagList($bookmark)); 71 $tagsSeparator = $this->conf->get('general.tags_separator', ' ');
72 if (empty($bookmark->getAdditionalContentEntry('search_highlight')['tags'])) {
73 return $this->formatTagList($bookmark);
74 }
75
76 $tags = $this->tokenizeSearchHighlightField(
77 $bookmark->getTagsString($tagsSeparator),
78 $bookmark->getAdditionalContentEntry('search_highlight')['tags']
79 );
80 $tags = $this->filterTagList(tags_str2array($tags, $tagsSeparator));
81 $tags = escape($tags);
82 $tags = $this->replaceTokensArray($tags);
83
84 return $tags;
46 } 85 }
47 86
48 /** 87 /**
49 * @inheritdoc 88 * @inheritdoc
50 */ 89 */
51 public function formatUrl($bookmark) 90 protected function formatTagString($bookmark)
91 {
92 return implode($this->conf->get('general.tags_separator'), $this->formatTagList($bookmark));
93 }
94
95 /**
96 * @inheritdoc
97 */
98 protected function formatUrl($bookmark)
52 { 99 {
53 if ($bookmark->isNote() && isset($this->contextData['index_url'])) { 100 if ($bookmark->isNote() && isset($this->contextData['index_url'])) {
54 return rtrim($this->contextData['index_url'], '/') . '/' . escape(ltrim($bookmark->getUrl(), '/')); 101 return rtrim($this->contextData['index_url'], '/') . '/' . escape(ltrim($bookmark->getUrl(), '/'));
@@ -80,8 +127,89 @@ class BookmarkDefaultFormatter extends BookmarkFormatter
80 /** 127 /**
81 * @inheritdoc 128 * @inheritdoc
82 */ 129 */
130 protected function formatUrlHtml($bookmark)
131 {
132 $url = $this->tokenizeSearchHighlightField(
133 $bookmark->getUrl() ?? '',
134 $bookmark->getAdditionalContentEntry('search_highlight')['url'] ?? []
135 );
136
137 return $this->replaceTokens(escape($url));
138 }
139
140 /**
141 * @inheritdoc
142 */
83 protected function formatThumbnail($bookmark) 143 protected function formatThumbnail($bookmark)
84 { 144 {
85 return escape($bookmark->getThumbnail()); 145 return escape($bookmark->getThumbnail());
86 } 146 }
147
148 /**
149 * Insert search highlight token in provided field content based on a list of search result positions
150 *
151 * @param string $fieldContent
152 * @param array|null $positions List of of search results with 'start' and 'end' positions.
153 *
154 * @return string Updated $fieldContent.
155 */
156 protected function tokenizeSearchHighlightField(string $fieldContent, ?array $positions): string
157 {
158 if (empty($positions)) {
159 return $fieldContent;
160 }
161
162 $insertedTokens = 0;
163 $tokenLength = strlen(static::SEARCH_HIGHLIGHT_OPEN);
164 foreach ($positions as $position) {
165 $position = [
166 'start' => $position['start'] + ($insertedTokens * $tokenLength),
167 'end' => $position['end'] + ($insertedTokens * $tokenLength),
168 ];
169
170 $content = mb_substr($fieldContent, 0, $position['start']);
171 $content .= static::SEARCH_HIGHLIGHT_OPEN;
172 $content .= mb_substr($fieldContent, $position['start'], $position['end'] - $position['start']);
173 $content .= static::SEARCH_HIGHLIGHT_CLOSE;
174 $content .= mb_substr($fieldContent, $position['end']);
175
176 $fieldContent = $content;
177
178 $insertedTokens += 2;
179 }
180
181 return $fieldContent;
182 }
183
184 /**
185 * Replace search highlight tokens with HTML highlighted span.
186 *
187 * @param string $fieldContent
188 *
189 * @return string updated content.
190 */
191 protected function replaceTokens(string $fieldContent): string
192 {
193 return str_replace(
194 [static::SEARCH_HIGHLIGHT_OPEN, static::SEARCH_HIGHLIGHT_CLOSE],
195 ['<span class="search-highlight">', '</span>'],
196 $fieldContent
197 );
198 }
199
200 /**
201 * Apply replaceTokens to an array of content strings.
202 *
203 * @param string[] $fieldContents
204 *
205 * @return array
206 */
207 protected function replaceTokensArray(array $fieldContents): array
208 {
209 foreach ($fieldContents as &$entry) {
210 $entry = $this->replaceTokens($entry);
211 }
212
213 return $fieldContents;
214 }
87} 215}