]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - vendor/wikimedia/remex-html/RemexHtml/TreeBuilder/InTable.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / vendor / wikimedia / remex-html / RemexHtml / TreeBuilder / InTable.php
1 <?php
2
3 namespace RemexHtml\TreeBuilder;
4 use RemexHtml\Tokenizer\Attributes;
5 use RemexHtml\Tokenizer\PlainAttributes;
6
7 /**
8  * The "in table" insertion mode
9  */
10 class InTable extends InsertionMode {
11         /**
12          * The tag names that are cleared when we "clear the stack back to a table context"
13          */
14         private static $tableContext = [
15                 'table' => true,
16                 'template' => true,
17                 'html' => true
18         ];
19
20         public function characters( $text, $start, $length, $sourceStart, $sourceLength ) {
21                 $allowed = [
22                         'table' => true,
23                         'tbody' => true,
24                         'tfoot' => true,
25                         'thead' => true,
26                         'tr' => true ];
27                 if ( isset( $allowed[$this->builder->stack->current->htmlName] ) ) {
28                         $this->builder->pendingTableCharacters = [];
29                         $this->dispatcher->switchAndSave( Dispatcher::IN_TABLE_TEXT )
30                                 ->characters( $text, $start, $length, $sourceStart, $sourceLength );
31                 } else {
32                         $this->builder->error( 'unexpected text in table, fostering', $sourceStart );
33                         $this->builder->fosterParenting = true;
34                         $this->dispatcher->inBody->characters(
35                                 $text, $start, $length, $sourceStart, $sourceLength );
36                         $this->builder->fosterParenting = false;
37                 }
38         }
39
40         public function startTag( $name, Attributes $attrs, $selfClose, $sourceStart, $sourceLength ) {
41                 $builder = $this->builder;
42                 $dispatcher = $this->dispatcher;
43                 $stack = $builder->stack;
44
45                 switch ( $name ) {
46                 case 'caption':
47                         $builder->clearStackBack( self::$tableContext, $sourceStart );
48                         $builder->afe->insertMarker();
49                         $dispatcher->switchMode( Dispatcher::IN_CAPTION );
50                         $builder->insertElement( $name, $attrs, false,
51                                 $sourceStart, $sourceLength );
52                         break;
53
54                 case 'colgroup':
55                         $builder->clearStackBack( self::$tableContext, $sourceStart );
56                         $dispatcher->switchMode( Dispatcher::IN_COLUMN_GROUP );
57                         $builder->insertElement( $name, $attrs, false,
58                                 $sourceStart, $sourceLength );
59                         break;
60
61                 case 'col':
62                         $builder->clearStackBack( self::$tableContext, $sourceStart );
63                         $builder->insertElement( 'colgroup', new PlainAttributes, false,
64                                 $sourceStart, 0 );
65                         $dispatcher->switchMode( Dispatcher::IN_COLUMN_GROUP )
66                                 ->startTag( $name, $attrs, $selfClose, $sourceStart, $sourceLength );
67                         break;
68
69                 case 'tbody':
70                 case 'tfoot':
71                 case 'thead':
72                         $builder->clearStackBack( self::$tableContext, $sourceStart );
73                         $builder->insertElement( $name, $attrs, false,
74                                 $sourceStart, $sourceLength );
75                         $dispatcher->switchMode( Dispatcher::IN_TABLE_BODY );
76                         break;
77
78                 case 'td':
79                 case 'th':
80                 case 'tr':
81                         $builder->clearStackBack( self::$tableContext, $sourceStart );
82                         $builder->insertElement( 'tbody', new PlainAttributes, false,
83                                 $sourceStart, $sourceLength );
84                         $dispatcher->switchMode( Dispatcher::IN_TABLE_BODY )
85                                 ->startTag( $name, $attrs, $selfClose, $sourceStart, $sourceLength );
86                         break;
87
88                 case 'table':
89                         $builder->error( 'unexpected <table> in table', $sourceStart );
90                         if ( !$stack->isInTableScope( 'table' ) ) {
91                                 // Ignore
92                                 break;
93                         }
94                         $builder->popAllUpToName( 'table', $sourceStart, 0 );
95                         $dispatcher->reset()
96                                 ->startTag( $name, $attrs, $selfClose, $sourceStart, $sourceLength );
97                         break;
98
99                 case 'style':
100                 case 'script':
101                 case 'template':
102                         $dispatcher->inHead->startTag( $name, $attrs, $selfClose, $sourceStart, $sourceLength );
103                         break;
104
105                 case 'form':
106                         if ( $stack->hasTemplate() || $builder->formElement !== null ) {
107                                 $builder->error( 'invalid form in table, ignoring', $sourceStart );
108                                 // Ignore
109                                 break;
110                         }
111                         $builder->error( 'invalid form in table, inserting void element', $sourceStart );
112                         $elt = $builder->insertElement( 'form', $attrs, true,
113                                 $sourceStart, $sourceLength );
114                         $builder->formElement = $elt;
115                         break;
116
117                 case 'input':
118                         if ( isset( $attrs['type'] ) && strcasecmp( $attrs['type'], 'hidden' ) === 0 ) {
119                                 $builder->error( 'begrudgingly accepting a hidden input in table mode',
120                                         $sourceStart );
121                                 $dispatcher->ack = true;
122                                 $builder->insertElement( $name, $attrs, true, $sourceStart, $sourceLength );
123                                 break;
124                         }
125                         // Fall through
126
127                 default:
128                         $builder->error( 'invalid start tag in table, fostering', $sourceStart );
129                         $builder->fosterParenting = true;
130                         $dispatcher->inBody->startTag( $name, $attrs, $selfClose, $sourceStart, $sourceLength );
131                         $builder->fosterParenting = false;
132                         break;
133                 }
134         }
135
136         public function endTag( $name, $sourceStart, $sourceLength ) {
137                 $builder = $this->builder;
138                 $stack = $builder->stack;
139                 $dispatcher = $this->dispatcher;
140
141                 switch ( $name ) {
142                 case 'table':
143                         if ( !$stack->isInTableScope( 'table' ) ) {
144                                 $builder->error( '</table> found but no table element in scope, ignoring', $sourceStart );
145                                 // Ignore
146                                 break;
147                         }
148                         $builder->popAllUpToName( 'table', $sourceStart, $sourceLength );
149                         $dispatcher->reset();
150                         break;
151
152                 case 'body':
153                 case 'caption':
154                 case 'col':
155                 case 'colgroup':
156                 case 'html':
157                 case 'tbody':
158                 case 'td':
159                 case 'tfoot':
160                 case 'th':
161                 case 'thead':
162                 case 'tr':
163                         $builder->error( 'ignoring invalid end tag inside table', $sourceStart );
164                         break;
165
166                 case 'template':
167                         $dispatcher->inHead->endTag( $name, $sourceStart, $sourceLength );
168                         break;
169
170                 default:
171                         $builder->error( 'unexpected end tag in table, fostering', $sourceStart );
172                         $builder->fosterParenting = true;
173                         $dispatcher->inBody->endTag( $name, $sourceStart, $sourceLength );
174                         $builder->fosterParenting = false;
175                 }
176         }
177
178         public function endDocument( $pos ) {
179                 $this->dispatcher->inBody->endDocument( $pos );
180         }
181 }