* Tidy compatibility mode, determines behavior of body/blockquote
*/
public $tidyCompat = false;
+ /**
+ * Reference to the current element
+ */
+ public $currentNode;
/**
* Create a new BalanceStack with a single BalanceElement on it,
$this->elements,
new BalanceElement( BalanceSets::HTML_NAMESPACE, 'html', [] )
);
+ $this->currentNode = $this->elements[0];
}
/**
Assert::parameterType( 'string', $value, '$value' );
if (
$this->fosterParentMode &&
- $this->currentNode()->isA( BalanceSets::$tableSectionRowSet )
+ $this->currentNode->isA( BalanceSets::$tableSectionRowSet )
) {
$this->fosterParent( $value );
} elseif (
$this->tidyCompat &&
- $this->currentNode()->isA( BalanceSets::$tidyPWrapSet )
+ $this->currentNode->isA( BalanceSets::$tidyPWrapSet )
) {
$this->insertHTMLELement( 'mw:p-wrap', [] );
return $this->insertText( $value );
} else {
- $this->currentNode()->appendChild( $value );
+ $this->currentNode->appendChild( $value );
}
}
public function insertElement( $elt ) {
Assert::parameterType( 'MediaWiki\Tidy\BalanceElement', $elt, '$elt' );
if (
- $this->currentNode()->isA( 'mw:p-wrap' ) &&
+ $this->currentNode->isA( 'mw:p-wrap' ) &&
!$elt->isA( BalanceSets::$tidyInlineSet )
) {
// Tidy compatibility.
}
if (
$this->fosterParentMode &&
- $this->currentNode()->isA( BalanceSets::$tableSectionRowSet )
+ $this->currentNode->isA( BalanceSets::$tableSectionRowSet )
) {
$elt = $this->fosterParent( $elt );
} else {
- $this->currentNode()->appendChild( $elt );
+ $this->currentNode->appendChild( $elt );
}
Assert::invariant( $elt->parent !== null, "$elt must be in tree" );
Assert::invariant( $elt->parent !== 'flat', "$elt must not have been previous flattened" );
array_push( $this->elements, $elt );
+ $this->currentNode = $elt;
return $elt;
}
BalanceSets::$thoroughImpliedEndTagsSet :
BalanceSets::$impliedEndTagsSet;
while ( $this->length() > 0 ) {
- if ( $butnot !== null && $this->currentNode()->isA( $butnot ) ) {
+ if ( $butnot !== null && $this->currentNode->isA( $butnot ) ) {
break;
}
- if ( !$this->currentNode()->isA( $endTagSet ) ) {
+ if ( !$this->currentNode->isA( $endTagSet ) ) {
break;
}
$this->pop();
}
}
- /**
- * Return the current node (the element in the stack with the largest
- * index).
- * @return BalanceElement
- * @see https://html.spec.whatwg.org/multipage/syntax.html#current-node
- */
- public function currentNode() {
- return $this->node( count( $this->elements ) - 1 );
- }
-
/**
* Return the adjusted current node.
*/
public function adjustedCurrentNode( $fragmentContext ) {
return ( $fragmentContext && $this->length() === 1 ) ?
- $fragmentContext : $this->currentNode();
+ $fragmentContext : $this->currentNode;
}
/**
'New element should not have already been flattened.'
);
$this->elements[$idx] = $elt;
+ if ( $idx === count( $this->elements ) - 1 ) {
+ $this->currentNode = $elt;
+ }
}
/**
*/
public function pop() {
$elt = array_pop( $this->elements );
+ if ( count( $this->elements ) ) {
+ $this->currentNode = $this->elements[ count( $this->elements ) - 1 ];
+ } else {
+ $this->currentNode = null;
+ }
if ( !$elt->isA( 'mw:p-wrap' ) ) {
$elt->flatten( $this->tidyCompat );
}
*/
public function popTag( $tag ) {
while ( $this->length() > 0 ) {
- if ( $this->currentNode()->isA( $tag ) ) {
+ if ( $this->currentNode->isA( $tag ) ) {
$this->pop();
break;
}
public function clearToContext( $set ) {
// Note that we don't loop to 0. Never pop the <html> elt off.
while ( $this->length() > 1 ) {
- if ( $this->currentNode()->isA( $set ) ) {
+ if ( $this->currentNode->isA( $set ) ) {
break;
}
$this->pop();
$idx = array_search( $elt, $this->elements, true );
Assert::parameter( $idx !== false, '$elt', 'must be in stack' );
array_splice( $this->elements, $idx, 1 );
+ if ( $idx === count( $this->elements ) ) {
+ $this->currentNode = $this->elements[$idx - 1];
+ }
if ( $flatten ) {
// serialize $elt into its parent
// otherwise, it will eventually serialize when the parent
Assert::parameterType( 'MediaWiki\Tidy\BalanceElement', $b, '$b' );
$idx = $this->indexOf( $a );
Assert::parameter( $idx !== false, '$a', 'must be in stack' );
- array_splice( $this->elements, $idx + 1, 0, [ $b ] );
+ if ( $idx === count( $this->elements ) - 1 ) {
+ array_push( $this->elements, $b );
+ $this->currentNode = $b;
+ } else {
+ array_splice( $this->elements, $idx + 1, 0, [ $b ] );
+ }
}
# Fostering and adoption.
// elements, then pop the current node off the stack of open
// elements and abort these steps.
if (
- $this->currentNode()->isA( $tag ) &&
- !$afe->isInList( $this->currentNode() )
+ $this->currentNode->isA( $tag ) &&
+ !$afe->isInList( $this->currentNode )
) {
$this->pop();
return true; // no more handling required
}
while ( true ) {
$this->stack->pop();
- $node = $this->stack->currentNode();
+ $node = $this->stack->currentNode;
if (
$node->isMathmlTextIntegrationPoint() ||
$node->isHtmlIntegrationPoint() ||
}
// "Any other start tag"
$adjusted = ( $this->fragmentContext && $this->stack->length()===1 ) ?
- $this->fragmentContext : $this->stack->currentNode();
+ $this->fragmentContext : $this->stack->currentNode;
$this->stack->insertForeignElement(
$adjusted->namespaceURI, $value, $attribs
);
if ( $this->stack->inButtonScope( 'p' ) ) {
$this->inBodyMode( 'endtag', 'p' );
}
- if ( $this->stack->currentNode()->isA( BalanceSets::$headingSet ) ) {
+ if ( $this->stack->currentNode->isA( BalanceSets::$headingSet ) ) {
$this->stack->pop();
}
$this->stack->insertHTMLElement( $value, $attribs );
case 'optgroup':
case 'option':
- if ( $this->stack->currentNode()->isA( 'option' ) ) {
+ if ( $this->stack->currentNode->isA( 'option' ) ) {
$this->inBodyMode( 'endtag', 'option' );
}
$this->afe->reconstruct( $this->stack );
if ( $token === 'text' ) {
if ( $this->textIntegrationMode ) {
return $this->inBodyMode( $token, $value, $attribs, $selfclose );
- } elseif ( $this->stack->currentNode()->isA( BalanceSets::$tableSectionRowSet ) ) {
+ } elseif ( $this->stack->currentNode->isA( BalanceSets::$tableSectionRowSet ) ) {
$this->pendingTableText = '';
$this->originalInsertionMode = $this->parseMode;
return $this->switchModeAndReprocess( 'inTableTextMode', $token, $value, $attribs, $selfclose );
} elseif ( $token === 'endtag' ) {
switch ( $value ) {
case 'colgroup':
- if ( !$this->stack->currentNode()->isA( 'colgroup' ) ) {
+ if ( !$this->stack->currentNode->isA( 'colgroup' ) ) {
return true; // Ignore the token.
}
$this->stack->pop();
}
// Anything else
- if ( !$this->stack->currentNode()->isA( 'colgroup' ) ) {
+ if ( !$this->stack->currentNode->isA( 'colgroup' ) ) {
return true; // Ignore the token.
}
$this->inColumnGroupMode( 'endtag', 'colgroup' );