Merge pull request #5987 from WoltLab/acp-dahsboard-box-hight
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / bbcode / BBCodeHandler.class.php
CommitLineData
dcc2332d 1<?php
a9229942 2
dcc2332d 3namespace wcf\system\bbcode;
a9229942 4
7a23a706 5use wcf\data\bbcode\BBCode;
dcc2332d 6use wcf\data\bbcode\BBCodeCache;
74c960dd 7use wcf\system\application\ApplicationHandler;
2ef8729b 8use wcf\system\package\license\LicenseApi;
dcc2332d 9use wcf\system\SingletonFactory;
e12c6ef4 10use wcf\system\WCF;
74c960dd 11use wcf\util\ArrayUtil;
070c42e0 12use wcf\util\JSON;
e046a126 13use wcf\util\StringUtil;
dcc2332d
MW
14
15/**
16 * Handles BBCodes displayed as buttons within the WYSIWYG editor.
a9229942
TD
17 *
18 * @author Alexander Ebert
19 * @copyright 2001-2019 WoltLab GmbH
20 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
dcc2332d 21 */
a9229942
TD
22class BBCodeHandler extends SingletonFactory
23{
24 /**
25 * list of BBCodes displayed as buttons
26 * @var BBCode[]
27 */
28 protected $buttonBBCodes = [];
29
30 /**
31 * list of BBCodes disallowed for usage
32 * @var BBCode[]
33 */
34 protected $disallowedBBCodes = [];
35
36 /**
37 * list of BBCodes which contain raw code (disabled BBCode parsing)
38 * @var BBCode[]
39 */
40 protected $sourceBBCodes;
41
42 /**
43 * meta information about highlighters
44 * @var mixed[]
45 */
46 protected $highlighterMeta;
47
48 /**
49 * @inheritDoc
50 */
51 protected function init()
52 {
53 foreach (BBCodeCache::getInstance()->getBBCodes() as $bbcode) {
54 if ($bbcode->showButton) {
55 $this->buttonBBCodes[] = $bbcode;
56 }
57 }
58 }
59
60 /**
61 * Returns true if the BBCode with the given tag is available in the WYSIWYG editor.
a9229942 62 */
63b4c880 63 public function isAvailableBBCode(string $bbCodeTag, bool $overrideFormattingRemoval = false): bool
a9229942 64 {
63b4c880
AE
65 if ($overrideFormattingRemoval === false) {
66 if ($bbCodeTag === "color" && \FORMATTING_REMOVE_COLOR) {
67 return false;
68 }
5536beb9 69
63b4c880
AE
70 if ($bbCodeTag === "font" && \FORMATTING_REMOVE_FONT) {
71 return false;
72 }
5536beb9 73
63b4c880
AE
74 if ($bbCodeTag === "size" && \FORMATTING_REMOVE_SIZE) {
75 return false;
76 }
5536beb9
AE
77 }
78
a9229942
TD
79 return !\in_array($bbCodeTag, $this->disallowedBBCodes);
80 }
81
82 /**
83 * Returns all bbcodes.
84 *
85 * @return BBCode[]
86 */
87 public function getBBCodes()
88 {
89 return BBCodeCache::getInstance()->getBBCodes();
90 }
91
92 /**
93 * Returns a list of BBCodes displayed as buttons.
94 *
95 * @param bool $excludeCoreBBCodes do not return bbcodes that are available by default
96 * @return BBCode[]
97 */
98 public function getButtonBBCodes($excludeCoreBBCodes = false)
99 {
100 $buttons = [];
101 $coreBBCodes = [
102 'align',
103 'b',
a42f47f6 104 'code',
a9229942 105 'color',
a42f47f6 106 'html',
a9229942
TD
107 'i',
108 'img',
109 'list',
110 's',
111 'size',
112 'sub',
113 'sup',
114 'quote',
a42f47f6 115 'spoiler',
a9229942 116 'table',
a42f47f6 117 'tt',
a9229942
TD
118 'u',
119 'url',
120 ];
121 foreach ($this->buttonBBCodes as $bbcode) {
122 if ($excludeCoreBBCodes && \in_array($bbcode->bbcodeTag, $coreBBCodes)) {
123 continue;
124 }
125
126 if ($this->isAvailableBBCode($bbcode->bbcodeTag)) {
127 $buttons[] = $bbcode;
128 }
129 }
130
131 return $buttons;
132 }
133
a9229942
TD
134 /**
135 * Sets the disallowed BBCodes.
136 *
137 * @param string[] $bbCodes
138 */
139 public function setDisallowedBBCodes(array $bbCodes)
140 {
141 $this->disallowedBBCodes = $bbCodes;
142 }
143
144 /**
145 * Returns a list of BBCodes which contain raw code (disabled BBCode parsing)
146 *
147 * @return BBCode[]
148 * @deprecated 3.1 - This method is no longer supported.
149 */
150 public function getSourceBBCodes()
151 {
152 return [];
153 }
154
155 /**
156 * Returns metadata about the highlighters.
157 *
158 * @return string[][]
159 */
160 public function getHighlighterMeta()
161 {
162 if ($this->highlighterMeta === null) {
163 $this->highlighterMeta = JSON::decode(\preg_replace(
164 '/.*\/\*!START\*\/\s*const\s*metadata\s*=\s*(.*)\s*;\s*\/\*!END\*\/.*/s',
165 '\\1',
166 \file_get_contents(WCF_DIR . '/js/WoltLabSuite/Core/prism-meta.js')
167 ));
168 }
169
170 return $this->highlighterMeta;
171 }
172
173 /**
174 * Returns a list of known highlighters.
175 *
176 * @return string[]
177 */
178 public function getHighlighters()
179 {
180 return \array_keys($this->getHighlighterMeta());
181 }
182
e046a126
AE
183 /**
184 * Returns the list of languages that are available for selection in the
185 * UI of CKEditor’s code block.
186 *
187 * @return list<string>
188 * @since 6.0
189 */
190 public function getCodeBlockLanguages(): array
191 {
192 return \explode("\n", StringUtil::unifyNewlines(\MESSAGE_PUBLIC_HIGHLIGHTERS));
193 }
194
a9229942
TD
195 /**
196 * Returns a list of hostnames that are permitted as image sources.
197 *
198 * @return string[]
199 * @since 5.2
200 */
201 public function getImageExternalSourceWhitelist()
202 {
203 $hosts = [];
204 // Hide these hosts unless external sources are actually denied.
205 if (!IMAGE_ALLOW_EXTERNAL_SOURCE) {
88960b62
TD
206 $hosts = ArrayUtil::trim(\explode(
207 "\n",
208 \sprintf(
209 "%s\n%s",
210 \IMAGE_EXTERNAL_SOURCE_WHITELIST,
211 \INTERNAL_HOSTNAMES
212 )
213 ));
a9229942
TD
214 }
215
2e238f48 216 $hosts[] = ApplicationHandler::getInstance()->getDomainName();
a9229942
TD
217
218 return \array_unique($hosts);
219 }
e12c6ef4
AE
220
221 /**
222 * Exports a require.js requirement for the localization of the editor based
223 * on the current locale. Returns an empty string when there is no available
224 * localization or the locale equals the bundled value 'en'.
225 *
226 * @since 6.0
227 */
228 public function getEditorLocalization(): string
229 {
230 $availableTranslations = [
231 'af',
232 'ar',
233 'ast',
234 'az',
235 'bg',
236 'bn',
237 'bs',
238 'ca',
239 'cs',
240 'da',
241 'de-ch',
242 'de',
243 'el',
244 'en-au',
245 'en-gb',
246 'eo',
247 'es-co',
248 'es',
249 'et',
250 'eu',
251 'fa',
252 'fi',
253 'fr',
254 'gl',
255 'gu',
256 'he',
257 'hi',
258 'hr',
259 'hu',
260 'id',
261 'it',
262 'ja',
263 'jv',
264 'kk',
265 'km',
266 'kn',
267 'ko',
268 'ku',
269 'lt',
270 'lv',
271 'ms',
272 'nb',
273 'ne',
274 'nl',
275 'no',
276 'oc',
277 'pl',
278 'pt-br',
279 'pt',
280 'ro',
281 'ru',
282 'si',
283 'sk',
284 'sl',
285 'sq',
286 'sr-latn',
287 'sr',
288 'sv',
289 'th',
290 'tk',
291 'tr',
292 'tt',
293 'ug',
294 'uk',
295 'ur',
296 'uz',
297 'vi',
298 'zh-cn',
299 'zh',
300 ];
301
2c52ac36 302 $locale = \strtolower(WCF::getLanguage()->getBcp47());
e12c6ef4
AE
303 if (\in_array($locale, $availableTranslations, true)) {
304 return \sprintf(
305 '"ckeditor5-translation/%s",',
306 $locale
307 );
308 }
309
2c52ac36
AE
310 // Some languages offer both specialized variants for certain locales
311 // but also provide a "generic" variant. For example, "en-gb" and "en".
312 [$languageCode] = \explode('-', $locale, 2);
313 if (\in_array($languageCode, $availableTranslations, true)) {
314 return \sprintf(
315 '"ckeditor5-translation/%s",',
316 $languageCode
317 );
e12c6ef4
AE
318 }
319
2c52ac36
AE
320 // The default locale "en" is part of the generated bundle, we must not
321 // yield any module if this locale is (implicitly) requested.
e12c6ef4
AE
322 return "";
323 }
2ef8729b
AE
324
325 /**
326 * @since 6.0
327 */
328 public function getCkeditorLicenseKey(): string
329 {
895acf5e
TD
330 $licenseApi = new LicenseApi();
331 $licenseData = $licenseApi->readFromFile();
332
19781b8e 333 if ($licenseData === null) {
2ef8729b
AE
334 return '';
335 }
336
19781b8e 337 return $licenseData->license['ckeditorLicenseKey'] ?? '';
2ef8729b 338 }
dcc2332d 339}