Passed
Push — development ( 8e8389...e156b5 )
by Spuds
01:10 queued 28s
created

Codes   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 1139
Duplicated Lines 0 %

Test Coverage

Coverage 91.2%

Importance

Changes 0
Metric Value
eloc 659
dl 0
loc 1139
ccs 456
cts 500
cp 0.912
rs 8.821
c 0
b 0
f 0
wmc 44

19 Methods

Rating   Name   Duplication   Size   Complexity  
A getCodesByChar() 0 3 1
A hasChar() 0 3 1
A getItemCodes() 0 17 1
A __construct() 0 13 3
A remove() 0 7 3
A setParsingCodes() 0 5 1
A add() 0 11 1
A getItemCodeTag() 0 7 1
A setForPrinting() 0 22 2
A getDisabled() 0 3 1
A restore() 0 8 2
A isDisabled() 0 3 1
B getForParsing() 0 29 7
A getCodesGroupedByTag() 0 14 3
A getCodes() 0 3 1
A disable() 0 5 1
C getDefault() 0 634 9
A getTags() 0 9 2
A setParsedTags() 0 10 3

How to fix   Complexity   

Complex Class

Complex classes like Codes often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Codes, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 *
5
 * @package   ElkArte Forum
6
 * @copyright ElkArte Forum contributors
7
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
8
 *
9
 * This file contains code covered by:
