mediawiki-skins-Citizen/resources/skins.citizen.scripts/checkbox.js

101 lines
2.7 KiB
JavaScript

/**
* Extend core checkboxHacks
*
* @see https://github.com/wikimedia/Vector/blob/master/resources/skins.vector.js/checkbox.js
*/
const
checkboxHack = require( 'mediawiki.page.ready' ).checkboxHack,
CHECKBOX_HACK_CONTAINER_SELECTOR = '.citizen-menu-checkbox-container',
CHECKBOX_HACK_CHECKBOX_SELECTOR = '.citizen-menu-checkbox-checkbox',
CHECKBOX_HACK_BUTTON_SELECTOR = '.citizen-menu-checkbox-button',
CHECKBOX_HACK_TARGET_SELECTOR = '.citizen-menu-checkbox-target';
/**
* Set the checked state and fire the 'input' event.
* Copied from core as it is not accessible outside
*
* @param {HTMLInputElement} checkbox
* @param {boolean} checked
* @return {void}
* @ignore
*/
function setCheckedState( checkbox, checked ) {
/** @type {Event} @ignore */
checkbox.checked = checked;
// Chrome and Firefox sends the builtin Event with .bubbles == true and .composed == true.
let e;
if ( typeof Event === 'function' ) {
e = new Event( 'input', { bubbles: true, composed: true } );
}
checkbox.dispatchEvent( e );
}
/**
* Dismiss the target when ESCAPE is pressed.
*
* @param {Window} window
* @param {HTMLInputElement} checkbox
* @return {function(): void} Cleanup function that removes the added event listeners.
* @ignore
*/
function bindDismissOnEscape( window, checkbox ) {
const onKeyup = ( /** @type {KeyboardEvent} */ event ) => {
// Only handle ESCAPE
if ( event.key !== 'Escape' ) {
return;
}
setCheckedState( checkbox, false );
};
window.addEventListener( 'keyup', onKeyup, true );
return function () {
window.removeEventListener( 'keyup', onKeyup );
};
}
/**
* Close all menus through unchecking all checkbox hacks
*
* @return {void}
*/
function uncheckCheckboxHacks() {
const checkboxes = document.querySelectorAll( CHECKBOX_HACK_CHECKBOX_SELECTOR + ':checked' );
checkboxes.forEach( ( checkbox ) => {
setCheckedState( checkbox, false );
} );
}
/**
* Enhance dropdownMenu functionality and accessibility using core's checkboxHack.
* Based on Vector
*
* @return {void}
*/
function bind() {
// Search for all dropdown containers using the CHECKBOX_HACK_CONTAINER_SELECTOR.
const containers = document.querySelectorAll( CHECKBOX_HACK_CONTAINER_SELECTOR );
containers.forEach( ( container ) => {
const
checkbox = container.querySelector( CHECKBOX_HACK_CHECKBOX_SELECTOR ),
button = container.querySelector( CHECKBOX_HACK_BUTTON_SELECTOR ),
target = container.querySelector( CHECKBOX_HACK_TARGET_SELECTOR );
if ( !( checkbox && button && target ) ) {
return;
}
// Core CheckboxHack
checkboxHack.bind( window, checkbox, button, target );
// Citizen CheckboxHack
bindDismissOnEscape( window, checkbox );
} );
}
module.exports = {
bind: bind,
uncheckCheckboxHacks: uncheckCheckboxHacks
};