Version 1
[yaffs-website] / vendor / masterminds / html5 / src / HTML5 / Parser / TreeBuildingRules.php
1 <?php
2 namespace Masterminds\HTML5\Parser;
3
4 /**
5  * Handles special-case rules for the DOM tree builder.
6  *
7  * Many tags have special rules that need to be accomodated on an
8  * individual basis. This class handles those rules.
9  *
10  * See section 8.1.2.4 of the spec.
11  *
12  * @todo - colgroup and col special behaviors
13  *       - body and head special behaviors
14  */
15 class TreeBuildingRules
16 {
17
18     protected static $tags = array(
19         'li' => 1,
20         'dd' => 1,
21         'dt' => 1,
22         'rt' => 1,
23         'rp' => 1,
24         'tr' => 1,
25         'th' => 1,
26         'td' => 1,
27         'thead' => 1,
28         'tfoot' => 1,
29         'tbody' => 1,
30         'table' => 1,
31         'optgroup' => 1,
32         'option' => 1
33     );
34
35     /**
36      * Build a new rules engine.
37      *
38      * @param \DOMDocument $doc
39      *            The DOM document to use for evaluation and modification.
40      */
41     public function __construct($doc)
42     {
43         $this->doc = $doc;
44     }
45
46     /**
47      * Returns true if the given tagname has special processing rules.
48      */
49     public function hasRules($tagname)
50     {
51         return isset(static::$tags[$tagname]);
52     }
53
54     /**
55      * Evaluate the rule for the current tag name.
56      *
57      * This may modify the existing DOM.
58      *
59      * @return \DOMElement The new Current DOM element.
60      */
61     public function evaluate($new, $current)
62     {
63         switch ($new->tagName) {
64             case 'li':
65                 return $this->handleLI($new, $current);
66             case 'dt':
67             case 'dd':
68                 return $this->handleDT($new, $current);
69             case 'rt':
70             case 'rp':
71                 return $this->handleRT($new, $current);
72             case 'optgroup':
73                 return $this->closeIfCurrentMatches($new, $current, array(
74                     'optgroup'
75                 ));
76             case 'option':
77                 return $this->closeIfCurrentMatches($new, $current, array(
78                     'option',
79                 ));
80             case 'tr':
81                 return $this->closeIfCurrentMatches($new, $current, array(
82                     'tr'
83                 ));
84             case 'td':
85             case 'th':
86                 return $this->closeIfCurrentMatches($new, $current, array(
87                     'th',
88                     'td'
89                 ));
90             case 'tbody':
91             case 'thead':
92             case 'tfoot':
93             case 'table': // Spec isn't explicit about this, but it's necessary.
94
95                 return $this->closeIfCurrentMatches($new, $current, array(
96                     'thead',
97                     'tfoot',
98                     'tbody'
99                 ));
100         }
101
102         return $current;
103     }
104
105     protected function handleLI($ele, $current)
106     {
107         return $this->closeIfCurrentMatches($ele, $current, array(
108             'li'
109         ));
110     }
111
112     protected function handleDT($ele, $current)
113     {
114         return $this->closeIfCurrentMatches($ele, $current, array(
115             'dt',
116             'dd'
117         ));
118     }
119
120     protected function handleRT($ele, $current)
121     {
122         return $this->closeIfCurrentMatches($ele, $current, array(
123             'rt',
124             'rp'
125         ));
126     }
127
128     protected function closeIfCurrentMatches($ele, $current, $match)
129     {
130         $tname = $current->tagName;
131         if (in_array($current->tagName, $match)) {
132             $current->parentNode->appendChild($ele);
133         } else {
134             $current->appendChild($ele);
135         }
136
137         return $ele;
138     }
139 }