]> git.immae.eu Git - github/shaarli/Shaarli.git/blame - application/formatter/BookmarkDefaultFormatter.php
Default formatter: add a setting to disable auto-linkification
[github/shaarli/Shaarli.git] / application / formatter / BookmarkDefaultFormatter.php
CommitLineData
336a28fa
A
1<?php
2
3namespace Shaarli\Formatter;
4
5/**
6 * Class BookmarkDefaultFormatter
7 *
8 * Default bookmark formatter.
9 * Escape values for HTML display and automatically add link to URL and hashtags.
10 *
11 * @package Shaarli\Formatter
12 */
13class BookmarkDefaultFormatter extends BookmarkFormatter
14{
4e3875c0
A
15 const SEARCH_HIGHLIGHT_OPEN = '|@@HIGHLIGHT';
16 const SEARCH_HIGHLIGHT_CLOSE = 'HIGHLIGHT@@|';
17
336a28fa
A
18 /**
19 * @inheritdoc
20 */
4e3875c0 21 protected function formatTitle($bookmark)
336a28fa
A
22 {
23 return escape($bookmark->getTitle());
24 }
25
26 /**
27 * @inheritdoc
28 */
4e3875c0
A
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)
336a28fa
A
43 {
44 $indexUrl = ! empty($this->contextData['index_url']) ? $this->contextData['index_url'] : '';
4e3875c0
A
45 $description = $this->tokenizeSearchHighlightField(
46 $bookmark->getDescription() ?? '',
47 $bookmark->getAdditionalContentEntry('search_highlight')['description'] ?? []
48 );
740b32b5
A
49 $description = format_description(
50 escape($description),
51 $indexUrl,
52 $this->conf->get('formatter_settings.autolink', true)
53 );
4e3875c0 54
740b32b5 55 return $this->replaceTokens($description);
336a28fa
A
56 }
57
58 /**
59 * @inheritdoc
60 */
61 protected function formatTagList($bookmark)
62 {
a39acb25 63 return escape(parent::formatTagList($bookmark));
336a28fa
A
64 }
65
66 /**
67 * @inheritdoc
68 */
4e3875c0
A
69 protected function formatTagListHtml($bookmark)
70 {
71 if (empty($bookmark->getAdditionalContentEntry('search_highlight')['tags'])) {
72 return $this->formatTagList($bookmark);
73 }
74
75 $tags = $this->tokenizeSearchHighlightField(
76 $bookmark->getTagsString(),
77 $bookmark->getAdditionalContentEntry('search_highlight')['tags']
78 );
79 $tags = $this->filterTagList(explode(' ', $tags));
80 $tags = escape($tags);
81 $tags = $this->replaceTokensArray($tags);
82
83 return $tags;
84 }
85
86 /**
87 * @inheritdoc
88 */
89 protected function formatTagString($bookmark)
336a28fa
A
90 {
91 return implode(' ', $this->formatTagList($bookmark));
92 }
93
94 /**
95 * @inheritdoc
96 */
4e3875c0 97 protected function formatUrl($bookmark)
336a28fa 98 {
62412317 99 if ($bookmark->isNote() && isset($this->contextData['index_url'])) {
301c7ab1 100 return rtrim($this->contextData['index_url'], '/') . '/' . escape(ltrim($bookmark->getUrl(), '/'));
336a28fa 101 }
301c7ab1 102
336a28fa
A
103 return escape($bookmark->getUrl());
104 }
105
106 /**
107 * @inheritdoc
108 */
109 protected function formatRealUrl($bookmark)
110 {
301c7ab1 111 if ($bookmark->isNote()) {
62412317 112 if (isset($this->contextData['index_url'])) {
301c7ab1
A
113 $prefix = rtrim($this->contextData['index_url'], '/') . '/';
114 }
115
62412317 116 if (isset($this->contextData['base_path'])) {
301c7ab1
A
117 $prefix = rtrim($this->contextData['base_path'], '/') . '/';
118 }
119
120 return escape($prefix ?? '') . escape(ltrim($bookmark->getUrl(), '/'));
336a28fa 121 }
301c7ab1 122
336a28fa
A
123 return escape($bookmark->getUrl());
124 }
125
4e3875c0
A
126 /**
127 * @inheritdoc
128 */
129 protected function formatUrlHtml($bookmark)
130 {
131 $url = $this->tokenizeSearchHighlightField(
132 $bookmark->getUrl() ?? '',
133 $bookmark->getAdditionalContentEntry('search_highlight')['url'] ?? []
134 );
135
136 return $this->replaceTokens(escape($url));
137 }
138
336a28fa
A
139 /**
140 * @inheritdoc
141 */
142 protected function formatThumbnail($bookmark)
143 {
144 return escape($bookmark->getThumbnail());
145 }
4e3875c0
A
146
147 /**
148 * Insert search highlight token in provided field content based on a list of search result positions
149 *
150 * @param string $fieldContent
151 * @param array|null $positions List of of search results with 'start' and 'end' positions.
152 *
153 * @return string Updated $fieldContent.
154 */
155 protected function tokenizeSearchHighlightField(string $fieldContent, ?array $positions): string
156 {
157 if (empty($positions)) {
158 return $fieldContent;
159 }
160
161 $insertedTokens = 0;
162 $tokenLength = strlen(static::SEARCH_HIGHLIGHT_OPEN);
163 foreach ($positions as $position) {
164 $position = [
165 'start' => $position['start'] + ($insertedTokens * $tokenLength),
166 'end' => $position['end'] + ($insertedTokens * $tokenLength),
167 ];
168
169 $content = mb_substr($fieldContent, 0, $position['start']);
170 $content .= static::SEARCH_HIGHLIGHT_OPEN;
171 $content .= mb_substr($fieldContent, $position['start'], $position['end'] - $position['start']);
172 $content .= static::SEARCH_HIGHLIGHT_CLOSE;
173 $content .= mb_substr($fieldContent, $position['end']);
174
175 $fieldContent = $content;
176
177 $insertedTokens += 2;
178 }
179
180 return $fieldContent;
181 }
182
183 /**
184 * Replace search highlight tokens with HTML highlighted span.
185 *
186 * @param string $fieldContent
187 *
188 * @return string updated content.
189 */
190 protected function replaceTokens(string $fieldContent): string
191 {
192 return str_replace(
193 [static::SEARCH_HIGHLIGHT_OPEN, static::SEARCH_HIGHLIGHT_CLOSE],
194 ['<span class="search-highlight">', '</span>'],
195 $fieldContent
196 );
197 }
198
199 /**
200 * Apply replaceTokens to an array of content strings.
201 *
202 * @param string[] $fieldContents
203 *
204 * @return array
205 */
206 protected function replaceTokensArray(array $fieldContents): array
207 {
208 foreach ($fieldContents as &$entry) {
209 $entry = $this->replaceTokens($entry);
210 }
211
212 return $fieldContents;
213 }
336a28fa 214}