Файловый менеджер - Редактировать - /var/www/html/mediawiki-1.43.1/vendor/wikimedia/parsoid/src/Utils/DOMTraverser.php
Ðазад
<?php declare( strict_types = 1 ); namespace Wikimedia\Parsoid\Utils; use Wikimedia\Parsoid\DOM\DocumentFragment; use Wikimedia\Parsoid\DOM\Element; use Wikimedia\Parsoid\DOM\Node; use Wikimedia\Parsoid\Ext\ParsoidExtensionAPI; /** * Class for helping us traverse the DOM. * * This class currently does a pre-order depth-first traversal. * See {@link DOMPostOrder} for post-order traversal. */ class DOMTraverser { /** * List of handlers to call on each node. Each handler is an array with the following fields: * - action: a callable to call * - nodeName: if set, only call it on nodes with this name * @var array<array{action:callable,nodeName:string}> * @see addHandler() */ private $handlers = []; /** * Should the handlers be called on attribute-embedded-HTML strings? */ private bool $applyToAttributeEmbeddedHTML; /** * @var bool */ private $traverseWithTplInfo; /** * @param bool $traverseWithTplInfo * @param bool $applyToAttributeEmbeddedHTML */ public function __construct( bool $traverseWithTplInfo = false, bool $applyToAttributeEmbeddedHTML = false ) { $this->traverseWithTplInfo = $traverseWithTplInfo; $this->applyToAttributeEmbeddedHTML = $applyToAttributeEmbeddedHTML; } /** * Add a handler to the DOM traverser. * * @param ?string $nodeName An optional node name filter * @param callable $action A callback, called on each node we traverse that matches nodeName. * Will be called with the following parameters: * - Node $node: the node being processed * - Env $env: the parser environment * - DTState $state: State. * Return value: Node|null|true. * - true: proceed normally * - Node: traversal will continue on the new node (further handlers will not be called * on the current node); after processing it and its siblings, it will continue with the * next sibling of the closest ancestor which has one. * - null: like the Node case, except there is no new node to process before continuing. */ public function addHandler( ?string $nodeName, callable $action ): void { $this->handlers[] = [ 'action' => $action, 'nodeName' => $nodeName, ]; } /** * @param Node $node * @param ?ParsoidExtensionAPI $extAPI * @param DTState|null $state * @return bool|mixed */ private function callHandlers( Node $node, ?ParsoidExtensionAPI $extAPI, ?DTState $state ) { $name = DOMCompat::nodeName( $node ); // Process embedded HTML first since the handlers below might // return a different node which aborts processing. By processing // attributes first, we ensure attribute are always processed. if ( $node instanceof Element && $this->applyToAttributeEmbeddedHTML ) { $self = $this; ContentUtils::processAttributeEmbeddedHTML( $extAPI, $node, static function ( string $html ) use ( $self, $extAPI, $state ) { $dom = $extAPI->htmlToDom( $html ); // We are processing a nested document (which by definition // is not a top-level document). // FIXME: // 1. This argument replicates existing behavior but is it sound? // In any case, we should first replicate existing behavior // and revisit this later. // 2. It is not clear if creating a *new* state is the right thing // or if reusing *parts* of the old state is the right thing. // One of the places where this matters is around the use of // $state->tplInfo. One could probably find arguments for either // direction. But, "independent parsing" semantics which Parsoid // is aiming for would lead us to use a new state or even a new // traversal object here and that feels a little bit "more correct" // than reusing partial state. $newState = $state ? new DTState( $state->env, $state->options, false ) : null; $self->traverse( $extAPI, $dom, $newState ); return $extAPI->domToHtml( $dom, true, true ); } ); } foreach ( $this->handlers as $handler ) { if ( $handler['nodeName'] === null || $handler['nodeName'] === $name ) { $result = call_user_func( $handler['action'], $node, $state ); if ( $result !== true ) { // Abort processing for this node return $result; } } } return true; } /** * Traverse the DOM and fire the handlers that are registered. * * Handlers can return * - the next node to process: aborts processing for current node (ie. no further handlers are * called) and continues processing on returned node. Essentially, that node and its siblings * replace the current node and its siblings for the purposes of the traversal; after they * are fully processed, the algorithm moves back to the parent of $workNode to look for * the next sibling. * - `null`: same as above, except it continues from the next sibling of the parent (or if * that does not exist, the next sibling of the grandparent etc). This is so that returning * `$workNode->nextSibling` works even when workNode is a last child of its parent. * - `true`: continues regular processing on current node. * * @param ?ParsoidExtensionAPI $extAPI * @param Node $workNode The starting node for the traversal. * The traversal could go beyond the subtree rooted at $workNode if * the handlers called during traversal return an arbitrary node elsewhere * in the DOM in which case the traversal scope can be pretty much the whole * DOM that $workNode is present in. This behavior would be confusing but * there is nothing in the traversal code to prevent that. * @param DTState|null $state */ public function traverse( ?ParsoidExtensionAPI $extAPI, Node $workNode, ?DTState $state = null ): void { $this->traverseInternal( true, $extAPI, $workNode, $state ); } /** * @param bool $isRootNode * @param ?ParsoidExtensionAPI $extAPI * @param Node $workNode * @param DTState|null $state */ private function traverseInternal( bool $isRootNode, ?ParsoidExtensionAPI $extAPI, Node $workNode, ?DTState $state ): void { while ( $workNode !== null ) { if ( $this->traverseWithTplInfo && $workNode instanceof Element ) { // Identify the first template/extension node. // You'd think the !tplInfo check isn't necessary since // we don't have nested transclusions, however, you can // get extensions in transclusions. if ( !( $state->tplInfo ?? null ) && WTUtils::isFirstEncapsulationWrapperNode( $workNode ) // Ensure this isn't just a meta marker, since we might // not be traversing after encapsulation. Note that the // valid data-mw assertion is the same test as used in // cleanup. && ( !WTUtils::isTplMarkerMeta( $workNode ) || DOMDataUtils::validDataMw( $workNode ) ) // Encapsulation info on sections should not be used to // traverse with since it's designed to be dropped and // may have expanded ranges. && !WTUtils::isParsoidSectionTag( $workNode ) ) { $about = DOMCompat::getAttribute( $workNode, 'about' ); $aboutSiblings = WTUtils::getAboutSiblings( $workNode, $about ); $state->tplInfo = (object)[ 'first' => $workNode, 'last' => end( $aboutSiblings ), 'clear' => false, ]; } } // Call the handlers on this workNode if ( $workNode instanceof DocumentFragment ) { $possibleNext = true; } else { $possibleNext = $this->callHandlers( $workNode, $extAPI, $state ); } // We may have walked passed the last about sibling or want to // ignore the template info in future processing. // In any case, it's up to the handler returning a possible next // to figure out. if ( $this->traverseWithTplInfo && ( $state->tplInfo->clear ?? false ) ) { $state->tplInfo = null; } if ( $possibleNext === true ) { // The 'continue processing' case if ( $workNode->hasChildNodes() ) { $this->traverseInternal( false, $extAPI, $workNode->firstChild, $state ); } if ( $isRootNode ) { // Confine the traverse to the tree rooted as the root node. // `$workNode->nextSibling` would take us outside that. $possibleNext = null; } else { $possibleNext = $workNode->nextSibling; } } elseif ( $isRootNode && $possibleNext !== $workNode ) { $isRootNode = false; } // Clear the template info after reaching the last about sibling. if ( $this->traverseWithTplInfo && ( ( $state->tplInfo->last ?? null ) === $workNode ) ) { $state->tplInfo = null; } $workNode = $possibleNext; } } }
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка