@@ -5,44 +5,44 @@ |
||
5 | 5 | */ |
6 | 6 | abstract class HTMLPurifier_ChildDef |
7 | 7 | { |
8 | - /** |
|
9 | - * Type of child definition, usually right-most part of class name lowercase. |
|
10 | - * Used occasionally in terms of context. |
|
11 | - */ |
|
12 | - public $type; |
|
8 | + /** |
|
9 | + * Type of child definition, usually right-most part of class name lowercase. |
|
10 | + * Used occasionally in terms of context. |
|
11 | + */ |
|
12 | + public $type; |
|
13 | 13 | |
14 | - /** |
|
15 | - * Bool that indicates whether or not an empty array of children is okay |
|
16 | - * |
|
17 | - * This is necessary for redundant checking when changes affecting |
|
18 | - * a child node may cause a parent node to now be disallowed. |
|
19 | - */ |
|
20 | - public $allow_empty; |
|
14 | + /** |
|
15 | + * Bool that indicates whether or not an empty array of children is okay |
|
16 | + * |
|
17 | + * This is necessary for redundant checking when changes affecting |
|
18 | + * a child node may cause a parent node to now be disallowed. |
|
19 | + */ |
|
20 | + public $allow_empty; |
|
21 | 21 | |
22 | - /** |
|
23 | - * Lookup array of all elements that this definition could possibly allow |
|
24 | - */ |
|
25 | - public $elements = array(); |
|
22 | + /** |
|
23 | + * Lookup array of all elements that this definition could possibly allow |
|
24 | + */ |
|
25 | + public $elements = array(); |
|
26 | 26 | |
27 | - /** |
|
28 | - * Get lookup of tag names that should not close this element automatically. |
|
29 | - * All other elements will do so. |
|
30 | - */ |
|
31 | - public function getAllowedElements($config) { |
|
32 | - return $this->elements; |
|
33 | - } |
|
27 | + /** |
|
28 | + * Get lookup of tag names that should not close this element automatically. |
|
29 | + * All other elements will do so. |
|
30 | + */ |
|
31 | + public function getAllowedElements($config) { |
|
32 | + return $this->elements; |
|
33 | + } |
|
34 | 34 | |
35 | - /** |
|
36 | - * Validates nodes according to definition and returns modification. |
|
37 | - * |
|
38 | - * @param $tokens_of_children Array of HTMLPurifier_Token |
|
39 | - * @param $config HTMLPurifier_Config object |
|
40 | - * @param $context HTMLPurifier_Context object |
|
41 | - * @return bool true to leave nodes as is |
|
42 | - * @return bool false to remove parent node |
|
43 | - * @return array of replacement child tokens |
|
44 | - */ |
|
45 | - abstract public function validateChildren($tokens_of_children, $config, $context); |
|
35 | + /** |
|
36 | + * Validates nodes according to definition and returns modification. |
|
37 | + * |
|
38 | + * @param $tokens_of_children Array of HTMLPurifier_Token |
|
39 | + * @param $config HTMLPurifier_Config object |
|
40 | + * @param $context HTMLPurifier_Context object |
|
41 | + * @return bool true to leave nodes as is |
|
42 | + * @return bool false to remove parent node |
|
43 | + * @return array of replacement child tokens |
|
44 | + */ |
|
45 | + abstract public function validateChildren($tokens_of_children, $config, $context); |
|
46 | 46 | } |
47 | 47 | |
48 | 48 | // vim: et sw=4 sts=4 |
@@ -12,37 +12,37 @@ |
||
12 | 12 | class HTMLPurifier_ChildDef_Chameleon extends HTMLPurifier_ChildDef |
13 | 13 | { |
14 | 14 | |
15 | - /** |
|
16 | - * Instance of the definition object to use when inline. Usually stricter. |
|
17 | - */ |
|
18 | - public $inline; |
|
15 | + /** |
|
16 | + * Instance of the definition object to use when inline. Usually stricter. |
|
17 | + */ |
|
18 | + public $inline; |
|
19 | 19 | |
20 | - /** |
|
21 | - * Instance of the definition object to use when block. |
|
22 | - */ |
|
23 | - public $block; |
|
20 | + /** |
|
21 | + * Instance of the definition object to use when block. |
|
22 | + */ |
|
23 | + public $block; |
|
24 | 24 | |
25 | - public $type = 'chameleon'; |
|
25 | + public $type = 'chameleon'; |
|
26 | 26 | |
27 | - /** |
|
28 | - * @param $inline List of elements to allow when inline. |
|
29 | - * @param $block List of elements to allow when block. |
|
30 | - */ |
|
31 | - public function __construct($inline, $block) { |
|
32 | - $this->inline = new HTMLPurifier_ChildDef_Optional($inline); |
|
33 | - $this->block = new HTMLPurifier_ChildDef_Optional($block); |
|
34 | - $this->elements = $this->block->elements; |
|
35 | - } |
|
27 | + /** |
|
28 | + * @param $inline List of elements to allow when inline. |
|
29 | + * @param $block List of elements to allow when block. |
|
30 | + */ |
|
31 | + public function __construct($inline, $block) { |
|
32 | + $this->inline = new HTMLPurifier_ChildDef_Optional($inline); |
|
33 | + $this->block = new HTMLPurifier_ChildDef_Optional($block); |
|
34 | + $this->elements = $this->block->elements; |
|
35 | + } |
|
36 | 36 | |
37 | - public function validateChildren($tokens_of_children, $config, $context) { |
|
38 | - if ($context->get('IsInline') === false) { |
|
39 | - return $this->block->validateChildren( |
|
40 | - $tokens_of_children, $config, $context); |
|
41 | - } else { |
|
42 | - return $this->inline->validateChildren( |
|
43 | - $tokens_of_children, $config, $context); |
|
44 | - } |
|
45 | - } |
|
37 | + public function validateChildren($tokens_of_children, $config, $context) { |
|
38 | + if ($context->get('IsInline') === false) { |
|
39 | + return $this->block->validateChildren( |
|
40 | + $tokens_of_children, $config, $context); |
|
41 | + } else { |
|
42 | + return $this->inline->validateChildren( |
|
43 | + $tokens_of_children, $config, $context); |
|
44 | + } |
|
45 | + } |
|
46 | 46 | } |
47 | 47 | |
48 | 48 | // vim: et sw=4 sts=4 |
@@ -8,83 +8,83 @@ |
||
8 | 8 | */ |
9 | 9 | class HTMLPurifier_ChildDef_Custom extends HTMLPurifier_ChildDef |
10 | 10 | { |
11 | - public $type = 'custom'; |
|
12 | - public $allow_empty = false; |
|
13 | - /** |
|
14 | - * Allowed child pattern as defined by the DTD |
|
15 | - */ |
|
16 | - public $dtd_regex; |
|
17 | - /** |
|
18 | - * PCRE regex derived from $dtd_regex |
|
19 | - * @private |
|
20 | - */ |
|
21 | - private $_pcre_regex; |
|
22 | - /** |
|
23 | - * @param $dtd_regex Allowed child pattern from the DTD |
|
24 | - */ |
|
25 | - public function __construct($dtd_regex) { |
|
26 | - $this->dtd_regex = $dtd_regex; |
|
27 | - $this->_compileRegex(); |
|
28 | - } |
|
29 | - /** |
|
30 | - * Compiles the PCRE regex from a DTD regex ($dtd_regex to $_pcre_regex) |
|
31 | - */ |
|
32 | - protected function _compileRegex() { |
|
33 | - $raw = str_replace(' ', '', $this->dtd_regex); |
|
34 | - if ($raw{0} != '(') { |
|
35 | - $raw = "($raw)"; |
|
36 | - } |
|
37 | - $el = '[#a-zA-Z0-9_.-]+'; |
|
38 | - $reg = $raw; |
|
11 | + public $type = 'custom'; |
|
12 | + public $allow_empty = false; |
|
13 | + /** |
|
14 | + * Allowed child pattern as defined by the DTD |
|
15 | + */ |
|
16 | + public $dtd_regex; |
|
17 | + /** |
|
18 | + * PCRE regex derived from $dtd_regex |
|
19 | + * @private |
|
20 | + */ |
|
21 | + private $_pcre_regex; |
|
22 | + /** |
|
23 | + * @param $dtd_regex Allowed child pattern from the DTD |
|
24 | + */ |
|
25 | + public function __construct($dtd_regex) { |
|
26 | + $this->dtd_regex = $dtd_regex; |
|
27 | + $this->_compileRegex(); |
|
28 | + } |
|
29 | + /** |
|
30 | + * Compiles the PCRE regex from a DTD regex ($dtd_regex to $_pcre_regex) |
|
31 | + */ |
|
32 | + protected function _compileRegex() { |
|
33 | + $raw = str_replace(' ', '', $this->dtd_regex); |
|
34 | + if ($raw{0} != '(') { |
|
35 | + $raw = "($raw)"; |
|
36 | + } |
|
37 | + $el = '[#a-zA-Z0-9_.-]+'; |
|
38 | + $reg = $raw; |
|
39 | 39 | |
40 | - // COMPLICATED! AND MIGHT BE BUGGY! I HAVE NO CLUE WHAT I'M |
|
41 | - // DOING! Seriously: if there's problems, please report them. |
|
40 | + // COMPLICATED! AND MIGHT BE BUGGY! I HAVE NO CLUE WHAT I'M |
|
41 | + // DOING! Seriously: if there's problems, please report them. |
|
42 | 42 | |
43 | - // collect all elements into the $elements array |
|
44 | - preg_match_all("/$el/", $reg, $matches); |
|
45 | - foreach ($matches[0] as $match) { |
|
46 | - $this->elements[$match] = true; |
|
47 | - } |
|
43 | + // collect all elements into the $elements array |
|
44 | + preg_match_all("/$el/", $reg, $matches); |
|
45 | + foreach ($matches[0] as $match) { |
|
46 | + $this->elements[$match] = true; |
|
47 | + } |
|
48 | 48 | |
49 | - // setup all elements as parentheticals with leading commas |
|
50 | - $reg = preg_replace("/$el/", '(,\\0)', $reg); |
|
49 | + // setup all elements as parentheticals with leading commas |
|
50 | + $reg = preg_replace("/$el/", '(,\\0)', $reg); |
|
51 | 51 | |
52 | - // remove commas when they were not solicited |
|
53 | - $reg = preg_replace("/([^,(|]\(+),/", '\\1', $reg); |
|
52 | + // remove commas when they were not solicited |
|
53 | + $reg = preg_replace("/([^,(|]\(+),/", '\\1', $reg); |
|
54 | 54 | |
55 | - // remove all non-paranthetical commas: they are handled by first regex |
|
56 | - $reg = preg_replace("/,\(/", '(', $reg); |
|
55 | + // remove all non-paranthetical commas: they are handled by first regex |
|
56 | + $reg = preg_replace("/,\(/", '(', $reg); |
|
57 | 57 | |
58 | - $this->_pcre_regex = $reg; |
|
59 | - } |
|
60 | - public function validateChildren($tokens_of_children, $config, $context) { |
|
61 | - $list_of_children = ''; |
|
62 | - $nesting = 0; // depth into the nest |
|
63 | - foreach ($tokens_of_children as $token) { |
|
64 | - if (!empty($token->is_whitespace)) continue; |
|
58 | + $this->_pcre_regex = $reg; |
|
59 | + } |
|
60 | + public function validateChildren($tokens_of_children, $config, $context) { |
|
61 | + $list_of_children = ''; |
|
62 | + $nesting = 0; // depth into the nest |
|
63 | + foreach ($tokens_of_children as $token) { |
|
64 | + if (!empty($token->is_whitespace)) continue; |
|
65 | 65 | |
66 | - $is_child = ($nesting == 0); // direct |
|
66 | + $is_child = ($nesting == 0); // direct |
|
67 | 67 | |
68 | - if ($token instanceof HTMLPurifier_Token_Start) { |
|
69 | - $nesting++; |
|
70 | - } elseif ($token instanceof HTMLPurifier_Token_End) { |
|
71 | - $nesting--; |
|
72 | - } |
|
68 | + if ($token instanceof HTMLPurifier_Token_Start) { |
|
69 | + $nesting++; |
|
70 | + } elseif ($token instanceof HTMLPurifier_Token_End) { |
|
71 | + $nesting--; |
|
72 | + } |
|
73 | 73 | |
74 | - if ($is_child) { |
|
75 | - $list_of_children .= $token->name . ','; |
|
76 | - } |
|
77 | - } |
|
78 | - // add leading comma to deal with stray comma declarations |
|
79 | - $list_of_children = ',' . rtrim($list_of_children, ','); |
|
80 | - $okay = |
|
81 | - preg_match( |
|
82 | - '/^,?'.$this->_pcre_regex.'$/', |
|
83 | - $list_of_children |
|
84 | - ); |
|
74 | + if ($is_child) { |
|
75 | + $list_of_children .= $token->name . ','; |
|
76 | + } |
|
77 | + } |
|
78 | + // add leading comma to deal with stray comma declarations |
|
79 | + $list_of_children = ',' . rtrim($list_of_children, ','); |
|
80 | + $okay = |
|
81 | + preg_match( |
|
82 | + '/^,?'.$this->_pcre_regex.'$/', |
|
83 | + $list_of_children |
|
84 | + ); |
|
85 | 85 | |
86 | - return (bool) $okay; |
|
87 | - } |
|
86 | + return (bool) $okay; |
|
87 | + } |
|
88 | 88 | } |
89 | 89 | |
90 | 90 | // vim: et sw=4 sts=4 |
@@ -61,7 +61,9 @@ |
||
61 | 61 | $list_of_children = ''; |
62 | 62 | $nesting = 0; // depth into the nest |
63 | 63 | foreach ($tokens_of_children as $token) { |
64 | - if (!empty($token->is_whitespace)) continue; |
|
64 | + if (!empty($token->is_whitespace)) { |
|
65 | + continue; |
|
66 | + } |
|
65 | 67 | |
66 | 68 | $is_child = ($nesting == 0); // direct |
67 | 69 |
@@ -72,11 +72,11 @@ |
||
72 | 72 | } |
73 | 73 | |
74 | 74 | if ($is_child) { |
75 | - $list_of_children .= $token->name . ','; |
|
75 | + $list_of_children .= $token->name.','; |
|
76 | 76 | } |
77 | 77 | } |
78 | 78 | // add leading comma to deal with stray comma declarations |
79 | - $list_of_children = ',' . rtrim($list_of_children, ','); |
|
79 | + $list_of_children = ','.rtrim($list_of_children, ','); |
|
80 | 80 | $okay = |
81 | 81 | preg_match( |
82 | 82 | '/^,?'.$this->_pcre_regex.'$/', |
@@ -9,12 +9,12 @@ |
||
9 | 9 | */ |
10 | 10 | class HTMLPurifier_ChildDef_Empty extends HTMLPurifier_ChildDef |
11 | 11 | { |
12 | - public $allow_empty = true; |
|
13 | - public $type = 'empty'; |
|
14 | - public function __construct() {} |
|
15 | - public function validateChildren($tokens_of_children, $config, $context) { |
|
16 | - return array(); |
|
17 | - } |
|
12 | + public $allow_empty = true; |
|
13 | + public $type = 'empty'; |
|
14 | + public function __construct() {} |
|
15 | + public function validateChildren($tokens_of_children, $config, $context) { |
|
16 | + return array(); |
|
17 | + } |
|
18 | 18 | } |
19 | 19 | |
20 | 20 | // vim: et sw=4 sts=4 |
@@ -5,116 +5,116 @@ |
||
5 | 5 | */ |
6 | 6 | class HTMLPurifier_ChildDef_List extends HTMLPurifier_ChildDef |
7 | 7 | { |
8 | - public $type = 'list'; |
|
9 | - // lying a little bit, so that we can handle ul and ol ourselves |
|
10 | - // XXX: This whole business with 'wrap' is all a bit unsatisfactory |
|
11 | - public $elements = array('li' => true, 'ul' => true, 'ol' => true); |
|
12 | - public function validateChildren($tokens_of_children, $config, $context) { |
|
13 | - // Flag for subclasses |
|
14 | - $this->whitespace = false; |
|
8 | + public $type = 'list'; |
|
9 | + // lying a little bit, so that we can handle ul and ol ourselves |
|
10 | + // XXX: This whole business with 'wrap' is all a bit unsatisfactory |
|
11 | + public $elements = array('li' => true, 'ul' => true, 'ol' => true); |
|
12 | + public function validateChildren($tokens_of_children, $config, $context) { |
|
13 | + // Flag for subclasses |
|
14 | + $this->whitespace = false; |
|
15 | 15 | |
16 | - // if there are no tokens, delete parent node |
|
17 | - if (empty($tokens_of_children)) return false; |
|
16 | + // if there are no tokens, delete parent node |
|
17 | + if (empty($tokens_of_children)) return false; |
|
18 | 18 | |
19 | - // the new set of children |
|
20 | - $result = array(); |
|
19 | + // the new set of children |
|
20 | + $result = array(); |
|
21 | 21 | |
22 | - // current depth into the nest |
|
23 | - $nesting = 0; |
|
22 | + // current depth into the nest |
|
23 | + $nesting = 0; |
|
24 | 24 | |
25 | - // a little sanity check to make sure it's not ALL whitespace |
|
26 | - $all_whitespace = true; |
|
25 | + // a little sanity check to make sure it's not ALL whitespace |
|
26 | + $all_whitespace = true; |
|
27 | 27 | |
28 | - $seen_li = false; |
|
29 | - $need_close_li = false; |
|
28 | + $seen_li = false; |
|
29 | + $need_close_li = false; |
|
30 | 30 | |
31 | - foreach ($tokens_of_children as $token) { |
|
32 | - if (!empty($token->is_whitespace)) { |
|
33 | - $result[] = $token; |
|
34 | - continue; |
|
35 | - } |
|
36 | - $all_whitespace = false; // phew, we're not talking about whitespace |
|
31 | + foreach ($tokens_of_children as $token) { |
|
32 | + if (!empty($token->is_whitespace)) { |
|
33 | + $result[] = $token; |
|
34 | + continue; |
|
35 | + } |
|
36 | + $all_whitespace = false; // phew, we're not talking about whitespace |
|
37 | 37 | |
38 | - if ($nesting == 1 && $need_close_li) { |
|
39 | - $result[] = new HTMLPurifier_Token_End('li'); |
|
40 | - $nesting--; |
|
41 | - $need_close_li = false; |
|
42 | - } |
|
38 | + if ($nesting == 1 && $need_close_li) { |
|
39 | + $result[] = new HTMLPurifier_Token_End('li'); |
|
40 | + $nesting--; |
|
41 | + $need_close_li = false; |
|
42 | + } |
|
43 | 43 | |
44 | - $is_child = ($nesting == 0); |
|
44 | + $is_child = ($nesting == 0); |
|
45 | 45 | |
46 | - if ($token instanceof HTMLPurifier_Token_Start) { |
|
47 | - $nesting++; |
|
48 | - } elseif ($token instanceof HTMLPurifier_Token_End) { |
|
49 | - $nesting--; |
|
50 | - } |
|
46 | + if ($token instanceof HTMLPurifier_Token_Start) { |
|
47 | + $nesting++; |
|
48 | + } elseif ($token instanceof HTMLPurifier_Token_End) { |
|
49 | + $nesting--; |
|
50 | + } |
|
51 | 51 | |
52 | - if ($is_child) { |
|
53 | - if ($token->name === 'li') { |
|
54 | - // good |
|
55 | - $seen_li = true; |
|
56 | - } elseif ($token->name === 'ul' || $token->name === 'ol') { |
|
57 | - // we want to tuck this into the previous li |
|
58 | - $need_close_li = true; |
|
59 | - $nesting++; |
|
60 | - if (!$seen_li) { |
|
61 | - // create a new li element |
|
62 | - $result[] = new HTMLPurifier_Token_Start('li'); |
|
63 | - } else { |
|
64 | - // backtrack until </li> found |
|
65 | - while(true) { |
|
66 | - $t = array_pop($result); |
|
67 | - if ($t instanceof HTMLPurifier_Token_End) { |
|
68 | - // XXX actually, these invariants could very plausibly be violated |
|
69 | - // if we are doing silly things with modifying the set of allowed elements. |
|
70 | - // FORTUNATELY, it doesn't make a difference, since the allowed |
|
71 | - // elements are hard-coded here! |
|
72 | - if ($t->name !== 'li') { |
|
73 | - trigger_error("Only li present invariant violated in List ChildDef", E_USER_ERROR); |
|
74 | - return false; |
|
75 | - } |
|
76 | - break; |
|
77 | - } elseif ($t instanceof HTMLPurifier_Token_Empty) { // bleagh |
|
78 | - if ($t->name !== 'li') { |
|
79 | - trigger_error("Only li present invariant violated in List ChildDef", E_USER_ERROR); |
|
80 | - return false; |
|
81 | - } |
|
82 | - // XXX this should have a helper for it... |
|
83 | - $result[] = new HTMLPurifier_Token_Start('li', $t->attr, $t->line, $t->col, $t->armor); |
|
84 | - break; |
|
85 | - } else { |
|
86 | - if (!$t->is_whitespace) { |
|
87 | - trigger_error("Only whitespace present invariant violated in List ChildDef", E_USER_ERROR); |
|
88 | - return false; |
|
89 | - } |
|
90 | - } |
|
91 | - } |
|
92 | - } |
|
93 | - } else { |
|
94 | - // start wrapping (this doesn't precisely mimic |
|
95 | - // browser behavior, but what browsers do is kind of |
|
96 | - // hard to mimic in a standards compliant way |
|
97 | - // XXX Actually, this has no impact in practice, |
|
98 | - // because this gets handled earlier. Arguably, |
|
99 | - // we should rip out all of that processing |
|
100 | - $result[] = new HTMLPurifier_Token_Start('li'); |
|
101 | - $nesting++; |
|
102 | - $seen_li = true; |
|
103 | - $need_close_li = true; |
|
104 | - } |
|
105 | - } |
|
106 | - $result[] = $token; |
|
107 | - } |
|
108 | - if ($need_close_li) { |
|
109 | - $result[] = new HTMLPurifier_Token_End('li'); |
|
110 | - } |
|
111 | - if (empty($result)) return false; |
|
112 | - if ($all_whitespace) { |
|
113 | - return false; |
|
114 | - } |
|
115 | - if ($tokens_of_children == $result) return true; |
|
116 | - return $result; |
|
117 | - } |
|
52 | + if ($is_child) { |
|
53 | + if ($token->name === 'li') { |
|
54 | + // good |
|
55 | + $seen_li = true; |
|
56 | + } elseif ($token->name === 'ul' || $token->name === 'ol') { |
|
57 | + // we want to tuck this into the previous li |
|
58 | + $need_close_li = true; |
|
59 | + $nesting++; |
|
60 | + if (!$seen_li) { |
|
61 | + // create a new li element |
|
62 | + $result[] = new HTMLPurifier_Token_Start('li'); |
|
63 | + } else { |
|
64 | + // backtrack until </li> found |
|
65 | + while(true) { |
|
66 | + $t = array_pop($result); |
|
67 | + if ($t instanceof HTMLPurifier_Token_End) { |
|
68 | + // XXX actually, these invariants could very plausibly be violated |
|
69 | + // if we are doing silly things with modifying the set of allowed elements. |
|
70 | + // FORTUNATELY, it doesn't make a difference, since the allowed |
|
71 | + // elements are hard-coded here! |
|
72 | + if ($t->name !== 'li') { |
|
73 | + trigger_error("Only li present invariant violated in List ChildDef", E_USER_ERROR); |
|
74 | + return false; |
|
75 | + } |
|
76 | + break; |
|
77 | + } elseif ($t instanceof HTMLPurifier_Token_Empty) { // bleagh |
|
78 | + if ($t->name !== 'li') { |
|
79 | + trigger_error("Only li present invariant violated in List ChildDef", E_USER_ERROR); |
|
80 | + return false; |
|
81 | + } |
|
82 | + // XXX this should have a helper for it... |
|
83 | + $result[] = new HTMLPurifier_Token_Start('li', $t->attr, $t->line, $t->col, $t->armor); |
|
84 | + break; |
|
85 | + } else { |
|
86 | + if (!$t->is_whitespace) { |
|
87 | + trigger_error("Only whitespace present invariant violated in List ChildDef", E_USER_ERROR); |
|
88 | + return false; |
|
89 | + } |
|
90 | + } |
|
91 | + } |
|
92 | + } |
|
93 | + } else { |
|
94 | + // start wrapping (this doesn't precisely mimic |
|
95 | + // browser behavior, but what browsers do is kind of |
|
96 | + // hard to mimic in a standards compliant way |
|
97 | + // XXX Actually, this has no impact in practice, |
|
98 | + // because this gets handled earlier. Arguably, |
|
99 | + // we should rip out all of that processing |
|
100 | + $result[] = new HTMLPurifier_Token_Start('li'); |
|
101 | + $nesting++; |
|
102 | + $seen_li = true; |
|
103 | + $need_close_li = true; |
|
104 | + } |
|
105 | + } |
|
106 | + $result[] = $token; |
|
107 | + } |
|
108 | + if ($need_close_li) { |
|
109 | + $result[] = new HTMLPurifier_Token_End('li'); |
|
110 | + } |
|
111 | + if (empty($result)) return false; |
|
112 | + if ($all_whitespace) { |
|
113 | + return false; |
|
114 | + } |
|
115 | + if ($tokens_of_children == $result) return true; |
|
116 | + return $result; |
|
117 | + } |
|
118 | 118 | } |
119 | 119 | |
120 | 120 | // vim: et sw=4 sts=4 |
@@ -62,7 +62,7 @@ |
||
62 | 62 | $result[] = new HTMLPurifier_Token_Start('li'); |
63 | 63 | } else { |
64 | 64 | // backtrack until </li> found |
65 | - while(true) { |
|
65 | + while (true) { |
|
66 | 66 | $t = array_pop($result); |
67 | 67 | if ($t instanceof HTMLPurifier_Token_End) { |
68 | 68 | // XXX actually, these invariants could very plausibly be violated |
@@ -14,7 +14,9 @@ discard block |
||
14 | 14 | $this->whitespace = false; |
15 | 15 | |
16 | 16 | // if there are no tokens, delete parent node |
17 | - if (empty($tokens_of_children)) return false; |
|
17 | + if (empty($tokens_of_children)) { |
|
18 | + return false; |
|
19 | + } |
|
18 | 20 | |
19 | 21 | // the new set of children |
20 | 22 | $result = array(); |
@@ -108,11 +110,15 @@ discard block |
||
108 | 110 | if ($need_close_li) { |
109 | 111 | $result[] = new HTMLPurifier_Token_End('li'); |
110 | 112 | } |
111 | - if (empty($result)) return false; |
|
113 | + if (empty($result)) { |
|
114 | + return false; |
|
115 | + } |
|
112 | 116 | if ($all_whitespace) { |
113 | 117 | return false; |
114 | 118 | } |
115 | - if ($tokens_of_children == $result) return true; |
|
119 | + if ($tokens_of_children == $result) { |
|
120 | + return true; |
|
121 | + } |
|
116 | 122 | return $result; |
117 | 123 | } |
118 | 124 | } |
@@ -9,18 +9,18 @@ |
||
9 | 9 | */ |
10 | 10 | class HTMLPurifier_ChildDef_Optional extends HTMLPurifier_ChildDef_Required |
11 | 11 | { |
12 | - public $allow_empty = true; |
|
13 | - public $type = 'optional'; |
|
14 | - public function validateChildren($tokens_of_children, $config, $context) { |
|
15 | - $result = parent::validateChildren($tokens_of_children, $config, $context); |
|
16 | - // we assume that $tokens_of_children is not modified |
|
17 | - if ($result === false) { |
|
18 | - if (empty($tokens_of_children)) return true; |
|
19 | - elseif ($this->whitespace) return $tokens_of_children; |
|
20 | - else return array(); |
|
21 | - } |
|
22 | - return $result; |
|
23 | - } |
|
12 | + public $allow_empty = true; |
|
13 | + public $type = 'optional'; |
|
14 | + public function validateChildren($tokens_of_children, $config, $context) { |
|
15 | + $result = parent::validateChildren($tokens_of_children, $config, $context); |
|
16 | + // we assume that $tokens_of_children is not modified |
|
17 | + if ($result === false) { |
|
18 | + if (empty($tokens_of_children)) return true; |
|
19 | + elseif ($this->whitespace) return $tokens_of_children; |
|
20 | + else return array(); |
|
21 | + } |
|
22 | + return $result; |
|
23 | + } |
|
24 | 24 | } |
25 | 25 | |
26 | 26 | // vim: et sw=4 sts=4 |
@@ -15,9 +15,13 @@ |
||
15 | 15 | $result = parent::validateChildren($tokens_of_children, $config, $context); |
16 | 16 | // we assume that $tokens_of_children is not modified |
17 | 17 | if ($result === false) { |
18 | - if (empty($tokens_of_children)) return true; |
|
19 | - elseif ($this->whitespace) return $tokens_of_children; |
|
20 | - else return array(); |
|
18 | + if (empty($tokens_of_children)) { |
|
19 | + return true; |
|
20 | + } elseif ($this->whitespace) { |
|
21 | + return $tokens_of_children; |
|
22 | + } else { |
|
23 | + return array(); |
|
24 | + } |
|
21 | 25 | } |
22 | 26 | return $result; |
23 | 27 | } |
@@ -5,113 +5,113 @@ |
||
5 | 5 | */ |
6 | 6 | class HTMLPurifier_ChildDef_Required extends HTMLPurifier_ChildDef |
7 | 7 | { |
8 | - /** |
|
9 | - * Lookup table of allowed elements. |
|
10 | - * @public |
|
11 | - */ |
|
12 | - public $elements = array(); |
|
13 | - /** |
|
14 | - * Whether or not the last passed node was all whitespace. |
|
15 | - */ |
|
16 | - protected $whitespace = false; |
|
17 | - /** |
|
18 | - * @param $elements List of allowed element names (lowercase). |
|
19 | - */ |
|
20 | - public function __construct($elements) { |
|
21 | - if (is_string($elements)) { |
|
22 | - $elements = str_replace(' ', '', $elements); |
|
23 | - $elements = explode('|', $elements); |
|
24 | - } |
|
25 | - $keys = array_keys($elements); |
|
26 | - if ($keys == array_keys($keys)) { |
|
27 | - $elements = array_flip($elements); |
|
28 | - foreach ($elements as $i => $x) { |
|
29 | - $elements[$i] = true; |
|
30 | - if (empty($i)) unset($elements[$i]); // remove blank |
|
31 | - } |
|
32 | - } |
|
33 | - $this->elements = $elements; |
|
34 | - } |
|
35 | - public $allow_empty = false; |
|
36 | - public $type = 'required'; |
|
37 | - public function validateChildren($tokens_of_children, $config, $context) { |
|
38 | - // Flag for subclasses |
|
39 | - $this->whitespace = false; |
|
8 | + /** |
|
9 | + * Lookup table of allowed elements. |
|
10 | + * @public |
|
11 | + */ |
|
12 | + public $elements = array(); |
|
13 | + /** |
|
14 | + * Whether or not the last passed node was all whitespace. |
|
15 | + */ |
|
16 | + protected $whitespace = false; |
|
17 | + /** |
|
18 | + * @param $elements List of allowed element names (lowercase). |
|
19 | + */ |
|
20 | + public function __construct($elements) { |
|
21 | + if (is_string($elements)) { |
|
22 | + $elements = str_replace(' ', '', $elements); |
|
23 | + $elements = explode('|', $elements); |
|
24 | + } |
|
25 | + $keys = array_keys($elements); |
|
26 | + if ($keys == array_keys($keys)) { |
|
27 | + $elements = array_flip($elements); |
|
28 | + foreach ($elements as $i => $x) { |
|
29 | + $elements[$i] = true; |
|
30 | + if (empty($i)) unset($elements[$i]); // remove blank |
|
31 | + } |
|
32 | + } |
|
33 | + $this->elements = $elements; |
|
34 | + } |
|
35 | + public $allow_empty = false; |
|
36 | + public $type = 'required'; |
|
37 | + public function validateChildren($tokens_of_children, $config, $context) { |
|
38 | + // Flag for subclasses |
|
39 | + $this->whitespace = false; |
|
40 | 40 | |
41 | - // if there are no tokens, delete parent node |
|
42 | - if (empty($tokens_of_children)) return false; |
|
41 | + // if there are no tokens, delete parent node |
|
42 | + if (empty($tokens_of_children)) return false; |
|
43 | 43 | |
44 | - // the new set of children |
|
45 | - $result = array(); |
|
44 | + // the new set of children |
|
45 | + $result = array(); |
|
46 | 46 | |
47 | - // current depth into the nest |
|
48 | - $nesting = 0; |
|
47 | + // current depth into the nest |
|
48 | + $nesting = 0; |
|
49 | 49 | |
50 | - // whether or not we're deleting a node |
|
51 | - $is_deleting = false; |
|
50 | + // whether or not we're deleting a node |
|
51 | + $is_deleting = false; |
|
52 | 52 | |
53 | - // whether or not parsed character data is allowed |
|
54 | - // this controls whether or not we silently drop a tag |
|
55 | - // or generate escaped HTML from it |
|
56 | - $pcdata_allowed = isset($this->elements['#PCDATA']); |
|
53 | + // whether or not parsed character data is allowed |
|
54 | + // this controls whether or not we silently drop a tag |
|
55 | + // or generate escaped HTML from it |
|
56 | + $pcdata_allowed = isset($this->elements['#PCDATA']); |
|
57 | 57 | |
58 | - // a little sanity check to make sure it's not ALL whitespace |
|
59 | - $all_whitespace = true; |
|
58 | + // a little sanity check to make sure it's not ALL whitespace |
|
59 | + $all_whitespace = true; |
|
60 | 60 | |
61 | - // some configuration |
|
62 | - $escape_invalid_children = $config->get('Core.EscapeInvalidChildren'); |
|
61 | + // some configuration |
|
62 | + $escape_invalid_children = $config->get('Core.EscapeInvalidChildren'); |
|
63 | 63 | |
64 | - // generator |
|
65 | - $gen = new HTMLPurifier_Generator($config, $context); |
|
64 | + // generator |
|
65 | + $gen = new HTMLPurifier_Generator($config, $context); |
|
66 | 66 | |
67 | - foreach ($tokens_of_children as $token) { |
|
68 | - if (!empty($token->is_whitespace)) { |
|
69 | - $result[] = $token; |
|
70 | - continue; |
|
71 | - } |
|
72 | - $all_whitespace = false; // phew, we're not talking about whitespace |
|
67 | + foreach ($tokens_of_children as $token) { |
|
68 | + if (!empty($token->is_whitespace)) { |
|
69 | + $result[] = $token; |
|
70 | + continue; |
|
71 | + } |
|
72 | + $all_whitespace = false; // phew, we're not talking about whitespace |
|
73 | 73 | |
74 | - $is_child = ($nesting == 0); |
|
74 | + $is_child = ($nesting == 0); |
|
75 | 75 | |
76 | - if ($token instanceof HTMLPurifier_Token_Start) { |
|
77 | - $nesting++; |
|
78 | - } elseif ($token instanceof HTMLPurifier_Token_End) { |
|
79 | - $nesting--; |
|
80 | - } |
|
76 | + if ($token instanceof HTMLPurifier_Token_Start) { |
|
77 | + $nesting++; |
|
78 | + } elseif ($token instanceof HTMLPurifier_Token_End) { |
|
79 | + $nesting--; |
|
80 | + } |
|
81 | 81 | |
82 | - if ($is_child) { |
|
83 | - $is_deleting = false; |
|
84 | - if (!isset($this->elements[$token->name])) { |
|
85 | - $is_deleting = true; |
|
86 | - if ($pcdata_allowed && $token instanceof HTMLPurifier_Token_Text) { |
|
87 | - $result[] = $token; |
|
88 | - } elseif ($pcdata_allowed && $escape_invalid_children) { |
|
89 | - $result[] = new HTMLPurifier_Token_Text( |
|
90 | - $gen->generateFromToken($token) |
|
91 | - ); |
|
92 | - } |
|
93 | - continue; |
|
94 | - } |
|
95 | - } |
|
96 | - if (!$is_deleting || ($pcdata_allowed && $token instanceof HTMLPurifier_Token_Text)) { |
|
97 | - $result[] = $token; |
|
98 | - } elseif ($pcdata_allowed && $escape_invalid_children) { |
|
99 | - $result[] = |
|
100 | - new HTMLPurifier_Token_Text( |
|
101 | - $gen->generateFromToken($token) |
|
102 | - ); |
|
103 | - } else { |
|
104 | - // drop silently |
|
105 | - } |
|
106 | - } |
|
107 | - if (empty($result)) return false; |
|
108 | - if ($all_whitespace) { |
|
109 | - $this->whitespace = true; |
|
110 | - return false; |
|
111 | - } |
|
112 | - if ($tokens_of_children == $result) return true; |
|
113 | - return $result; |
|
114 | - } |
|
82 | + if ($is_child) { |
|
83 | + $is_deleting = false; |
|
84 | + if (!isset($this->elements[$token->name])) { |
|
85 | + $is_deleting = true; |
|
86 | + if ($pcdata_allowed && $token instanceof HTMLPurifier_Token_Text) { |
|
87 | + $result[] = $token; |
|
88 | + } elseif ($pcdata_allowed && $escape_invalid_children) { |
|
89 | + $result[] = new HTMLPurifier_Token_Text( |
|
90 | + $gen->generateFromToken($token) |
|
91 | + ); |
|
92 | + } |
|
93 | + continue; |
|
94 | + } |
|
95 | + } |
|
96 | + if (!$is_deleting || ($pcdata_allowed && $token instanceof HTMLPurifier_Token_Text)) { |
|
97 | + $result[] = $token; |
|
98 | + } elseif ($pcdata_allowed && $escape_invalid_children) { |
|
99 | + $result[] = |
|
100 | + new HTMLPurifier_Token_Text( |
|
101 | + $gen->generateFromToken($token) |
|
102 | + ); |
|
103 | + } else { |
|
104 | + // drop silently |
|
105 | + } |
|
106 | + } |
|
107 | + if (empty($result)) return false; |
|
108 | + if ($all_whitespace) { |
|
109 | + $this->whitespace = true; |
|
110 | + return false; |
|
111 | + } |
|
112 | + if ($tokens_of_children == $result) return true; |
|
113 | + return $result; |
|
114 | + } |
|
115 | 115 | } |
116 | 116 | |
117 | 117 | // vim: et sw=4 sts=4 |
@@ -27,7 +27,10 @@ discard block |
||
27 | 27 | $elements = array_flip($elements); |
28 | 28 | foreach ($elements as $i => $x) { |
29 | 29 | $elements[$i] = true; |
30 | - if (empty($i)) unset($elements[$i]); // remove blank |
|
30 | + if (empty($i)) { |
|
31 | + unset($elements[$i]); |
|
32 | + } |
|
33 | + // remove blank |
|
31 | 34 | } |
32 | 35 | } |
33 | 36 | $this->elements = $elements; |
@@ -39,7 +42,9 @@ discard block |
||
39 | 42 | $this->whitespace = false; |
40 | 43 | |
41 | 44 | // if there are no tokens, delete parent node |
42 | - if (empty($tokens_of_children)) return false; |
|
45 | + if (empty($tokens_of_children)) { |
|
46 | + return false; |
|
47 | + } |
|
43 | 48 | |
44 | 49 | // the new set of children |
45 | 50 | $result = array(); |
@@ -104,12 +109,16 @@ discard block |
||
104 | 109 | // drop silently |
105 | 110 | } |
106 | 111 | } |
107 | - if (empty($result)) return false; |
|
112 | + if (empty($result)) { |
|
113 | + return false; |
|
114 | + } |
|
108 | 115 | if ($all_whitespace) { |
109 | 116 | $this->whitespace = true; |
110 | 117 | return false; |
111 | 118 | } |
112 | - if ($tokens_of_children == $result) return true; |
|
119 | + if ($tokens_of_children == $result) { |
|
120 | + return true; |
|
121 | + } |
|
113 | 122 | return $result; |
114 | 123 | } |
115 | 124 | } |
@@ -5,84 +5,84 @@ |
||
5 | 5 | */ |
6 | 6 | class HTMLPurifier_ChildDef_StrictBlockquote extends HTMLPurifier_ChildDef_Required |
7 | 7 | { |
8 | - protected $real_elements; |
|
9 | - protected $fake_elements; |
|
10 | - public $allow_empty = true; |
|
11 | - public $type = 'strictblockquote'; |
|
12 | - protected $init = false; |
|
8 | + protected $real_elements; |
|
9 | + protected $fake_elements; |
|
10 | + public $allow_empty = true; |
|
11 | + public $type = 'strictblockquote'; |
|
12 | + protected $init = false; |
|
13 | 13 | |
14 | - /** |
|
15 | - * @note We don't want MakeWellFormed to auto-close inline elements since |
|
16 | - * they might be allowed. |
|
17 | - */ |
|
18 | - public function getAllowedElements($config) { |
|
19 | - $this->init($config); |
|
20 | - return $this->fake_elements; |
|
21 | - } |
|
14 | + /** |
|
15 | + * @note We don't want MakeWellFormed to auto-close inline elements since |
|
16 | + * they might be allowed. |
|
17 | + */ |
|
18 | + public function getAllowedElements($config) { |
|
19 | + $this->init($config); |
|
20 | + return $this->fake_elements; |
|
21 | + } |
|
22 | 22 | |
23 | - public function validateChildren($tokens_of_children, $config, $context) { |
|
23 | + public function validateChildren($tokens_of_children, $config, $context) { |
|
24 | 24 | |
25 | - $this->init($config); |
|
25 | + $this->init($config); |
|
26 | 26 | |
27 | - // trick the parent class into thinking it allows more |
|
28 | - $this->elements = $this->fake_elements; |
|
29 | - $result = parent::validateChildren($tokens_of_children, $config, $context); |
|
30 | - $this->elements = $this->real_elements; |
|
27 | + // trick the parent class into thinking it allows more |
|
28 | + $this->elements = $this->fake_elements; |
|
29 | + $result = parent::validateChildren($tokens_of_children, $config, $context); |
|
30 | + $this->elements = $this->real_elements; |
|
31 | 31 | |
32 | - if ($result === false) return array(); |
|
33 | - if ($result === true) $result = $tokens_of_children; |
|
32 | + if ($result === false) return array(); |
|
33 | + if ($result === true) $result = $tokens_of_children; |
|
34 | 34 | |
35 | - $def = $config->getHTMLDefinition(); |
|
36 | - $block_wrap_start = new HTMLPurifier_Token_Start($def->info_block_wrapper); |
|
37 | - $block_wrap_end = new HTMLPurifier_Token_End( $def->info_block_wrapper); |
|
38 | - $is_inline = false; |
|
39 | - $depth = 0; |
|
40 | - $ret = array(); |
|
35 | + $def = $config->getHTMLDefinition(); |
|
36 | + $block_wrap_start = new HTMLPurifier_Token_Start($def->info_block_wrapper); |
|
37 | + $block_wrap_end = new HTMLPurifier_Token_End( $def->info_block_wrapper); |
|
38 | + $is_inline = false; |
|
39 | + $depth = 0; |
|
40 | + $ret = array(); |
|
41 | 41 | |
42 | - // assuming that there are no comment tokens |
|
43 | - foreach ($result as $i => $token) { |
|
44 | - $token = $result[$i]; |
|
45 | - // ifs are nested for readability |
|
46 | - if (!$is_inline) { |
|
47 | - if (!$depth) { |
|
48 | - if ( |
|
49 | - ($token instanceof HTMLPurifier_Token_Text && !$token->is_whitespace) || |
|
50 | - (!$token instanceof HTMLPurifier_Token_Text && !isset($this->elements[$token->name])) |
|
51 | - ) { |
|
52 | - $is_inline = true; |
|
53 | - $ret[] = $block_wrap_start; |
|
54 | - } |
|
55 | - } |
|
56 | - } else { |
|
57 | - if (!$depth) { |
|
58 | - // starting tokens have been inline text / empty |
|
59 | - if ($token instanceof HTMLPurifier_Token_Start || $token instanceof HTMLPurifier_Token_Empty) { |
|
60 | - if (isset($this->elements[$token->name])) { |
|
61 | - // ended |
|
62 | - $ret[] = $block_wrap_end; |
|
63 | - $is_inline = false; |
|
64 | - } |
|
65 | - } |
|
66 | - } |
|
67 | - } |
|
68 | - $ret[] = $token; |
|
69 | - if ($token instanceof HTMLPurifier_Token_Start) $depth++; |
|
70 | - if ($token instanceof HTMLPurifier_Token_End) $depth--; |
|
71 | - } |
|
72 | - if ($is_inline) $ret[] = $block_wrap_end; |
|
73 | - return $ret; |
|
74 | - } |
|
42 | + // assuming that there are no comment tokens |
|
43 | + foreach ($result as $i => $token) { |
|
44 | + $token = $result[$i]; |
|
45 | + // ifs are nested for readability |
|
46 | + if (!$is_inline) { |
|
47 | + if (!$depth) { |
|
48 | + if ( |
|
49 | + ($token instanceof HTMLPurifier_Token_Text && !$token->is_whitespace) || |
|
50 | + (!$token instanceof HTMLPurifier_Token_Text && !isset($this->elements[$token->name])) |
|
51 | + ) { |
|
52 | + $is_inline = true; |
|
53 | + $ret[] = $block_wrap_start; |
|
54 | + } |
|
55 | + } |
|
56 | + } else { |
|
57 | + if (!$depth) { |
|
58 | + // starting tokens have been inline text / empty |
|
59 | + if ($token instanceof HTMLPurifier_Token_Start || $token instanceof HTMLPurifier_Token_Empty) { |
|
60 | + if (isset($this->elements[$token->name])) { |
|
61 | + // ended |
|
62 | + $ret[] = $block_wrap_end; |
|
63 | + $is_inline = false; |
|
64 | + } |
|
65 | + } |
|
66 | + } |
|
67 | + } |
|
68 | + $ret[] = $token; |
|
69 | + if ($token instanceof HTMLPurifier_Token_Start) $depth++; |
|
70 | + if ($token instanceof HTMLPurifier_Token_End) $depth--; |
|
71 | + } |
|
72 | + if ($is_inline) $ret[] = $block_wrap_end; |
|
73 | + return $ret; |
|
74 | + } |
|
75 | 75 | |
76 | - private function init($config) { |
|
77 | - if (!$this->init) { |
|
78 | - $def = $config->getHTMLDefinition(); |
|
79 | - // allow all inline elements |
|
80 | - $this->real_elements = $this->elements; |
|
81 | - $this->fake_elements = $def->info_content_sets['Flow']; |
|
82 | - $this->fake_elements['#PCDATA'] = true; |
|
83 | - $this->init = true; |
|
84 | - } |
|
85 | - } |
|
76 | + private function init($config) { |
|
77 | + if (!$this->init) { |
|
78 | + $def = $config->getHTMLDefinition(); |
|
79 | + // allow all inline elements |
|
80 | + $this->real_elements = $this->elements; |
|
81 | + $this->fake_elements = $def->info_content_sets['Flow']; |
|
82 | + $this->fake_elements['#PCDATA'] = true; |
|
83 | + $this->init = true; |
|
84 | + } |
|
85 | + } |
|
86 | 86 | } |
87 | 87 | |
88 | 88 | // vim: et sw=4 sts=4 |
@@ -34,7 +34,7 @@ |
||
34 | 34 | |
35 | 35 | $def = $config->getHTMLDefinition(); |
36 | 36 | $block_wrap_start = new HTMLPurifier_Token_Start($def->info_block_wrapper); |
37 | - $block_wrap_end = new HTMLPurifier_Token_End( $def->info_block_wrapper); |
|
37 | + $block_wrap_end = new HTMLPurifier_Token_End($def->info_block_wrapper); |
|
38 | 38 | $is_inline = false; |
39 | 39 | $depth = 0; |
40 | 40 | $ret = array(); |
@@ -29,8 +29,12 @@ discard block |
||
29 | 29 | $result = parent::validateChildren($tokens_of_children, $config, $context); |
30 | 30 | $this->elements = $this->real_elements; |
31 | 31 | |
32 | - if ($result === false) return array(); |
|
33 | - if ($result === true) $result = $tokens_of_children; |
|
32 | + if ($result === false) { |
|
33 | + return array(); |
|
34 | + } |
|
35 | + if ($result === true) { |
|
36 | + $result = $tokens_of_children; |
|
37 | + } |
|
34 | 38 | |
35 | 39 | $def = $config->getHTMLDefinition(); |
36 | 40 | $block_wrap_start = new HTMLPurifier_Token_Start($def->info_block_wrapper); |
@@ -66,10 +70,16 @@ discard block |
||
66 | 70 | } |
67 | 71 | } |
68 | 72 | $ret[] = $token; |
69 | - if ($token instanceof HTMLPurifier_Token_Start) $depth++; |
|
70 | - if ($token instanceof HTMLPurifier_Token_End) $depth--; |
|
73 | + if ($token instanceof HTMLPurifier_Token_Start) { |
|
74 | + $depth++; |
|
75 | + } |
|
76 | + if ($token instanceof HTMLPurifier_Token_End) { |
|
77 | + $depth--; |
|
78 | + } |
|
79 | + } |
|
80 | + if ($is_inline) { |
|
81 | + $ret[] = $block_wrap_end; |
|
71 | 82 | } |
72 | - if ($is_inline) $ret[] = $block_wrap_end; |
|
73 | 83 | return $ret; |
74 | 84 | } |
75 | 85 |
@@ -31,197 +31,197 @@ |
||
31 | 31 | */ |
32 | 32 | class HTMLPurifier_ChildDef_Table extends HTMLPurifier_ChildDef |
33 | 33 | { |
34 | - public $allow_empty = false; |
|
35 | - public $type = 'table'; |
|
36 | - public $elements = array('tr' => true, 'tbody' => true, 'thead' => true, |
|
37 | - 'tfoot' => true, 'caption' => true, 'colgroup' => true, 'col' => true); |
|
38 | - public function __construct() {} |
|
39 | - public function validateChildren($tokens_of_children, $config, $context) { |
|
40 | - if (empty($tokens_of_children)) return false; |
|
41 | - |
|
42 | - // this ensures that the loop gets run one last time before closing |
|
43 | - // up. It's a little bit of a hack, but it works! Just make sure you |
|
44 | - // get rid of the token later. |
|
45 | - $tokens_of_children[] = false; |
|
46 | - |
|
47 | - // only one of these elements is allowed in a table |
|
48 | - $caption = false; |
|
49 | - $thead = false; |
|
50 | - $tfoot = false; |
|
51 | - |
|
52 | - // as many of these as you want |
|
53 | - $cols = array(); |
|
54 | - $content = array(); |
|
55 | - |
|
56 | - $nesting = 0; // current depth so we can determine nodes |
|
57 | - $is_collecting = false; // are we globbing together tokens to package |
|
58 | - // into one of the collectors? |
|
59 | - $collection = array(); // collected nodes |
|
60 | - $tag_index = 0; // the first node might be whitespace, |
|
61 | - // so this tells us where the start tag is |
|
62 | - $tbody_mode = false; // if true, then we need to wrap any stray |
|
63 | - // <tr>s with a <tbody>. |
|
64 | - |
|
65 | - foreach ($tokens_of_children as $token) { |
|
66 | - $is_child = ($nesting == 0); |
|
67 | - |
|
68 | - if ($token === false) { |
|
69 | - // terminating sequence started |
|
70 | - } elseif ($token instanceof HTMLPurifier_Token_Start) { |
|
71 | - $nesting++; |
|
72 | - } elseif ($token instanceof HTMLPurifier_Token_End) { |
|
73 | - $nesting--; |
|
74 | - } |
|
75 | - |
|
76 | - // handle node collection |
|
77 | - if ($is_collecting) { |
|
78 | - if ($is_child) { |
|
79 | - // okay, let's stash the tokens away |
|
80 | - // first token tells us the type of the collection |
|
81 | - switch ($collection[$tag_index]->name) { |
|
82 | - case 'tbody': |
|
83 | - $tbody_mode = true; |
|
84 | - case 'tr': |
|
85 | - $content[] = $collection; |
|
86 | - break; |
|
87 | - case 'caption': |
|
88 | - if ($caption !== false) break; |
|
89 | - $caption = $collection; |
|
90 | - break; |
|
91 | - case 'thead': |
|
92 | - case 'tfoot': |
|
93 | - $tbody_mode = true; |
|
94 | - // XXX This breaks rendering properties with |
|
95 | - // Firefox, which never floats a <thead> to |
|
96 | - // the top. Ever. (Our scheme will float the |
|
97 | - // first <thead> to the top.) So maybe |
|
98 | - // <thead>s that are not first should be |
|
99 | - // turned into <tbody>? Very tricky, indeed. |
|
100 | - |
|
101 | - // access the appropriate variable, $thead or $tfoot |
|
102 | - $var = $collection[$tag_index]->name; |
|
103 | - if ($$var === false) { |
|
104 | - $$var = $collection; |
|
105 | - } else { |
|
106 | - // Oops, there's a second one! What |
|
107 | - // should we do? Current behavior is to |
|
108 | - // transmutate the first and last entries into |
|
109 | - // tbody tags, and then put into content. |
|
110 | - // Maybe a better idea is to *attach |
|
111 | - // it* to the existing thead or tfoot? |
|
112 | - // We don't do this, because Firefox |
|
113 | - // doesn't float an extra tfoot to the |
|
114 | - // bottom like it does for the first one. |
|
115 | - $collection[$tag_index]->name = 'tbody'; |
|
116 | - $collection[count($collection)-1]->name = 'tbody'; |
|
117 | - $content[] = $collection; |
|
118 | - } |
|
119 | - break; |
|
120 | - case 'colgroup': |
|
121 | - $cols[] = $collection; |
|
122 | - break; |
|
123 | - } |
|
124 | - $collection = array(); |
|
125 | - $is_collecting = false; |
|
126 | - $tag_index = 0; |
|
127 | - } else { |
|
128 | - // add the node to the collection |
|
129 | - $collection[] = $token; |
|
130 | - } |
|
131 | - } |
|
132 | - |
|
133 | - // terminate |
|
134 | - if ($token === false) break; |
|
135 | - |
|
136 | - if ($is_child) { |
|
137 | - // determine what we're dealing with |
|
138 | - if ($token->name == 'col') { |
|
139 | - // the only empty tag in the possie, we can handle it |
|
140 | - // immediately |
|
141 | - $cols[] = array_merge($collection, array($token)); |
|
142 | - $collection = array(); |
|
143 | - $tag_index = 0; |
|
144 | - continue; |
|
145 | - } |
|
146 | - switch($token->name) { |
|
147 | - case 'caption': |
|
148 | - case 'colgroup': |
|
149 | - case 'thead': |
|
150 | - case 'tfoot': |
|
151 | - case 'tbody': |
|
152 | - case 'tr': |
|
153 | - $is_collecting = true; |
|
154 | - $collection[] = $token; |
|
155 | - continue; |
|
156 | - default: |
|
157 | - if (!empty($token->is_whitespace)) { |
|
158 | - $collection[] = $token; |
|
159 | - $tag_index++; |
|
160 | - } |
|
161 | - continue; |
|
162 | - } |
|
163 | - } |
|
164 | - } |
|
165 | - |
|
166 | - if (empty($content)) return false; |
|
167 | - |
|
168 | - $ret = array(); |
|
169 | - if ($caption !== false) $ret = array_merge($ret, $caption); |
|
170 | - if ($cols !== false) foreach ($cols as $token_array) $ret = array_merge($ret, $token_array); |
|
171 | - if ($thead !== false) $ret = array_merge($ret, $thead); |
|
172 | - if ($tfoot !== false) $ret = array_merge($ret, $tfoot); |
|
173 | - |
|
174 | - if ($tbody_mode) { |
|
175 | - // a little tricky, since the start of the collection may be |
|
176 | - // whitespace |
|
177 | - $inside_tbody = false; |
|
178 | - foreach ($content as $token_array) { |
|
179 | - // find the starting token |
|
180 | - foreach ($token_array as $t) { |
|
181 | - if ($t->name === 'tr' || $t->name === 'tbody') { |
|
182 | - break; |
|
183 | - } |
|
184 | - } // iterator variable carries over |
|
185 | - if ($t->name === 'tr') { |
|
186 | - if ($inside_tbody) { |
|
187 | - $ret = array_merge($ret, $token_array); |
|
188 | - } else { |
|
189 | - $ret[] = new HTMLPurifier_Token_Start('tbody'); |
|
190 | - $ret = array_merge($ret, $token_array); |
|
191 | - $inside_tbody = true; |
|
192 | - } |
|
193 | - } elseif ($t->name === 'tbody') { |
|
194 | - if ($inside_tbody) { |
|
195 | - $ret[] = new HTMLPurifier_Token_End('tbody'); |
|
196 | - $inside_tbody = false; |
|
197 | - $ret = array_merge($ret, $token_array); |
|
198 | - } else { |
|
199 | - $ret = array_merge($ret, $token_array); |
|
200 | - } |
|
201 | - } else { |
|
202 | - trigger_error("tr/tbody in content invariant failed in Table ChildDef", E_USER_ERROR); |
|
203 | - } |
|
204 | - } |
|
205 | - if ($inside_tbody) { |
|
206 | - $ret[] = new HTMLPurifier_Token_End('tbody'); |
|
207 | - } |
|
208 | - } else { |
|
209 | - foreach ($content as $token_array) { |
|
210 | - // invariant: everything in here is <tr>s |
|
211 | - $ret = array_merge($ret, $token_array); |
|
212 | - } |
|
213 | - } |
|
214 | - |
|
215 | - if (!empty($collection) && $is_collecting == false){ |
|
216 | - // grab the trailing space |
|
217 | - $ret = array_merge($ret, $collection); |
|
218 | - } |
|
219 | - |
|
220 | - array_pop($tokens_of_children); // remove phantom token |
|
221 | - |
|
222 | - return ($ret === $tokens_of_children) ? true : $ret; |
|
223 | - |
|
224 | - } |
|
34 | + public $allow_empty = false; |
|
35 | + public $type = 'table'; |
|
36 | + public $elements = array('tr' => true, 'tbody' => true, 'thead' => true, |
|
37 | + 'tfoot' => true, 'caption' => true, 'colgroup' => true, 'col' => true); |
|
38 | + public function __construct() {} |
|
39 | + public function validateChildren($tokens_of_children, $config, $context) { |
|
40 | + if (empty($tokens_of_children)) return false; |
|
41 | + |
|
42 | + // this ensures that the loop gets run one last time before closing |
|
43 | + // up. It's a little bit of a hack, but it works! Just make sure you |
|
44 | + // get rid of the token later. |
|
45 | + $tokens_of_children[] = false; |
|
46 | + |
|
47 | + // only one of these elements is allowed in a table |
|
48 | + $caption = false; |
|
49 | + $thead = false; |
|
50 | + $tfoot = false; |
|
51 | + |
|
52 | + // as many of these as you want |
|
53 | + $cols = array(); |
|
54 | + $content = array(); |
|
55 | + |
|
56 | + $nesting = 0; // current depth so we can determine nodes |
|
57 | + $is_collecting = false; // are we globbing together tokens to package |
|
58 | + // into one of the collectors? |
|
59 | + $collection = array(); // collected nodes |
|
60 | + $tag_index = 0; // the first node might be whitespace, |
|
61 | + // so this tells us where the start tag is |
|
62 | + $tbody_mode = false; // if true, then we need to wrap any stray |
|
63 | + // <tr>s with a <tbody>. |
|
64 | + |
|
65 | + foreach ($tokens_of_children as $token) { |
|
66 | + $is_child = ($nesting == 0); |
|
67 | + |
|
68 | + if ($token === false) { |
|
69 | + // terminating sequence started |
|
70 | + } elseif ($token instanceof HTMLPurifier_Token_Start) { |
|
71 | + $nesting++; |
|
72 | + } elseif ($token instanceof HTMLPurifier_Token_End) { |
|
73 | + $nesting--; |
|
74 | + } |
|
75 | + |
|
76 | + // handle node collection |
|
77 | + if ($is_collecting) { |
|
78 | + if ($is_child) { |
|
79 | + // okay, let's stash the tokens away |
|
80 | + // first token tells us the type of the collection |
|
81 | + switch ($collection[$tag_index]->name) { |
|
82 | + case 'tbody': |
|
83 | + $tbody_mode = true; |
|
84 | + case 'tr': |
|
85 | + $content[] = $collection; |
|
86 | + break; |
|
87 | + case 'caption': |
|
88 | + if ($caption !== false) break; |
|
89 | + $caption = $collection; |
|
90 | + break; |
|
91 | + case 'thead': |
|
92 | + case 'tfoot': |
|
93 | + $tbody_mode = true; |
|
94 | + // XXX This breaks rendering properties with |
|
95 | + // Firefox, which never floats a <thead> to |
|
96 | + // the top. Ever. (Our scheme will float the |
|
97 | + // first <thead> to the top.) So maybe |
|
98 | + // <thead>s that are not first should be |
|
99 | + // turned into <tbody>? Very tricky, indeed. |
|
100 | + |
|
101 | + // access the appropriate variable, $thead or $tfoot |
|
102 | + $var = $collection[$tag_index]->name; |
|
103 | + if ($$var === false) { |
|
104 | + $$var = $collection; |
|
105 | + } else { |
|
106 | + // Oops, there's a second one! What |
|
107 | + // should we do? Current behavior is to |
|
108 | + // transmutate the first and last entries into |
|
109 | + // tbody tags, and then put into content. |
|
110 | + // Maybe a better idea is to *attach |
|
111 | + // it* to the existing thead or tfoot? |
|
112 | + // We don't do this, because Firefox |
|
113 | + // doesn't float an extra tfoot to the |
|
114 | + // bottom like it does for the first one. |
|
115 | + $collection[$tag_index]->name = 'tbody'; |
|
116 | + $collection[count($collection)-1]->name = 'tbody'; |
|
117 | + $content[] = $collection; |
|
118 | + } |
|
119 | + break; |
|
120 | + case 'colgroup': |
|
121 | + $cols[] = $collection; |
|
122 | + break; |
|
123 | + } |
|
124 | + $collection = array(); |
|
125 | + $is_collecting = false; |
|
126 | + $tag_index = 0; |
|
127 | + } else { |
|
128 | + // add the node to the collection |
|
129 | + $collection[] = $token; |
|
130 | + } |
|
131 | + } |
|
132 | + |
|
133 | + // terminate |
|
134 | + if ($token === false) break; |
|
135 | + |
|
136 | + if ($is_child) { |
|
137 | + // determine what we're dealing with |
|
138 | + if ($token->name == 'col') { |
|
139 | + // the only empty tag in the possie, we can handle it |
|
140 | + // immediately |
|
141 | + $cols[] = array_merge($collection, array($token)); |
|
142 | + $collection = array(); |
|
143 | + $tag_index = 0; |
|
144 | + continue; |
|
145 | + } |
|
146 | + switch($token->name) { |
|
147 | + case 'caption': |
|
148 | + case 'colgroup': |
|
149 | + case 'thead': |
|
150 | + case 'tfoot': |
|
151 | + case 'tbody': |
|
152 | + case 'tr': |
|
153 | + $is_collecting = true; |
|
154 | + $collection[] = $token; |
|
155 | + continue; |
|
156 | + default: |
|
157 | + if (!empty($token->is_whitespace)) { |
|
158 | + $collection[] = $token; |
|
159 | + $tag_index++; |
|
160 | + } |
|
161 | + continue; |
|
162 | + } |
|
163 | + } |
|
164 | + } |
|
165 | + |
|
166 | + if (empty($content)) return false; |
|
167 | + |
|
168 | + $ret = array(); |
|
169 | + if ($caption !== false) $ret = array_merge($ret, $caption); |
|
170 | + if ($cols !== false) foreach ($cols as $token_array) $ret = array_merge($ret, $token_array); |
|
171 | + if ($thead !== false) $ret = array_merge($ret, $thead); |
|
172 | + if ($tfoot !== false) $ret = array_merge($ret, $tfoot); |
|
173 | + |
|
174 | + if ($tbody_mode) { |
|
175 | + // a little tricky, since the start of the collection may be |
|
176 | + // whitespace |
|
177 | + $inside_tbody = false; |
|
178 | + foreach ($content as $token_array) { |
|
179 | + // find the starting token |
|
180 | + foreach ($token_array as $t) { |
|
181 | + if ($t->name === 'tr' || $t->name === 'tbody') { |
|
182 | + break; |
|
183 | + } |
|
184 | + } // iterator variable carries over |
|
185 | + if ($t->name === 'tr') { |
|
186 | + if ($inside_tbody) { |
|
187 | + $ret = array_merge($ret, $token_array); |
|
188 | + } else { |
|
189 | + $ret[] = new HTMLPurifier_Token_Start('tbody'); |
|
190 | + $ret = array_merge($ret, $token_array); |
|
191 | + $inside_tbody = true; |
|
192 | + } |
|
193 | + } elseif ($t->name === 'tbody') { |
|
194 | + if ($inside_tbody) { |
|
195 | + $ret[] = new HTMLPurifier_Token_End('tbody'); |
|
196 | + $inside_tbody = false; |
|
197 | + $ret = array_merge($ret, $token_array); |
|
198 | + } else { |
|
199 | + $ret = array_merge($ret, $token_array); |
|
200 | + } |
|
201 | + } else { |
|
202 | + trigger_error("tr/tbody in content invariant failed in Table ChildDef", E_USER_ERROR); |
|
203 | + } |
|
204 | + } |
|
205 | + if ($inside_tbody) { |
|
206 | + $ret[] = new HTMLPurifier_Token_End('tbody'); |
|
207 | + } |
|
208 | + } else { |
|
209 | + foreach ($content as $token_array) { |
|
210 | + // invariant: everything in here is <tr>s |
|
211 | + $ret = array_merge($ret, $token_array); |
|
212 | + } |
|
213 | + } |
|
214 | + |
|
215 | + if (!empty($collection) && $is_collecting == false){ |
|
216 | + // grab the trailing space |
|
217 | + $ret = array_merge($ret, $collection); |
|
218 | + } |
|
219 | + |
|
220 | + array_pop($tokens_of_children); // remove phantom token |
|
221 | + |
|
222 | + return ($ret === $tokens_of_children) ? true : $ret; |
|
223 | + |
|
224 | + } |
|
225 | 225 | } |
226 | 226 | |
227 | 227 | // vim: et sw=4 sts=4 |
@@ -113,7 +113,7 @@ discard block |
||
113 | 113 | // doesn't float an extra tfoot to the |
114 | 114 | // bottom like it does for the first one. |
115 | 115 | $collection[$tag_index]->name = 'tbody'; |
116 | - $collection[count($collection)-1]->name = 'tbody'; |
|
116 | + $collection[count($collection) - 1]->name = 'tbody'; |
|
117 | 117 | $content[] = $collection; |
118 | 118 | } |
119 | 119 | break; |
@@ -143,7 +143,7 @@ discard block |
||
143 | 143 | $tag_index = 0; |
144 | 144 | continue; |
145 | 145 | } |
146 | - switch($token->name) { |
|
146 | + switch ($token->name) { |
|
147 | 147 | case 'caption': |
148 | 148 | case 'colgroup': |
149 | 149 | case 'thead': |
@@ -212,7 +212,7 @@ discard block |
||
212 | 212 | } |
213 | 213 | } |
214 | 214 | |
215 | - if (!empty($collection) && $is_collecting == false){ |
|
215 | + if (!empty($collection) && $is_collecting == false) { |
|
216 | 216 | // grab the trailing space |
217 | 217 | $ret = array_merge($ret, $collection); |
218 | 218 | } |
@@ -37,7 +37,9 @@ discard block |
||
37 | 37 | 'tfoot' => true, 'caption' => true, 'colgroup' => true, 'col' => true); |
38 | 38 | public function __construct() {} |
39 | 39 | public function validateChildren($tokens_of_children, $config, $context) { |
40 | - if (empty($tokens_of_children)) return false; |
|
40 | + if (empty($tokens_of_children)) { |
|
41 | + return false; |
|
42 | + } |
|
41 | 43 | |
42 | 44 | // this ensures that the loop gets run one last time before closing |
43 | 45 | // up. It's a little bit of a hack, but it works! Just make sure you |
@@ -85,7 +87,9 @@ discard block |
||
85 | 87 | $content[] = $collection; |
86 | 88 | break; |
87 | 89 | case 'caption': |
88 | - if ($caption !== false) break; |
|
90 | + if ($caption !== false) { |
|
91 | + break; |
|
92 | + } |
|
89 | 93 | $caption = $collection; |
90 | 94 | break; |
91 | 95 | case 'thead': |
@@ -131,7 +135,9 @@ discard block |
||
131 | 135 | } |
132 | 136 | |
133 | 137 | // terminate |
134 | - if ($token === false) break; |
|
138 | + if ($token === false) { |
|
139 | + break; |
|
140 | + } |
|
135 | 141 | |
136 | 142 | if ($is_child) { |
137 | 143 | // determine what we're dealing with |
@@ -163,13 +169,23 @@ discard block |
||
163 | 169 | } |
164 | 170 | } |
165 | 171 | |
166 | - if (empty($content)) return false; |
|
172 | + if (empty($content)) { |
|
173 | + return false; |
|
174 | + } |
|
167 | 175 | |
168 | 176 | $ret = array(); |
169 | - if ($caption !== false) $ret = array_merge($ret, $caption); |
|
170 | - if ($cols !== false) foreach ($cols as $token_array) $ret = array_merge($ret, $token_array); |
|
171 | - if ($thead !== false) $ret = array_merge($ret, $thead); |
|
172 | - if ($tfoot !== false) $ret = array_merge($ret, $tfoot); |
|
177 | + if ($caption !== false) { |
|
178 | + $ret = array_merge($ret, $caption); |
|
179 | + } |
|
180 | + if ($cols !== false) { |
|
181 | + foreach ($cols as $token_array) $ret = array_merge($ret, $token_array); |
|
182 | + } |
|
183 | + if ($thead !== false) { |
|
184 | + $ret = array_merge($ret, $thead); |
|
185 | + } |
|
186 | + if ($tfoot !== false) { |
|
187 | + $ret = array_merge($ret, $tfoot); |
|
188 | + } |
|
173 | 189 | |
174 | 190 | if ($tbody_mode) { |
175 | 191 | // a little tricky, since the start of the collection may be |