const
CANCEL_GLYPH = 'close',
Icon = require( './Icon' ),
IconButton = require( './IconButton' );
/**
* A set of shared icons.
*
* Factory methods are used to keep separate features that use the same icons
* from accidentally manipulating one another's DOM when calling methods like
* `remove`.
*
* @class icons
* @singleton
* @uses Icon
*/
const icons = {
CANCEL_GLYPH,
// Exported to support testing and stubbing
Icon,
IconButton,
/**
* Gets a back icon
*
* The icon should be used to inform the user that the front-end is
* communicating with the back-end.
*
* @memberof icons
* @instance
* @return {IconButton}
*/
back() {
return new icons.IconButton( {
tagName: 'button',
icon: 'previous',
additionalClassNames: 'back',
label: mw.msg( 'mobile-frontend-overlay-close' )
} );
},
/**
* Gets a cancel icon
*
* The icon should be used to inform the user that the front-end is
* communicating with the back-end.
*
* @memberof icons
* @instance
* @param {string} [variant]
* @param {Object} [props] to extend
* @return {IconButton}
*/
cancel( variant, props = {} ) {
const glyph = variant ? `${ CANCEL_GLYPH }-${ variant }` : `${ CANCEL_GLYPH }`;
props.additionalClassNames = props.additionalClassNames || '';
props.additionalClassNames += ' cancel';
return new icons.IconButton( Object.assign( {
tagName: 'button',
icon: glyph,
label: mw.msg( 'mobile-frontend-overlay-close' )
}, props ) );
},
/**
* Gets a spinner icon. This uses IconButton but should never actually
* be a button or have full button styles, as its purely presentational
*
* The icon should be used to inform the user that the front-end is
* communicating with the back-end.
*
* @memberof icons
* @instance
* @param {Object} [props] See `Icon` for more details
* @return {IconButton}
*/
spinner( props = {} ) {
if ( props.additionalClassNames === undefined ) {
props.additionalClassNames = 'spinner loading';
}
const spinner = new icons.IconButton( Object.assign( {
tagName: 'span',
icon: 'spinner',
label: mw.msg( 'mobile-frontend-loading-message' )
}, props ) );
// Update the element to not use button classes or attributes
spinner.$el.removeClass();
// eslint-disable-next-line mediawiki/class-doc
spinner.$el.addClass( props.additionalClassNames );
spinner.$el.attr( 'type', '' );
if ( spinner.options.isIconOnly ) {
spinner.$el.addClass( 'mf-spinner-icon-element' );
}
return spinner;
},
/**
* Gets a failure (error) icon
*
* @memberof icons
* @instance
* @return {IconButton}
*/
error() {
return new icons.IconButton( {
icon: 'alert-invert',
additionalClassNames: 'load-fail-msg-icon'
} );
},
/**
* Gets a non-filled watch star icon.
*
* @memberof icons
* @instance
* @param {Object} props
* @return {IconButton}
*/
watch( props = {} ) {
props.additionalClassNames = props.additionalClassNames || '';
props.additionalClassNames += ' watch-this-article';
return new icons.IconButton( Object.assign( {
icon: 'star-subtle'
}, props ) );
},
/**
* Gets a filled watch star icon.
*
* @memberof icons
* @instance
* @param {Object} props
* @return {IconButton}
*/
watched( props = {} ) {
props.additionalClassNames = props.additionalClassNames || '';
props.additionalClassNames += ' watch-this-article watched';
return new icons.IconButton( Object.assign( {
icon: 'unStar-progressive'
}, props ) );
}
};
module.exports = icons;