���ѧۧݧ�ӧ�� �ާ֧ߧ֧էا֧� - ���֧էѧܧ�ڧ��ӧѧ�� - /home/rickpfrv/wiki.craftaro.com/vendor/wikimedia/parsoid/src/Wt2Html/PP/Processors/PWrap.php
���ѧ٧ѧ�
<?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Wt2Html\PP\Processors; use Wikimedia\Assert\UnreachableException; use Wikimedia\Parsoid\Config\Env; use Wikimedia\Parsoid\DOM\Comment; use Wikimedia\Parsoid\DOM\DocumentFragment; use Wikimedia\Parsoid\DOM\Element; use Wikimedia\Parsoid\DOM\Node; use Wikimedia\Parsoid\DOM\Text; use Wikimedia\Parsoid\NodeData\TempData; use Wikimedia\Parsoid\Utils\DOMCompat; use Wikimedia\Parsoid\Utils\DOMDataUtils; use Wikimedia\Parsoid\Utils\DOMUtils; use Wikimedia\Parsoid\Wikitext\Consts; use Wikimedia\Parsoid\Wt2Html\Wt2HtmlDOMProcessor; class PWrap implements Wt2HtmlDOMProcessor { /** * Flattens an array with other arrays for elements into * an array without nested arrays. * * @param array[] $a * @return array */ private function flatten( array $a ): array { return $a === [] ? [] : array_merge( ...$a ); } /** * @param Element $elt * @return bool */ private static function pWrapOptionalChildren( Element $elt ): bool { foreach ( $elt->childNodes as $c ) { if ( !self::pWrapOptional( $c ) ) { return false; } } return true; } /** * Is a P-wrapper optional for this node? * * The following nodes do not need p wrappers of their own: * - whitespace nodes * - comment nodes * - HTML metadata tags generated by wikitext (not always rendering-transparent) * and these metatags don't need p-wrappers of their own. Both Remex and Parsoid * have identical p-wrapping behavior on these tags. This is a superset of * \\MediaWiki\Tidy\RemexCompatMunger::$metadataElements. * - parsoid-added span wrappers around pwrap-optional nodes * * @param Node $n * @return bool */ public static function pWrapOptional( Node $n ): bool { return ( $n instanceof Text && preg_match( '/^\s*$/D', $n->nodeValue ) ) || $n instanceof Comment || isset( Consts::$HTML['MetaDataTags'][DOMCompat::nodeName( $n )] ) || ( $n instanceof Element && DOMDataUtils::getDataParsoid( $n )->getTempFlag( TempData::WRAPPER ) && self::pWrapOptionalChildren( $n ) ); } /** * Can we split the subtree rooted at $n into multiple adjacent * subtrees rooted in a clone of $n where each of those subtrees * get a contiguous subset of $n's children? * * This is probably equivalent to asking if this node supports the * adoption agency algorithm in the HTML5 spec. * * @param Node $n * @return bool */ private function isSplittableTag( Node $n ): bool { // Seems safe to split span, sub, sup, cite tags // // However, if we want to mimic Parsoid and HTML5 spec // precisely, we should only use isFormattingElt(n) return DOMUtils::isFormattingElt( $n ); } /** * Merge a contiguous run of split subtrees that have identical pwrap properties * * @param Element $n * @param array $a * @return array */ private function mergeRuns( Element $n, array $a ): array { $ret = []; // This flag should be transferred to the rightmost // clone of this node in the loop below. $ndp = DOMDataUtils::getDataParsoid( $n ); $origAIEnd = $ndp->autoInsertedEnd ?? null; $origEndTSR = $ndp->tmp->endTSR ?? null; $i = -1; foreach ( $a as $v ) { if ( $i < 0 ) { $ret[] = [ 'pwrap' => $v['pwrap'], 'node' => $n ]; $i++; } elseif ( $ret[$i]['pwrap'] === null ) { // @phan-suppress-previous-line PhanTypeInvalidDimOffset $ret[$i]['pwrap'] = $v['pwrap']; } elseif ( $ret[$i]['pwrap'] !== $v['pwrap'] && $v['pwrap'] !== null ) { // @phan-suppress-previous-line PhanTypeInvalidDimOffset // @phan-suppress-next-line PhanTypeInvalidDimOffset $dp = DOMDataUtils::getDataParsoid( $ret[$i]['node'] ); $dp->autoInsertedEnd = true; unset( $dp->tmp->endTSR ); $cnode = $n->cloneNode(); '@phan-var Element $cnode'; // @var Element $cnode if ( $n->hasAttribute( DOMDataUtils::DATA_OBJECT_ATTR_NAME ) ) { DOMDataUtils::setNodeData( $cnode, DOMDataUtils::getNodeData( $n )->clone() ); } $ret[] = [ 'pwrap' => $v['pwrap'], 'node' => $cnode ]; $i++; DOMDataUtils::getDataParsoid( $ret[$i]['node'] )->autoInsertedStart = true; } $ret[$i]['node']->appendChild( $v['node'] ); } if ( $i >= 0 ) { $dp = DOMDataUtils::getDataParsoid( $ret[$i]['node'] ); if ( $origAIEnd ) { $dp->autoInsertedEnd = true; unset( $dp->tmp->endTSR ); } else { unset( $dp->autoInsertedEnd ); if ( $origEndTSR ) { $dp->getTemp()->endTSR = $origEndTSR; } } } return $ret; } /** * Implements the split operation described in the algorithm below. * * The values of 'pwrap' here bear out in pWrapDOM below. * * true: opens a paragaph or continues adding to a paragraph * false: closes a paragraph * null: agnostic, doesn't open or close a paragraph * * @param Node $n * @return array */ private function split( Node $n ): array { if ( $this->pWrapOptional( $n ) ) { // Set 'pwrap' to null so p-wrapping doesn't break // a run of wrappable nodes because of these. return [ [ 'pwrap' => null, 'node' => $n ] ]; } elseif ( $n instanceof Text ) { return [ [ 'pwrap' => true, 'node' => $n ] ]; } elseif ( !$this->isSplittableTag( $n ) || count( $n->childNodes ) === 0 ) { // block tag OR non-splittable inline tag return [ [ 'pwrap' => !DOMUtils::hasBlockTag( $n ), 'node' => $n ] ]; } else { DOMUtils::assertElt( $n ); // splittable inline tag // split for each child and merge runs $children = $n->childNodes; $splits = []; foreach ( $children as $child ) { $splits[] = $this->split( $child ); } return $this->mergeRuns( $n, $this->flatten( $splits ) ); } } /** * Wrap children of '$root' with paragraph tags * so that the final output has the following properties: * * 1. A paragraph will have at least one non-whitespace text * node or an non-block element node in its subtree. * * 2. Two paragraph nodes aren't siblings of each other. * * 3. If a child of $root is not a paragraph node, it is one of: * - a white-space only text node * - a comment node * - a block element * - a splittable inline element which has some block node * on *all* paths from it to all leaves in its subtree. * - a non-splittable inline element which has some block node * on *some* path from it to a leaf in its subtree. * * This output is generated with the following algorithm * * 1. Block nodes are skipped over * 2. Non-splittable inline nodes that have a block tag * in its subtree are skipped over. * 3. A splittable inline node, I, that has at least one block tag * in its subtree is split into multiple tree such that * - each new tree is $rooted in I * - the trees alternate between two kinds * (a) it has no block node inside * => pwrap is true * (b) all paths from I to its leaves have some block node inside * => pwrap is false * 4. A paragraph tag is wrapped around adjacent runs of comment nodes, * text nodes, and an inline node that has no block node embedded inside. * This paragraph tag does not start with nodes for which p-wrapping is * optional (as determined by the pWrapOptional helper). The current * algorithm also ensures that it doesn't end with one of those either * (if it impacts template / param / annotation range building). * * @param Element|DocumentFragment $root */ private function pWrapDOM( Node $root ) { $state = new PWrapState(); $c = $root->firstChild; while ( $c ) { $next = $c->nextSibling; if ( DOMUtils::isRemexBlockNode( $c ) ) { $state->reset(); } else { $vs = $this->split( $c ); foreach ( $vs as $v ) { $n = $v['node']; if ( $v['pwrap'] === false ) { $state->reset(); $root->insertBefore( $n, $next ); } elseif ( $v['pwrap'] === null ) { if ( $state->p ) { $state->p->appendChild( $n ); $state->processOptionalNode( $n ); } else { $root->insertBefore( $n, $next ); } } elseif ( $v['pwrap'] === true ) { if ( !$state->p ) { $state->p = $root->ownerDocument->createElement( 'p' ); $root->insertBefore( $state->p, $next ); } $state->p->appendChild( $n ); } else { throw new UnreachableException( 'Unexpected value for pwrap.' ); } } } $c = $next; } $state->reset(); } /** * This function walks the DOM tree $rooted at '$root' * and uses pWrapDOM to add appropriate paragraph wrapper * tags around children of nodes with tag name '$tagName'. * * @param Element|DocumentFragment $root * @param string $tagName */ private function pWrapInsideTag( Node $root, string $tagName ) { $c = $root->firstChild; while ( $c ) { $next = $c->nextSibling; if ( $c instanceof Element ) { if ( DOMCompat::nodeName( $c ) === $tagName ) { $this->pWrapDOM( $c ); } else { $this->pWrapInsideTag( $c, $tagName ); } } $c = $next; } } /** * Wrap children of <body> as well as children of * <blockquote> found anywhere in the DOM tree. * * @inheritDoc */ public function run( Env $env, Node $root, array $options = [], bool $atTopLevel = false ): void { '@phan-var Element|DocumentFragment $root'; // @var Element|DocumentFragment $root $this->pWrapDOM( $root ); $this->pWrapInsideTag( $root, 'blockquote' ); } }
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | ���֧ߧ֧�ѧ�ڧ� ����ѧߧڧ��: 0.3 |
proxy
|
phpinfo
|
���ѧ����ۧܧ