User:Dlrohrer2003/portlet-toggle.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/* Collapsible Portlets
 * =============================================================================
 * Description: Toggles the visibility of portlets by clicking on each portlet's
 *              header.
 *      Author: [[User:Dlrohrer2003]]
 *     License: GNU-GPL v2 or higher
 */


// The style sheet for this script
mw.loader.load( '//en.wikipedia.org/w/index.php?title=User:Dlrohrer2003/portlet-toggle.css&action=raw&ctype=text/css', 'text/css' );

mw.loader.using( [ 'mediawiki.cookie' ], function () {
	'use strict';

	const cookiePrefix = mw.config.get( 'skin' ) + '-nav-';
	const portletHeaderSelectors = 'h3';
	const portletBodySelectors = 'div, ul';
	const portletCollapsedClass = 'collapsible-portlet-collapsed';

	let tabIndex = Array
		.from( document.querySelectorAll( '[tabindex]' ), element => +element.tabIndex )
		.reduce( ( a, b ) => Math.max( a, b ), 0 ) + 1;

	document
		.querySelectorAll( '#searchInput, .searchButton' )
		.forEach( element => element.tabIndex = tabIndex++ );


	function portletToggleHandler( event ) {

		// Left click (usually), Middle click, Enter, or Space
		if ( event.button === 0 || event.button === 1 || event.key === 'Enter' || event.key === ' ' ) {

			const portlet = event.currentTarget.parentNode;

			// Toggle the portlet's visibility class.
			portlet.classList.toggle( portletCollapsedClass );

			// Set the cookie to the state the portlet has been set to
			mw.cookie.set(
				portlet.id,
				!portlet.classList.contains( portletCollapsedClass ),
				{ prefix: cookiePrefix, sameSite: 'Strict' }
			);
		}
		if ( event.key !== 'Tab' ) {
			event.preventDefault();
		}
	}


	function makeCollapsible( portlet ) {

		const portletHeader = portlet.querySelector( portletHeaderSelectors );
		const portletBody = portlet.querySelector( portletBodySelectors );

		portletHeader.classList.add( 'collapsible-portlet-header' );
		portletHeader.tabIndex = tabIndex++;

		portletHeader.addEventListener( 'keydown', portletToggleHandler );
		portletHeader.addEventListener( 'mousedown', portletToggleHandler );

		portletBody.classList.add( 'collapsible-portlet-body' );

		// Set the initial class of the portlet based on the cookie
		if ( mw.cookie.get( portlet.id, cookiePrefix ) === 'false' ) {
			portlet.classList.add( portletCollapsedClass );
		}
	}

	document
		.querySelectorAll( '#mw_portlets, #quickbar, #mw-panel, #sidebar, .sidebar-inner' )
		.forEach( portletContainer => {

			portletContainer.classList.add( 'collapsible-portlet-container' );

			Array
				.from( portletContainer.querySelectorAll( '.mw-portlet:not( #p-search )' ) )
				.filter( element => element.querySelector( portletHeaderSelectors ) )
				.forEach( makeCollapsible );
		 });
});