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