Skip to content

Load per-component JS init modules so tooltip/popover open on MediaWiki 1.43+#79

Closed
malberts wants to merge 1 commit into
masterfrom
fix/tooltip-popover-mw143
Closed

Load per-component JS init modules so tooltip/popover open on MediaWiki 1.43+#79
malberts wants to merge 1 commit into
masterfrom
fix/tooltip-popover-mw143

Conversation

@malberts
Copy link
Copy Markdown
Collaborator

@malberts malberts commented May 21, 2026

Closes #68.

Completes the fix for #68 by resolving the tooltip, popover and carousel sub-bugs left out of #75 (which addressed only the modal symptom).

Root cause

The per-component JS init modules ext.bootstrapComponents.{tooltip,popover,carousel}.fix each declare a scripts: entry in extension.json that initialises the Bootstrap library on the trigger elements (.tooltip(), .popover(), .carousel()). Without these modules reaching the page, hover on a .bootstrap-tooltip and click on a [data-toggle="popover"] do nothing.

HooksHandler::onParserAfterParse is supposed to load them via the getActiveComponents() foreach, but two issues break that path:

  1. Only ImageModal registers itself as active. Tooltip, popover, and carousel parser hooks never call registerComponentAsActive(), so getActiveComponents() never contains them and the foreach never iterates over their modules.
  2. Even when the foreach does run (for ImageModal), it calls addModuleStyles() — which loads only the CSS half. The scripts: half of a module never reaches the page through that call.

Fix

Move per-component init module loading to OutputPageParserOutput::process(), where the three init modules are added unconditionally to the persistent OutputPage via addModules(). Each init script is a single jQuery selector + initializer call ($('[data-toggle="tooltip"]').tooltip() etc.); on a page without the matching trigger markup the selector returns an empty collection and the initializer no-ops. Per-request cost on tooltip/popover/carousel-free pages: three small DOM queries served from a cached ResourceLoader bundle — negligible.

Scope

  • 1 source file: src/Hooks/OutputPageParserOutput.php — adds one addModules call in process() listing the three per-component init modules
  • 1 test file: tests/phpunit/Unit/Hooks/OutputPageParserOutputTest.php (rewritten the two process() cases to assert the union of addModules calls — same mocking pattern PR Fix modal trigger not opening modals on MediaWiki 1.43+ #75 used in testHookOutputPageParserOutputLoadsModules)

Net: +37 / −7 lines.

Verification

Tested on MW 1.43.8 + Chameleon BS4 (where the bug manifests) and on the oldest supported floor MW 1.39.17 across three BS4 skins — Vector, Chameleon BS4, and Medik:

Tooltip hover Popover click
MW 1.43.8 + Chameleon BS4 sub68-mw143-tooltip-hover sub68-mw143-popover-click
MW 1.39.17 + Vector sub68-mw139-tooltip-hover sub68-mw139-popover-click
MW 1.39.17 + Chameleon BS4 sub68-mw139-chameleon-tooltip sub68-mw139-chameleon-popover
MW 1.39.17 + Medik sub68-mw139-medik-tooltip sub68-mw139-medik-popover

Module + instance state on both stacks after page load:

ext.bootstrap.scripts:                ready
ext.bootstrapComponents.tooltip.fix:  ready
ext.bootstrapComponents.popover.fix:  ready
ext.bootstrapComponents.carousel.fix: ready
jQuery(.bootstrap-tooltip).data("bs.tooltip"):   <object>
jQuery([data-toggle=popover]).data("bs.popover"): <object>

Tests

PHPUnit (--group mediawiki-databaseless) on MW 1.39:

Tests Failures
Master (post-#75) 338 6
Patched (this PR) 338 6

Same 6 pre-existing failures in BootstrapComponentsServiceTest / ImageModalTriggerTest / ImageModalTest (manual-thumbnail variants). All unrelated to the JS-init module path.

🤖 Generated with Claude Code

The per-component JS init modules (tooltip.fix, popover.fix, carousel.fix)
each declare a scripts entry in extension.json that calls the Bootstrap
library on the trigger elements. Without these modules reaching the
page, hover on a .bootstrap-tooltip and click on a data-toggle="popover"
element do nothing.

HooksHandler::onParserAfterParse iterates getActiveComponents() and
calls addModuleStyles() per component, but getActiveComponents() is
only populated by ImageModal — tooltip, popover, and carousel never
register themselves as active. So the foreach never reaches their .fix
modules at all; even if it did, addModuleStyles loads only CSS.

Queue the per-component init modules unconditionally on OutputPage from
the OutputPageParserOutput hook. addModules is the right call (loads
the JS via mw.loader). Each init script is a no-op on pages without
the corresponding trigger markup.

Verified on a fresh MW 1.39.17 + Vector + BC stack and on a MW 1.43.8
+ Chameleon BS4 + BC stack: tooltip hover and popover click both
produce the expected popups. PHPUnit unit suite remains green relative
to baseline (6 pre-existing failures unchanged).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@malberts
Copy link
Copy Markdown
Collaborator Author

Superseded by #80 — that PR closes the same #68 sub-bugs but takes the architecturally-correct path: restores BC's intended sparse-loading scheme via the AbstractComponent chokepoint, rather than this PR's unconditional-load workaround in OutputPageParserOutput::process().

Net: #80 is +5 lines / -0 (vs #79's +37 / -7), with no workaround-flavour code, and on a tooltip-only page only tooltip.fix loads (#79 would have unconditionally loaded all three).

@malberts malberts closed this May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tooltip, Popover and Modal stop working after a cache purge on MW 1.43.3

1 participant