mediawiki-skins-Vector/resources/skins.vector.js/portlets.js
Jon Robson 4cf50596bb Avoid nullish coalescing operators
Bug: T350519
Change-Id: If9a8a68aa9c6766b8cf9fb84ed526317d4d723ca
2023-11-06 11:10:44 -08:00

141 lines
4.4 KiB
JavaScript

const dropdownMenus = require( './dropdownMenus.js' );
/**
* An object containing the data to help create a portlet.
*
* @typedef {Object} Hint
* @property {string} type
*/
/**
* Creates default portlet.
*
* @param {Element} portlet
* @param {boolean} isDropdown
* @return {Element}
*/
function addDefaultPortlet( portlet, isDropdown ) {
const ul = portlet.querySelector( 'ul' );
if ( !ul ) {
return portlet;
}
ul.classList.add( 'vector-menu-content-list' );
const label = portlet.querySelector( 'label' );
if ( label ) {
const labelDiv = document.createElement( 'div' );
labelDiv.classList.add( 'vector-menu-heading' );
if ( !isDropdown ) {
labelDiv.innerHTML = label.textContent || '';
portlet.insertBefore( labelDiv, label );
label.remove();
}
}
let wrapper = portlet.querySelector( 'div:last-child' );
if ( wrapper ) {
ul.remove();
wrapper.appendChild( ul );
wrapper.classList.add( 'vector-menu-content' );
} else {
wrapper = document.createElement( 'div' );
wrapper.classList.add( 'vector-menu-content' );
ul.remove();
wrapper.appendChild( ul );
portlet.appendChild( wrapper );
}
portlet.classList.add( 'vector-menu' );
return portlet;
}
/**
* A hook handler for util.addPortlet hook.
* It creates a portlet based on the hint, and adabt it to vector skin.
*
* @param {Element} content
* @return {Element}
*/
function makeDropdown( content ) {
const id = content.id;
const label = content.querySelector( 'label' );
if ( !content.parentNode || !label ) {
return content;
}
label.id = `${id}-dropdown-label`;
label.setAttribute( 'for', `${id}-dropdown-checkbox` );
label.classList.add( 'vector-dropdown-label' );
label.setAttribute( 'aria-hidden', 'true' );
const labelSpan = document.createElement( 'span' );
labelSpan.textContent = label.textContent;
label.textContent = '';
labelSpan.classList.add( 'vector-dropdown-label-text' );
label.appendChild( labelSpan );
const dropdown = document.createElement( 'div' );
const checkbox = document.createElement( 'input' );
const dropdownContent = document.createElement( 'div' );
dropdownContent.classList.add( 'vector-dropdown-content' );
checkbox.type = 'checkbox';
checkbox.id = `${id}-dropdown-checkbox`;
checkbox.setAttribute( 'role', 'button' );
checkbox.setAttribute( 'aria-haspopup', 'true' );
checkbox.setAttribute( 'data-event-name', `ui.dropdown-${id}-dropdown` );
checkbox.classList.add( 'vector-dropdown-checkbox' );
checkbox.setAttribute( 'aria-label', label.textContent || '' );
dropdown.id = `${id}-dropdown`;
dropdown.classList.add( 'vector-dropdown', `${id}-dropdown` );
dropdown.appendChild( checkbox );
dropdown.appendChild( label );
dropdown.appendChild( dropdownContent );
content.parentNode.insertBefore( dropdown, content );
dropdownContent.appendChild( content );
dropdownMenus.dropdownMenus( [ dropdown ] );
return dropdown;
}
/**
* A hook handler for util.addPortlet hook.
* It creates a portlet based on the hint, and adapt it to vector skin.
* If #p-cactions is used, the new portlet will be converted into a dropdown.
*
* @param {Element} portlet
* @param {string|null} before
* @return {Element}
*/
function addPortletHandler( portlet, before ) {
const isDropdown = !!( before && before === '#p-cactions' );
portlet.classList.remove( 'mw-portlet-js' );
const transformedPortlet = addDefaultPortlet( portlet, isDropdown );
if ( isDropdown ) {
const pageToolsDropdown = document.querySelector( '#vector-page-tools-dropdown' );
const pageToolsMarker = pageToolsDropdown ? pageToolsDropdown.parentNode : null;
// Guard against unexpected changes to HTML.
if ( pageToolsMarker === null || !pageToolsMarker.parentNode ) {
throw new Error( 'Vector 2022 addPortletLink: No #vector-page-tools-dropdown element in the DOM.' );
}
const dropdown = makeDropdown( transformedPortlet );
pageToolsMarker.parentNode.insertBefore( dropdown, pageToolsMarker );
return transformedPortlet;
}
return transformedPortlet;
}
/**
*
* @return {{addPortletHandler: (function(Element, string): Element)}}
*/
function main() {
mw.hook( 'util.addPortlet' ).add( addPortletHandler );
// Update any portlets that were created prior to the hook being registered.
document.querySelectorAll( '.mw-portlet-js' ).forEach( ( node ) => {
const nextID = node && node.nextElementSibling && node.nextElementSibling.id;
addPortletHandler( node, nextID ? `#${nextID}` : null );
} );
return {
addPortletHandler
};
}
module.exports = {
main, addPortletHandler
};