3 namespace RemexHtml\TreeBuilder;
4 use RemexHtml\Tokenizer\Attributes;
5 use RemexHtml\Tokenizer\PlainAttributes;
8 * The "in table" insertion mode
10 class InTable extends InsertionMode {
12 * The tag names that are cleared when we "clear the stack back to a table context"
14 private static $tableContext = [
20 public function characters( $text, $start, $length, $sourceStart, $sourceLength ) {
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 );
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;
40 public function startTag( $name, Attributes $attrs, $selfClose, $sourceStart, $sourceLength ) {
41 $builder = $this->builder;
42 $dispatcher = $this->dispatcher;
43 $stack = $builder->stack;
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 );
55 $builder->clearStackBack( self::$tableContext, $sourceStart );
56 $dispatcher->switchMode( Dispatcher::IN_COLUMN_GROUP );
57 $builder->insertElement( $name, $attrs, false,
58 $sourceStart, $sourceLength );
62 $builder->clearStackBack( self::$tableContext, $sourceStart );
63 $builder->insertElement( 'colgroup', new PlainAttributes, false,
65 $dispatcher->switchMode( Dispatcher::IN_COLUMN_GROUP )
66 ->startTag( $name, $attrs, $selfClose, $sourceStart, $sourceLength );
72 $builder->clearStackBack( self::$tableContext, $sourceStart );
73 $builder->insertElement( $name, $attrs, false,
74 $sourceStart, $sourceLength );
75 $dispatcher->switchMode( Dispatcher::IN_TABLE_BODY );
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 );
89 $builder->error( 'unexpected <table> in table', $sourceStart );
90 if ( !$stack->isInTableScope( 'table' ) ) {
94 $builder->popAllUpToName( 'table', $sourceStart, 0 );
96 ->startTag( $name, $attrs, $selfClose, $sourceStart, $sourceLength );
102 $dispatcher->inHead->startTag( $name, $attrs, $selfClose, $sourceStart, $sourceLength );
106 if ( $stack->hasTemplate() || $builder->formElement !== null ) {
107 $builder->error( 'invalid form in table, ignoring', $sourceStart );
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;
118 if ( isset( $attrs['type'] ) && strcasecmp( $attrs['type'], 'hidden' ) === 0 ) {
119 $builder->error( 'begrudgingly accepting a hidden input in table mode',
121 $dispatcher->ack = true;
122 $builder->insertElement( $name, $attrs, true, $sourceStart, $sourceLength );
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;
136 public function endTag( $name, $sourceStart, $sourceLength ) {
137 $builder = $this->builder;
138 $stack = $builder->stack;
139 $dispatcher = $this->dispatcher;
143 if ( !$stack->isInTableScope( 'table' ) ) {
144 $builder->error( '</table> found but no table element in scope, ignoring', $sourceStart );
148 $builder->popAllUpToName( 'table', $sourceStart, $sourceLength );
149 $dispatcher->reset();
163 $builder->error( 'ignoring invalid end tag inside table', $sourceStart );
167 $dispatcher->inHead->endTag( $name, $sourceStart, $sourceLength );
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;
178 public function endDocument( $pos ) {
179 $this->dispatcher->inBody->endDocument( $pos );