$length, $sourceStart, $sourceLength );
}
+ private function trace( $msg ) {
+ // echo "[RCM] $msg\n";
+ }
+
/**
* Insert or reparent an element. Create p-wrappers or split the tag stack
* as necessary.
if ( $under && $parentData->isPWrapper && !$inline ) {
// [B/b] The element is non-inline and the parent is a p-wrapper,
// close the parent and insert into its parent instead
+ $this->trace( 'insert B/b' );
$newParent = $this->serializer->getParentNode( $parent );
$parent = $newParent;
$parentData = $parent->snData;
// [CS/b, DS/i] The parent is splittable and the current element is
// inline in block context, or if the current element is a block
// under a p-wrapper, split the tag stack.
+ $this->trace( $inline ? 'insert DS/i' : 'insert CS/b' );
$newRef = $this->splitTagStack( $newRef, $inline, $sourceStart );
$parent = $newRef;
$parentData = $parent->snData;
} elseif ( $under && $parentData->needsPWrapping && $inline ) {
// [A/i] If the element is inline and we are in body/blockquote,
// we need to create a p-wrapper
+ $this->trace( 'insert A/i' );
$newRef = $this->insertPWrapper( $newRef, $sourceStart );
$parent = $newRef;
$parentData = $parent->snData;
// [CU/b] If the element is non-inline and (despite attempting to
// split above) there is still an ancestor p-wrap, disable that
// p-wrap
+ $this->trace( 'insert CU/b' );
$this->disablePWrapper( $parent, $sourceStart );
+ } else {
+ // [A/b, B/i, C/i, D/b, DU/i] insert as normal
+ $this->trace( 'insert normal' );
}
- // else [A/b, B/i, C/i, D/b, DU/i] insert as normal
// An element with element children is a non-blank element
$parentData->nonblankNodeCount++;
public function reparentChildren( Element $element, Element $newParent, $sourceStart ) {
$self = $element->userData;
+ if ( $self->snData->childPElement ) {
+ // Reparent under the p-wrapper instead, so that e.g.
+ // <blockquote><mw:p-wrap>...</mw:p-wrap></blockquote>
+ // becomes
+ // <blockquote><mw:p-wrap><i>...</i></mw:p-wrap></blockquote>
+
+ // The formatting element should not be the parent of the p-wrap.
+ // Without this special case, the insertElement() of the <i> below
+ // would be diverted into the p-wrapper, causing infinite recursion
+ // (T178632)
+ $this->reparentChildren( $self->snData->childPElement, $newParent, $sourceStart );
+ return;
+ }
+
$children = $self->children;
$self->children = [];
$this->insertElement( TreeBuilder::UNDER, $element, $newParent, false, $sourceStart, 0 );
$newParentId = $newParentNode->id;
foreach ( $children as $child ) {
if ( is_object( $child ) ) {
+ $this->trace( "reparent <{$child->name}>" );
$child->parentId = $newParentId;
}
}
public function __set( $name, $value ) {
throw new \Exception( "Cannot set property \"$name\"" );
}
+
+ /**
+ * Get a text representation of the current state of the serializer, for
+ * debugging.
+ *
+ * @return string
+ */
+ public function dump() {
+ if ( $this->childPElement ) {
+ $parts[] = 'childPElement=' . $this->childPElement->getDebugTag();
+ }
+ if ( $this->ancestorPNode ) {
+ $parts[] = "ancestorPNode=<{$this->ancestorPNode->name}>";
+ }
+ if ( $this->wrapBaseNode ) {
+ $parts[] = "wrapBaseNode=<{$this->wrapBaseNode->name}>";
+ }
+ if ( $this->currentCloneElement ) {
+ $parts[] = "currentCloneElement=" . $this->currentCloneElement->getDebugTag();
+ }
+ if ( $this->isPWrapper ) {
+ $parts[] = 'isPWrapper';
+ }
+ if ( $this->isSplittable ) {
+ $parts[] = 'isSplittable';
+ }
+ if ( $this->needsPWrapping ) {
+ $parts[] = 'needsPWrapping';
+ }
+ if ( $this->nonblankNodeCount ) {
+ $parts[] = "nonblankNodeCount={$this->nonblankNodeCount}";
+ }
+ $s = "RemexMungerData {\n";
+ foreach ( $parts as $part ) {
+ $s .= " $part\n";
+ }
+ $s .= "}\n";
+ return $s;
+ }
}