mirror of
https://gerrit.wikimedia.org/r/mediawiki/skins/Vector.git
synced 2024-12-03 03:37:24 +00:00
97147857b2
* Removes server rendered vector-tab-noicon class from legacy Vector as it is not currently used. * Adds menuTabs.js responsible for adding the vector-tab-noicon class when menu items are added to tabbed menus. This is only used in vector-22. * Adds unit test Bug: T320691 Change-Id: Iffad86125f8754305f592ddc19d894866bd6dedc
151 lines
5.4 KiB
JavaScript
151 lines
5.4 KiB
JavaScript
var languageButton = require( './languageButton.js' ),
|
|
echo = require( './echo.js' ),
|
|
initSearchLoader = require( './searchLoader.js' ).initSearchLoader,
|
|
dropdownMenus = require( './dropdownMenus.js' ).dropdownMenus,
|
|
sidebarPersistence = require( './sidebarPersistence.js' ),
|
|
watchstar = require( './watchstar.js' ),
|
|
// @ts-ignore
|
|
menuTabs = require( './menuTabs.js' ),
|
|
checkbox = require( './checkbox.js' );
|
|
|
|
/**
|
|
* Wait for first paint before calling this function. That's its whole purpose.
|
|
*
|
|
* Some CSS animations and transitions are "disabled" by default as a workaround to this old Chrome
|
|
* bug, https://bugs.chromium.org/p/chromium/issues/detail?id=332189, which otherwise causes them to
|
|
* render in their terminal state on page load. By adding the `vector-animations-ready` class to the
|
|
* `html` root element **after** first paint, the animation selectors suddenly match causing the
|
|
* animations to become "enabled" when they will work properly. A similar pattern is used in Minerva
|
|
* (see T234570#5779890, T246419).
|
|
*
|
|
* Example usage in Less:
|
|
*
|
|
* ```less
|
|
* .foo {
|
|
* color: #f00;
|
|
* transform: translateX( -100% );
|
|
* }
|
|
*
|
|
* // This transition will be disabled initially for JavaScript users. It will never be enabled for
|
|
* // non-JavaScript users.
|
|
* .vector-animations-ready .foo {
|
|
* transition: transform 100ms ease-out;
|
|
* }
|
|
* ```
|
|
*
|
|
* @param {Document} document
|
|
* @return {void}
|
|
*/
|
|
function enableCssAnimations( document ) {
|
|
document.documentElement.classList.add( 'vector-animations-ready' );
|
|
}
|
|
|
|
/**
|
|
* In https://phabricator.wikimedia.org/T313409 #p-namespaces was renamed to #p-associatedPages
|
|
* This code maps items added by gadgets to the new menu.
|
|
* This code can be removed in MediaWiki 1.40.
|
|
*/
|
|
function addNamespacesGadgetSupport() {
|
|
// Set up hidden dummy portlet.
|
|
var dummyPortlet = document.createElement( 'div' );
|
|
dummyPortlet.setAttribute( 'id', 'p-namespaces' );
|
|
dummyPortlet.setAttribute( 'style', 'display: none;' );
|
|
dummyPortlet.appendChild( document.createElement( 'ul' ) );
|
|
document.body.appendChild( dummyPortlet );
|
|
mw.hook( 'util.addPortletLink' ).add( function ( /** @type {Element} */ node ) {
|
|
// If it was added to p-namespaces, show warning and move.
|
|
// eslint-disable-next-line no-jquery/no-global-selector
|
|
if ( $( '#p-namespaces' ).find( node ).length ) {
|
|
// eslint-disable-next-line no-jquery/no-global-selector
|
|
$( '#p-associated-pages ul' ).append( node );
|
|
// @ts-ignore
|
|
mw.log.warn( 'Please update call to mw.util.addPortletLink with ID p-namespaces. Use p-associatedPages instead.' );
|
|
// in case it was empty before:
|
|
mw.util.showPortlet( 'p-associated-pages' );
|
|
}
|
|
} );
|
|
}
|
|
|
|
/**
|
|
* @param {Window} window
|
|
* @return {void}
|
|
*/
|
|
function main( window ) {
|
|
enableCssAnimations( window.document );
|
|
sidebarPersistence.init();
|
|
checkbox.init( window.document );
|
|
initSearchLoader( document );
|
|
languageButton();
|
|
echo();
|
|
dropdownMenus();
|
|
// menuTabs should follow `dropdownMenus` as that can move menu items from a
|
|
// tab menu to a dropdown.
|
|
menuTabs();
|
|
addNamespacesGadgetSupport();
|
|
if ( document.body.classList.contains( 'vector-feature-visual-enhancement-next-enabled' ) ) {
|
|
watchstar();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {Window} window
|
|
* @return {void}
|
|
*/
|
|
function init( window ) {
|
|
var now = mw.now();
|
|
// This is the earliest time we can run JS for users (and bucket anonymous
|
|
// users for A/B tests).
|
|
// Where the browser supports it, for a 10% sample of users
|
|
// we record a value to give us a sense of the expected delay in running A/B tests or
|
|
// disabling JS features. This will inform us on various things including what to expect
|
|
// with regards to delay while running A/B tests to anonymous users.
|
|
// When EventLogging is not available this will reject.
|
|
// This code can be removed by the end of the Desktop improvements project.
|
|
// https://www.mediawiki.org/wiki/Desktop_improvements
|
|
mw.loader.using( 'ext.eventLogging' ).then( function () {
|
|
if (
|
|
mw.eventLog &&
|
|
mw.eventLog.eventInSample( 100 /* 1 in 100 */ ) &&
|
|
window.performance &&
|
|
window.performance.timing &&
|
|
window.performance.timing.navigationStart
|
|
) {
|
|
mw.track( 'timing.Vector.ready', now - window.performance.timing.navigationStart ); // milliseconds
|
|
}
|
|
} );
|
|
}
|
|
|
|
init( window );
|
|
|
|
/**
|
|
* Because stickyHeader.js clones the user menu, it must initialize before
|
|
* dropdownMenus.js initializes in order for the sticky header's user menu to
|
|
* bind the necessary checkboxHack event listeners. This is solved by using
|
|
* mw.loader.using to ensure that the skins.vector.es6 module initializes first
|
|
* followed by initializing this module. If the es6 module loading fails (which
|
|
* can happen in browsers that don't support es6), continue to initialize this
|
|
* module.
|
|
*/
|
|
function initAfterEs6Module() {
|
|
mw.loader.using( 'skins.vector.es6' ).then( function () {
|
|
// Loading of the 'skins.vector.es6' module has succeeded. Initialize the
|
|
// `skins.vector.es6` module first.
|
|
require( /** @type {string} */ ( 'skins.vector.es6' ) ).main();
|
|
// Initialize this module second.
|
|
main( window );
|
|
}, function () {
|
|
// Loading of the 'skins.vector.es6' has failed (e.g. this will fail in
|
|
// browsers that don't support ES6) so only initialize this module.
|
|
main( window );
|
|
} );
|
|
}
|
|
|
|
if ( document.readyState === 'interactive' || document.readyState === 'complete' ) {
|
|
initAfterEs6Module();
|
|
} else {
|
|
// This is needed when document.readyState === 'loading'.
|
|
document.addEventListener( 'DOMContentLoaded', function () {
|
|
initAfterEs6Module();
|
|
} );
|
|
}
|