1<?php
2
3namespace RemexHtml\TreeBuilder;
4
5use RemexHtml\Tokenizer\Attributes;
6
7/**
8 * The "in caption" insertion mode
9 */
10class InCaption 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		$builder = $this->builder;
18		$stack = $builder->stack;
19		switch ( $name ) {
20			case 'caption':
21			case 'col':
22			case 'colgroup':
23			case 'tbody':
24			case 'td':
25			case 'tfoot':
26			case 'th':
27			case 'thead':
28			case 'tr':
29				$builder->error( "start tag <$name> not allowed in caption", $sourceStart );
30				if ( !$stack->isInTableScope( 'caption' ) ) {
31					// Ignore
32					return;
33				}
34				$builder->popAllUpToName( 'caption', $sourceStart, 0 );
35				$builder->afe->clearToMarker();
36				$this->dispatcher->switchMode( Dispatcher::IN_TABLE )
37					->startTag( $name, $attrs, $selfClose, $sourceStart, $sourceLength );
38				break;
39
40			default:
41				$this->dispatcher->inBody->startTag( $name, $attrs, $selfClose,
42					$sourceStart, $sourceLength );
43		}
44	}
45
46	public function endTag( $name, $sourceStart, $sourceLength ) {
47		$dispatcher = $this->dispatcher;
48		$builder = $this->builder;
49		$stack = $builder->stack;
50
51		switch ( $name ) {
52		case 'caption':
53			if ( !$stack->isInTableScope( 'caption' ) ) {
54				$builder->error( "</caption> matches a start tag which is not in scope, ignoring",
55					$sourceStart );
56				return;
57			}
58
59			$builder->generateImpliedEndTags( false, $sourceStart );
60			if ( $stack->current->htmlName !== 'caption' ) {
61				$builder->error( "</caption> found but another element is open", $sourceStart );
62			}
63			$builder->popAllUpToName( 'caption', $sourceStart, $sourceLength );
64			$builder->afe->clearToMarker();
65			$dispatcher->switchMode( Dispatcher::IN_TABLE );
66			break;
67
68		case 'table':
69			if ( !$stack->isInTableScope( 'caption' ) ) {
70				$builder->error( '</table> found in caption, but there is no ' .
71					'caption in scope, ignoring', $sourceStart );
72				return;
73			}
74			$builder->generateImpliedEndTags( false, $sourceStart );
75			if ( $stack->current->htmlName !== 'caption' ) {
76				$builder->error( '</table> found in caption, closing caption', $sourceStart );
77			}
78			$builder->popAllUpToName( 'caption', $sourceStart, 0 );
79			$builder->afe->clearToMarker();
80			$dispatcher->switchMode( Dispatcher::IN_TABLE )
81				->endTag( $name, $sourceStart, $sourceLength );
82			break;
83
84		case 'body':
85		case 'col':
86		case 'colgroup':
87		case 'html':
88		case 'tbody':
89		case 'td':
90		case 'tfoot':
91		case 'th':
92		case 'thead':
93		case 'tr':
94			$this->builder->error( "end tag </$name> ignored in caption mode", $sourceStart );
95			break;
96
97		default:
98			$this->dispatcher->inBody->endTag( $name, $sourceStart, $sourceLength );
99		}
100	}
101
102	public function endDocument( $pos ) {
103		$this->dispatcher->inBody->endDocument( $pos );
104	}
105}
106