10
 * copyright: 2011 Simple Machines (http://www.simplemachines.org)
11
 *
12
 * @version 2.0 dev
13
 *
14
 */
15
16
namespace BBC;
17
18
// @todo add attribute for TEST_PARAM_STRING and TEST_CONTENT so people can test the content
19
// @todo change ATTR_TEST to be able to test the entire message with the current offset
20
21
/**
22
 * Class Codes
23
 *
24
 * @package BBC
25
 */
26
class Codes
27
{
28
	/** the tag's name - must be lowercase */
29
	public const ATTR_TAG = 1;
30
31
	/** One of self::TYPE_* */
32
	public const ATTR_TYPE = 2;
33
34
	/** An optional array of parameters, for the form
35
	    [tag abc=123]content[/tag].  The array is an associative array
36
	    where the keys are the parameter names, and the values are an
37
	    array which *may* contain any of self::PARAM_ATTR_*  */
38
	public const ATTR_PARAM = 3;
39
40
	/** A regular expression to test immediately after the tag's
41
	    '=', ' ' or ']'.  Typically, should have a \] at the end.
42
	    Optional. */
43
	public const ATTR_TEST = 4;
44
45
	/** Only available for unparsed_content, closed, unparsed_commas_content, and unparsed_equals_content.
46
	    $1 is replaced with the content of the tag.
47
	    Parameters are replaced in the form {param}.
48
	    For unparsed_commas_content, $2, $3, ..., $n are replaced. */
49
	public const ATTR_CONTENT = 5;
50
51
	/** Only when content is not used, to go before any content.
52
	    For unparsed_equals, $1 is replaced with the value.
53
	    For unparsed_commas, $1, $2, ..., $n are replaced. */
54
	public const ATTR_BEFORE = 6;
55
56
	/** Similar to before in every way, except that it is used when the tag is closed. */
57
	public const ATTR_AFTER = 7;
58
59
	/** Used in place of content when the tag is disabled.
60
	    For closed, default is '', otherwise it is '$1' if block_level is false, '<div>$1</div>' elsewise. */
61
	public const ATTR_DISABLED_CONTENT = 8;
62
63
	/** Used in place of before when disabled. Defaults to '<div>' if block_level, '' if not. */
64
	public const ATTR_DISABLED_BEFORE = 9;
65
66
	/** Used in place of after when disabled. Defaults to '</div>' if block_level, '' if not. */
67
	public const ATTR_DISABLED_AFTER = 10;
68
69
	/** Set to true the tag is a "block level" tag, similar to HTML.
70
	    Block level tags cannot be nested inside tags that are not block level, and will not be implicitly closed as easily.
71
	    One break following a block level tag may also be removed. */
72
	public const ATTR_BLOCK_LEVEL = 11;
73
74
	/** Trim the whitespace after the opening tag or the closing tag or both.
75
	    One of self::TRIM_*
76
	    Optional */
77
	public const ATTR_TRIM = 12;
78
79
	/** Except when type is missing or 'closed', a callback to validate the data as $data.
80
	    Depending on the tag's type, $data may be a string or an array of strings (corresponding to the replacement.) */
81
	public const ATTR_VALIDATE = 13;
82
83
	/** When type is unparsed_equals or parsed_equals only, may be not set,
84
	    'optional', or 'required' corresponding to if the content may be quoted.
85
	    This allows the parser to read [tag="abc]def[esdf]"] properly. */
86
	public const ATTR_QUOTED = 14;
87
88
	/** An array of tag names, or not set.
89
	    If set, the enclosing tag *must* be one of the listed tags, or parsing won't occur. */
90
	public const ATTR_REQUIRE_PARENTS = 15;
91
92
	/** similar to require_parents, if set children won't be parsed if they are not in the list. */
93
	public const ATTR_REQUIRE_CHILDREN = 16;
94
95
	/** Similar to, but very different from, require_parents.
96
	    If it is set the listed tags will not be parsed inside the tag. */
97
	public const ATTR_DISALLOW_PARENTS = 17;
98
99
	/** Similar to, but very different from, require_children.
100
	   If it is set the listed tags will not be parsed inside the tag. */
101
	public const ATTR_DISALLOW_CHILDREN = 18;
102
103
	/** When ATTR_DISALLOW_PARENTS is used, this gets put before the tag. */
104
	public const ATTR_DISALLOW_BEFORE = 19;
105
106
	/** When ATTR_DISALLOW_PARENTS is used, this gets put after the tag. */
107
	public const ATTR_DISALLOW_AFTER = 20;
108
109
	/** an array restricting what BBC can be in the parsed_equals parameter, if desired. */
110
	public const ATTR_PARSED_TAGS_ALLOWED = 21;
111
112
	/** (bool) Turn uris like https://www.google.com in to links */
113
	public const ATTR_AUTOLINK = 22;
114
115
	/** The length of the tag */
116
	public const ATTR_LENGTH = 23;
117
118
	/** Whether the tag is disabled */
119
	public const ATTR_DISABLED = 24;
120
121
	/** If the message contains a code with this, the message should not be cached */
122
	public const ATTR_NO_CACHE = 25;
123
124
	/** If to reset ATTR_CONTENT to a new value, useful when build content tag in addons */
125
	public const ATTR_RESET = 26;
126
127
	/** [tag]parsed content[/tag] */
128
	public const TYPE_PARSED_CONTENT = 0;
129
130
	/** [tag=xyz]parsed content[/tag] */
131
	public const TYPE_UNPARSED_EQUALS = 1;
132
133
	/** [tag=parsed data]parsed content[/tag] */
134
	public const TYPE_PARSED_EQUALS = 2;
135
136
	/** [tag]unparsed content[/tag] */
137
	public const TYPE_UNPARSED_CONTENT = 3;
138
139
	/** [tag], [tag/], [tag /] */
140
	public const TYPE_CLOSED = 4;
141
142
	/** [tag=1,2,3]parsed content[/tag] */
143
	public const TYPE_UNPARSED_COMMAS = 5;
144
145
	/** [tag=1,2,3]unparsed content[/tag] */
146
	public const TYPE_UNPARSED_COMMAS_CONTENT = 6;
147
148
	/** [tag=...]unparsed content[/tag] */
149
	public const TYPE_UNPARSED_EQUALS_CONTENT = 7;
150
151
	/** [*] */
152
	public const TYPE_ITEMCODE = 8;
153
154
	/** a regular expression to validate and match the value. */
155
	public const PARAM_ATTR_MATCH = 0;
156
157
	/** @var int Constant that represents if the value should be quoted. */
158
	public const PARAM_ATTR_QUOTED = 1;
159
160
	/** callback to evaluate on the data, which is $data. */
161
	public const PARAM_ATTR_VALIDATE = 2;
162
163
	/** a string in which to replace $1 with the data. Either it or validate may be used, not both. */
164
	public const PARAM_ATTR_VALUE = 3;
165
166
	/** true if the parameter is optional. */
167
	public const PARAM_ATTR_OPTIONAL = 4;
168
169
	/** @var int Constant that represents no trimming. */
170
	public const TRIM_NONE = 0;
171
172
	/** @var int Constant that represents trimming inside of a tag. */
173
	public const TRIM_INSIDE = 1;
174
175
	/** @var int Constant that represents trimming outside of a tag. */
176
	public const TRIM_OUTSIDE = 2;
177
178
	/** @var int Constant that represents trimming both the left and right sides of a string. */
179
	public const TRIM_BOTH = 3;
180
181
	// These are mainly for *ATTR_QUOTED since there are 3 options
182
	public const OPTIONAL = -1;
183
184
	public const NONE = 0;
185
186
	public const REQUIRED = 1;
187
188
	/** @var string can be used to build tags in a ATTR_VALIDATE function and consumed in ATTR_CONTEXT */
189
	public static $contentTag;
190
191
	/** An array of self::ATTR_*
192
	    ATTR_TAG and ATTR_TYPE are required for every tag.
193
	    The rest of the attributes depend on the type and other options. */
194
	protected $bbc = [];
195
196
	protected $itemcodes = [];
197
198
	protected $disabled = [];
199
200
	protected $parsing_codes = [];
201
202
	/**
203
	 * Codes constructor.
204
	 *
205
	 * @param array $tags
206
	 * @param array $disabled
207
	 */
208
	public function __construct(array $additional_bbc = array(), array $disabled = array())
209
	{
210
		foreach ($disabled as $tag)
211
		{
212
			$this->disable($tag);
213
		}
214
215
		foreach ($additional_bbc as $tag)
216
		{
217
			$this->add($tag);
218
		}
219
220
		$this->bbc = $this->getDefault();
221
	}
222
223
	/**
224
	 * Add a code
225
	 *
226
	 * @param array $code
227
	 */
228
	public function add(array $code)
229
	{
230
231
		// $first_char = $code[self::ATTR_TAG][0];
232
233
		// if (!isset($this->bbc[$first_char]))
234
		// {
235
		//		$this->bbc[$first_char] = array();
236
		// }
237
238
		$this->bbc[] = $code;
239
	}
240
241
	/**
242
	 * Remove a BBC code from the render stack
243
	 *
244
	 * @param $tag
245 2
	 */
246
	public function remove($tag)
247 2
	{
248
		foreach ($this->bbc as $k => $v)
249 2
		{
250
			if ($tag === $v[self::ATTR_TAG])
251
			{
252
				unset($this->bbc[$k]);
253
			}
254 2
		}
255
	}
256
257
	/**
258
	 * Load all of the default BBC codes
259 2
	 *
260 2
	 * @return mixed
261
	 */
262
	public function getDefault()
263
	{
264
		global $modSettings, $txt, $scripturl;
265
266
		// This array can be arranged in any order.
267
		return array_merge($this->bbc, array(
268
			array(
269
				self::ATTR_TAG => 'abbr',
270
				self::ATTR_TYPE => self::TYPE_UNPARSED_EQUALS,
271
				self::ATTR_TEST => '([A-Za-z][A-Za-z0-9_\-\s&;]*)',
272
				self::ATTR_BEFORE => '<abbr title="$1">',
273
				self::ATTR_AFTER => '</abbr>',
274
				self::ATTR_QUOTED => self::OPTIONAL,
275
				self::ATTR_DISABLED_AFTER => ' ($1)',
276
				self::ATTR_BLOCK_LEVEL => false,
277
				self::ATTR_AUTOLINK => true,
278
				self::ATTR_LENGTH => 4,
279
			),
280
			array(
281
				self::ATTR_TAG => 'anchor',
282
				self::ATTR_TYPE => self::TYPE_UNPARSED_EQUALS,
283
				self::ATTR_TEST => '[#]?([A-Za-z][A-Za-z0-9_\-]*)',
284
				self::ATTR_BEFORE => '<span id="post_$1">',
285
				self::ATTR_AFTER => '</span>',
286
				self::ATTR_BLOCK_LEVEL => false,
287
				self::ATTR_AUTOLINK => true,
288
				self::ATTR_LENGTH => 6,
289
			),
290
			array(
291
				self::ATTR_TAG => 'b',
292
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
293
				self::ATTR_BEFORE => '<strong class="bbc_strong">',
294
				self::ATTR_AFTER => '</strong>',
295
				self::ATTR_BLOCK_LEVEL => false,
296
				self::ATTR_AUTOLINK => true,
297
				self::ATTR_LENGTH => 1,
298
			),
299
			array(
300
				self::ATTR_TAG => 'br',
301 14
				self::ATTR_TYPE => self::TYPE_CLOSED,
302
				self::ATTR_CONTENT => '<br />',
303 2
				self::ATTR_BLOCK_LEVEL => false,
304
				self::ATTR_AUTOLINK => false,
305
				self::ATTR_LENGTH => 2,
306 2
			),
307
			array(
308 2
				self::ATTR_TAG => 'center',
309 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
310 2
				self::ATTR_BEFORE => '<div class="centertext">',
311 2
				self::ATTR_AFTER => '</div>',
312 2
				self::ATTR_BLOCK_LEVEL => true,
313 2
				self::ATTR_AUTOLINK => true,
314 2
				self::ATTR_LENGTH => 6,
315 2
			),
316 2
			array(
317 2
				self::ATTR_TAG => 'code',
318
				self::ATTR_TYPE => self::TYPE_UNPARSED_CONTENT,
319
				self::ATTR_CONTENT => '<div class="codeheader">' . $txt['code'] . ': <a href="#" onclick="return elkSelectText(this);" class="codeoperation">' . $txt['code_select'] . '</a></div><pre class="bbc_code prettyprint">$1</pre>',
320 2
				self::ATTR_VALIDATE => $this->isDisabled('code') ? null : static function (&$data) {
321 2
					$data = tabToHtmlTab(strtr($data, array('[' => '&#91;', ']' => '&#93;')));
322 2
				},
323 2
				self::ATTR_BLOCK_LEVEL => true,
324 2
				self::ATTR_AUTOLINK => false,
325 2
				self::ATTR_LENGTH => 4,
326 2
			),
327 2
			array(
328
				self::ATTR_TAG => 'code',
329
				self::ATTR_TYPE => self::TYPE_UNPARSED_EQUALS_CONTENT,
330 2
				self::ATTR_CONTENT => '<div class="codeheader">' . $txt['code'] . ': ($2) <a href="#" onclick="return elkSelectText(this);" class="codeoperation">' . $txt['code_select'] . '</a></div><pre class="bbc_code prettyprint">$1</pre>',
331 2
				self::ATTR_VALIDATE => $this->isDisabled('code') ? null : static function (&$data) {
332 2
					$data[0] = tabToHtmlTab(strtr($data[0], array('[' => '&#91;', ']' => '&#93;')));
333 2
				},
334 2
				self::ATTR_BLOCK_LEVEL => true,
335 2
				self::ATTR_AUTOLINK => false,
336 2
				self::ATTR_LENGTH => 4,
337
			),
338
			array(
339 2
				self::ATTR_TAG => 'color',
340 2
				self::ATTR_TYPE => self::TYPE_UNPARSED_EQUALS,
341 2
				self::ATTR_TEST => '(#[\da-fA-F]{3}|#[\da-fA-F]{6}|[A-Za-z]{1,20}|rgb\((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\s?,\s?){2}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\))',
342 2
				self::ATTR_BEFORE => '<span style="color: $1;" class="bbc_color">',
343 2
				self::ATTR_AFTER => '</span>',
344 2
				self::ATTR_BLOCK_LEVEL => false,
345
				self::ATTR_AUTOLINK => true,
346
				self::ATTR_LENGTH => 5,
347 2
			),
348 2
			array(
349 2
				self::ATTR_TAG => 'email',
350 2
				self::ATTR_TYPE => self::TYPE_UNPARSED_CONTENT,
351 2
				self::ATTR_CONTENT => '<a href="mailto:$1" class="bbc_email">$1</a>',
352 2
				self::ATTR_BLOCK_LEVEL => false,
353 2
				self::ATTR_AUTOLINK => false,
354
				self::ATTR_LENGTH => 5,
355
			),
356 2
			array(
357 2
				self::ATTR_TAG => 'email',
358 2
				self::ATTR_TYPE => self::TYPE_UNPARSED_EQUALS,
359
				self::ATTR_BEFORE => '<a href="mailto:$1" class="bbc_email">',
360 4
				self::ATTR_AFTER => '</a>',
361 6
				self::ATTR_DISALLOW_CHILDREN => array(
362 2
					'email' => 1,
363 2
					'url' => 1,
364 2
					'iurl' => 1,
365
				),
366
				self::ATTR_DISABLED_AFTER => ' ($1)',
367 2
				self::ATTR_BLOCK_LEVEL => false,
368 2
				self::ATTR_AUTOLINK => false,
369 2
				self::ATTR_LENGTH => 5,
370
			),
371 2
			array(
372 4
				self::ATTR_TAG => 'footnote',
373 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
374 2
				self::ATTR_BEFORE => '<sup class="bbc_footnotes">%fn%',
375 2
				self::ATTR_AFTER => '%fn%</sup>',
376
				self::ATTR_TRIM => self::TRIM_NONE,
377
				self::ATTR_DISALLOW_PARENTS => array(
378 2
					'footnote' => 1,
379 2
					'code' => 1,
380 2
					'anchor' => 1,
381 2
					'url' => 1,
382 2
					'iurl' => 1,
383 2
				),
384 2
				self::ATTR_DISALLOW_BEFORE => '',
385 2
				self::ATTR_DISALLOW_AFTER => '',
386
				self::ATTR_BLOCK_LEVEL => false,
387
				self::ATTR_AUTOLINK => true,
388 2
				self::ATTR_LENGTH => 8,
389 2
			),
390 2
			array(
391 2
				self::ATTR_TAG => 'font',
392 2
				self::ATTR_TYPE => self::TYPE_UNPARSED_EQUALS,
393 2
				self::ATTR_TEST => '[A-Za-z0-9_,\-\s]+?',
394
				self::ATTR_BEFORE => '<span style="font-family: $1;" class="bbc_font">',
395
				self::ATTR_AFTER => '</span>',
396 2
				self::ATTR_BLOCK_LEVEL => false,
397 2
				self::ATTR_AUTOLINK => true,
398 2
				self::ATTR_LENGTH => 4,
399 2
			),
400 2
			array(
401
				self::ATTR_TAG => 'hr',
402
				self::ATTR_TYPE => self::TYPE_CLOSED,
403
				self::ATTR_CONTENT => '<hr />',
404
				self::ATTR_BLOCK_LEVEL => true,
405 2
				self::ATTR_AUTOLINK => false,
406 2
				self::ATTR_LENGTH => 2,
407 2
			),
408 2
			array(
409
				self::ATTR_TAG => 'i',
410
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
411 2
				self::ATTR_BEFORE => '<em>',
412 2
				self::ATTR_AFTER => '</em>',
413 2
				self::ATTR_BLOCK_LEVEL => false,
414 2
				self::ATTR_AUTOLINK => true,
415 2
				self::ATTR_LENGTH => 1,
416 2
			),
417
			array(
418
				self::ATTR_TAG => 'icode',
419
				self::ATTR_TYPE => self::TYPE_UNPARSED_CONTENT,
420
				self::ATTR_CONTENT => '<span class="bbc_code_inline">$1</span>',
421
				self::ATTR_VALIDATE => $this->isDisabled('icode') ? null : static function (&$data) {
422
					$data = strtr($data, array('[' => '&#91;', ']' => '&#93;'));
423 2
				},
424 2
				self::ATTR_BLOCK_LEVEL => false,
425 2
				self::ATTR_AUTOLINK => false,
426 2
				self::ATTR_LENGTH => 5,
427 2
			),
428
			array(
429
				self::ATTR_TAG => 'img',
430 2
				self::ATTR_TYPE => self::TYPE_UNPARSED_CONTENT,
431 2
				self::ATTR_PARAM => array(
432 2
					'width' => array(
433 2
						self::PARAM_ATTR_VALUE => 'width:100%;max-width:$1px;',
434 2
						self::PARAM_ATTR_MATCH => '(\d+)',
435 2
						self::PARAM_ATTR_OPTIONAL => true,
436 2
					),
437 2
					'height' => array(
438
						self::PARAM_ATTR_VALUE => 'max-height:$1px;',
439
						self::PARAM_ATTR_MATCH => '(\d+)',
440 2
						self::PARAM_ATTR_OPTIONAL => true,
441 2
					),
442 2
					'title' => array(
443 2
						self::PARAM_ATTR_MATCH => '(.+?)',
444 2
						self::PARAM_ATTR_OPTIONAL => true,
445 2
					),
446
					'alt' => array(
447
						self::PARAM_ATTR_MATCH => '(.+?)',
448 2
						self::PARAM_ATTR_OPTIONAL => true,
449 2
					),
450 2
				),
451 2
				self::ATTR_CONTENT => '<img src="$1" title="{title}" alt="{alt}" style="{width}{height}" class="bbc_img resized" />',
452 2
				self::ATTR_VALIDATE => static function (&$data) {
453 2
					$data = addProtocol($data);
454 2
				},
455
				self::ATTR_DISABLED_CONTENT => '($1)',
456
				self::ATTR_BLOCK_LEVEL => false,
457 2
				self::ATTR_AUTOLINK => false,
458 2
				self::ATTR_LENGTH => 3,
459 2
			),
460
			array(
461 2
				self::ATTR_TAG => 'img',
462 2
				self::ATTR_TYPE => self::TYPE_UNPARSED_CONTENT,
463 2
				self::ATTR_CONTENT => '<img src="$1" alt="" class="bbc_img" />',
464
				self::ATTR_VALIDATE => static function (&$data) {
465
					$data = addProtocol($data);
466 2
				},
467 2
				self::ATTR_DISABLED_CONTENT => '($1)',
468 2
				self::ATTR_BLOCK_LEVEL => false,
469
				self::ATTR_AUTOLINK => false,
470
				self::ATTR_LENGTH => 3,
471 2
			),
472 2
			array(
473
				self::ATTR_TAG => 'iurl',
474
				self::ATTR_TYPE => self::TYPE_UNPARSED_CONTENT,
475 2
				self::ATTR_CONTENT => '<a href="$1" class="bbc_link">$1</a>',
476 2
				self::ATTR_VALIDATE => static function (&$data) {
477
					//$data = removeBr($data);
478
					$data = addProtocol($data);
479 2
				},
480
				self::ATTR_BLOCK_LEVEL => false,
481 2
				self::ATTR_AUTOLINK => false,
482 4
				self::ATTR_LENGTH => 4,
483 2
			),
484 2
			array(
485 2
				self::ATTR_TAG => 'iurl',
486 2
				self::ATTR_TYPE => self::TYPE_UNPARSED_EQUALS,
487
				self::ATTR_BEFORE => '<a href="$1" class="bbc_link">',
488
				self::ATTR_AFTER => '</a>',
489 2
				self::ATTR_VALIDATE => static function (&$data) {
490 2
					$data = $data[0] === '#' ? '#post_' . substr($data, 1) : addProtocol($data);
491 2
				},
492
				self::ATTR_DISALLOW_CHILDREN => array(
493 2
					'email' => 1,
494 4
					'url' => 1,
495 2
					'iurl' => 1,
496 2
				),
497 2
				self::ATTR_DISABLED_AFTER => ' ($1)',
498 2
				self::ATTR_BLOCK_LEVEL => false,
499
				self::ATTR_AUTOLINK => false,
500
				self::ATTR_LENGTH => 4,
501 2
			),
502 2
			array(
503 2
				self::ATTR_TAG => 'left',
504
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
505
				self::ATTR_BEFORE => '<div style="text-align: left;">',
506
				self::ATTR_AFTER => '</div>',
507 2
				self::ATTR_BLOCK_LEVEL => true,
508 2
				self::ATTR_AUTOLINK => true,
509 2
				self::ATTR_LENGTH => 4,
510 2
			),
511
			array(
512
				self::ATTR_TAG => 'li',
513 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
514 2
				self::ATTR_BEFORE => '<li>',
515 2
				self::ATTR_AFTER => '</li>',
516 2
				self::ATTR_TRIM => self::TRIM_OUTSIDE,
517
				self::ATTR_REQUIRE_PARENTS => array(
518 2
					'list' => 1,
519 4
				),
520 2
				self::ATTR_BLOCK_LEVEL => true,
521
				self::ATTR_DISABLED_BEFORE => '',
522
				self::ATTR_DISABLED_AFTER => '<br />',
523
				self::ATTR_AUTOLINK => true,
524
				self::ATTR_LENGTH => 2,
525 2
			),
526 2
			array(
527 2
				self::ATTR_TAG => 'list',
528 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
529
				self::ATTR_BEFORE => '<ul class="bbc_list">',
530
				self::ATTR_AFTER => '</ul>',
531 2
				self::ATTR_TRIM => self::TRIM_INSIDE,
532 2
				self::ATTR_REQUIRE_CHILDREN => array(
533 2
					'li' => 1,
534 2
					'list' => 1,
535 2
				),
536 2
				self::ATTR_BLOCK_LEVEL => true,
537 2
				self::ATTR_AUTOLINK => true,
538
				self::ATTR_LENGTH => 4,
539
			),
540 2
			array(
541 2
				self::ATTR_TAG => 'list',
542 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
543 2
				self::ATTR_PARAM => array(
544 2
					'type' => array(
545 2
						self::PARAM_ATTR_MATCH => '(none|disc|circle|square|decimal|decimal-leading-zero|lower-roman|upper-roman|lower-alpha|upper-alpha|lower-greek|lower-latin|upper-latin|hebrew|armenian|georgian|cjk-ideographic|hiragana|katakana|hiragana-iroha|katakana-iroha)',
546
					),
547
				),
548 2
				self::ATTR_BEFORE => '<ul class="bbc_list" style="list-style-type: {type};">',
549 2
				self::ATTR_AFTER => '</ul>',
550 2
				self::ATTR_TRIM => self::TRIM_INSIDE,
551 2
				self::ATTR_REQUIRE_CHILDREN => array(
552 2
					'li' => 1,
553
				),
554
				self::ATTR_BLOCK_LEVEL => true,
555 2
				self::ATTR_AUTOLINK => true,
556 2
				self::ATTR_LENGTH => 4,
557 2
			),
558 2
			array(
559 2
				self::ATTR_TAG => 'me',
560 2
				self::ATTR_TYPE => self::TYPE_UNPARSED_EQUALS,
561
				self::ATTR_BEFORE => '<div class="meaction">&nbsp;$1 ',
562
				self::ATTR_AFTER => '</div>',
563
				self::ATTR_QUOTED => self::OPTIONAL,
564 2
				self::ATTR_BLOCK_LEVEL => true,
565 2
				self::ATTR_DISABLED_BEFORE => '/me ',
566 2
				self::ATTR_DISABLED_AFTER => '<br />',
567
				self::ATTR_AUTOLINK => true,
568
				self::ATTR_LENGTH => 2,
569 2
			),
570 2
			array(
571 2
				self::ATTR_TAG => 'member',
572
				self::ATTR_TYPE => self::TYPE_UNPARSED_EQUALS,
573 2
				self::ATTR_TEST => '\d*',
574
				self::ATTR_BEFORE => '<span class="bbc_mention"><a href="' . $scripturl . '?action=profile;u=$1">@',
575
				self::ATTR_AFTER => '</a></span>',
576 2
				self::ATTR_DISABLED_BEFORE => '@',
577 2
				self::ATTR_DISABLED_AFTER => '',
578 2
				self::ATTR_BLOCK_LEVEL => false,
579 2
				self::ATTR_AUTOLINK => true,
580
				self::ATTR_LENGTH => 6,
581
			),
582 2
			array(
583 2
				self::ATTR_TAG => 'nobbc',
584 2
				self::ATTR_TYPE => self::TYPE_UNPARSED_CONTENT,
585
				self::ATTR_CONTENT => '$1',
586
				self::ATTR_BLOCK_LEVEL => false,
587 2
				self::ATTR_AUTOLINK => true,
588 2
				self::ATTR_LENGTH => 5,
589 2
			),
590 2
			array(
591 2
				self::ATTR_TAG => 'pre',
592 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
593 2
				self::ATTR_BEFORE => '<pre class="bbc_pre">',
594 2
				self::ATTR_AFTER => '</pre>',
595 2
				self::ATTR_BLOCK_LEVEL => false,
596 2
				self::ATTR_AUTOLINK => true,
597
				self::ATTR_LENGTH => 3,
598
			),
599 2
			array(
600 2
				self::ATTR_TAG => 'quote',
601 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
602 2
				self::ATTR_BEFORE => '<blockquote class="bbc_quote"><cite>' . $txt['quote'] . '</cite>',
603 2
				self::ATTR_AFTER => '</blockquote>',
604 2
				self::ATTR_BLOCK_LEVEL => true,
605 2
				self::ATTR_AUTOLINK => true,
606 2
				self::ATTR_LENGTH => 5,
607 2
			),
608 2
			array(
609
				self::ATTR_TAG => 'quote',
610
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
611 2
				self::ATTR_PARAM => array(
612 2
					'author' => array(
613 2
						self::PARAM_ATTR_MATCH => '([^<>]{1,192}?)',
614 2
						self::PARAM_ATTR_QUOTED => self::OPTIONAL,
615 2
					),
616 2
				),
617
				self::ATTR_BEFORE => '<blockquote class="bbc_quote"><cite>' . $txt['quote_from'] . ': {author}</cite>',
618
				self::ATTR_AFTER => '</blockquote>',
619 2
				self::ATTR_BLOCK_LEVEL => true,
620 2
				self::ATTR_AUTOLINK => true,
621 2
				self::ATTR_LENGTH => 5,
622 2
			),
623 2
			array(
624 2
				self::ATTR_TAG => 'quote',
625 2
				self::ATTR_TYPE => self::TYPE_PARSED_EQUALS,
626
				self::ATTR_BEFORE => '<blockquote class="bbc_quote"><cite>' . $txt['quote_from'] . ': $1</cite>',
627
				self::ATTR_AFTER => '</blockquote>',
628 2
				self::ATTR_QUOTED => self::OPTIONAL,
629 2
				self::ATTR_PARSED_TAGS_ALLOWED => array(
630 2
					'url',
631 2
					'iurl',
632 2
				),
633 2
				self::ATTR_BLOCK_LEVEL => true,
634 2
				self::ATTR_AUTOLINK => true,
635
				self::ATTR_LENGTH => 5,
636
			),
637 2
			array(
638 2
				self::ATTR_TAG => 'quote',
639 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
640
				self::ATTR_PARAM => array(
641 2
					'author' => array(
642 2
						self::PARAM_ATTR_MATCH => '([^<>]{1,192}?)',
643
					),
644
					'link' => array(
645 2
						self::PARAM_ATTR_MATCH => '(?:board=\d+;)?((?:topic|threadid)=[\dmsg#\./]{1,40}(?:;start=[\dmsg#\./]{1,40})?|msg=\d{1,40}|action=profile;u=\d+)',
646 2
					),
647 2
					'date' => array(
648 2
						self::PARAM_ATTR_MATCH => '(\d+)',
649 2
						self::PARAM_ATTR_VALIDATE => 'htmlTime',
650
					),
651
				),
652 2
				self::ATTR_BEFORE => '<blockquote class="bbc_quote"><cite><a href="' . $scripturl . '?{link}">' . $txt['quote_from'] . ': {author} &ndash;' . ($modSettings['todayMod'] == 3 ? '' : ' ' . $txt['search_on']) . ' {date}</a></cite>',
653 2
				self::ATTR_AFTER => '</blockquote>',
654 2
				self::ATTR_BLOCK_LEVEL => true,
655 2
				self::ATTR_AUTOLINK => true,
656 2
				self::ATTR_LENGTH => 5,
657 2
			),
658
			array(
659
				self::ATTR_TAG => 'quote',
660
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
661 2
				self::ATTR_PARAM => array(
662 2
					'author' => array(
663 2
						self::PARAM_ATTR_MATCH => '([^<>]{1,192}?)',
664
					),
665
				),
666 2
				self::ATTR_BEFORE => '<blockquote class="bbc_quote"><cite>' . $txt['quote_from'] . ': {author}</cite>',
667 2
				self::ATTR_AFTER => '</blockquote>',
668 2
				self::ATTR_BLOCK_LEVEL => true,
669
				self::ATTR_AUTOLINK => true,
670 2
				self::ATTR_LENGTH => 5,
671
			),
672
			array(
673 2
				self::ATTR_TAG => 'right',
674
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
675
				self::ATTR_BEFORE => '<div style="text-align: right;">',
676 2
				self::ATTR_AFTER => '</div>',
677 2
				self::ATTR_BLOCK_LEVEL => true,
678
				self::ATTR_AUTOLINK => true,
679
				self::ATTR_LENGTH => 5,
680 2
			),
681 2
			array(
682 2
				self::ATTR_TAG => 's',
683 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
684 2
				self::ATTR_BEFORE => '<del>',
685
				self::ATTR_AFTER => '</del>',
686
				self::ATTR_BLOCK_LEVEL => false,
687 2
				self::ATTR_AUTOLINK => true,
688 2
				self::ATTR_LENGTH => 1,
689 2
			),
690
			array(
691 2
				self::ATTR_TAG => 'size',
692
				self::ATTR_TYPE => self::TYPE_UNPARSED_EQUALS,
693
				self::ATTR_TEST => '[1-7]{1}',
694 2
				self::ATTR_BEFORE => '<span style="font-size: $1;" class="bbc_size">',
695 2
				self::ATTR_AFTER => '</span>',
696 2
				self::ATTR_VALIDATE => static function (&$data) {
697 2
					$sizes = array(1 => 0.7, 2 => 1.0, 3 => 1.35, 4 => 1.45, 5 => 2.0, 6 => 2.65, 7 => 3.95);
698 2
					$data = $sizes[(int) $data] . 'em';
699
				},
700
				self::ATTR_DISALLOW_PARENTS => array(
701 2
					'size' => 1,
702 2
				),
703 2
				self::ATTR_DISALLOW_BEFORE => '<span>',
704 2
				self::ATTR_DISALLOW_AFTER => '</span>',
705 2
				self::ATTR_BLOCK_LEVEL => false,
706 2
				self::ATTR_AUTOLINK => true,
707 2
				self::ATTR_LENGTH => 4,
708
			),
709
			array(
710 2
				self::ATTR_TAG => 'size',
711 2
				self::ATTR_TYPE => self::TYPE_UNPARSED_EQUALS,
712 2
				self::ATTR_TEST => '([1-9][\d]?p[xt]|small(?:er)?|large[r]?|x[x]?-(?:small|large)|medium|(0\.[1-9]|[1-9](\.[\d][\d]?)?)?em)',
713 2
				self::ATTR_BEFORE => '<span style="font-size: $1;" class="bbc_size">',
714 2
				self::ATTR_AFTER => '</span>',
715 2
				self::ATTR_DISALLOW_PARENTS => array('size' => 1),
716 2
				self::ATTR_DISALLOW_BEFORE => '<span>',
717
				self::ATTR_DISALLOW_AFTER => '</span>',
718
				self::ATTR_BLOCK_LEVEL => false,
719 2
				self::ATTR_AUTOLINK => true,
720 2
				self::ATTR_LENGTH => 4,
721 2
			),
722 2
			array(
723 2
				self::ATTR_TAG => 'spoiler',
724
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
725 2
				self::ATTR_BEFORE => '<span class="spoilerheader">' . $txt['spoiler'] . '</span><div class="spoiler"><div class="bbc_spoiler" style="display: none;">',
726 2
				self::ATTR_AFTER => '</div></div>',
727 4
				self::ATTR_BLOCK_LEVEL => true,
728 2
				self::ATTR_AUTOLINK => true,
729
				self::ATTR_LENGTH => 7,
730
			),
731 2
			array(
732 2
				self::ATTR_TAG => 'sub',
733 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
734 2
				self::ATTR_BEFORE => '<sub>',
735 2
				self::ATTR_AFTER => '</sub>',
736
				self::ATTR_BLOCK_LEVEL => false,
737
				self::ATTR_AUTOLINK => true,
738 2
				self::ATTR_LENGTH => 3,
739 2
			),
740 2
			array(
741 2
				self::ATTR_TAG => 'sup',
742 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
743 2
				self::ATTR_BEFORE => '<sup>',
744 2
				self::ATTR_AFTER => '</sup>',
745 2
				self::ATTR_BLOCK_LEVEL => false,
746 2
				self::ATTR_AUTOLINK => true,
747 2
				self::ATTR_LENGTH => 3,
748 2
			),
749
			array(
750
				self::ATTR_TAG => 'table',
751 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
752 2
				self::ATTR_BEFORE => '<div class="bbc_table_container"><table class="bbc_table">',
753 2
				self::ATTR_AFTER => '</table></div>',
754 2
				self::ATTR_TRIM => self::TRIM_BOTH,
755 2
				self::ATTR_REQUIRE_CHILDREN => array(
756 2
					'tr' => 1,
757 2
				),
758
				self::ATTR_BLOCK_LEVEL => true,
759
				self::ATTR_AUTOLINK => true,
760 2
				self::ATTR_LENGTH => 5,
761 2
			),
762 2
			array(
763 2
				self::ATTR_TAG => 'td',
764 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
765 2
				self::ATTR_BEFORE => '<td>',
766 2
				self::ATTR_AFTER => '</td>',
767
				self::ATTR_REQUIRE_PARENTS => array(
768
					'tr' => 1,
769 2
				),
770 2
				self::ATTR_TRIM => self::TRIM_OUTSIDE,
771 2
				self::ATTR_BLOCK_LEVEL => true,
772 2
				self::ATTR_DISABLED_BEFORE => '',
773 2
				self::ATTR_DISABLED_AFTER => '',
774 2
				self::ATTR_AUTOLINK => true,
775 2
				self::ATTR_LENGTH => 2,
776
			),
777
			array(
778 2
				self::ATTR_TAG => 'th',
779 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
780 2
				self::ATTR_BEFORE => '<th>',
781 2
				self::ATTR_AFTER => '</th>',
782 2
				self::ATTR_REQUIRE_PARENTS => array(
783 2
					'tr' => 1,
784
				),
785
				self::ATTR_TRIM => self::TRIM_OUTSIDE,
786 2
				self::ATTR_BLOCK_LEVEL => true,
787 2
				self::ATTR_DISABLED_BEFORE => '',
788 2
				self::ATTR_DISABLED_AFTER => '',
789
				self::ATTR_AUTOLINK => true,
790
				self::ATTR_LENGTH => 2,
791 2
			),
792 2
			array(
793 2
				self::ATTR_TAG => 'tr',
794 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
795 2
				self::ATTR_BEFORE => '<tr>',
796
				self::ATTR_AFTER => '</tr>',
797
				self::ATTR_REQUIRE_PARENTS => array(
798 2
					'table' => 1,
799 2
				),
800 2
				self::ATTR_REQUIRE_CHILDREN => array(
801 2
					'td' => 1,
802 2
					'th' => 1,
803 2
				),
804
				self::ATTR_TRIM => self::TRIM_BOTH,
805
				self::ATTR_BLOCK_LEVEL => true,
806 2
				self::ATTR_DISABLED_BEFORE => '',
807 2
				self::ATTR_DISABLED_AFTER => '',
808 2
				self::ATTR_AUTOLINK => true,
809 2
				self::ATTR_LENGTH => 2,
810 2
			),
811
			array(
812
				self::ATTR_TAG => 'tt',
813 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
814 2
				self::ATTR_BEFORE => '<span class="bbc_tt">',
815 2
				self::ATTR_AFTER => '</span>',
816 2
				self::ATTR_BLOCK_LEVEL => false,
817 2
				self::ATTR_AUTOLINK => true,
818 2
				self::ATTR_LENGTH => 2,
819
			),
820
			array(
821 2
				self::ATTR_TAG => 'u',
822 2
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
823 2
				self::ATTR_BEFORE => '<span class="bbc_u">',
824 2
				self::ATTR_AFTER => '</span>',
825 2
				self::ATTR_BLOCK_LEVEL => false,
826
				self::ATTR_AUTOLINK => true,
827
				self::ATTR_LENGTH => 1,
828 2
			),
829
			array(
830
				self::ATTR_TAG => 'url',
831
				self::ATTR_TYPE => self::TYPE_UNPARSED_CONTENT,
832 2
				self::ATTR_CONTENT => &self::$contentTag,
833 2
				self::ATTR_VALIDATE => static function (&$data) {
834 2
					$data = addProtocol($data);
835 2
836 2
					self::$contentTag = '<a href="$1" class="bbc_link" target="_blank"';
837 2
					self::$contentTag .= validateURLAllowList($data) ? ' rel="noopener ugc">' : ' rel="noopener noreferrer nofollow ugc">';
838
					self::$contentTag .= '$1</a>';
839
				},
840 2
				self::ATTR_BLOCK_LEVEL => false,
841 2
				self::ATTR_AUTOLINK => false,
842 2
				self::ATTR_LENGTH => 3,
843 2
			),
844 2
			array(
845 2
				self::ATTR_TAG => 'url',
846 2
				self::ATTR_TYPE => self::TYPE_UNPARSED_EQUALS,
847
				self::ATTR_BEFORE => &self::$contentTag,
848
				self::ATTR_AFTER => '</a>',
849 2
				self::ATTR_VALIDATE => static function (&$data) {
850 2
					$data = addProtocol($data);
851 2
852 2
					self::$contentTag = '<a href="$1" class="bbc_link" target="_blank"';
853 2
					self::$contentTag .= validateURLAllowList($data) ? ' rel="noopener ugc">' : ' rel="noopener noreferrer nofollow ugc">';
854 2
				},
855 2
				self::ATTR_DISALLOW_CHILDREN => array(
856
					'email' => 1,
857
					'url' => 1,
858 2
					'iurl' => 1,
859 2
				),
860 2
				self::ATTR_DISABLED_AFTER => ' ($1)',
861
				self::ATTR_BLOCK_LEVEL => false,
862 4
				self::ATTR_AUTOLINK => false,
863 4
				self::ATTR_LENGTH => 3,
864 2
			),
865 2
			array(
866 2
				self::ATTR_TAG => 'url',
867
				self::ATTR_TYPE => self::TYPE_PARSED_CONTENT,
868
				self::ATTR_BEFORE => '<a href="{url}" class="bbc_link" target="_blank" rel="{follow}">',
869 2
				self::ATTR_AFTER => '</a>',
870 2
				self::ATTR_PARAM => array(
871 2
					'url' => array(
872 2
						self::PARAM_ATTR_MATCH => '([^\s\]]+\]?)',
873
						// preparse will check the domain allowList
874 12
						self::PARAM_ATTR_VALIDATE => static function($param) {
875 14
							return addProtocol($param);
876 2
						}
877
					),
878
					'follow' => array(
879
						self::PARAM_ATTR_MATCH => '([^\s\]]+\]?)',
880
						self::PARAM_ATTR_VALIDATE => static function($param) {
881 2
							// preparse will validate permissions
882 2
							$on = in_array($param, ['follow', 'true', 'on', 'yes'], true);
883 2
							return ($on) ? 'noopener ugc' : 'noopener noreferrer nofollow ugc';
884 2
						}
885
					),
886
				),
887
				self::ATTR_DISALLOW_CHILDREN => array(
888
					'email' => 1,
889
					'url' => 1,
890
					'iurl' => 1,
891
				),
892
				self::ATTR_DISABLED_AFTER => ' ($1)',
893
				self::ATTR_BLOCK_LEVEL => false,
894 4
				self::ATTR_AUTOLINK => false,
895
				self::ATTR_LENGTH => 3
896
			),
897 4
		));
898
	}
899
900
	/**
901
	 * Returns the item codes array, used for simple lists, e.g. [*]
902
	 *
903
	 * @return array
904
	 */
905
	public function getItemCodes()
906
	{
907
		$item_codes = array(
908 4
			'*' => 'disc',
909
			'@' => 'disc',
910 4
			'+' => 'square',
911
			'x' => 'square',
912
			'#' => 'decimal',
913
			'0' => 'decimal',
914
			'o' => 'circle',
915
			'O' => 'circle',
916
		);
917
918
		// Want to add some more ?
919
		call_integration_hook('integrate_item_codes', array(&$item_codes));
920
921
		return $item_codes;
922
	}
923
924
	/**
925
	 * Return the current Default BBC codes and those added by modifications
926
	 *
927
	 * @return array|mixed
928
	 */
929
	public function getCodes()
930
	{
931
		return $this->bbc;
932
	}
933
934
	/**
935
	 * Returns an array of installed bbc codes grouped by attr type e.g. quote[0], quote[1]
936
	 *
937
	 * @return array
938
	 */
939
	public function getCodesGroupedByTag()
940
	{
941
		$bbc = array();
942
		foreach ($this->bbc as $code)
943
		{
944
			if (!isset($bbc[$code[self::ATTR_TAG]]))
945
			{
946
				$bbc[$code[self::ATTR_TAG]] = array();
947
			}
948
949 4
			$bbc[$code[self::ATTR_TAG]][] = $code;
950
		}
951 4
952 4
		return $bbc;
953
	}
954 4
955
	/**
956
	 * Return the list of BBC tags, like b, i, spoiler
957 4
	 *
958
	 * @return array
959
	 */
960
	public function getTags()
961
	{
962
		$tags = array();
963
		foreach ($this->bbc as $tag)
964
		{
965
			$tags[$tag[self::ATTR_TAG]] = $tag[self::ATTR_TAG];
966 4
		}
967
968 4
		return $tags;
969 4
	}
970 4
971
	/**
972 4
	 * @return array
973
	 * @todo besides the itemcodes (just add a arg $with_itemcodes), this way should be standard and saved like that.
974 2
	 * Even, just remove the itemcodes when needed
975
	 *
976
	 */
977 2
	public function getForParsing()
978
	{
979 2
		$bbc = $this->bbc;
980
		$item_codes = $this->getItemCodes();
981
		call_integration_hook('bbc_codes_parsing', array(&$bbc, &$item_codes));
982 2
983
		if (!$this->isDisabled('li') && !$this->isDisabled('list'))
984
		{
985
			foreach (array_keys($item_codes) as $c)
986 4
			{
987
				// Skip anything "bad"
988
				if (!is_string($c) || trim($c) === '')
989 4
				{
990
					continue;
991 4
				}
992
993
				$bbc[$c] = $this->getItemCodeTag($c);
994 4
			}
995
		}
996
997
		$return = array();
998
999
		// Find the first letter of the tag faster
1000
		foreach ($bbc as $code)
1001
		{
1002
			$return[$code[self::ATTR_TAG][0]][] = $code;
1003
		}
1004
1005
		return $return;
1006
	}
1007
1008
	/**
1009
	 * Returns the first letter of all valid bbc codes for the parser
1010
	 *
1011
	 * @return $this
1012
	 * @todo not used
1013
	 *
1014
	 */
1015
	public function setParsingCodes()
1016
	{
1017
		$this->parsing_codes = $this->getForParsing();
1018
1019
		return $this;
1020
	}
1021
1022
	/**
1023
	 * Return if the found code [X is possibly a valid one by checking
1024
	 * if we have a code that begins with X
1025
	 *
1026
	 * @param $char
1027
	 *
1028
	 * @return bool
1029
	 * @todo not used
1030
	 *
1031
	 */
1032
	public function hasChar($char)
1033
	{
1034
		return isset($this->parsing_codes[$char]);
1035
	}
1036
1037
	/**
1038
	 * Get BCC codes by character start
1039
	 *
1040
	 * @param $char
1041
	 *
1042
	 * @return mixed
1043
	 * @todo not used
1044
	 *
1045
	 */
1046
	public function getCodesByChar($char)
1047 2
	{
1048
		return $this->parsing_codes[$char];
1049
	}
1050 2
1051 2
	/**
1052 2
	 * Generates item code tags
1053 2
	 *
1054
	 * @param $code
1055
	 *
1056
	 * @return array
1057
	 */
1058
	protected function getItemCodeTag($code)
1059
	{
1060
		return array(
1061
			self::ATTR_TAG => $code,
1062
			self::ATTR_TYPE => self::TYPE_ITEMCODE,
1063
			self::ATTR_BLOCK_LEVEL => true,
1064
			self::ATTR_LENGTH => 1,
1065
		);
1066
	}
1067
1068
	/**
1069
	 * Disables certain tags when we are going to print
1070
	 *
1071
	 * @return $this
1072
	 */
1073
	public function setForPrinting()
1074
	{
1075
		// Colors can't well be displayed... supposed to be black and white.
1076
		$this->disable('color');
1077
		$this->disable('me');
1078
1079
		// Links are useless on paper... just show the link.
1080
		$this->disable('url');
1081
		$this->disable('iurl');
1082
		$this->disable('email');
1083
1084
		// @todo Change maybe?
1085
		if (!isset($_GET['images']))
1086
		{
1087
			$this->disable('img');
1088
			$this->disable('attach');
1089
		}
1090
1091
		// @todo Interface/setting to add more?
1092 14
		call_integration_hook('integrate_bbc_set_printing', array($this));
1093
1094 14
		return $this;
1095
	}
1096
1097
	/**
1098
	 * Return if a tag is disabled
1099
	 *
1100
	 * @param string $tag
1101
	 *
1102 14
	 * @return bool
1103
	 */
1104 14
	public function isDisabled($tag)
1105
	{
1106
		return isset($this->disabled[$tag]);
1107
	}
1108
1109
	/**
1110
	 * If BBC Parsing is enabled
1111
	 *
1112
	 * @return array
1113
	 */
1114
	public function getDisabled()
1115
	{
1116
		return $this->disabled;
1117
	}
1118
1119
	/**
1120
	 * Disable a tag from parsing
1121
	 *
1122
	 * @param $tag
1123
	 *
1124
	 * @return bool
1125
	 */
1126
	public function disable($tag)
1127
	{
1128
		$this->disabled[$tag] = $tag;
1129
1130
		return isset($this->disabled[$tag]);
1131
	}
1132
1133
	/**
1134
	 * Restore a disabled tag
1135
	 *
1136
	 * @param $tag
1137
	 *
1138
	 * @return bool
1139
	 */
1140
	public function restore($tag)
1141
	{
1142
		if (isset($this->disabled[$tag]))
1143 2
		{
1144
			unset($this->disabled[$tag]);
1145 2
		}
1146
1147 2
		return !isset($this->disabled[$tag]);
1148
	}
1149
1150 2
	/**
1151
	 * Set the tags that will be parsed
1152 2
	 *
1153
	 * @param $parse_tags
1154
	 */
1155 2
	public function setParsedTags($parse_tags)
1156
	{
1157
		foreach ($this->bbc as $k => $code)
1158
		{
1159
			if (!in_array($code[self::ATTR_TAG], $parse_tags))
1160
			{
1161
				//$this->remove($code);
1162
				unset($this->bbc[$k]);
1163
1164
				$this->disabled[$code[self::ATTR_TAG]] = $code[self::ATTR_TAG];
1165
			}
1166
		}
1167
	}
1168
}
1169