>
*/
private static $defaultScope = [
HTMLData::NS_HTML => [
'applet' => true,
'caption' => true,
'html' => true,
'table' => true,
'td' => true,
'th' => true,
'marquee' => true,
'object' => true,
'template' => true,
],
HTMLData::NS_MATHML => [
'mi' => true,
'mo' => true,
'mn' => true,
'ms' => true,
'mtext' => true,
'annotation-xml' => true,
],
HTMLData::NS_SVG => [
'foreignObject' => true,
'desc' => true,
'title' => true,
],
];
/**
* The element types which break the table scope.
* @var array>
*/
private static $tableScope = [
HTMLData::NS_HTML => [
'html' => true,
'table' => true,
'template' => true,
]
];
/**
* The element types which break the list scope. This is lazy-initialised.
* @var array>
*/
private static $listScope;
/**
* The element types which break the button scope. This is lazy-initialised.
* @var array>
*/
private static $buttonScope;
public function push( Element $elt ) {
$n = count( $this->elements );
$this->elements[$n] = $elt;
$this->current = $elt;
$elt->stackIndex = $n;
}
public function pop() {
$elt = array_pop( $this->elements );
$elt->stackIndex = null;
$n = count( $this->elements );
$this->current = $n ? $this->elements[$n - 1] : null;
return $elt;
}
public function replace( Element $oldElt, Element $elt ) {
$idx = $oldElt->stackIndex;
$this->elements[$idx] = $elt;
$oldElt->stackIndex = null;
$elt->stackIndex = $idx;
if ( $idx === count( $this->elements ) - 1 ) {
$this->current = $elt;
}
}
public function remove( Element $elt ) {
$eltIndex = $elt->stackIndex;
$n = count( $this->elements );
for ( $i = $eltIndex + 1; $i < $n; $i++ ) {
$this->elements[$i]->stackIndex --;
}
$elt->stackIndex = null;
}
public function isInScope( $name ) {
return $this->isInSpecificScope( $name, self::$defaultScope );
}
public function isElementInScope( Element $elt ) {
for ( $i = count( $this->elements ) - 1; $i >= 0; $i-- ) {
$node = $this->elements[$i];
if ( $node === $elt ) {
return true;
}
if ( isset( self::$defaultScope[$node->namespace][$node->name] ) ) {
return false;
}
}
return false;
}
public function isOneOfSetInScope( $names ) {
for ( $i = count( $this->elements ) - 1; $i >= 0; $i-- ) {
$node = $this->elements[$i];
if ( $node->namespace === HTMLData::NS_HTML && isset( $names[$node->name] ) ) {
return true;
}
if ( isset( self::$defaultScope[$node->namespace][$node->name] ) ) {
return false;
}
}
return false;
}
public function isInListScope( $name ) {
if ( self::$listScope === null ) {
self::$listScope = self::$defaultScope;
self::$listScope[HTMLData::NS_HTML] += [
'ol' => true,
'li' => true
];
}
return $this->isInSpecificScope( $name, self::$listScope );
}
public function isInButtonScope( $name ) {
if ( self::$buttonScope === null ) {
self::$buttonScope = self::$defaultScope;
self::$buttonScope[HTMLData::NS_HTML]['button'] = true;
}
return $this->isInSpecificScope( $name, self::$buttonScope );
}
public function isInTableScope( $name ) {
return $this->isInSpecificScope( $name, self::$tableScope );
}
public function isInSelectScope( $name ) {
for ( $i = count( $this->elements ) - 1; $i >= 0; $i-- ) {
$node = $this->elements[$i];
if ( $node->namespace === HTMLData::NS_HTML && $node->name === $name ) {
return true;
}
if ( $node->namespace !== HTMLData::NS_HTML ) {
return false;
}
if ( $node->name !== 'optgroup' && $node->name !== 'option' ) {
return false;
}
}
return false;
}
private function isInSpecificScope( $name, $set ) {
for ( $i = count( $this->elements ) - 1; $i >= 0; $i-- ) {
$node = $this->elements[$i];
if ( $node->namespace === HTMLData::NS_HTML && $node->name === $name ) {
return true;
}
if ( isset( $set[$node->namespace][$node->name] ) ) {
return false;
}
}
return false;
}
public function item( $idx ) {
return $this->elements[$idx];
}
public function length() {
return count( $this->elements );
}
public function hasTemplate() {
foreach ( $this->elements as $elt ) {
if ( $elt->namespace === HTMLData::NS_HTML && $elt->name === 'template' ) {
return true;
}
}
return false;
}
}