Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
98.68% |
75 / 76 |
|
75.00% |
3 / 4 |
CRAP | |
0.00% |
0 / 1 |
InRow | |
98.68% |
75 / 76 |
|
75.00% |
3 / 4 |
32 | |
0.00% |
0 / 1 |
characters | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
startTag | |
100.00% |
28 / 28 |
|
100.00% |
1 / 1 |
12 | |||
endTag | |
97.78% |
44 / 45 |
|
0.00% |
0 / 1 |
18 | |||
endDocument | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | namespace Wikimedia\RemexHtml\TreeBuilder; |
4 | |
5 | use Wikimedia\RemexHtml\Tokenizer\Attributes; |
6 | |
7 | /** |
8 | * The "in row" insertion mode |
9 | */ |
10 | class InRow extends InsertionMode { |
11 | private static $tableRowContext = [ |
12 | 'tr' => true, |
13 | 'template' => true, |
14 | 'html' => true, |
15 | ]; |
16 | |
17 | public function characters( $text, $start, $length, $sourceStart, $sourceLength ) { |
18 | $this->dispatcher->inTable->characters( $text, $start, $length, |
19 | $sourceStart, $sourceLength ); |
20 | } |
21 | |
22 | public function startTag( $name, Attributes $attrs, $selfClose, $sourceStart, $sourceLength ) { |
23 | $builder = $this->builder; |
24 | $stack = $builder->stack; |
25 | $dispatcher = $this->dispatcher; |
26 | |
27 | switch ( $name ) { |
28 | case 'th': |
29 | case 'td': |
30 | $builder->clearStackBack( self::$tableRowContext, $sourceStart ); |
31 | $builder->insertElement( $name, $attrs, false, $sourceStart, $sourceLength ); |
32 | $dispatcher->switchMode( Dispatcher::IN_CELL ); |
33 | $builder->afe->insertMarker(); |
34 | break; |
35 | |
36 | case 'caption': |
37 | case 'col': |
38 | case 'colgroup': |
39 | case 'tbody': |
40 | case 'tfoot': |
41 | case 'thead': |
42 | case 'tr': |
43 | if ( !$stack->isInTableScope( 'tr' ) ) { |
44 | $builder->error( "<$name> should close the tr but it is not in scope", |
45 | $sourceStart ); |
46 | // Ignore |
47 | return; |
48 | } |
49 | $builder->clearStackBack( self::$tableRowContext, $sourceStart ); |
50 | $builder->pop( $sourceStart, 0 ); |
51 | $dispatcher->switchMode( Dispatcher::IN_TABLE_BODY ) |
52 | ->startTag( $name, $attrs, $selfClose, $sourceStart, $sourceLength ); |
53 | break; |
54 | |
55 | default: |
56 | $dispatcher->inTable->startTag( $name, $attrs, $selfClose, |
57 | $sourceStart, $sourceLength ); |
58 | } |
59 | } |
60 | |
61 | public function endTag( $name, $sourceStart, $sourceLength ) { |
62 | $builder = $this->builder; |
63 | $stack = $builder->stack; |
64 | $dispatcher = $this->dispatcher; |
65 | |
66 | switch ( $name ) { |
67 | case 'tr': |
68 | if ( !$stack->isInTableScope( 'tr' ) ) { |
69 | $builder->error( '</tr> found but no tr element in scope', $sourceStart ); |
70 | // Ignore |
71 | return; |
72 | } |
73 | $builder->clearStackBack( self::$tableRowContext, $sourceStart ); |
74 | $builder->pop( $sourceStart, $sourceLength ); |
75 | $dispatcher->switchMode( Dispatcher::IN_TABLE_BODY ); |
76 | break; |
77 | |
78 | case 'table': |
79 | if ( !$stack->isInTableScope( 'tr' ) ) { |
80 | $builder->error( "</table> should close the tr but it is not in scope", |
81 | $sourceStart ); |
82 | // Ignore |
83 | return; |
84 | } |
85 | $builder->clearStackBack( self::$tableRowContext, $sourceStart ); |
86 | $builder->pop( $sourceStart, 0 ); |
87 | $dispatcher->switchMode( Dispatcher::IN_TABLE_BODY ) |
88 | ->endTag( $name, $sourceStart, $sourceLength ); |
89 | break; |
90 | |
91 | case 'tbody': |
92 | case 'tfoot': |
93 | case 'thead': |
94 | if ( !$stack->isInTableScope( $name ) ) { |
95 | $builder->error( "</$name> encountered but there is no $name element in scope", |
96 | $sourceStart ); |
97 | return; |
98 | } |
99 | if ( !$stack->isInTableScope( 'tr' ) ) { |
100 | return; |
101 | } |
102 | $builder->clearStackBack( self::$tableRowContext, $sourceStart ); |
103 | $builder->pop( $sourceStart, 0 ); |
104 | $dispatcher->switchMode( Dispatcher::IN_TABLE_BODY ) |
105 | ->endTag( $name, $sourceStart, $sourceLength ); |
106 | break; |
107 | |
108 | case 'body': |
109 | case 'caption': |
110 | case 'col': |
111 | case 'colgroup': |
112 | case 'html': |
113 | case 'td': |
114 | case 'th': |
115 | $builder->error( "</$name> encountered in row mode, ignoring", $sourceStart ); |
116 | return; |
117 | |
118 | default: |
119 | $dispatcher->inTable->endTag( $name, $sourceStart, $sourceLength ); |
120 | } |
121 | } |
122 | |
123 | public function endDocument( $pos ) { |
124 | $this->dispatcher->inTable->endDocument( $pos ); |
125 | } |
126 | } |