mediawiki-skins-Vector/resources/skins.vector.js/dropdownMenus.js
Jon Robson 64df4fde20 Remove dancing tabs with CSS only solution
Remove JavaScript that collapses tabs and replace with an easier
to maintain breakpoint based solution.

Tabs will now collapse below the tablet breakpoint

Note: In the case of mw.util.addPortletLink, to add items to the
`views` menu, these will not be collapsed into the more menu and
must now be explicitly added to both menus, ie. if the window is
resized these will hide and not appear in the more menu.

However, when mw.util.addPortletLink attempts to add to `views` menu
when there is not available space, we will redirect those links to
the more (`cactions`) dropdown menu.

Bug: T306229
Change-Id: I34ace0aeb3e23d8f6a8c5a8680bb492f37e343ad
2022-04-28 17:57:10 +00:00

120 lines
3.9 KiB
JavaScript

/** @interface CheckboxHack */
var
checkboxHack = /** @type {CheckboxHack} */ require( /** @type {string} */( 'mediawiki.page.ready' ) ).checkboxHack,
CHECKBOX_HACK_CONTAINER_SELECTOR = '.vector-menu-dropdown',
CHECKBOX_HACK_CHECKBOX_SELECTOR = '.vector-menu-checkbox',
CHECKBOX_HACK_BUTTON_SELECTOR = '.vector-menu-heading',
CHECKBOX_HACK_TARGET_SELECTOR = '.vector-menu-content';
/**
* Add the ability for users to toggle dropdown menus using the enter key (as
* well as space) using core's checkboxHack.
*/
function bind() {
// Search for all dropdown containers using the CHECKBOX_HACK_CONTAINER_SELECTOR.
var containers = document.querySelectorAll( CHECKBOX_HACK_CONTAINER_SELECTOR );
Array.prototype.forEach.call( containers, function ( container ) {
var
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;
}
checkboxHack.bind( window, checkbox, button, target );
} );
}
/**
* T295085: Close all dropdown menus when page is unloaded to prevent them from
* being open when navigating back to a page.
*/
function bindCloseOnUnload() {
addEventListener( 'beforeunload', function () {
var checkboxes = document.querySelectorAll( CHECKBOX_HACK_CHECKBOX_SELECTOR + ':checked' );
Array.prototype.forEach.call( checkboxes, function ( checkbox ) {
/** @type {HTMLInputElement} */ ( checkbox ).checked = false;
} );
} );
}
/**
* Adds icon placeholder for gadgets to use.
*
* @typedef {Object} PortletLinkData
* @property {string|null} id
*/
/**
* @param {HTMLElement} item
* @param {PortletLinkData} data
*/
function addPortletLinkHandler( item, data ) {
var link = item.querySelector( 'a' );
var $menu = $( item ).parents( '.vector-menu' );
var menuElement = $menu.length && $menu.get( 0 ) || null;
// Dropdowns which have not got the noicon class are icon capable.
var isIconCapable = menuElement && menuElement.classList.contains(
'vector-menu-dropdown'
) && !menuElement.classList.contains(
'vector-menu-dropdown-noicon'
);
// The views menu has limited space so we need to decide whether there is space
// to accomodate the new item and if not to redirect to the more dropdown.
/* eslint-disable no-jquery/no-global-selector */
if ( $menu.prop( 'id' ) === 'p-views' ) {
// @ts-ignore if undefined as NaN will be ignored
var availableWidth = $( '.mw-article-toolbar-container' ).width() -
// @ts-ignore
$( '#p-namespaces' ).width() - $( '#p-variants' ).width() -
// @ts-ignore
$( '#p-views' ).width() - $( '#p-cactions' ).width();
var moreDropdown = document.querySelector( '#p-cactions ul' );
// If the screen width is less than 720px then the views menu is hidden
if ( moreDropdown && ( availableWidth < 0 || window.innerWidth < 720 ) ) {
moreDropdown.appendChild( item );
// reveal if hidden
mw.util.showPortlet( 'p-cactions' );
}
}
/* eslint-enable no-jquery/no-global-selector */
if ( isIconCapable && link ) {
// If class was previously added this will be a no-op so it is safe to call even
// if we've previously enhanced it.
link.classList.add(
'mw-ui-icon',
'mw-ui-icon-before'
);
if ( data.id ) {
// The following class allows gadgets developers to style or hide an icon.
// * mw-ui-icon-vector-gadget-<id>
// The class is considered stable and should not be removed without
// a #user-notice.
link.classList.add( 'mw-ui-icon-vector-gadget-' + data.id );
}
}
}
// Enhance previously added items.
Array.prototype.forEach.call(
document.querySelectorAll( '.mw-list-item-js' ),
function ( item ) {
addPortletLinkHandler( item, {
id: item.getAttribute( 'id' )
} );
}
);
mw.hook( 'util.addPortletLink' ).add( addPortletLinkHandler );
module.exports = function dropdownMenus() {
bind();
bindCloseOnUnload();
};