mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Cite
synced 2024-11-28 00:40:12 +00:00
Cite: Remove more Parsoid internals knowledge
* Remove use of $env from ReferencesData and RefGroup by providing high-level helpers in ParsoidExtensionAPI. - Given a fragment id, provide helpers to fetch fragment DOM or fragment HTML - Fetch the URI for the current page (being parsed) * There is still a lot of subtle knowledge Cite has about how data-parsoid and data-mw attributes are held off to the side in a bag and all the pp* and load/store manipulation of those attributes. It would be an interesting exercise to purge this implementation of those notions OR figure out high-level concepts that we document as being part of Parsoid reality that we'll forever support. Bug: T242746 Change-Id: I29ff154f2f17123b9756dfd2f3b422f0b30222b1
This commit is contained in:
parent
1f87104378
commit
d0a9c42c98
|
@ -6,10 +6,9 @@ namespace Wikimedia\Parsoid\Ext\Cite;
|
|||
use DOMDocument;
|
||||
use DOMElement;
|
||||
use stdClass;
|
||||
use Wikimedia\Parsoid\Config\Env;
|
||||
use Wikimedia\Parsoid\Config\ParsoidExtensionAPI;
|
||||
use Wikimedia\Parsoid\Utils\DOMDataUtils;
|
||||
use Wikimedia\Parsoid\Utils\DOMUtils;
|
||||
use Wikimedia\Parsoid\Utils\Title;
|
||||
|
||||
/**
|
||||
* Helper class used by `<references>` implementation.
|
||||
|
@ -43,24 +42,21 @@ class RefGroup {
|
|||
|
||||
/**
|
||||
* Generate leading linkbacks
|
||||
* @param ParsoidExtensionAPI $extApi
|
||||
* @param string $href
|
||||
* @param string|null $group
|
||||
* @param string $text
|
||||
* @param DOMDocument $ownerDoc
|
||||
* @param Env $env
|
||||
* @return DOMElement
|
||||
*/
|
||||
private static function createLinkback(
|
||||
string $href, ?string $group, string $text, DOMDocument $ownerDoc, Env $env
|
||||
ParsoidExtensionAPI $extApi,
|
||||
string $href, ?string $group, string $text, DOMDocument $ownerDoc
|
||||
): DOMElement {
|
||||
$a = $ownerDoc->createElement( 'a' );
|
||||
$s = $ownerDoc->createElement( 'span' );
|
||||
$textNode = $ownerDoc->createTextNode( $text . ' ' );
|
||||
$title = Title::newFromText(
|
||||
$env->getPageConfig()->getTitle(),
|
||||
$env->getSiteConfig()
|
||||
);
|
||||
$a->setAttribute( 'href', $env->makeLink( $title ) . '#' . $href );
|
||||
$a->setAttribute( 'href', $extApi->getPageUri() . '#' . $href );
|
||||
$s->setAttribute( 'class', 'mw-linkback-text' );
|
||||
if ( $group ) {
|
||||
$a->setAttribute( 'data-mw-group', $group );
|
||||
|
@ -71,11 +67,13 @@ class RefGroup {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Env $env
|
||||
* @param ParsoidExtensionAPI $extApi
|
||||
* @param DOMElement $refsList
|
||||
* @param stdClass $ref
|
||||
*/
|
||||
public function renderLine( Env $env, DOMElement $refsList, stdClass $ref ): void {
|
||||
public function renderLine(
|
||||
ParsoidExtensionAPI $extApi, DOMElement $refsList, stdClass $ref
|
||||
): void {
|
||||
$ownerDoc = $refsList->ownerDocument;
|
||||
|
||||
// Generate the li and set ref content first, so the HTML gets parsed.
|
||||
|
@ -83,7 +81,7 @@ class RefGroup {
|
|||
$li = $ownerDoc->createElement( 'li' );
|
||||
$refDir = $ref->dir;
|
||||
$refTarget = $ref->target;
|
||||
$refContent = $ref->content;
|
||||
$refContentId = $ref->contentId;
|
||||
$refGroup = $ref->group;
|
||||
DOMDataUtils::addAttributes( $li, [
|
||||
'about' => '#' . $refTarget,
|
||||
|
@ -99,15 +97,15 @@ class RefGroup {
|
|||
'class' => 'mw-reference-text',
|
||||
]
|
||||
);
|
||||
if ( $refContent ) {
|
||||
$content = $env->getFragment( $refContent )[0];
|
||||
if ( $refContentId ) {
|
||||
$content = $extApi->getContentDOM( $refContentId );
|
||||
DOMUtils::migrateChildrenBetweenDocs( $content, $reftextSpan );
|
||||
DOMDataUtils::visitAndLoadDataAttribs( $reftextSpan );
|
||||
}
|
||||
$li->appendChild( $reftextSpan );
|
||||
|
||||
if ( count( $ref->linkbacks ) === 1 ) {
|
||||
$linkback = self::createLinkback( $ref->id, $refGroup, "↑", $ownerDoc, $env );
|
||||
$linkback = self::createLinkback( $extApi, $ref->id, $refGroup, "↑", $ownerDoc );
|
||||
$linkback->setAttribute( 'rel', 'mw:referencedBy' );
|
||||
$li->insertBefore( $linkback, $reftextSpan );
|
||||
} else {
|
||||
|
@ -118,7 +116,7 @@ class RefGroup {
|
|||
|
||||
foreach ( $ref->linkbacks as $i => $lb ) {
|
||||
$span->appendChild(
|
||||
self::createLinkback( $lb, $refGroup, (string)( $i + 1 ), $ownerDoc, $env )
|
||||
self::createLinkback( $extApi, $lb, $refGroup, (string)( $i + 1 ), $ownerDoc )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ declare( strict_types = 1 );
|
|||
namespace Wikimedia\Parsoid\Ext\Cite;
|
||||
|
||||
use DOMElement;
|
||||
use Wikimedia\Parsoid\Config\Env;
|
||||
use Wikimedia\Parsoid\Config\ParsoidExtensionAPI;
|
||||
|
||||
/**
|
||||
|
@ -23,17 +22,17 @@ class RefProcessor {
|
|||
|
||||
/**
|
||||
* @param DOMElement $body
|
||||
* @param Env $env
|
||||
* @param mixed $unused unused Env object FIXME: stop passing this through?
|
||||
* @param array $options
|
||||
* @param bool $atTopLevel
|
||||
*/
|
||||
public function run(
|
||||
DOMElement $body, Env $env, array $options = [], bool $atTopLevel = false
|
||||
DOMElement $body, $unused, array $options = [], bool $atTopLevel = false
|
||||
): void {
|
||||
if ( $atTopLevel ) {
|
||||
$refsData = new ReferencesData( $env );
|
||||
$refsData = new ReferencesData();
|
||||
References::processRefs( $this->extApi, $refsData, $body );
|
||||
References::insertMissingReferencesIntoDOM( $refsData, $body );
|
||||
References::insertMissingReferencesIntoDOM( $this->extApi, $refsData, $body );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ class References extends ExtensionTag {
|
|||
DOMElement $node, ReferencesData $refsData, ?string $referencesAboutId = null,
|
||||
?string $referencesGroup = '', array &$nestedRefsHTML = []
|
||||
): void {
|
||||
$env = $refsData->getEnv();
|
||||
$env = $extApi->getEnv();
|
||||
$doc = $node->ownerDocument;
|
||||
$nestedInReferences = $referencesAboutId !== null;
|
||||
|
||||
|
@ -114,12 +114,12 @@ class References extends ExtensionTag {
|
|||
$typeOf = $node->getAttribute( 'typeof' );
|
||||
$isTplWrapper = DOMUtils::matchTypeOf( $node, '/^mw:Transclusion$/' );
|
||||
$nodeType = preg_replace( '#mw:DOMFragment/sealed/ref#', '', $typeOf, 1 );
|
||||
$content = $nodeDp->html;
|
||||
$contentId = $nodeDp->html;
|
||||
$tplDmw = $isTplWrapper ? DOMDataUtils::getDataMw( $node ) : null;
|
||||
|
||||
// This is the <sup> that's the meat of the sealed fragment
|
||||
/** @var DOMElement $c */
|
||||
$c = $env->getFragment( $content )[0];
|
||||
$c = $extApi->getContentDOM( $contentId );
|
||||
DOMUtils::assertElt( $c );
|
||||
// All the actions that require loaded data-attributes on `c` are done
|
||||
// here so that we can quickly store those away for later.
|
||||
|
@ -142,7 +142,7 @@ class References extends ExtensionTag {
|
|||
// elt has a group attribute, what takes precedence?
|
||||
$group = $refDmw->attrs->group ?? $referencesGroup ?? '';
|
||||
$refName = $refDmw->attrs->name ?? '';
|
||||
$ref = $refsData->add( $env, $group, $refName, $about, $nestedInReferences );
|
||||
$ref = $refsData->add( $extApi, $group, $refName, $about, $nestedInReferences );
|
||||
|
||||
// Add ref-index linkback
|
||||
$linkBack = $doc->createElement( 'sup' );
|
||||
|
@ -150,7 +150,7 @@ class References extends ExtensionTag {
|
|||
// FIXME: Lot of useless work for an edge case
|
||||
if ( !empty( $cDp->empty ) ) {
|
||||
// Discard wrapper if there was no input wikitext
|
||||
$content = null;
|
||||
$contentId = null;
|
||||
if ( !empty( $cDp->selfClose ) ) {
|
||||
unset( $refDmw->body );
|
||||
} else {
|
||||
|
@ -234,27 +234,29 @@ class References extends ExtensionTag {
|
|||
$node->parentNode->replaceChild( $linkBack, $node );
|
||||
} else {
|
||||
// We don't need to delete the node now since it'll be removed in
|
||||
// `insertReferencesIntoDOM` when all the children all cleaned out.
|
||||
// `insertReferencesIntoDOM` when all the children are cleaned out.
|
||||
array_push( $nestedRefsHTML, ContentUtils::ppToXML( $linkBack ), "\n" );
|
||||
}
|
||||
|
||||
// Keep the first content to compare multiple <ref>s with the same name.
|
||||
if ( !$ref->content ) {
|
||||
$ref->content = $content;
|
||||
if ( !$ref->contentId ) {
|
||||
$ref->contentId = $contentId;
|
||||
$ref->dir = strtolower( $refDmw->attrs->dir ?? '' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ParsoidExtensionAPI $extApi
|
||||
* @param DOMElement $refsNode
|
||||
* @param ReferencesData $refsData
|
||||
* @param array $nestedRefsHTML
|
||||
* @param bool $autoGenerated
|
||||
*/
|
||||
private static function insertReferencesIntoDOM(
|
||||
DOMElement $refsNode, ReferencesData $refsData, array $nestedRefsHTML, bool $autoGenerated = false
|
||||
ParsoidExtensionAPI $extApi, DOMElement $refsNode,
|
||||
ReferencesData $refsData, array $nestedRefsHTML, bool $autoGenerated = false
|
||||
): void {
|
||||
$env = $refsData->getEnv();
|
||||
$env = $extApi->getEnv();
|
||||
$isTplWrapper = DOMUtils::matchTypeOf( $refsNode, '/^mw:Transclusion$/' );
|
||||
$dp = DOMDataUtils::getDataParsoid( $refsNode );
|
||||
$group = $dp->group ?? '';
|
||||
|
@ -311,7 +313,7 @@ class References extends ExtensionTag {
|
|||
|
||||
if ( $refGroup ) {
|
||||
foreach ( $refGroup->refs as $ref ) {
|
||||
$refGroup->renderLine( $env, $refsNode, $ref );
|
||||
$refGroup->renderLine( $extApi, $refsNode, $ref );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,13 +326,14 @@ class References extends ExtensionTag {
|
|||
* We process them as if there was an implicit `<references />` tag at
|
||||
* the end of the DOM.
|
||||
*
|
||||
* @param ParsoidExtensionAPI $extApi
|
||||
* @param ReferencesData $refsData
|
||||
* @param DOMNode $node
|
||||
*/
|
||||
public static function insertMissingReferencesIntoDOM(
|
||||
ReferencesData $refsData, DOMNode $node
|
||||
ParsoidExtensionAPI $extApi, ReferencesData $refsData, DOMNode $node
|
||||
): void {
|
||||
$env = $refsData->getEnv();
|
||||
$env = $extApi->getEnv();
|
||||
$doc = $node->ownerDocument;
|
||||
|
||||
foreach ( $refsData->getRefGroups() as $groupName => $refsGroup ) {
|
||||
|
@ -360,7 +363,7 @@ class References extends ExtensionTag {
|
|||
$node->appendChild( $doc->createTextNode( "\n" ) );
|
||||
$node->appendChild( $frag );
|
||||
|
||||
self::insertReferencesIntoDOM( $frag, $refsData, [ '' ], true );
|
||||
self::insertReferencesIntoDOM( $extApi, $frag, $refsData, [ '' ], true );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -398,7 +401,7 @@ class References extends ExtensionTag {
|
|||
$referencesGroup,
|
||||
$nestedRefsHTML
|
||||
);
|
||||
self::insertReferencesIntoDOM( $child, $refsData, $nestedRefsHTML );
|
||||
self::insertReferencesIntoDOM( $extApi, $child, $refsData, $nestedRefsHTML );
|
||||
} else {
|
||||
// Look for <ref>s embedded in data attributes
|
||||
$extApi->processHiddenHTMLInDataAttributes( $child,
|
||||
|
|
|
@ -4,17 +4,11 @@ declare( strict_types = 1 );
|
|||
namespace Wikimedia\Parsoid\Ext\Cite;
|
||||
|
||||
use stdClass;
|
||||
use Wikimedia\Parsoid\Config\Env;
|
||||
use Wikimedia\Parsoid\Utils\ContentUtils;
|
||||
use Wikimedia\Parsoid\Config\ParsoidExtensionAPI;
|
||||
use Wikimedia\Parsoid\Wt2Html\TT\Sanitizer;
|
||||
|
||||
class ReferencesData {
|
||||
|
||||
/**
|
||||
* @var Env
|
||||
*/
|
||||
private $env;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
|
@ -27,11 +21,9 @@ class ReferencesData {
|
|||
|
||||
/**
|
||||
* ReferencesData constructor.
|
||||
* @param Env $env
|
||||
*/
|
||||
public function __construct( Env $env ) {
|
||||
public function __construct() {
|
||||
$this->index = 0;
|
||||
$this->env = $env;
|
||||
$this->refGroups = [];
|
||||
}
|
||||
|
||||
|
@ -73,7 +65,7 @@ class ReferencesData {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Env $env
|
||||
* @param ParsoidExtensionAPI $extApi
|
||||
* @param string $groupName
|
||||
* @param string $refName
|
||||
* @param string $about
|
||||
|
@ -81,7 +73,7 @@ class ReferencesData {
|
|||
* @return stdClass
|
||||
*/
|
||||
public function add(
|
||||
Env $env, string $groupName, string $refName, string $about, bool $skipLinkback
|
||||
ParsoidExtensionAPI $extApi, string $groupName, string $refName, string $about, bool $skipLinkback
|
||||
): stdClass {
|
||||
$group = $this->getRefGroup( $groupName, true );
|
||||
$refName = $this->makeValidIdAttr( $refName );
|
||||
|
@ -89,14 +81,11 @@ class ReferencesData {
|
|||
|
||||
if ( $hasRefName && isset( $group->indexByName[$refName] ) ) {
|
||||
$ref = $group->indexByName[$refName];
|
||||
if ( $ref->content && !$ref->hasMultiples ) {
|
||||
if ( $ref->contentId && !$ref->hasMultiples ) {
|
||||
$ref->hasMultiples = true;
|
||||
// Use the non-pp version here since we've already stored attribs
|
||||
// before putting them in the map.
|
||||
$ref->cachedHtml = ContentUtils::toXML(
|
||||
$env->getFragment( $ref->content )[0],
|
||||
[ 'innerXML' => true ]
|
||||
);
|
||||
$ref->cachedHtml = $extApi->getContentHTML( $ref->contentId );
|
||||
}
|
||||
} else {
|
||||
// The ids produced Cite.php have some particulars:
|
||||
|
@ -114,7 +103,7 @@ class ReferencesData {
|
|||
|
||||
$ref = (object)[
|
||||
'about' => $about,
|
||||
'content' => null,
|
||||
'contentId' => null,
|
||||
'dir' => '',
|
||||
'group' => $group->name,
|
||||
'groupIndex' => count( $group->refs ) + 1,
|
||||
|
@ -140,13 +129,6 @@ class ReferencesData {
|
|||
return $ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Env
|
||||
*/
|
||||
public function getEnv(): Env {
|
||||
return $this->env;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RefGroup[]
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue