mirror of
https://gerrit.wikimedia.org/r/mediawiki/skins/MinervaNeue
synced 2024-12-01 09:16:34 +00:00
edb4385345
A list that toggles visibility via the checkbox hack is needed in at least two spots: the page actions overflow menu and the user menu. This patch makes several refactors to turn what was previously hardcoded into page actions a reusable component: - Start a new components directory. Components are reusable and composable. The subdirectories are organized by function, not ResourceLoader module bundling which greatly improves the ability to see a component's full functionality in one directory instead of examining the entire codebase. See updates to README. - Extract pageactions.less into: - ToggleList.less: LESS for any checkbox hack list. - DropDownList.less: LESS for lists that open downwards. - MenuListItem.less: LESS for list items of menus. The division makes it easier to see concerns, dependencies, and change code. - Move pageActionMenu.mustache to a component and extract ToggleList template. - Extract ToggleList.js from Toolbar.js. Bug: T214540 Change-Id: I171831469a6733c458bc5c7ba249a5096ca975b8
165 lines
4.6 KiB
JavaScript
165 lines
4.6 KiB
JavaScript
( function ( M, track, msg ) {
|
|
var MAX_PRINT_TIMEOUT = 3000,
|
|
mobile = M.require( 'mobile.startup' ),
|
|
Icon = mobile.Icon,
|
|
icons = mobile.icons,
|
|
lazyImageLoader = mobile.lazyImages.lazyImageLoader,
|
|
browser = mobile.Browser.getSingleton(),
|
|
GLYPH = 'download';
|
|
|
|
/**
|
|
* Helper function to retrieve the Android version
|
|
* @ignore
|
|
* @param {string} userAgent User Agent
|
|
* @return {number|false} An integer.
|
|
*/
|
|
function getAndroidVersion( userAgent ) {
|
|
var match = userAgent.toLowerCase().match( /android\s(\d\.]*)/ );
|
|
return match ? parseInt( match[ 1 ] ) : false;
|
|
}
|
|
|
|
/**
|
|
* Helper function to retrieve the Chrome/Chromium version
|
|
* @ignore
|
|
* @param {string} userAgent User Agent
|
|
* @return {number|false} An integer.
|
|
*/
|
|
function getChromeVersion( userAgent ) {
|
|
var match = userAgent.toLowerCase().match( /chrom(e|ium)\/(\d+)\./ );
|
|
return match ? parseInt( match[ 2 ] ) : false;
|
|
}
|
|
|
|
/**
|
|
* Checks whether DownloadIcon is available for given user agent
|
|
*
|
|
* @memberof DownloadIcon
|
|
* @instance
|
|
* @param {Window} windowObj
|
|
* @param {Page} page to download
|
|
* @param {string} userAgent User agent
|
|
* @param {number[]} supportedNamespaces where printing is possible
|
|
* @return {boolean}
|
|
*/
|
|
function isAvailable( windowObj, page, userAgent, supportedNamespaces ) {
|
|
var androidVersion = getAndroidVersion( userAgent ),
|
|
chromeVersion = getChromeVersion( userAgent );
|
|
|
|
// Download button is restricted to certain namespaces T181152.
|
|
// Defaults to 0, in case cached JS has been served.
|
|
if ( supportedNamespaces.indexOf( page.getNamespaceId() ) === -1 ||
|
|
page.isMainPage() ) {
|
|
// namespace is not supported or it's a main page
|
|
return false;
|
|
}
|
|
|
|
if ( browser.isIos() || chromeVersion === false ||
|
|
windowObj.chrome === undefined
|
|
) {
|
|
// we support only chrome/chromium on desktop/android
|
|
return false;
|
|
}
|
|
if ( ( androidVersion && androidVersion < 5 ) || chromeVersion < 41 ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
/**
|
|
* onClick handler for button that invokes print function
|
|
* @param {Icon} icon
|
|
* @param {Icon} spinner
|
|
*/
|
|
function onClick( icon, spinner ) {
|
|
function doPrint() {
|
|
icon.timeout = clearTimeout( icon.timeout );
|
|
track( 'minerva.downloadAsPDF', {
|
|
action: 'callPrint'
|
|
} );
|
|
window.print();
|
|
icon.$el.show();
|
|
spinner.$el.hide();
|
|
}
|
|
|
|
function doPrintBeforeTimeout() {
|
|
if ( icon.timeout ) {
|
|
doPrint();
|
|
}
|
|
}
|
|
// The click handler may be invoked multiple times so if a pending print is occurring
|
|
// do nothing.
|
|
if ( !icon.timeout ) {
|
|
track( 'minerva.downloadAsPDF', {
|
|
action: 'fetchImages'
|
|
} );
|
|
icon.$el.hide();
|
|
spinner.$el.show();
|
|
// If all image downloads are taking longer to load then the MAX_PRINT_TIMEOUT
|
|
// abort the spinner and print regardless.
|
|
icon.timeout = setTimeout( doPrint, MAX_PRINT_TIMEOUT );
|
|
lazyImageLoader.loadImages( lazyImageLoader.queryPlaceholders( document.getElementById( 'content' ) ) )
|
|
.then( doPrintBeforeTimeout, doPrintBeforeTimeout );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets a click handler for the download icon
|
|
* Expects to be run in the context of an icon using `Function.bind`
|
|
*
|
|
* @param {Icon} spinner
|
|
* @returns {function}
|
|
*/
|
|
function getOnClickHandler( spinner ) {
|
|
return function () {
|
|
onClick( this, spinner );
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generate a download icon for triggering print functionality if
|
|
* printing is available
|
|
*
|
|
* @param {Skin} skin
|
|
* @param {number[]} supportedNamespaces
|
|
* @param {Window} [windowObj] window object
|
|
* @param {boolean} [hasText] Use icon + button style.
|
|
* @returns {jQuery.Object|null}
|
|
*/
|
|
function downloadPageAction( skin, supportedNamespaces, windowObj, hasText ) {
|
|
var
|
|
modifier = hasText ? 'toggle-list-item__anchor--menu' : 'mw-ui-icon-element',
|
|
icon,
|
|
spinner = icons.spinner( {
|
|
hasText: hasText,
|
|
modifier: modifier
|
|
} );
|
|
|
|
if (
|
|
isAvailable(
|
|
windowObj, skin.page, navigator.userAgent,
|
|
supportedNamespaces
|
|
)
|
|
) {
|
|
icon = new Icon( {
|
|
glyphPrefix: 'minerva',
|
|
title: msg( 'minerva-download' ),
|
|
name: GLYPH,
|
|
tagName: 'button',
|
|
events: {
|
|
// will be bound to `this`
|
|
click: getOnClickHandler( spinner )
|
|
},
|
|
hasText: hasText,
|
|
label: hasText ? mw.msg( 'minerva-download' ) : '',
|
|
modifier: modifier
|
|
} );
|
|
|
|
return $( '<li>' ).addClass( 'page-actions-menu__list-item' ).append( icon.$el ).append( spinner.$el.hide() );
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
M.define( 'skins.minerva.scripts/test/getOnClickHandler', getOnClickHandler );
|
|
M.define( 'skins.minerva.scripts/test/isAvailable', isAvailable );
|
|
M.define( 'skins.minerva.scripts/downloadPageAction', downloadPageAction );
|
|
}( mw.mobileFrontend, mw.track, mw.msg ) );
|