MDL-85300 output: ensure Bootstrap tooltips load for dynamic content.

Prior to this change, tooltips would only load for elements in the
initial page DOM without considering those elements subsequently added
dynamically (e.g. via AJAX).

Co-authored-by: Sebastian Gundersen <[email protected]>
This commit is contained in:
Paul Holden
2025-12-16 13:26:10 +00:00
co-authored by Sebastian Gundersen
parent 5cf0c68c51
commit 5a25aada32
3 changed files with 21 additions and 5 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
define("theme_boost/loader",["exports","./aria","./index","core/pending","./bootstrap/util/sanitizer","./pending","./bootstrap/dom/event-handler"],(function(_exports,Aria,Bootstrap,_pending,_sanitizer,_pending2,_eventHandler){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}
define("theme_boost/loader",["exports","./aria","./index","core/pending","core_filters/events","./bootstrap/util/sanitizer","./pending","./bootstrap/dom/event-handler"],(function(_exports,Aria,Bootstrap,_pending,_events,_sanitizer,_pending2,_eventHandler){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}
/**
* Template renderer for Moodle. Load and render Moodle templates with Mustache.
*
@@ -6,6 +6,6 @@ define("theme_boost/loader",["exports","./aria","./index","core/pending","./boot
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since 2.9
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.Bootstrap=void 0,Aria=_interopRequireWildcard(Aria),Bootstrap=_interopRequireWildcard(Bootstrap),_exports.Bootstrap=Bootstrap,_pending=_interopRequireDefault(_pending),_pending2=_interopRequireDefault(_pending2),_eventHandler=_interopRequireDefault(_eventHandler);const pendingPromise=new _pending.default("theme_boost/loader:init");(0,_pending2.default)(),Aria.init(),(()=>{[...document.querySelectorAll('a[data-bs-toggle="tab"]')].map((tabTriggerEl=>tabTriggerEl.addEventListener("shown.bs.tab",(e=>{var hash=e.target.getAttribute("href");history.replaceState?history.replaceState(null,null,hash):location.hash=hash}))));const hash=window.location.hash;if(hash){const tab=document.querySelector('[role="tablist"] [href="'+hash+'"]');tab&&tab.click()}})(),(()=>{const popoverTriggerList=document.querySelectorAll('[data-bs-toggle="popover"]'),popoverConfig={container:"body",trigger:"focus",allowList:Object.assign(_sanitizer.DefaultAllowlist,{table:[],thead:[],tbody:[],tr:[],th:[],td:[]})};[...popoverTriggerList].map((popoverTriggerEl=>new Bootstrap.Popover(popoverTriggerEl,popoverConfig))),document.addEventListener("core/modal:bodyRendered",(e=>{[...e.target.querySelectorAll('[data-bs-toggle="popover"]')].map((popoverTriggerEl=>new Bootstrap.Popover(popoverTriggerEl,popoverConfig)))})),document.addEventListener("keydown",(e=>{const popoverTrigger=e.target.closest('[data-bs-toggle="popover"]');"Escape"===e.key&&popoverTrigger&&Bootstrap.Popover.getOrCreateInstance(popoverTrigger).hide(),"Enter"===e.key&&popoverTrigger&&Bootstrap.Popover.getOrCreateInstance(popoverTrigger).show()})),document.addEventListener("click",(e=>{const popoverTrigger=e.target.closest('[data-bs-toggle="popover"]');if(!popoverTrigger)return;const popover=Bootstrap.Popover.getOrCreateInstance(popoverTrigger);popover._isShown()||popover.show()}))})(),(()=>{const tooltipList=[...document.querySelectorAll('[data-bs-toggle="tooltip"]')].map((tooltipTriggerEl=>new Bootstrap.Tooltip(tooltipTriggerEl)));document.addEventListener("keydown",(e=>{"Escape"===e.key&&tooltipList.forEach((tooltip=>{tooltip.hide()}))}))})(),_eventHandler.default.off(document,"keydown.bs.dropdown.data-api",".dropdown-menu",Bootstrap.Dropdown.dataApiKeydownHandler),_eventHandler.default.on(document.body,"keydown.bs.dropdown.data-api",".dropdown-menu",Bootstrap.Dropdown.dataApiKeydownHandler),pendingPromise.resolve()}));
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.Bootstrap=void 0,Aria=_interopRequireWildcard(Aria),Bootstrap=_interopRequireWildcard(Bootstrap),_exports.Bootstrap=Bootstrap,_pending=_interopRequireDefault(_pending),_pending2=_interopRequireDefault(_pending2),_eventHandler=_interopRequireDefault(_eventHandler);const enableTooltips=function(){let rootElement=arguments.length>0&&void 0!==arguments[0]?arguments[0]:document;const tooltipTriggerList=rootElement.querySelectorAll('[data-bs-toggle="tooltip"]'),tooltipList=[...tooltipTriggerList].map((tooltipTriggerEl=>new Bootstrap.Tooltip(tooltipTriggerEl)));document.addEventListener("keydown",(e=>{"Escape"===e.key&&tooltipList.forEach((tooltip=>{tooltip.hide()}))}))},pendingPromise=new _pending.default("theme_boost/loader:init");(0,_pending2.default)(),Aria.init(),(()=>{[...document.querySelectorAll('a[data-bs-toggle="tab"]')].map((tabTriggerEl=>tabTriggerEl.addEventListener("shown.bs.tab",(e=>{var hash=e.target.getAttribute("href");history.replaceState?history.replaceState(null,null,hash):location.hash=hash}))));const hash=window.location.hash;if(hash){const tab=document.querySelector('[role="tablist"] [href="'+hash+'"]');tab&&tab.click()}})(),(()=>{const popoverTriggerList=document.querySelectorAll('[data-bs-toggle="popover"]'),popoverConfig={container:"body",trigger:"focus",allowList:Object.assign(_sanitizer.DefaultAllowlist,{table:[],thead:[],tbody:[],tr:[],th:[],td:[]})};[...popoverTriggerList].map((popoverTriggerEl=>new Bootstrap.Popover(popoverTriggerEl,popoverConfig))),document.addEventListener("core/modal:bodyRendered",(e=>{[...e.target.querySelectorAll('[data-bs-toggle="popover"]')].map((popoverTriggerEl=>new Bootstrap.Popover(popoverTriggerEl,popoverConfig)))})),document.addEventListener("keydown",(e=>{const popoverTrigger=e.target.closest('[data-bs-toggle="popover"]');"Escape"===e.key&&popoverTrigger&&Bootstrap.Popover.getOrCreateInstance(popoverTrigger).hide(),"Enter"===e.key&&popoverTrigger&&Bootstrap.Popover.getOrCreateInstance(popoverTrigger).show()})),document.addEventListener("click",(e=>{const popoverTrigger=e.target.closest('[data-bs-toggle="popover"]');if(!popoverTrigger)return;const popover=Bootstrap.Popover.getOrCreateInstance(popoverTrigger);popover._isShown()||popover.show()}))})(),enableTooltips(),document.addEventListener(_events.eventTypes.filterContentUpdated,(e=>{e.detail.nodes.forEach((node=>{node instanceof HTMLElement&&enableTooltips(node)}))})),_eventHandler.default.off(document,"keydown.bs.dropdown.data-api",".dropdown-menu",Bootstrap.Dropdown.dataApiKeydownHandler),_eventHandler.default.on(document.body,"keydown.bs.dropdown.data-api",".dropdown-menu",Bootstrap.Dropdown.dataApiKeydownHandler),pendingPromise.resolve()}));
//# sourceMappingURL=loader.min.js.map
File diff suppressed because one or more lines are too long
+18 -2
View File
@@ -25,6 +25,7 @@
import * as Aria from './aria';
import * as Bootstrap from './index';
import Pending from 'core/pending';
import {eventTypes} from 'core_filters/events';
import {DefaultAllowlist} from './bootstrap/util/sanitizer';
import setupBootstrapPendingChecks from './pending';
import EventHandler from './bootstrap/dom/event-handler';
@@ -95,9 +96,10 @@ const enablePopovers = () => {
/**
* Enable tooltips
*
* @param {Element} rootElement
*/
const enableTooltips = () => {
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
const enableTooltips = (rootElement = document) => {
const tooltipTriggerList = rootElement.querySelectorAll('[data-bs-toggle="tooltip"]');
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new Bootstrap.Tooltip(tooltipTriggerEl));
document.addEventListener('keydown', e => {
@@ -109,6 +111,19 @@ const enableTooltips = () => {
});
};
/**
* Enable tooltips for dynamic content updates
*/
const enableTooltipsOnContentUpdated = () => {
document.addEventListener(eventTypes.filterContentUpdated, e => {
e.detail.nodes.forEach(node => {
if (node instanceof HTMLElement) {
enableTooltips(node);
}
});
});
};
/**
* Realocate Bootstrap events to the body element.
*
@@ -140,6 +155,7 @@ enablePopovers();
// Enable all tooltips.
enableTooltips();
enableTooltipsOnContentUpdated();
// Realocate Bootstrap events to the body element.
realocateBootstrapEvents();