mirror of
https://gerrit.wikimedia.org/r/mediawiki/skins/Vector.git
synced 2024-11-05 14:22:56 +00:00
9b2bcbbcae
requestAnimationFrame (rAF) is called before styles are computed. Performing a style read there can require a forced style recalcution which interrupts the browser's natural rendering life cycle. To gracefully observe layout of the page without inducing the cost to render it, it should be accessed after rendering. A suitable API to schedule time there is requestIdleCallback. In any event, if the code that needs this measurement executes very early for some reason, it is still computed on-demand which means it can't cause any functional regression. Change-Id: I0d8d3a0b158fa3d9e0895760d0691757f918d91d
97 lines
3.1 KiB
JavaScript
97 lines
3.1 KiB
JavaScript
/**
|
|
* Vector-specific scripts
|
|
*/
|
|
/* eslint-disable no-jquery/no-global-selector */
|
|
$( function () {
|
|
|
|
/**
|
|
* Collapsible tabs
|
|
*/
|
|
var $cactions = $( '#p-cactions' ),
|
|
$tabContainer = $( '#p-views ul' ),
|
|
// Avoid forced style calculation during page load
|
|
initialCactionsWidth = function () {
|
|
var width = $cactions.width();
|
|
initialCactionsWidth = function () {
|
|
return width;
|
|
};
|
|
return width;
|
|
};
|
|
|
|
mw.requestIdleCallback( initialCactionsWidth );
|
|
|
|
/**
|
|
* Focus search input at the very end
|
|
*/
|
|
$( '#searchInput' ).attr( 'tabindex', $( document ).lastTabIndex() + 1 );
|
|
|
|
// Bind callback functions to animate our drop down menu in and out
|
|
// and then call the collapsibleTabs function on the menu
|
|
$tabContainer
|
|
.on( 'beforeTabCollapse', function () {
|
|
// If the dropdown was hidden, show it
|
|
if ( $cactions.hasClass( 'emptyPortlet' ) ) {
|
|
$cactions.removeClass( 'emptyPortlet' );
|
|
// eslint-disable-next-line no-jquery/no-animate
|
|
$cactions.find( 'h3' )
|
|
.css( 'width', '1px' )
|
|
.animate( { width: initialCactionsWidth() }, 'normal' );
|
|
}
|
|
} )
|
|
.on( 'beforeTabExpand', function () {
|
|
// If we're removing the last child node right now, hide the dropdown
|
|
if ( $cactions.find( 'li' ).length === 1 ) {
|
|
// eslint-disable-next-line no-jquery/no-animate
|
|
$cactions.find( 'h3' ).animate( { width: '1px' }, 'normal', function () {
|
|
$( this ).attr( 'style', '' )
|
|
.parent().addClass( 'emptyPortlet' );
|
|
} );
|
|
}
|
|
} )
|
|
.collapsibleTabs( {
|
|
expandCondition: function ( eleWidth ) {
|
|
// This looks a bit awkward because we're doing expensive queries as late
|
|
// as possible.
|
|
var distance = $.collapsibleTabs.calculateTabDistance();
|
|
// If there are at least eleWidth + 1 pixels of free space, expand.
|
|
// We add 1 because .width() will truncate fractional values but .offset() will not.
|
|
if ( distance >= eleWidth + 1 ) {
|
|
return true;
|
|
} else {
|
|
// Maybe we can still expand? Account for the width of the "Actions" dropdown
|
|
// if the expansion would hide it.
|
|
if ( $cactions.find( 'li' ).length === 1 ) {
|
|
return distance >= eleWidth + 1 - initialCactionsWidth();
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
},
|
|
collapseCondition: function () {
|
|
var collapsibleWidth = 0;
|
|
|
|
// This looks a bit awkward because we're doing expensive queries as late
|
|
// as possible.
|
|
// TODO: The dropdown itself should probably "fold" to just the down-arrow
|
|
// (hiding the text) if it can't fit on the line?
|
|
|
|
// Never collapse if there is no overlap.
|
|
if ( $.collapsibleTabs.calculateTabDistance() >= 0 ) {
|
|
return false;
|
|
}
|
|
|
|
// Always collapse if the "More" button is already shown.
|
|
if ( !$cactions.hasClass( 'emptyPortlet' ) ) {
|
|
return true;
|
|
}
|
|
|
|
$tabContainer.children( 'li.collapsible' ).each( function ( index, element ) {
|
|
collapsibleWidth += $( element ).width();
|
|
// Stop this possibly expensive loop the moment the condition is met.
|
|
return !( collapsibleWidth > initialCactionsWidth() );
|
|
} );
|
|
return collapsibleWidth > initialCactionsWidth();
|
|
}
|
|
} );
|
|
} );
|