From c446e9533c397441423c5677eb67caf064af0d2f Mon Sep 17 00:00:00 2001 From: OriginalAuthority Date: Fri, 8 Aug 2025 14:49:35 +0100 Subject: [PATCH 01/30] Initial DOMProcessor --- .../Parsoid/PortableInfoboxDOMProcessor.php | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 includes/Parsoid/PortableInfoboxDOMProcessor.php diff --git a/includes/Parsoid/PortableInfoboxDOMProcessor.php b/includes/Parsoid/PortableInfoboxDOMProcessor.php new file mode 100644 index 00000000..8d45a7a7 --- /dev/null +++ b/includes/Parsoid/PortableInfoboxDOMProcessor.php @@ -0,0 +1,80 @@ +firstChild; + + // insipiration taken from Ext:Cite + // and also + while ( $child !== null ) { + $nextChild = $child->nextSibling; + if ( $child instanceof Element ) { + // we're only interested in PIs in this function + if ( DOMUtils::hasTypeOf( $child, 'mw:Extension/infobox' ) ) { + $dataMw = DOMDataUtils::getDataMw( $child ); + $parts = $dataMw->parts; + + // remove the existing stuff that is generated on the first pass of Parsoid + // Note: this is probably a bit of a hacky solution, since we will have already + // processed the parser tag at this point and ended up with the mangled HTML + // ideally, we would do all of this in the main parse, but Parsoid does not currently + // grant us the ability to do that, so just remove whatever gobbldy-guck was generated + // in the first pass. This is probably a bit of a performance hog, but it will be cached in the + // parser cache for subsequent reads so is a one-shot-pony until the cache expires. + while ( $child->firstChild ) { + $child->removeChild( $child->firstChild ); + } + + $doc = $child->ownerDocument; + + foreach ( $parts as $part ) { + // add our parts to the params info + // this will get us the key => value of the parameters that the + // user passed to the template from the article, + // ie we might get something like + // params['name'] = [ 'k' => 'name', 'valueWt' => 'John Doe' ] + // which is something akin to what PortableInfoboxParserTagController::renderInfobox() + // expects to be passed, albeit we'll need to fudge it a bit! + $params = $part->paramInfos ?? []; + + $this->buildInfoboxContent( $child, $doc, $params ); + } + + } + } + $child = $nextChild; + } + } + + /** + * Buil the actual infobox, and return the data back to Parsoid where it will be sent back + * to the caller and saved to the cache. We do not have acces to the frame here, but what we do have + * is the wikitext parameters which Parsoid kindly stuffed into the data-mw attrib. This is enough + * for us to call the same functions as the legacy parser does to get ourselves an infobox + * @param Element $container + * @param Document $doc the main document which is being parsed + * @param array $params a key => value of the parameters the user passed to the template + * @return void [Writes to DOM] + */ + private function buildInfoboxContent( Element $container, Document $doc, array $params ): void { + // no-op at present + } +} \ No newline at end of file From 97603afcb6ab4ac87afa7e3d6e10042fd4748d00 Mon Sep 17 00:00:00 2001 From: OriginalAuthority Date: Fri, 8 Aug 2025 14:51:35 +0100 Subject: [PATCH 02/30] Bump version to 1.0 so we can track which functions were added when --- extension.json | 2 +- includes/Parsoid/PortableInfoboxDOMProcessor.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extension.json b/extension.json index 349d9bbd..09cc288b 100644 --- a/extension.json +++ b/extension.json @@ -7,7 +7,7 @@ ], "url": "https://github.com/Universal-Omega/PortableInfobox", "descriptionmsg": "portable-infobox-desc", - "version": "0.8", + "version": "1.0", "type": "parserhook", "license-name": "GPL-3.0-or-later", "requires": { diff --git a/includes/Parsoid/PortableInfoboxDOMProcessor.php b/includes/Parsoid/PortableInfoboxDOMProcessor.php index 8d45a7a7..122acef3 100644 --- a/includes/Parsoid/PortableInfoboxDOMProcessor.php +++ b/includes/Parsoid/PortableInfoboxDOMProcessor.php @@ -13,9 +13,9 @@ class PortableInfoboxDOMProcessor extends DOMProcessor { /** - * @inheritDoc * Note, this is a WIP at present, see comments throughout. * Will probably need to be revised at a later stage when Parsoid API is more mature + * @since 1.0 */ public function wtPostprocess( ParsoidExtensionAPI $extApi, Node $node, array $options From 79a4dc5476b0e48a7a21ff2c77a6b746b0d40648 Mon Sep 17 00:00:00 2001 From: OriginalAuthority Date: Fri, 8 Aug 2025 18:57:06 +0100 Subject: [PATCH 03/30] Begin InfoboxTag and Controller --- extension.json | 9 +- includes/Parsoid/InfoboxTag.php | 67 ++++++++ .../ParsoidPortableInfoboxController.php | 154 ++++++++++++++++++ 3 files changed, 228 insertions(+), 2 deletions(-) create mode 100644 includes/Parsoid/InfoboxTag.php create mode 100644 includes/Parsoid/ParsoidPortableInfoboxController.php diff --git a/extension.json b/extension.json index 09cc288b..5f3e1818 100644 --- a/extension.json +++ b/extension.json @@ -15,7 +15,11 @@ }, "config": { "AllInfoboxesExcludedSubpages": { - "value": [ "doc", "draft", "test" ] + "value": [ + "doc", + "draft", + "test" + ] }, "PortableInfoboxCacheRenderers": { "value": false @@ -125,5 +129,6 @@ "APIListModules": { "allinfoboxes": "PortableInfobox\\Controllers\\ApiQueryAllInfoboxes" }, + "ParsoidModules": [ "PortableInfobox\\Parsoid\\InfoboxTag" ], "manifest_version": 2 -} +} \ No newline at end of file diff --git a/includes/Parsoid/InfoboxTag.php b/includes/Parsoid/InfoboxTag.php new file mode 100644 index 00000000..2af968ab --- /dev/null +++ b/includes/Parsoid/InfoboxTag.php @@ -0,0 +1,67 @@ + 'PortableInfobox', + 'tags' => [ + [ + 'name' => 'infobox', + 'handler' => self::class + ] + ], + 'domProcessors' => [ + 'PortableInfobox\\Parsoid\\PortableInfoboxDOMProcessor' + ] + ]; + } + + /** + * @inheritDoc + */ + public function sourceToDom( ParsoidExtensionAPI $api, string $src, array $args ) + { + $domFragments = $api->extTagToDOM( $args, $src, [ + 'wrapperTag' => 'aside', + 'parseOpts' => [ + 'extTag' => 'infobox', + 'context' => 'inline' + ] + ]); + + $portableInfoboxController = ParsoidPortableInfoboxController::newInstance(); + + // lets add any of the safe arguments back to the HTML representation + // see: https://github.com/Universal-Omega/PortableInfobox/blob/main/templates/PortableInfoboxWrapper.hbs + // for our safe arguments/classes + // note: this is probably not the way to do this? Inspo taken from + // namespace Wikimedia\Parsoid\Ext\Gallery\Gallery::class line 252 + if ( $domFragments->firstChild instanceof Element ) { + $portableInfoboxController->prepareInfobox( $domFragments->firstChild, $api->extArgsToArray( $args ) ); + } + + // this is a bit messed up as these methods are deprecated, but the documentation + // for the replacement methods doesn't exist or make sense + // this is commented out at present, as these scripts and styles will be added + // by the legacy parser (might need it here to stick these in the parser cache also?) + // $api->getMetadata()->addModules( [ 'ext.PortableInfobox.scripts' ] ); + // $api->getMetadata()->addModuleStyles( [ 'ext.PortableInfobox.styles' ] ); + + // return this back. At this point, we have constructed the outer tag (