]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - vendor/wikimedia/remex-html/RemexHtml/TreeBuilder/InHead.php
MediaWiki 1.30.2
[autoinstalls/mediawiki.git] / vendor / wikimedia / remex-html / RemexHtml / TreeBuilder / InHead.php
1 <?php
2
3 namespace RemexHtml\TreeBuilder;
4 use RemexHtml\Tokenizer\Attributes;
5 use RemexHtml\Tokenizer\Tokenizer;
6
7 /**
8  * The "in head" insertion mode
9  */
10 class InHead extends InsertionMode {
11         public function characters( $text, $start, $length, $sourceStart, $sourceLength ) {
12                 // Split and insert whitespace
13                 list( $part1, $part2 ) = $this->splitInitialMatch(
14                         true, "\t\n\f\r ", $text, $start, $length, $sourceStart, $sourceLength );
15
16                 list( $start, $length, $sourceStart, $sourceLength ) = $part1;
17                 if ( $length ) {
18                         $this->builder->insertCharacters( $text, $start, $length, $sourceStart,
19                                 $sourceLength );
20                 }
21
22                 // Handle non-whitespace specially
23                 list( $start, $length, $sourceStart, $sourceLength ) = $part2;
24                 if ( !$length ) {
25                         return;
26                 }
27
28                 $elt = $this->builder->pop( $sourceStart, 0 );
29                 if ( $elt->htmlName !== 'head' ) {
30                         throw new \Exception( 'In head mode but current element is not <head>' );
31                 }
32                 $this->dispatcher->switchMode( Dispatcher::AFTER_HEAD )
33                         ->characters( $text, $start, $length, $sourceStart, $sourceLength );
34         }
35
36         public function startTag( $name, Attributes $attrs, $selfClose, $sourceStart, $sourceLength ) {
37                 $void = false;
38                 $tokenizerState = null;
39                 $textMode = null;
40                 $mode = null;
41                 $builder = $this->builder;
42                 $dispatcher = $this->dispatcher;
43
44                 switch ( $name ) {
45                 case 'html':
46                         $this->dispatcher->inBody->startTag( $name, $attrs, $selfClose,
47                                 $sourceStart, $sourceLength );
48                         return;
49
50                 case 'base':
51                 case 'basefont':
52                 case 'bgsound':
53                 case 'link':
54                         $void = true;
55                         $dispatcher->ack = true;
56                         break;
57
58                 case 'meta':
59                         $void = true;
60                         $dispatcher->ack = true;
61                         // charset handling omitted
62                         break;
63
64                 case 'title':
65                         $tokenizerState = Tokenizer::STATE_RCDATA;
66                         $textMode = Dispatcher::TEXT;
67                         break;
68
69                 case 'noscript':
70                         if ( !$this->builder->scriptingFlag ) {
71                                 $mode = Dispatcher::IN_HEAD_NOSCRIPT;
72                                 break;
73                         }
74                         /*. missing_break; .*/
75                 case 'noframes':
76                 case 'style':
77                         $tokenizerState = Tokenizer::STATE_RAWTEXT;
78                         $textMode = Dispatcher::TEXT;
79                         break;
80
81                 case 'script':
82                         $tokenizerState = Tokenizer::STATE_SCRIPT_DATA;
83                         $textMode = Dispatcher::TEXT;
84                         break;
85
86                 case 'template':
87                         $this->builder->afe->insertMarker();
88                         $this->builder->framesetOK = false;
89                         $mode = Dispatcher::IN_TEMPLATE;
90                         $this->dispatcher->templateModeStack->push( Dispatcher::IN_TEMPLATE );
91                         break;
92
93                 case 'head':
94                         $this->builder->error( 'unexpected head tag in head, ignoring', $sourceStart );
95                         return;
96
97                 default:
98                         $elt = $this->builder->pop( $sourceStart, 0 );
99                         if ( $elt->htmlName !== 'head' ) {
100                                 throw new \Exception( "In head mode but current element is not <head>" );
101                         }
102                         $this->dispatcher->switchMode( Dispatcher::AFTER_HEAD )
103                                 ->startTag( $name, $attrs, $selfClose, $sourceStart, $sourceLength );
104                         return;
105                 }
106
107                 // Generic element insertion, for all cases that didn't return above
108                 $this->builder->insertElement( $name, $attrs, $void,
109                         $sourceStart, $sourceLength );
110                 if ( $tokenizerState !== null ) {
111                         $this->builder->tokenizer->switchState( $tokenizerState, $name );
112                 }
113                 if ( $textMode !== null ) {
114                         $this->dispatcher->switchAndSave( $textMode );
115                 } elseif ( $mode !== null ) {
116                         $this->dispatcher->switchMode( $mode );
117                 }
118         }
119
120         public function endTag( $name, $sourceStart, $sourceLength ) {
121                 $builder = $this->builder;
122                 $stack = $builder->stack;
123
124                 switch ( $name ) {
125                 case 'head':
126                         $builder->pop( $sourceStart, $sourceLength );
127                         $this->dispatcher->switchMode( Dispatcher::AFTER_HEAD );
128                         break;
129
130                 case 'body':
131                 case 'html':
132                 case 'br':
133                         $builder->pop( $sourceStart, 0 );
134                         $this->dispatcher->switchMode( Dispatcher::AFTER_HEAD )
135                                 ->endTag( $name, $sourceStart, $sourceLength );
136                         break;
137
138                 case 'template':
139                         if ( !$stack->hasTemplate() ) {
140                                 $builder->error( 'found </template> but there is no open template, ignoring',
141                                         $sourceStart );
142                                 return;
143                         }
144                         $builder->generateImpliedEndTagsThoroughly( $sourceStart );
145                         if ( $stack->current->htmlName !== 'template' ) {
146                                 $builder->error( 'found </template> when other tags are still open', $sourceStart );
147                         }
148                         $builder->popAllUpToName( 'template', $sourceStart, $sourceLength );
149                         $builder->afe->clearToMarker();
150                         $this->dispatcher->templateModeStack->pop();
151                         $this->dispatcher->reset();
152                         break;
153
154                 default:
155                         $builder->error( "ignoring </$name> in head", $sourceStart );
156                 }
157         }
158
159         public function endDocument( $pos ) {
160                 $this->builder->pop( $pos, 0 );
161                 $this->dispatcher->switchMode( Dispatcher::AFTER_HEAD )
162                         ->endDocument( $pos );
163         }
164 }