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