From 83397c4f236097dd905ad39cac934b4bd175c6c1 Mon Sep 17 00:00:00 2001 From: Morne Alberts Date: Fri, 22 May 2026 12:01:46 +0200 Subject: [PATCH 1/7] Bump Bootstrap framework dependency to ^6.0 for the BS5 lift `mediawiki/bootstrap` ^6.0 ships Bootstrap framework 5.3.x; the prior ^5.0 ships BS4. Adds a `dev-master` branch alias to 6.x-dev so the v6 development line is explicit. Wires the new `ext.bootstrapComponents.modal.js` init script onto the `modal.fix` module. The init script (added in a follow-up commit) calls `bootstrap.Modal.getOrCreateInstance` on every `.modal`, replacing the implicit jQuery `[data-toggle="modal"]` lifecycle that BS4 ran automatically and BS5 no longer does. Co-Authored-By: Claude Opus 4.7 --- composer.json | 7 ++++++- extension.json | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 7513d55..e610206 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "require": { "php": ">=8.1", "composer/installers": "^2|^1.0.1", - "mediawiki/bootstrap": "^5.0" + "mediawiki/bootstrap": "^6.0" }, "require-dev": { "mediawiki/mediawiki-codesniffer": "46.0.0", @@ -58,5 +58,10 @@ "composer phpunit", "composer cs" ] + }, + "extra": { + "branch-alias": { + "dev-master": "6.x-dev" + } } } diff --git a/extension.json b/extension.json index 80eb3e8..7958374 100644 --- a/extension.json +++ b/extension.json @@ -109,7 +109,9 @@ "scripts": "ext.bootstrapComponents.carousel.js" }, "ext.bootstrapComponents.modal.fix": { - "styles": "ext.bootstrapComponents.modal.fix.css" + "dependencies": "ext.bootstrap.scripts", + "styles": "ext.bootstrapComponents.modal.fix.css", + "scripts": "ext.bootstrapComponents.modal.js" }, "ext.bootstrapComponents.modal.vector-fix": { "styles": "ext.bootstrapComponents.modal.vector-fix.css" From f82ba78b7b09c5b9069fcb9f0b7a644e151ed2db Mon Sep 17 00:00:00 2001 From: Morne Alberts Date: Fri, 22 May 2026 12:21:56 +0200 Subject: [PATCH 2/7] Switch per-component JS init from jQuery to vanilla Bootstrap 5 API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BootstrapComponents' JS modules wired Popover and Tooltip via jQuery's top-level `$( '...' ).popover()` / `.tooltip()` calls. Bootstrap 5 dropped its jQuery dependency entirely, so the per-component init that BC owns has to switch to vanilla DOM + `bootstrap.X.getOrCreateInstance` calls. Switch all four init modules accordingly: * targets the BS5 `data-bs-toggle` attribute set by the PHP emitters, * calls the relevant `bootstrap.Modal|Popover|Tooltip|Carousel` constructor on every matching element after DOMContentLoaded. Popover and Tooltip are opt-in in BS5 (no framework-side delegation) so their init scripts are required. Modal and Carousel aren't strictly required — BS5 still auto-binds modal trigger clicks and carousel `data-bs-ride` via its data-api — but the explicit loops mirror Popover/Tooltip's shape and ensure programmatic `bootstrap.Modal.getOrCreateInstance(el).show()` works without first racing the data-api init. `ext.bootstrapComponents.modal.js` is new and wired onto `modal.fix` in the previous commit. The other three replace the jQuery `$(...).popover()` / `$(...).tooltip()` / `$(...).carousel()` top-level calls. Co-Authored-By: Claude Opus 4.7 --- modules/ext.bootstrapComponents.carousel.js | 27 ++++++++++++++--- modules/ext.bootstrapComponents.modal.js | 28 +++++++++++++++++ modules/ext.bootstrapComponents.popover.js | 33 ++++++++++++++++----- modules/ext.bootstrapComponents.tooltip.js | 28 +++++++++++++---- 4 files changed, 98 insertions(+), 18 deletions(-) create mode 100644 modules/ext.bootstrapComponents.modal.js diff --git a/modules/ext.bootstrapComponents.carousel.js b/modules/ext.bootstrapComponents.carousel.js index 941f604..8d64a04 100644 --- a/modules/ext.bootstrapComponents.carousel.js +++ b/modules/ext.bootstrapComponents.carousel.js @@ -1,5 +1,5 @@ /** - * Contains javascript code executed when tooltips are used. + * Contains javascript code executed when carousels are used. * * @copyright (C) 2018, Tobias Oetterer, Paderborn University * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License, version 3 (or later) @@ -23,6 +23,25 @@ * @author Tobias Oetterer */ -$(function () { - $('.carousel').carousel(); -}); +( function () { + 'use strict'; + + // Wait for DOM to be ready + if ( document.readyState === 'loading' ) { + document.addEventListener( 'DOMContentLoaded', initCarousels ); + } else { + initCarousels(); + } + + function initCarousels() { + if ( typeof bootstrap === 'undefined' || !bootstrap.Carousel ) { + // eslint-disable-next-line no-console + console.warn( 'BootstrapComponents: bootstrap.Carousel is not available; carousels will not cycle.' ); + return; + } + const carouselElements = document.querySelectorAll( '.carousel' ); + carouselElements.forEach( function ( element ) { + new bootstrap.Carousel( element ); + } ); + } +}() ); diff --git a/modules/ext.bootstrapComponents.modal.js b/modules/ext.bootstrapComponents.modal.js new file mode 100644 index 0000000..345d81f --- /dev/null +++ b/modules/ext.bootstrapComponents.modal.js @@ -0,0 +1,28 @@ +/** + * Initialises Bootstrap modal containers on the page so their triggers can open them. + */ + +( function () { + 'use strict'; + + // Wait for DOM to be ready + if ( document.readyState === 'loading' ) { + document.addEventListener( 'DOMContentLoaded', initModals ); + } else { + initModals(); + } + + function initModals() { + if ( typeof bootstrap === 'undefined' || !bootstrap.Modal ) { + // eslint-disable-next-line no-console + console.warn( 'BootstrapComponents: bootstrap.Modal is not available; modal triggers will not work.' ); + return; + } + // Instantiate every .modal element so trigger clicks (or programmatic + // bootstrap.Modal.getOrCreateInstance(el).show()) work as expected. + const modalList = document.querySelectorAll( '.modal' ); + modalList.forEach( function ( modalEl ) { + bootstrap.Modal.getOrCreateInstance( modalEl ); + } ); + } +}() ); diff --git a/modules/ext.bootstrapComponents.popover.js b/modules/ext.bootstrapComponents.popover.js index 82a03ea..f0de8ed 100644 --- a/modules/ext.bootstrapComponents.popover.js +++ b/modules/ext.bootstrapComponents.popover.js @@ -22,11 +22,28 @@ * @ingroup BootstrapComponents * @author Tobias Oetterer */ -$( function() { - $(document).ready(function(){ - $('[data-toggle="popover"]').popover({ - html: true - }); - }); - } -); + +( function () { + 'use strict'; + + // Wait for DOM to be ready + if ( document.readyState === 'loading' ) { + document.addEventListener( 'DOMContentLoaded', initPopovers ); + } else { + initPopovers(); + } + + function initPopovers() { + if ( typeof bootstrap === 'undefined' || !bootstrap.Popover ) { + // eslint-disable-next-line no-console + console.warn( 'BootstrapComponents: bootstrap.Popover is not available; popover triggers will not work.' ); + return; + } + const popoverTriggerList = document.querySelectorAll( '[data-bs-toggle="popover"]' ); + popoverTriggerList.forEach( function ( popoverTriggerEl ) { + new bootstrap.Popover( popoverTriggerEl, { + html: true + } ); + } ); + } +}() ); diff --git a/modules/ext.bootstrapComponents.tooltip.js b/modules/ext.bootstrapComponents.tooltip.js index 575e021..a9dabd7 100644 --- a/modules/ext.bootstrapComponents.tooltip.js +++ b/modules/ext.bootstrapComponents.tooltip.js @@ -23,9 +23,25 @@ * @author Tobias Oetterer */ -$( function() { - $(document).ready(function(){ - $('[data-toggle="tooltip"]').tooltip(); - }); - } -); \ No newline at end of file +( function () { + 'use strict'; + + // Wait for DOM to be ready + if ( document.readyState === 'loading' ) { + document.addEventListener( 'DOMContentLoaded', initTooltips ); + } else { + initTooltips(); + } + + function initTooltips() { + if ( typeof bootstrap === 'undefined' || !bootstrap.Tooltip ) { + // eslint-disable-next-line no-console + console.warn( 'BootstrapComponents: bootstrap.Tooltip is not available; tooltip triggers will not work.' ); + return; + } + const tooltipTriggerList = document.querySelectorAll( '[data-bs-toggle="tooltip"]' ); + tooltipTriggerList.forEach( function ( tooltipTriggerEl ) { + new bootstrap.Tooltip( tooltipTriggerEl ); + } ); + } +}() ); From 8f59891b97357beaf8fdbd86a6e35cdfc75b2fab Mon Sep 17 00:00:00 2001 From: Morne Alberts Date: Fri, 22 May 2026 12:26:05 +0200 Subject: [PATCH 3/7] Rename BS4 data-* attributes to data-bs-* across PHP emitters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bootstrap 5 namespaced all its data-attribute hooks with a `bs-` prefix (`data-bs-toggle`, `data-bs-target`, etc.) to stop conflicting with authoring code. Update every BC component that emits these attributes plus `ModalBuilder` and its trigger-matching regexes: * `Components/Modal.php` — `data-toggle`/`data-target` on the trigger button. * `Components/Popover.php` — `data-toggle`, `data-content`, `data-placement`, `data-trigger`. * `Components/Tooltip.php` — `data-toggle`, `data-placement`. * `Components/Carousel.php` — `data-ride`, `data-slide`, `data-slide-to`, `data-target` on indicators. * `Components/Card.php` — `data-toggle`/`data-target` on collapsible card heads, `data-parent` on accordion children. * `Components/Collapse.php` — `data-toggle` on the toggle button. * `Components/Alert.php` — `data-dismiss` on the close button. * `ModalBuilder.php` — `data-toggle`/`data-target`/`data-dismiss` in the emitted markup, plus the `preg_match` regexes that test for a user-supplied trigger pointing at the modal. Co-Authored-By: Claude Opus 4.7 --- src/Components/Alert.php | 2 +- src/Components/Card.php | 6 +++--- src/Components/Carousel.php | 10 +++++----- src/Components/Collapse.php | 2 +- src/Components/Modal.php | 4 ++-- src/Components/Popover.php | 8 ++++---- src/Components/Tooltip.php | 4 ++-- src/ModalBuilder.php | 14 +++++++------- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/Components/Alert.php b/src/Components/Alert.php index 92a62d0..e597f00 100644 --- a/src/Components/Alert.php +++ b/src/Components/Alert.php @@ -111,7 +111,7 @@ private function renderDismissButton() { [ 'type' => 'button', 'class' => 'close', - 'data-dismiss' => 'alert', + 'data-bs-dismiss' => 'alert', 'aria-label' => wfMessage( 'bootstrap-components-close-element' )->inContentLanguage()->text(), ], Html::rawElement( diff --git a/src/Components/Card.php b/src/Components/Card.php index 27008aa..216f2d2 100644 --- a/src/Components/Card.php +++ b/src/Components/Card.php @@ -83,7 +83,7 @@ protected function placeMe( $input ) { 'class' => $this->arrayToString( $innerClass, ' ' ), ]; if ( $this->isCollapsible() ) { - $innerAttributes['data-parent'] = $this->getDataParent(); + $innerAttributes['data-bs-parent'] = $this->getDataParent(); $innerAttributes['aria-labelledby'] = $this->getId() . '_header'; } @@ -240,8 +240,8 @@ private function processAdditionToCard( string $type ): string { if ( $type == 'header' ) { if ( $this->isCollapsible() ) { $newAttributes += [ - 'data-toggle' => 'collapse', - 'data-target' => '#' . $this->getId(), + 'data-bs-toggle' => 'collapse', + 'data-bs-target' => '#' . $this->getId(), 'aria-controls' => $this->getId(), 'aria-expanded' => $this->getValueFor( 'active' ) ? 'true' : 'false', 'id' => $this->getId() . '_header' diff --git a/src/Components/Carousel.php b/src/Components/Carousel.php index 63485cf..8102809 100644 --- a/src/Components/Carousel.php +++ b/src/Components/Carousel.php @@ -63,7 +63,7 @@ protected function placeMe( $input ) { 'class' => $this->arrayToString( $class, ' ' ), 'style' => $this->arrayToString( $style, ';' ), 'id' => $this->getId(), - 'data-ride' => 'carousel', + 'data-bs-ride' => 'carousel', ], $this->generateIndicators( count( $images ) ) . Html::rawElement( @@ -90,7 +90,7 @@ private function buildControls() { 'class' => 'carousel-control-prev', 'href' => '#' . $this->getId(), 'role' => 'button', - 'data-slide' => 'prev', + 'data-bs-slide' => 'prev', ], Html::rawElement( 'span', [ 'class' => 'carousel-control-prev-icon', 'aria-hidden' => 'true' ] ) ) . Html::rawElement( @@ -99,7 +99,7 @@ private function buildControls() { 'class' => 'carousel-control-next', 'href' => '#' . $this->getId(), 'role' => 'button', - 'data-slide' => 'next', + 'data-bs-slide' => 'next', ], Html::rawElement( 'span', [ 'class' => 'carousel-control-next-icon', 'aria-hidden' => 'true' ] ) ); @@ -188,8 +188,8 @@ private function generateIndicators( $num ) { $inner .= "\t" . Html::rawElement( 'li', [ - 'data-target' => '#' . $this->getId(), - 'data-slide-to' => $i, + 'data-bs-target' => '#' . $this->getId(), + 'data-bs-slide-to' => $i, 'class' => $class, ] ) . PHP_EOL; diff --git a/src/Components/Collapse.php b/src/Components/Collapse.php index 2321f6d..b69ad58 100644 --- a/src/Components/Collapse.php +++ b/src/Components/Collapse.php @@ -74,7 +74,7 @@ protected function placeMe( $input ) { */ private function generateButton( ParserRequest $parserRequest ) { $button = new Button( $this->getComponentLibrary(), $this->getParserOutputHelper(), $this->getNestingController() ); - $button->injectRawAttributes( [ 'data-toggle' => 'collapse' ] ); + $button->injectRawAttributes( [ 'data-bs-toggle' => 'collapse' ] ); $buttonAttributes = $parserRequest->getAttributes(); unset( $buttonAttributes['id'] ); diff --git a/src/Components/Modal.php b/src/Components/Modal.php index cd93556..3468e1e 100644 --- a/src/Components/Modal.php +++ b/src/Components/Modal.php @@ -106,8 +106,8 @@ private function generateButton( $text ) { [ 'type' => 'button', 'class' => 'modal-trigger btn btn-' . $this->getValueFor( 'color', 'default' ), - 'data-toggle' => 'modal', - 'data-target' => '#' . $this->getId(), + 'data-bs-toggle' => 'modal', + 'data-bs-target' => '#' . $this->getId(), ], $text ); diff --git a/src/Components/Popover.php b/src/Components/Popover.php index 1a5dc1d..cec5415 100644 --- a/src/Components/Popover.php +++ b/src/Components/Popover.php @@ -87,11 +87,11 @@ private function buildHtmlElements( $input, $text, $heading ) { $attributes = array_merge( $attributes, [ - 'data-toggle' => 'popover', + 'data-bs-toggle' => 'popover', 'title' => $heading, - 'data-content' => str_replace( "\n", " ", trim( $input ) ), - 'data-placement' => $this->getValueFor( 'placement' ), - 'data-trigger' => $this->getValueFor( 'trigger' ), + 'data-bs-content' => str_replace( "\n", " ", trim( $input ) ), + 'data-bs-placement' => $this->getValueFor( 'placement' ), + 'data-bs-trigger' => $this->getValueFor( 'trigger' ), ] ); $tag = "button"; diff --git a/src/Components/Tooltip.php b/src/Components/Tooltip.php index a981fe4..e166804 100644 --- a/src/Components/Tooltip.php +++ b/src/Components/Tooltip.php @@ -85,8 +85,8 @@ private function buildHtmlElements( $input, $tooltip ) { $attributes = array_merge( $attributes, [ - 'data-placement' => $this->getValueFor( 'placement' ), - 'data-toggle' => 'tooltip', + 'data-bs-placement' => $this->getValueFor( 'placement' ), + 'data-bs-toggle' => 'tooltip', 'title' => $tooltip, ] ); diff --git a/src/ModalBuilder.php b/src/ModalBuilder.php index c9ed806..e490ef9 100644 --- a/src/ModalBuilder.php +++ b/src/ModalBuilder.php @@ -103,8 +103,8 @@ public static function wrapTriggerElement( $element, $id ) { 'span', [ 'class' => 'modal-trigger', - 'data-toggle' => 'modal', - 'data-target' => '#' . $id, + 'data-bs-toggle' => 'modal', + 'data-bs-target' => '#' . $id, ], $element ); @@ -139,7 +139,7 @@ public function __construct( * Parses the modal. * * Emits the trigger followed by the modal container inline. The container is - * `position: fixed` and is addressed via `data-target="#id"`, so its DOM + * `position: fixed` and is addressed via `data-bs-target="#id"`, so its DOM * placement is not significant. * * @return string @@ -306,8 +306,8 @@ protected function buildModal() { */ protected function buildTrigger() { $trigger = $this->getTrigger(); - if ( preg_match( '/data-toggle[^"]+"modal/', $trigger ) - && preg_match( '/data-target[^"]+"#' . $this->getId() . '"/', $trigger ) + if ( preg_match( '/data-bs-toggle[^"]+"modal/', $trigger ) + && preg_match( '/data-bs-target[^"]+"#' . $this->getId() . '"/', $trigger ) && preg_match( '/class[^"]+"[^"]*modal-trigger' . '/', $trigger ) ) { return $trigger; @@ -449,7 +449,7 @@ private function generateFooter( $footer = '' ) { [ 'type' => 'button', 'class' => 'btn btn-default', - 'data-dismiss' => 'modal', + 'data-bs-dismiss' => 'modal', 'aria-label' => $close, ], $close @@ -479,7 +479,7 @@ private function generateHeader( $header = '' ) { [ 'type' => 'button', 'class' => 'close', - 'data-dismiss' => 'modal', + 'data-bs-dismiss' => 'modal', 'aria-label' => wfMessage( 'bootstrap-components-close-element' )->inContentLanguage()->text(), ], Html::rawElement( From e91db520121db924e785d6f86a1f649b0ee55152 Mon Sep 17 00:00:00 2001 From: Morne Alberts Date: Fri, 22 May 2026 12:28:08 +0200 Subject: [PATCH 4/7] Update PHP emitters for BS5 class names and component structures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bootstrap 5 dropped several BS3/BS4 class names that BC's PHP emitters were hard-coding. Update the affected sites to BS5 equivalents: * `Components/Badge.php` — `badge-pill` -> `rounded-pill`, and the `badge-` family -> the BS5 `text-bg-` utilities that set background AND a contrasting foreground. * `Components/Alert.php` — close button switches from BS4's `class="close"` + `×` shape to BS5's self-styled `class="btn-close"` (no inner span; the X is drawn by the class via a background SVG). * `Components/Jumbotron.php` — `.jumbotron` was removed in BS5; recreate the same look with utility classes per the BS5 example. * `ModalBuilder.php` — same close-button shape change as Alert, and switch the footer dismiss button from BS4's removed `btn-default` to `btn-secondary` (BS5 default colour). * `Components/Modal.php` — whitespace-only realign of the array literal to keep keys consistent with the renamed `data-bs-*` entries. `color="default"` on Modal / Popover / Button / Badge is deliberately left as-is. BS5 (and BS4) have no rule for `*-default`, so it renders effectively-unstyled; back-compat for existing wikitext is preserved by accepting the value, not by translating it. See the migration guide for the decision and the recommended user-side replacements. Co-Authored-By: Claude Opus 4.7 --- src/Components/Alert.php | 15 ++++----------- src/Components/Badge.php | 4 ++-- src/Components/Jumbotron.php | 4 +++- src/Components/Modal.php | 4 ++-- src/ModalBuilder.php | 19 +++++++------------ 5 files changed, 18 insertions(+), 28 deletions(-) diff --git a/src/Components/Alert.php b/src/Components/Alert.php index e597f00..77dffea 100644 --- a/src/Components/Alert.php +++ b/src/Components/Alert.php @@ -109,18 +109,11 @@ private function renderDismissButton() { return Html::rawElement( 'button', [ - 'type' => 'button', - 'class' => 'close', + 'type' => 'button', + 'class' => 'btn-close', 'data-bs-dismiss' => 'alert', - 'aria-label' => wfMessage( 'bootstrap-components-close-element' )->inContentLanguage()->text(), - ], - Html::rawElement( - 'span', - [ - 'aria-hidden' => 'true', - ], - '×' - ) + 'aria-label' => wfMessage( 'bootstrap-components-close-element' )->inContentLanguage()->text(), + ] ); } } diff --git a/src/Components/Badge.php b/src/Components/Badge.php index 6dc1cd3..6f068a2 100644 --- a/src/Components/Badge.php +++ b/src/Components/Badge.php @@ -72,10 +72,10 @@ private function calculateClassAttribute() { $class = [ 'badge' ]; if ( (bool)$this->getValueFor( 'pill' ) ) { - $class[] = 'badge-pill'; + $class[] = 'rounded-pill'; } - $class[] = 'badge-' . $this->getValueFor( 'color', 'primary' ); + $class[] = 'text-bg-' . $this->getValueFor( 'color', 'primary' ); return $class; } } diff --git a/src/Components/Jumbotron.php b/src/Components/Jumbotron.php index 89d4739..2f52e8a 100644 --- a/src/Components/Jumbotron.php +++ b/src/Components/Jumbotron.php @@ -44,7 +44,9 @@ class Jumbotron extends AbstractComponent { * @param string $input */ protected function placeMe( $input ) { - list ( $class, $style ) = $this->processCss( 'jumbotron', [] ); + // Bootstrap 5 dropped `.jumbotron` in favour of composing the same look + // from utility classes. See https://getbootstrap.com/docs/5.3/examples/jumbotron/. + list ( $class, $style ) = $this->processCss( [ 'p-5', 'mb-4', 'bg-body-tertiary', 'rounded-3' ], [] ); # @hack: the outer container is a workaround, to get all the necessary css if not inside a grid container # @fixme: used inside mw content, the width calculation for smaller screens is broken (as of Bootstrap 1.2.3) return Html::rawElement( diff --git a/src/Components/Modal.php b/src/Components/Modal.php index 3468e1e..2e6f89b 100644 --- a/src/Components/Modal.php +++ b/src/Components/Modal.php @@ -104,8 +104,8 @@ private function generateButton( $text ) { return Html::rawElement( 'button', [ - 'type' => 'button', - 'class' => 'modal-trigger btn btn-' . $this->getValueFor( 'color', 'default' ), + 'type' => 'button', + 'class' => 'modal-trigger btn btn-' . $this->getValueFor( 'color', 'default' ), 'data-bs-toggle' => 'modal', 'data-bs-target' => '#' . $this->getId(), ], diff --git a/src/ModalBuilder.php b/src/ModalBuilder.php index e490ef9..24b9c11 100644 --- a/src/ModalBuilder.php +++ b/src/ModalBuilder.php @@ -447,10 +447,10 @@ private function generateFooter( $footer = '' ) { $footer . Html::rawElement( 'button', [ - 'type' => 'button', - 'class' => 'btn btn-default', + 'type' => 'button', + 'class' => 'btn btn-secondary', 'data-bs-dismiss' => 'modal', - 'aria-label' => $close, + 'aria-label' => $close, ], $close ) @@ -477,16 +477,11 @@ private function generateHeader( $header = '' ) { $button = Html::rawElement( 'button', [ - 'type' => 'button', - 'class' => 'close', + 'type' => 'button', + 'class' => 'btn-close', 'data-bs-dismiss' => 'modal', - 'aria-label' => wfMessage( 'bootstrap-components-close-element' )->inContentLanguage()->text(), - ], - Html::rawElement( - 'span', - [ 'aria-hidden' => 'true' ], - '×' - ) + 'aria-label' => wfMessage( 'bootstrap-components-close-element' )->inContentLanguage()->text(), + ] ); return Html::rawElement( 'div', From 32de64bdedce6d411c9075fb70fbee95713b9bc3 Mon Sep 17 00:00:00 2001 From: Morne Alberts Date: Fri, 22 May 2026 12:31:35 +0200 Subject: [PATCH 5/7] Emit BS5 button indicators in Carousel instead of BS3
    /
  1. Bootstrap 5's carousel indicator example uses `' . PHP_EOL . '', + . '', 'isHTML' => true, 'noparse' => true, ], @@ -104,15 +104,15 @@ public function galleryDataProvider() { ], [], [ - 0 => '', 'isHTML' => true, 'noparse' => true, ], diff --git a/tests/phpunit/Unit/Components/AlertTest.php b/tests/phpunit/Unit/Components/AlertTest.php index 1046fa2..98cc997 100644 --- a/tests/phpunit/Unit/Components/AlertTest.php +++ b/tests/phpunit/Unit/Components/AlertTest.php @@ -83,17 +83,17 @@ public function placeMeArgumentsProvider() { 'dismiss_arbitrary' => [ $this->input, [ 'dismissible' => 'bla' ], - '', + '', ], 'dismiss' => [ $this->input, [ 'dismissible' => true ], - '', + '', ], 'fading' => [ $this->input, [ 'dismissible' => 'fade', 'color' => 'warning' ], - '', + '', ], 'manual id, no dismiss' => [ $this->input, diff --git a/tests/phpunit/Unit/Components/BadgeTest.php b/tests/phpunit/Unit/Components/BadgeTest.php index 3c772b0..6b27199 100644 --- a/tests/phpunit/Unit/Components/BadgeTest.php +++ b/tests/phpunit/Unit/Components/BadgeTest.php @@ -69,7 +69,7 @@ public function placeMeArgumentsProvider() { 'simple' => [ $this->input, [], - '' . $this->input . '', + '' . $this->input . '', ], 'empty' => [ '', @@ -79,22 +79,22 @@ public function placeMeArgumentsProvider() { 'manual id' => [ $this->input, [ 'id' => 'book' ], - '' . $this->input . '', + '' . $this->input . '', ], 'style and class' => [ $this->input, [ 'class' => 'dummy nice', 'style' => 'float:right;background-color:#80266e' ], - '' . $this->input . '', + '' . $this->input . '', ], 'pill' => [ $this->input, [ 'pill' => 'true' ], - '' . $this->input . '', + '' . $this->input . '', ], 'no pill' => [ $this->input, [ 'pill' => 0 ], - '' . $this->input . '', + '' . $this->input . '', ], ]; } diff --git a/tests/phpunit/Unit/Components/ButtonTest.php b/tests/phpunit/Unit/Components/ButtonTest.php index d7897da..7ffc080 100644 --- a/tests/phpunit/Unit/Components/ButtonTest.php +++ b/tests/phpunit/Unit/Components/ButtonTest.php @@ -80,7 +80,7 @@ public function testCanInjectRawAttributes() { ); $instance->injectRawAttributes( - [ 'data-toggle' => 'foo', 'data-target' => '#bar' ] + [ 'data-bs-toggle' => 'foo', 'data-bs-target' => '#bar' ] ); $generatedOutput = $instance->parseComponent( $parserRequest ); @@ -91,7 +91,7 @@ public function testCanInjectRawAttributes() { $this->assertMatchesRegularExpression( '~^' . $this->input . '$~', + . '" data-bs-toggle="foo" data-bs-target="#bar">' . $this->input . '$~', $generatedOutput ); } diff --git a/tests/phpunit/Unit/Components/CardTest.php b/tests/phpunit/Unit/Components/CardTest.php index 5792c45..ff785d6 100644 --- a/tests/phpunit/Unit/Components/CardTest.php +++ b/tests/phpunit/Unit/Components/CardTest.php @@ -148,7 +148,7 @@ public function placeMeArgumentsProvider() { 'footer-style'=> 'padding:5px', ], '
    ' - . '
    ' + . '
    ' . '

    HEADING TEXT

    [[File:Serenity.png]]' . '
    ' . $this->input . '
    [[File:Serenity.png|class=card-img-bottom]]
    ', @@ -179,12 +179,12 @@ public function placeMeInsideAccordionArgumentsProvider() { 'simple' => [ $this->input, [], - '
    ' . $this->input . '
    ', + '
    ' . $this->input . '
    ', ], 'text missing' => [ '', [ 'header' => 'watch this', 'footer' => 'watch what?', 'collapsible' => 'false', ], - '
    ', + '
    ', ], 'all attributes' => [ $this->input, @@ -198,12 +198,12 @@ public function placeMeInsideAccordionArgumentsProvider() { 'heading' => 'HEADING TEXT', 'footer' => 'FOOTER TEXT', ], - '

    HEADING TEXT

    ' . $this->input . '
    ', + '

    HEADING TEXT

    ' . $this->input . '
    ', ], 'collapsible false' => [ $this->input, [ 'collapsible' => 'false', ], - '
    ' . $this->input . '
    ', + '
    ' . $this->input . '
    ', ], ]; } diff --git a/tests/phpunit/Unit/Components/CarouselTest.php b/tests/phpunit/Unit/Components/CarouselTest.php index ea34e21..6433abe 100644 --- a/tests/phpunit/Unit/Components/CarouselTest.php +++ b/tests/phpunit/Unit/Components/CarouselTest.php @@ -79,17 +79,17 @@ public function placeMeArgumentsProvider() { 'simple' => [ '[[File:Mal.jpg|Malcolm Reynolds_0]]', [ '[[File:Mal.jpg|Malcolm Reynolds]]' => true, '[[File:Wash.jpg|link' => '|Hoban Washburne]]' ], - '
    ', ], 'images missing' => [ $this->input, @@ -105,15 +105,15 @@ public function placeMeArgumentsProvider() { 'fade' => true, 'style' => 'float:none;background-color:black', ], - '', ], ]; } diff --git a/tests/phpunit/Unit/Components/CollapseTest.php b/tests/phpunit/Unit/Components/CollapseTest.php index 79dc909..4f9fad0 100644 --- a/tests/phpunit/Unit/Components/CollapseTest.php +++ b/tests/phpunit/Unit/Components/CollapseTest.php @@ -69,27 +69,27 @@ public function placeMeArgumentsProvider() { 'simple' => [ $this->input, [], - '#bsc_collapse_NULL
    ' . $this->input . '
    ', + '#bsc_collapse_NULL
    ' . $this->input . '
    ', ], 'color_unknown' => [ $this->input, [ 'color' => 'unknown' ], - '#bsc_collapse_NULL
    ' . $this->input . '
    ', + '#bsc_collapse_NULL
    ' . $this->input . '
    ', ], 'button text' => [ $this->input, [ 'text' => 'BUTTON' ], - 'BUTTON
    ' . $this->input . '
    ', + 'BUTTON
    ' . $this->input . '
    ', ], 'manual id' => [ $this->input, [ 'color' => 'success', 'id' => 'alliance' ], - '#alliance
    ' . $this->input . '
    ', + '#alliance
    ' . $this->input . '
    ', ], 'style and class' => [ $this->input, [ 'class' => 'dummy nice', 'style' => 'float:right;background-color:green' ], - '#bsc_collapse_NULL
    ' . $this->input . '
    ', + '#bsc_collapse_NULL
    ' . $this->input . '
    ', ], ]; } diff --git a/tests/phpunit/Unit/Components/JumbotronTest.php b/tests/phpunit/Unit/Components/JumbotronTest.php index 9d73690..86ad7d5 100644 --- a/tests/phpunit/Unit/Components/JumbotronTest.php +++ b/tests/phpunit/Unit/Components/JumbotronTest.php @@ -69,17 +69,17 @@ public function placeMeArgumentsProvider() { 'simple' => [ $this->input, [], - '
    ' . $this->input . '
    ', + '
    ' . $this->input . '
    ', ], 'manual id' => [ $this->input, [ 'id' => 'hms_dortmunder' ], - '
    ' . $this->input . '
    ', + '
    ' . $this->input . '
    ', ], 'style and class' => [ $this->input, [ 'class' => 'dummy nice', 'style' => 'float:right;background-color:green' ], - '
    ' . $this->input . '
    ', + '
    ' . $this->input . '
    ', ], ]; } diff --git a/tests/phpunit/Unit/Components/ModalTest.php b/tests/phpunit/Unit/Components/ModalTest.php index 3bb715a..2a6d5f8 100644 --- a/tests/phpunit/Unit/Components/ModalTest.php +++ b/tests/phpunit/Unit/Components/ModalTest.php @@ -79,9 +79,9 @@ public function placeMeArgumentsProvider() { 'simple' => [ $this->input, [ 'text' => 'BUTTON' ], - '', - '' . "\n", + '', + '' . "\n", ], 'text missing' => [ $this->input, @@ -95,9 +95,9 @@ public function placeMeArgumentsProvider() { 'text' => 'beforeSerenityafter', 'size' => 'none', ], - 'beforeSerenityafter', - '' . "\n", + 'beforeSerenityafter', + '' . "\n", ], 'all attributes' => [ $this->input, @@ -106,9 +106,9 @@ public function placeMeArgumentsProvider() { 'id' => 'firefly0', 'size' => 'lg', 'class' => 'shiny', 'style' => 'float:right;background-color:black', 'heading' => 'You can\'t take the sky from me!', ], - 'Serenity', - '' . "\n", + 'Serenity', + '' . "\n", ], ]; } diff --git a/tests/phpunit/Unit/Components/PopoverTest.php b/tests/phpunit/Unit/Components/PopoverTest.php index 4bc20e9..b99a9d6 100644 --- a/tests/phpunit/Unit/Components/PopoverTest.php +++ b/tests/phpunit/Unit/Components/PopoverTest.php @@ -69,7 +69,7 @@ public function placeMeArgumentsProvider() { 'simple' => [ $this->input, [ 'heading' => 'heading', 'text' => 'BUTTON' ], - '', + '', ], 'heading empty' => [ $this->input, @@ -87,7 +87,7 @@ public function placeMeArgumentsProvider() { 'heading' => 'heading', 'text' => 'BUTTON', 'class' => 'dummy nice', 'style' => 'float:right;background-color:green', 'placement' => 'right', 'trigger' => 'hover', 'id' => 'cudgel', 'size' => 'sm' ], - '', + '', ], ]; } diff --git a/tests/phpunit/Unit/Components/TooltipTest.php b/tests/phpunit/Unit/Components/TooltipTest.php index 810b0a3..8cfcc85 100644 --- a/tests/phpunit/Unit/Components/TooltipTest.php +++ b/tests/phpunit/Unit/Components/TooltipTest.php @@ -74,7 +74,7 @@ public function placeMeArgumentsProvider() { 'simple' => [ $this->input, [ 'text' => 'simple' ], - '' . $this->input . '', + '' . $this->input . '', ], 'empty' => [ '', @@ -89,7 +89,7 @@ public function placeMeArgumentsProvider() { 'id, style and class' => [ $this->input, [ 'text' => 'simple', 'class' => 'dummy nice', 'style' => 'float:right;background-color:#80266e', 'id' => 'vera' ], - '' . $this->input . '', + '' . $this->input . '', ], ]; } diff --git a/tests/phpunit/Unit/ImageModalTest.php b/tests/phpunit/Unit/ImageModalTest.php index 4baf897..8fcd47c 100644 --- a/tests/phpunit/Unit/ImageModalTest.php +++ b/tests/phpunit/Unit/ImageModalTest.php @@ -295,9 +295,9 @@ public function canParseDataProvider(): array 'no params' => [ [], [], - '~~', - '' . "\n", + '~~', + '' . "\n", ], 'frame params w/o thumbnail' => [ [ @@ -309,9 +309,9 @@ public function canParseDataProvider(): array 'valign' => 'text-top', ], [], - '~
    test_alt
    ~', - '' . "\n", + '~
    test_alt
    ~', + '' . "\n", ], 'manual width, frameless' => [ [ @@ -322,9 +322,9 @@ public function canParseDataProvider(): array 'width' => 200, 'page' => 7, ], - '~
    ~', - '' . "\n", + '~
    ~', + '' . "\n", ], 'thumbnail, manual width' => [ [ @@ -335,9 +335,9 @@ public function canParseDataProvider(): array 'width' => 200, 'page' => 7, ], - '~
    ~', - '' . "\n", + '~
    ~', + '' . "\n", ], 'manual thumbnail, NOT centered' => [ [ @@ -346,9 +346,9 @@ public function canParseDataProvider(): array 'framed' => false, ], [], - '~
    ~', - '' . "\n", + '~
    ~', + '' . "\n", ], 'framed' => [ [ @@ -356,9 +356,9 @@ public function canParseDataProvider(): array 'framed' => false, ], [], - '~
    ~', - '' . "\n", + '~
    ~', + '' . "\n", ], 'centered' => [ [ @@ -367,9 +367,9 @@ public function canParseDataProvider(): array [ 'width' => 200, ], - '~
    ~', - '' . "\n", + '~
    ~', + '' . "\n", ], 'manual thumbnail, upright' => [ [ @@ -378,9 +378,9 @@ public function canParseDataProvider(): array 'manualthumb' => 'Shuttle.png', ], [], - '~
    ~', - '' . "\n", + '~
    ~', + '' . "\n", ], ]; } diff --git a/tests/phpunit/Unit/ImageModalTriggerTest.php b/tests/phpunit/Unit/ImageModalTriggerTest.php index 1ac28bb..19121c8 100644 --- a/tests/phpunit/Unit/ImageModalTriggerTest.php +++ b/tests/phpunit/Unit/ImageModalTriggerTest.php @@ -164,7 +164,7 @@ public function canParseProvider() { 'page' => false, ], [ - '~~', + '~~', ] ], 'frame params w/o thumbnail' => [ @@ -184,7 +184,7 @@ public function canParseProvider() { 'page' => false, ], [ - '~
    ~', + '~
    ~', '~test_alt~', ] ], @@ -206,7 +206,7 @@ public function canParseProvider() { 'page' => 7, ], [ - '~
    ~', + '~
    ~', '~~', ] ], @@ -228,7 +228,7 @@ public function canParseProvider() { 'page' => 7, ], [ - '~
    ~', + '~
    ~', '~
    ~', '~
    ~', ] @@ -252,7 +252,7 @@ public function canParseProvider() { 'page' => false, ], [ - '~
    ~', + '~
    ~', '~
    ~', '~~', ] @@ -274,7 +274,7 @@ public function canParseProvider() { 'page' => false, ], [ - '~
    ~', + '~
    ~', '~
    ~', ] ], @@ -296,7 +296,7 @@ public function canParseProvider() { 'page' => false, ], [ - '~
    ~', + '~
    ~', ] ], 'manual thumbnail, upright' => [ @@ -318,7 +318,7 @@ public function canParseProvider() { 'page' => false, ], [ - '~
    ~', + '~' . "\n", ], 'scarce' => [ 'id1', @@ -92,9 +92,9 @@ public function parseDataProvider() { '', '', '', - 'trigger1', - '' . "\n", + 'trigger1', + '' . "\n", ], ]; } diff --git a/tests/phpunit/Unit/mw.bootstrap.parse.tests.lua b/tests/phpunit/Unit/mw.bootstrap.parse.tests.lua index a62be76..cdd035f 100644 --- a/tests/phpunit/Unit/mw.bootstrap.parse.tests.lua +++ b/tests/phpunit/Unit/mw.bootstrap.parse.tests.lua @@ -55,7 +55,7 @@ local tests = { return removeId ( mw.bootstrap.parse( component, input, args ) ) end, args = { 'alert', 'Alert content', { color = 'success', dismissible = 'fade', noStrip = true } }, - expect = { '' } + expect = { '' } }, } From 722da89a0432c02fede8144a3b2159b346c4d24d Mon Sep 17 00:00:00 2001 From: Morne Alberts Date: Fri, 22 May 2026 12:37:51 +0200 Subject: [PATCH 7/7] Update docs for Bootstrap 5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * `docs/release-notes.md` — write a focused 6.0.0 entry covering the actual BS5-lift changes (Bootstrap-extension bump, attribute renames, JS modules, class-name updates, carousel indicator markup, `color="default"` back-compat note). The MediaWiki (1.43) and PHP (8.1) floors are unchanged from 5.x and not listed under "Breaking changes". The bug-fix entries that already shipped in 5.2.3 / 5.2.4 are not re-listed under 6.0 since 6.0 inherits them from the 5.x line. * `docs/migration-guide.md` — new file. Step-by-step upgrade guide for wiki admins moving from BC 5.x (Bootstrap 4) to BC 6.0 (BS5). Explicitly notes that the MW and PHP floors are unchanged; the only new requirement is `mediawiki/bootstrap` ^6.0. * `docs/components.md` — note the jumbotron now emits utility classes instead of the removed `.jumbotron` class. * `docs/components/*.md` — update Bootstrap-version text references (`4.1` -> `5.3` doc URLs, "default" colour notes). * `docs/known-issues.md` — replace the pre-5.2.4 modal-backdrop workaround sections (which told users to add `.modal-backdrop { display: none }` to their wiki CSS) with a single entry describing the current shipped behaviour: the workaround CSS now rides along with the extension and is applied automatically on Vector and Vector 2022 (the only two skins where the page-container traps the modal under its backdrop on MW 1.43+). Point at #91 for the root-cause tracking. Refresh the navbar-overlaps-modal section opener so it no longer leans on the removed backdrop-troubleshooting context. Co-Authored-By: Claude Opus 4.7 --- docs/components.md | 2 + docs/components/accordion.md | 3 +- docs/components/alert.md | 5 +-- docs/components/badge.md | 5 +-- docs/components/button.md | 5 +-- docs/components/card.md | 5 +-- docs/components/carousel.md | 3 +- docs/components/collapse.md | 3 +- docs/components/jumbotron.md | 20 +++++++-- docs/components/modal.md | 5 +-- docs/components/popover.md | 5 +-- docs/components/tooltip.md | 3 +- docs/known-issues.md | 36 ++++++----------- docs/migration-guide.md | 78 +++++++++++++++++++++++++++++++++++- docs/release-notes.md | 14 ++++++- 15 files changed, 136 insertions(+), 56 deletions(-) diff --git a/docs/components.md b/docs/components.md index d02f2b0..36336f2 100644 --- a/docs/components.md +++ b/docs/components.md @@ -22,6 +22,8 @@ the following components are available to be used inside the wiki text: want to hide and show large amount of content. * **[Jumbotron](components/jumbotron.md)**: A jumbotron indicates a big box for calling extra attention to some special content or information. + _Bootstrap 5 removed `.jumbotron`; the parser function is retained, + now emitting BS5 utility classes for an equivalent look._ * **[Modal](components/modal.md)**: The Modal component is a dialog box/popup window that is displayed on top of the current page. * **[Popover](components/popover.md)**: The Popover component produces a diff --git a/docs/components/accordion.md b/docs/components/accordion.md index ca1ffdd..78d1c21 100644 --- a/docs/components/accordion.md +++ b/docs/components/accordion.md @@ -40,6 +40,5 @@ add multiple css styles, separate them by a semicolon. ### Links -* https://getbootstrap.com/docs/4.1/components/collapse/#accordion-example -* https://www.w3schools.com/bootstrap4/bootstrap_collapse.asp +* https://getbootstrap.com/docs/5.3/components/accordion/ diff --git a/docs/components/alert.md b/docs/components/alert.md index 0a0907a..55df8c2 100644 --- a/docs/components/alert.md +++ b/docs/components/alert.md @@ -54,6 +54,5 @@ add multiple css styles, separate them by a semicolon. ### Links -* https://getbootstrap.com/docs/4.1/components/alerts/ -* https://www.w3schools.com/bootstrap4/bootstrap_alerts.asp -* https://getbootstrap.com/docs/4.1/utilities/colors/ +* https://getbootstrap.com/docs/5.3/components/alerts/ +* https://getbootstrap.com/docs/5.3/utilities/colors/ diff --git a/docs/components/badge.md b/docs/components/badge.md index 31eb228..6c054c1 100644 --- a/docs/components/badge.md +++ b/docs/components/badge.md @@ -52,7 +52,6 @@ add multiple css styles, separate them by a semicolon. ### Links -* https://getbootstrap.com/docs/4.1/components/badge/ -* https://www.w3schools.com/bootstrap4/bootstrap_badges.asp -* https://getbootstrap.com/docs/4.1/utilities/colors/ +* https://getbootstrap.com/docs/5.3/components/badge/ +* https://getbootstrap.com/docs/5.3/utilities/colors/ * diff --git a/docs/components/button.md b/docs/components/button.md index c228f21..852ab9f 100644 --- a/docs/components/button.md +++ b/docs/components/button.md @@ -78,7 +78,6 @@ background with button color. ### Links -* https://getbootstrap.com/docs/4.1/components/buttons/ -* https://www.w3schools.com/bootstrap4/bootstrap_buttons.asp -* https://getbootstrap.com/docs/4.1/utilities/colors/ +* https://getbootstrap.com/docs/5.3/components/buttons/ +* https://getbootstrap.com/docs/5.3/utilities/colors/ * diff --git a/docs/components/card.md b/docs/components/card.md index a059ffe..cf473c1 100644 --- a/docs/components/card.md +++ b/docs/components/card.md @@ -109,6 +109,5 @@ add multiple css styles, separate them by a semicolon. ### Links -* https://getbootstrap.com/docs/4.1/components/card/ -* https://www.w3schools.com/bootstrap4/bootstrap_cards.asp -* https://getbootstrap.com/docs/4.1/utilities/colors/ +* https://getbootstrap.com/docs/5.3/components/card/ +* https://getbootstrap.com/docs/5.3/utilities/colors/ diff --git a/docs/components/carousel.md b/docs/components/carousel.md index 1a8f7fd..44d1858 100644 --- a/docs/components/carousel.md +++ b/docs/components/carousel.md @@ -38,5 +38,4 @@ attributes, otherwise the parser will drop all but one: ``` ### Links -* https://getbootstrap.com/docs/4.1/components/carousel/ -* https://www.w3schools.com/bootstrap4/bootstrap_carousel.asp +* https://getbootstrap.com/docs/5.3/components/carousel/ diff --git a/docs/components/collapse.md b/docs/components/collapse.md index 8b6abd7..1bf65e0 100644 --- a/docs/components/collapse.md +++ b/docs/components/collapse.md @@ -29,5 +29,4 @@ be used as the trigger element. In this case, all but the attributes ### Links -* https://getbootstrap.com/docs/4.1/components/collapse/ -* https://www.w3schools.com/bootstrap4/bootstrap_collapse.asp +* https://getbootstrap.com/docs/5.3/components/collapse/ diff --git a/docs/components/jumbotron.md b/docs/components/jumbotron.md index 86a34bd..8f63dde 100644 --- a/docs/components/jumbotron.md +++ b/docs/components/jumbotron.md @@ -1,9 +1,21 @@ ## Jumbotron + +> **⚠️ Deprecated.** Bootstrap 5 removed the `.jumbotron` component. The +> `bootstrap_jumbotron` parser function is retained for backward compatibility +> and now emits the equivalent Bootstrap 5 utility-class combination +> (`p-5 mb-4 bg-body-tertiary rounded-3`) per the official migration guide +> linked below. New content should prefer composing utility classes directly. +> The parser function may be removed in a future major release. + A jumbotron indicates a big box for calling extra attention to some special content or information. -A jumbotron is displayed as a grey box with rounded corners. It also enlarges -the font sizes of the text inside it. +A jumbotron is displayed as a light box with rounded corners. Note that the +Bootstrap 4 `.jumbotron` class also enlarged contained headings automatically; +the Bootstrap 5 utility-class composition does not. If you want the +BS4-era larger-font look, apply `display-*` / `fs-*` utility classes on +your headings and paragraphs inside the tag. The migration guide and example +linked below show the canonical pattern. See also: * [Alert](alert.md) @@ -33,5 +45,5 @@ add multiple css styles, separate them by a semicolon. ### Links -* https://getbootstrap.com/docs/4.1/components/jumbotron/ -* https://www.w3schools.com/bootstrap4/bootstrap_jumbotron.asp +* https://getbootstrap.com/docs/5.3/migration/#jumbotron +* https://getbootstrap.com/docs/5.3/examples/jumbotron/ diff --git a/docs/components/modal.md b/docs/components/modal.md index 2bfe7a4..8978e87 100644 --- a/docs/components/modal.md +++ b/docs/components/modal.md @@ -76,8 +76,7 @@ be used as the trigger element. ### Links -* https://getbootstrap.com/docs/4.1/components/modal/ -* https://www.w3schools.com/bootstrap4/bootstrap_modal.asp -* https://getbootstrap.com/docs/4.1/utilities/colors/ +* https://getbootstrap.com/docs/5.3/components/modal/ +* https://getbootstrap.com/docs/5.3/utilities/colors/ Please, see also the [known issues](../known-issues.md) with this component. diff --git a/docs/components/popover.md b/docs/components/popover.md index 5b75e1f..2acb18d 100644 --- a/docs/components/popover.md +++ b/docs/components/popover.md @@ -94,6 +94,5 @@ behaviour with: ### Links -* https://getbootstrap.com/docs/4.1/components/popovers/ -* https://www.w3schools.com/bootstrap4/bootstrap_popover.asp -* https://getbootstrap.com/docs/4.1/utilities/colors/ +* https://getbootstrap.com/docs/5.3/components/popovers/ +* https://getbootstrap.com/docs/5.3/utilities/colors/ diff --git a/docs/components/tooltip.md b/docs/components/tooltip.md index 726af56..fcf2af7 100644 --- a/docs/components/tooltip.md +++ b/docs/components/tooltip.md @@ -51,5 +51,4 @@ following to your `Mediawiki:Common.css`: ``` ### Links -* https://getbootstrap.com/docs/4.1/components/tooltips/ -* https://www.w3schools.com/bootstrap4/bootstrap_tooltip.asp +* https://getbootstrap.com/docs/5.3/components/tooltips/ diff --git a/docs/known-issues.md b/docs/known-issues.md index 23b8ea5..0c7d55b 100644 --- a/docs/known-issues.md +++ b/docs/known-issues.md @@ -6,36 +6,26 @@ elements. When you put popovers on a page with modals (or image modals), the modals break. -### Modals and vector -Modals are not fully compatible with the vector skin. Therefore they are -missing the backdrop. Also, you might notice a slight "wobble" in -vector's header every time the modal pops up. - ### Modals and definition lists Some user experience broken html output when trying to use modals as the term in definition lists. Using the html equivalent causes the same problem. -### Modal backdrops -Sometimes, not only in vector skin, modal backdrops (the greying out of -the background) tend to stack the wrong way. In these instances the -z-index of the modal and the backdrop are ignored and the backdrop -overlays the modal and everything else. You cannot even close the modal -and have to reload the page. - -When this happens with your installation you have to disable backdrops -altogether. Please add the following to your `MediaWiki:Common.css` or -anywhere else where css is processed: -```css -.modal-backdrop { - display: none; -} -``` +### Modal backdrops on Vector and Vector 2022 +On these two skins the page-container creates a stacking context that +traps the modal beneath its own backdrop. BC ships a CSS workaround +(`modules/ext.bootstrapComponents.modal.vector-fix.css`) that suppresses +the backdrop on those skins, applied automatically; no configuration is +required. Chameleon, Medik, MonoBook, and Timeless don't establish a +trapping ancestor, so the standard Bootstrap stack works correctly on +those skins without the workaround. The root-cause fix (modal teleport +/ portal out of the trapping container) is tracked at +[issue #91](https://github.com/oetterer/BootstrapComponents/issues/91). ### Navbar overlaps modal -Oftentimes when you have problems with the backdrop, your z-index calculation -is off. Then it can also happen, that your Navbar overlaps the modal. In that case -simply "push" the modal further down. For example: +If your skin has a sticky or fixed navbar, the modal heading can slip +behind it. Push the modal down by a navbar-height in your skin or wiki +CSS, for example: ```css .modal { top: 60px; diff --git a/docs/migration-guide.md b/docs/migration-guide.md index 8a84850..11c6049 100644 --- a/docs/migration-guide.md +++ b/docs/migration-guide.md @@ -1,7 +1,83 @@ ## Migration Guide +### Migrating from Bootstrap 4 (BootstrapComponents 5.x) to Bootstrap 5 (BootstrapComponents 6.0) + +BootstrapComponents 6.0 upgrades the underlying Bootstrap framework from version 4 to version 5.3. This guide helps you understand the changes and migrate your wiki. + +#### System Requirements +The MediaWiki (1.43 or later) and PHP (8.1 or later) floors are unchanged from BC 5.x; the only new requirement in 6.0 is the underlying Bootstrap extension version. +- **Bootstrap extension:** `mediawiki/bootstrap` ^6.0 (provides Bootstrap 5.3); BC 5.x used `^5.0` (Bootstrap 4). + +#### User Impact +Most existing wiki markup using BootstrapComponents continues to work without changes; the extension handles most Bootstrap 5 migrations internally. The notable exceptions are noted below. + +#### Component Changes + +##### Jumbotron +The Jumbotron component still works but now uses Bootstrap 5 utility classes instead of the removed `.jumbotron` class. The visual appearance should be similar but may have minor differences. Consider: +- Using utility classes directly: `
    ` +- Or continue using `` tag which is now implemented using these utilities +- Reference: https://getbootstrap.com/docs/5.3/examples/jumbotron/ + +##### `color="default"` +Bootstrap 5 has no `default` colour family (it was dropped in BS4 already). BC accepts `color="default"` for back-compat but the resulting `*-default` classes are effectively unstyled at the framework level. If you want the BS3-era neutral look, pick a real BS5 colour explicitly: `color="secondary"` (mid-grey filled, matches the BS4 upstream recommendation) or `color="light"` (light filled, closer to BS3's actual visual character). + +##### Badge Pill +If you're using custom CSS targeting `.badge-pill`, update to `.rounded-pill`: +```css +/* Old */ +.badge-pill { ... } + +/* New */ +.rounded-pill { ... } +``` + +##### Alert and Modal Close Buttons +Close buttons now use Bootstrap 5's `.btn-close` class. If you have custom CSS targeting `.close`: +```css +/* Old */ +.close { ... } + +/* New */ +.btn-close { ... } +``` + +#### JavaScript Changes +Bootstrap 5 removed jQuery dependency. If you have custom JavaScript interacting with Bootstrap components: + +**Old (Bootstrap 4 + jQuery):** +```javascript +$('.carousel').carousel(); +$('[data-toggle="tooltip"]').tooltip(); +``` + +**New (Bootstrap 5 vanilla JS):** +```javascript +document.querySelectorAll('.carousel').forEach(el => { + new bootstrap.Carousel(el); +}); +document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(el => { + new bootstrap.Tooltip(el); +}); +``` + +#### Data Attributes +If you're using custom HTML with Bootstrap data attributes, update to the `data-bs-*` prefix: +- `data-toggle` → `data-bs-toggle` +- `data-target` → `data-bs-target` +- `data-dismiss` → `data-bs-dismiss` +- `data-slide` → `data-bs-slide` +- `data-parent` → `data-bs-parent` +- `data-content` → `data-bs-content` +- `data-placement` → `data-bs-placement` +- `data-trigger` → `data-bs-trigger` + +--- + +### Migrating from Bootstrap 3 (BootstrapComponents 1.x) to Bootstrap 4 (BootstrapComponents 4.x-5.x) + There have been some changes between versions ~1.0 and ~4.0. Foremost is that -the new BootstrapComponents utilizes Twitter Bootstrap4. Therefore, it mirrors +the new BootstrapComponents utilizes Twitter Bootstrap 4. Therefore, it mirrors changes made by Bootstrap. Also, extension loading must now be done manually in your LocalSettings, no diff --git a/docs/release-notes.md b/docs/release-notes.md index c25a1c6..8aea1b2 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -5,8 +5,18 @@ Released on TBD Breaking changes: -* requires MediaWiki 1.43 or later -* requires PHP 8.1 or later +* requires `mediawiki/bootstrap` ^6.0 (Bootstrap 5) + +Changes: +* migrate to Bootstrap 5.3 +* component init no longer requires jQuery +* badge classes updated: `badge-pill` becomes `rounded-pill`, `badge-` becomes `text-bg-` +* alert and modal close buttons use the Bootstrap 5 `btn-close` shape +* jumbotron now composes utility classes; Bootstrap 5 removed `.jumbotron` +* carousel indicators use `