mirror of
https://gerrit.wikimedia.org/r/mediawiki/skins/MinervaNeue
synced 2024-12-24 19:43:28 +00:00
842a91590a
* eslint-config-wikimedia: 0.27.0 → 0.28.2 The following rules are failing and were disabled: * tests/selenium: * implicit-arrow-linebreak * no-mixed-spaces-and-tabs * grunt-banana-checker: 0.11.1 → 0.13.0 * stylelint-config-wikimedia: 0.16.1 → 0.17.2 The following rules no longer exist and were removed: * stylistic/selector-list-comma-newline-after * braces: 3.0.2 → 3.0.3 * https://github.com/advisories/GHSA-grv7-fg5c-xmjg Change-Id: Ia94454c1da778f241085714e1601a0233d547570
230 lines
6.6 KiB
JavaScript
230 lines
6.6 KiB
JavaScript
/**
|
|
* @typedef PageIssue
|
|
* @ignore
|
|
* @property {string} severity A SEVERITY_LEVEL key.
|
|
* @property {boolean} grouped True if part of a group of multiple issues, false if singular.
|
|
* @property {Icon} icon
|
|
*/
|
|
/**
|
|
* @typedef {Object} IssueSummary
|
|
* @ignore
|
|
* @property {PageIssue} issue
|
|
* @property {jQuery} $el where the issue was extracted from
|
|
* @property {string} iconString a string representation of icon.
|
|
* This is kept for template compatibility (our views do not yet support composition).
|
|
* @property {string} text HTML string.
|
|
*/
|
|
|
|
// Icons are matching the type selector below use a TYPE_* icon. When unmatched, the icon is
|
|
// chosen by severity. Their color is always determined by severity, too.
|
|
const ICON_NAME = {
|
|
// Generic severity icons.
|
|
SEVERITY: {
|
|
DEFAULT: 'issue-generic',
|
|
LOW: 'issue-severity-low',
|
|
MEDIUM: 'issue-severity-medium',
|
|
HIGH: 'issue-generic'
|
|
},
|
|
|
|
// Icons customized by type.
|
|
TYPE: {
|
|
MOVE: 'issue-type-move',
|
|
POINT_OF_VIEW: 'issue-type-point-of-view'
|
|
}
|
|
};
|
|
const ICON_COLOR = {
|
|
DEFAULT: 'defaultColor',
|
|
LOW: 'lowColor',
|
|
MEDIUM: 'mediumColor',
|
|
HIGH: 'highColor'
|
|
};
|
|
// How severities order and compare from least to greatest. For the multiple issues
|
|
// template, severity should be considered the maximum of all its contained issues.
|
|
const SEVERITY_LEVEL = {
|
|
DEFAULT: 0,
|
|
LOW: 1,
|
|
MEDIUM: 2,
|
|
HIGH: 3
|
|
};
|
|
// Match the template's color CSS selector to a severity level concept. Derived via the
|
|
// Ambox templates and sub-templates for the top five wikis and tested on page issues
|
|
// inventory:
|
|
// - https://people.wikimedia.org/~jdrewniak/page_issues_inventory
|
|
// - https://en.wikipedia.org/wiki/Template:Ambox
|
|
// - https://es.wikipedia.org/wiki/Plantilla:Metaplantilla_de_avisos
|
|
// - https://ja.wikipedia.org/wiki/Template:Ambox
|
|
// - https://ru.wikipedia.org/wiki/Шаблон:Ambox
|
|
// - https://it.wikipedia.org/wiki/Template:Avviso
|
|
// Severity is the class associated with the color. The ResourceLoader config mimics the
|
|
// idea by using severity for color variants. Severity is determined independently of icons.
|
|
// These selectors should be migrated to their templates.
|
|
const SEVERITY_REGEX = {
|
|
// recommended (T206177), en, it
|
|
LOW: /mobile-issue-severity-low|ambox-style|avviso-stile/,
|
|
// recommended, en, it
|
|
MEDIUM: /mobile-issue-severity-medium|ambox-content|avviso-contenuto/,
|
|
// recommended, en, en, es / ru, it
|
|
HIGH: /mobile-issue-severity-high|ambox-speedy|ambox-delete|ambox-serious|avviso-importante/
|
|
// ..And everything else that doesn't match should be considered DEFAULT.
|
|
};
|
|
// As above but used to identify specific templates requiring icon customization.
|
|
const TYPE_REGEX = {
|
|
// recommended (opt-in) / en, es / ru, it (long term only recommended should be used)
|
|
MOVE: /mobile-issue-move|ambox-converted|ambox-move|ambox-merge|avviso-struttura/,
|
|
|
|
POINT_OF_VIEW: new RegExp( [
|
|
// recommended (opt-in)
|
|
'mobile-issue-pov',
|
|
// FIXME: en classes: plan to remove these provided can get adoption of recommended
|
|
'ambox-Advert',
|
|
'ambox-autobiography',
|
|
'ambox-believerpov',
|
|
'ambox-COI',
|
|
'ambox-coverage',
|
|
'ambox-criticism',
|
|
'ambox-fanpov',
|
|
'ambox-fringe-theories',
|
|
'ambox-geographical-imbalance',
|
|
'ambox-globalize',
|
|
'ambox-npov-language',
|
|
'ambox-POV',
|
|
'ambox-pseudo',
|
|
'ambox-systemic-bias',
|
|
'ambox-unbalanced',
|
|
'ambox-usgovtpov'
|
|
].join( '|' ) )
|
|
// ..And everything else that doesn't match is mapped to a "SEVERITY" type.
|
|
};
|
|
const GROUPED_PARENT_REGEX = /mw-collapsible-content/;
|
|
// Variants supported by specific types. The "severity icon" supports all severities but the
|
|
// type icons only support one each by ResourceLoader.
|
|
const TYPE_SEVERITY = {
|
|
MOVE: 'DEFAULT',
|
|
POINT_OF_VIEW: 'MEDIUM'
|
|
};
|
|
|
|
/**
|
|
* @param {Element} box
|
|
* @return {string} An SEVERITY_SELECTOR key.
|
|
* @private
|
|
*/
|
|
function parseSeverity( box ) {
|
|
let severity;
|
|
const identified = Object.keys( SEVERITY_REGEX ).some( ( key ) => {
|
|
const regex = SEVERITY_REGEX[ key ];
|
|
severity = key;
|
|
return regex.test( box.className );
|
|
} );
|
|
return identified ? severity : 'DEFAULT';
|
|
}
|
|
|
|
/**
|
|
* @param {Element} box
|
|
* @param {string} severity An SEVERITY_LEVEL key.
|
|
* @return {{name: string, severity: string}} An ICON_NAME.
|
|
* @private
|
|
*/
|
|
function parseType( box, severity ) {
|
|
let identifiedType;
|
|
const identified = Object.keys( TYPE_REGEX ).some( ( type ) => {
|
|
const regex = TYPE_REGEX[ type ];
|
|
identifiedType = type;
|
|
return regex.test( box.className );
|
|
} );
|
|
return {
|
|
name: identified ? ICON_NAME.TYPE[ identifiedType ] : ICON_NAME.SEVERITY[ severity ],
|
|
severity: identified ? TYPE_SEVERITY[ identifiedType ] : severity
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @param {Element} box
|
|
* @return {boolean} True if part of a group of multiple issues, false if singular.
|
|
* @private
|
|
*/
|
|
function parseGroup( box ) {
|
|
return !!box.parentNode && GROUPED_PARENT_REGEX.test( box.parentNode.className );
|
|
}
|
|
|
|
/**
|
|
* @ignore
|
|
* @param {Element} box
|
|
* @param {string} severity An SEVERITY_LEVEL key.
|
|
* @return {string} A severity or type ISSUE_ICON.
|
|
*/
|
|
function iconName( box, severity ) {
|
|
const nameSeverity = parseType( box, severity );
|
|
// The icon with color variant as expected by ResourceLoader,
|
|
// {iconName}-{severityColorVariant}.
|
|
return nameSeverity.name + '-' + ICON_COLOR[ nameSeverity.severity ];
|
|
}
|
|
|
|
/**
|
|
* @ignore
|
|
* @param {string[]} severityLevels an array of SEVERITY_KEY values.
|
|
* @return {string} The greatest SEVERITY_LEVEL key.
|
|
*/
|
|
function maxSeverity( severityLevels ) {
|
|
return severityLevels.reduce( ( max, severity ) => SEVERITY_LEVEL[ max ] > SEVERITY_LEVEL[ severity ] ? max : severity, 'DEFAULT' );
|
|
}
|
|
|
|
/**
|
|
* @ignore
|
|
* @param {Element} box
|
|
* @return {PageIssue}
|
|
*/
|
|
function parse( box ) {
|
|
const severity = parseSeverity( box );
|
|
const iconElement = document.createElement( 'div' );
|
|
iconElement.classList.add( `minerva-icon--${ iconName( box, severity ) }`, 'minerva-ambox-icon' );
|
|
return {
|
|
severity,
|
|
grouped: parseGroup( box ),
|
|
iconElement
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Extract a summary message from a cleanup template generated element that is
|
|
* friendly for mobile display.
|
|
*
|
|
* @ignore
|
|
* @param {Object} $box element to extract the message from
|
|
* @return {IssueSummary}
|
|
*/
|
|
function extract( $box ) {
|
|
const SELECTOR = '.mbox-text, .ambox-text';
|
|
const $container = $( '<div>' );
|
|
|
|
$box.find( SELECTOR ).each( ( _i, el ) => {
|
|
const $el = $( el );
|
|
// Clean up talk page boxes
|
|
$el.find( 'table, .noprint' ).remove();
|
|
const contents = $el.html();
|
|
|
|
if ( contents ) {
|
|
$( '<p>' ).html( contents ).appendTo( $container );
|
|
}
|
|
} );
|
|
|
|
const pageIssue = parse( $box.get( 0 ) );
|
|
|
|
return {
|
|
issue: pageIssue,
|
|
$el: $box,
|
|
text: $container.html()
|
|
};
|
|
}
|
|
|
|
module.exports = {
|
|
extract,
|
|
parse,
|
|
maxSeverity,
|
|
iconName,
|
|
test: {
|
|
parseSeverity,
|
|
parseType,
|
|
parseGroup
|
|
}
|
|
};
|