Update: page issue icons

- Fix a bug where the all issues endpoint would incorrectly collect
  issues from all sections.

- Update the page issue iconography. This increases the size of the
  delivered code and images by 1743 B minified uncompressed according to
  mw.inspect() (from 16.4 KiB to 18.1 KiB).

- Add support for identifying page issue severity based on template CSS
  classes.

- For multiple issues templates, show the highest priority icon.

Bug: T191528
Change-Id: Ie0a4c83ec7cfb856ec581d058797109746e3cb99
This commit is contained in:
Stephen Niedzielski 2018-07-10 15:06:51 -05:00
parent 99bc9d8c55
commit d2f6c38fe7
23 changed files with 364 additions and 121 deletions

View File

@ -82,12 +82,12 @@ class MinervaHooks {
'targets' => [ 'mobile', 'desktop' ],
'scripts' => [
// additional scaffolding (minus initialisation scripts)
'resources/skins.minerva.scripts/utils.js',
'resources/skins.minerva.scripts/pageIssueParser.js',
'resources/skins.minerva.scripts/DownloadIcon.js',
'resources/skins.minerva.scripts/AB.js',
// test files
'tests/qunit/skins.minerva.scripts/test_DownloadIcon.js',
'tests/qunit/skins.minerva.scripts/test_utils.js',
'tests/qunit/skins.minerva.scripts/test_pageIssueParser.js',
'tests/qunit/skins.minerva.scripts/test_AB.js',
'tests/qunit/skins.minerva.notifications.badge/test_NotificationBadge.js'
],

View File

@ -84,6 +84,10 @@ table.ambox {
left: -8px;
}
.mw-ui-icon:before {
.background-size(75%, auto);
}
.ambox-learn-more {
color: @linkColor;
display: inline-block;

View File

Before

Width:  |  Height:  |  Size: 335 B

After

Width:  |  Height:  |  Size: 335 B

View File

Before

Width:  |  Height:  |  Size: 448 B

After

Width:  |  Height:  |  Size: 448 B

View File

@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><title>ambox-content</title><g id="ambox-content" fill="none" fill-rule="evenodd"><path d="M10 0C4.477 0 0 4.477 0 10s4.477 10 10 10 10-4.477 10-10S15.523 0 10 0zm1 16H9v-2h2v2zm0-4H9V4h2v8z" id="Page-1" fill="#FF5D01"/></g></svg>

Before

Width:  |  Height:  |  Size: 328 B

View File

@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><title>ambox-default</title><g id="ambox-default" fill="none" fill-rule="evenodd"><path d="M19.638 17.36L11.528 3.3a1.85 1.85 0 0 0-1.53-1.09 1.85 1.85 0 0 0-1.52 1.09L.358 17.36C-.482 18.81.208 20 1.878 20h16.24c1.67 0 2.36-1.19 1.52-2.64zm-8.64-.36h-2v-2h2v2zm0-4h-2V7h2v6z" id="Page-1" fill="#54595D"/></g></svg>

Before

Width:  |  Height:  |  Size: 413 B

View File

@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><title>ambox-speedy</title><g id="ambox-speedy" fill="none" fill-rule="evenodd"><path d="M19.638 17.36L11.528 3.3a1.85 1.85 0 0 0-1.53-1.09 1.85 1.85 0 0 0-1.52 1.09L.358 17.36C-.482 18.81.208 20 1.878 20h16.24c1.67 0 2.36-1.19 1.52-2.64zm-8.64-.36h-2v-2h2v2zm0-4h-2V7h2v6z" id="Page-1" fill="#D33"/></g></svg>

Before

Width:  |  Height:  |  Size: 408 B

View File

@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><title>ambox-move</title><g id="ambox-move" fill="none" fill-rule="evenodd"><path id="left" fill="#36C" d="M18 13H8V9l-6 5 6 5v-4h10z"/><path id="left-copy" fill="#D33" transform="rotate(-180 10 6)" d="M18 5H8V1L2 6l6 5V7h10z"/></g></svg>

Before

Width:  |  Height:  |  Size: 336 B

View File

@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><title>ambox-content.ambox-pov</title><g id="ambox-content.ambox-pov" fill="none" fill-rule="evenodd"><path d="M5 9L1 4h8L5 9zm-2.659 5.251l-.592-1.91 16.41-5.092.592 1.91-16.41 5.092zM15 12l4 5h-8l4-5z" id="Combined-Shape" fill="#54595D"/></g></svg>

Before

Width:  |  Height:  |  Size: 348 B

View File

@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><title>ambox-protection</title><g id="ambox-protection" fill="none" fill-rule="evenodd"><path d="M16.07 8H15V5s0-5-5-5-5 5-5 5v3H3.93A1.93 1.93 0 0 0 2 9.93v8.15A1.93 1.93 0 0 0 3.93 20h12.14A1.93 1.93 0 0 0 18 18.07V9.93A1.93 1.93 0 0 0 16.07 8zM10 16a2 2 0 1 1 0-4 2 2 0 0 1 0 4zm3-8H7V5.5C7 4 7 2 10 2s3 2 3 3.5V8z" id="Page-1" fill="#54595D"/></g></svg>

Before

Width:  |  Height:  |  Size: 455 B

View File

@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><title>ambox-speedy</title><g id="ambox-speedy" fill="none" fill-rule="evenodd"><path d="M19.638 17.36L11.528 3.3a1.85 1.85 0 0 0-1.53-1.09 1.85 1.85 0 0 0-1.52 1.09L.358 17.36C-.482 18.81.208 20 1.878 20h16.24c1.67 0 2.36-1.19 1.52-2.64zm-8.64-.36h-2v-2h2v2zm0-4h-2V7h2v6z" id="Page-1" fill="#D33"/></g></svg>

Before

Width:  |  Height:  |  Size: 408 B

View File

@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><title>ambox-style</title><g id="ambox-style" fill="none" fill-rule="evenodd"><g id="Group" transform="translate(2 1)"><path d="M16.09 10.44c-1.37-.326-3.422-2.752-4.825-4.612l-8.81 6.155 2.33 3.335c.816 1.169 2.28 1.81 4.02 1.66a23.12 23.12 0 0 1-1.583-1.988.357.357 0 0 1 .585-.409c.336.48 1.083 1.467 1.849 2.266.838-.189 1.722-.553 2.615-1.121-1.297-.822-2.184-2.354-2.23-2.436a.357.357 0 0 1 .619-.355c.011.02.991 1.709 2.271 2.347.931-.66 1.61-1.302 2.102-1.891-2.096-.398-3.142-1.86-3.194-1.934a.357.357 0 0 1 .584-.41c.009.012.353.49 1.023.936.63.42 1.326.673 2.075.759.586-.88.758-1.583.807-1.961a.31.31 0 0 0-.239-.341z" id="Combined-Shape" fill="#F5A623" fill-rule="nonzero"/><path d="M9.716 3.65a.928.928 0 0 0-1.293-.229L6.024 5.096 2.65.265a.62.62 0 0 0-.862-.153L.265 1.175a.619.619 0 0 0-.153.862l3.375 4.832-2.333 1.63a.928.928 0 0 0-.23 1.292l1.212 1.735 8.796-6.144A44.037 44.037 0 0 1 9.716 3.65z" id="Shape" fill="#774B20"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>alert</title><path d="M19.64 16.36L11.53 2.3A1.85 1.85 0 0 0 10 1.21 1.85 1.85 0 0 0 8.48 2.3L.36 16.36C-.48 17.81.21 19 1.88 19h16.24c1.67 0 2.36-1.19 1.52-2.64zM11 16H9v-2h2zm0-4H9V6h2z"/></svg>

After

Width:  |  Height:  |  Size: 324 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"><title>notice</title><path d="M10 0a10 10 0 1 0 10 10A10 10 0 0 0 10 0zm1 16H9v-2h2zm0-4H9V4h2z"/></svg>

After

Width:  |  Height:  |  Size: 225 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><g><path d="M6 8l2-3 2-3H2l2 3z"/><path d="M14 12l-2 3-2 3h8l-2-3z"/><path transform="rotate(-22.5 10 10)" d="M1.5 9h17v2h-17z"/></g></svg>

After

Width:  |  Height:  |  Size: 250 B

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 20 20"><style>.st0{clip-path:url(#SVGID_2_);fill:#f5a623}.st1{clip-path:url(#SVGID_4_);fill:#774b20}</style><g><g><defs><path id="SVGID_1_" d="M17.9 11.9c-1.4-.3-3.4-2.8-4.8-4.6l-8.8 6.2 2.3 3.3c.8 1.2 2.3 1.8 4 1.7-.8-.9-1.5-1.9-1.6-2-.1-.2 0-.4.1-.5.2-.1.4-.1.5.1.3.5 1.1 1.5 1.8 2.3.8-.2 1.7-.6 2.6-1.1-1.3-.8-2.2-2.4-2.2-2.4-.1-.2 0-.4.1-.5.2-.1.4 0 .5.1 0 0 1 1.7 2.3 2.3.9-.7 1.6-1.3 2.1-1.9-2.1-.4-3.1-1.9-3.2-1.9-.1-.2-.1-.4.1-.5.2-.1.4-.1.5.1a4.907 4.907 0 0 0 3.1 1.7c.6-.9.8-1.6.8-2 .1-.2 0-.3-.2-.4z"/></defs><clipPath id="SVGID_2_"><use xlink:href="#SVGID_1_" overflow="visible"/></clipPath><path class="st0" d="M-.7 2.3h23.9v21.2H-.7z"/></g><g><defs><path id="SVGID_3_" d="M11.6 5.2c-.3-.4-.9-.5-1.3-.2L7.9 6.6 4.5 1.8c-.2-.3-.6-.4-.9-.2L2.1 2.7c-.3.2-.3.6-.2.8l3.4 4.8L3 10c-.4.3-.5.9-.2 1.3L4 13l8.8-6.1c-.8-1-1.2-1.7-1.2-1.7z"/></defs><clipPath id="SVGID_4_"><use xlink:href="#SVGID_3_" overflow="visible"/></clipPath><path class="st1" d="M-3.2-3.5h20.9V18H-3.2z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><style>.st0{fill:#36c}.st1{fill:#d33}</style><g><path class="st0" d="M6 8.7V12H0v4h6v3l3-2.6 3-2.6-3-2.5z"/><path class="st1" d="M14 4V.7l-3 2.6-3 2.5 3 2.6 3 2.6V8h6V4z"/></g></svg>

After

Width:  |  Height:  |  Size: 293 B

View File

@ -15,8 +15,7 @@
( function () {
var page = M.getCurrentPage(),
getIconFromAmbox = M.require( 'skins.minerva.scripts/utils' )
.getIconFromAmbox,
pageIssueParser = M.require( 'skins.minerva.scripts/pageIssueParser' ),
overlayManager = M.require( 'skins.minerva.scripts/overlayManager' ),
CleanupOverlay = M.require( 'mobile.issues/CleanupOverlay' );
@ -26,13 +25,15 @@
* @param {Object} $box element to extract the message from
* @ignore
* @typedef {Object} IssueSummary
* @prop {PageIssue} pageIssue
* @prop {string} icon HTML string.
* @prop {string} text HTML string.
* @return {IssueSummary}
*/
function extractMessage( $box ) {
var selector = '.mbox-text, .ambox-text',
$container = $( '<div>' );
$container = $( '<div>' ),
pageIssue;
$box.find( selector ).each( function () {
var contents,
@ -45,8 +46,11 @@
$( '<p>' ).html( contents ).appendTo( $container );
}
} );
pageIssue = pageIssueParser.parse( $box.get( 0 ) );
return {
icon: getIconFromAmbox( $box ).toHtmlString(),
pageIssue: pageIssue,
icon: pageIssue.icon.toHtmlString(),
text: $container.html()
};
}
@ -85,7 +89,8 @@
selector = 'table.ambox, table.tmbox, table.cmbox, table.fmbox',
$metadata = $container.find( selector ),
issues = [],
$link;
$link,
severity;
// clean it up a little
$metadata.find( '.NavFrame' ).remove();
@ -107,10 +112,12 @@
allIssues[section] = issues;
if ( inline ) {
severity = pageIssueParser.maxSeverity(
issues.map( function ( issue ) { return issue.pageIssue; } )
);
new Icon( {
glyphPrefix: 'minerva',
name: 'warning',
isSmall: true
name: pageIssueParser.iconName( $metadata, severity )
} ).prependTo( $metadata.find( '.mbox-text' ) );
$learnMore = $( '<span>' )
.addClass( 'ambox-learn-more' )
@ -148,7 +155,7 @@
// Note section.all may not exist, depending on the structure of the HTML page.
// It will only exist when Minerva has been run in desktop mode.
// If it's absent, we'll reduce all the other lists into one.
return section.all || Object.keys( allIssues ).reduce(
return allIssues.all || Object.keys( allIssues ).reduce(
function ( all, key ) {
return all.concat( allIssues[key] );
},

View File

@ -0,0 +1,168 @@
( function ( M ) {
/**
* @typedef PageIssue
* @prop {string} severity A SEVERITY_LEVEL key.
* @prop {Icon} icon
*/
var Icon = M.require( 'mobile.startup/Icon' ),
// 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.
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'
}
},
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.
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.
SEVERITY_REGEX = {
LOW: /ambox-style|avviso-stile/, // en, it
MEDIUM: /ambox-content|avviso-contenuto/, // en, it
HIGH: /ambox-speedy|ambox-delete|ambox-serious|avviso-importante/ // en, en, es / ru, it
// ..And everything else that doesn't match should be considered DEFAULT.
},
// As above but used to identify specific templates requiring icon customization.
TYPE_REGEX = {
MOVE: /ambox-move|ambox-merge|avviso-struttura/, // en, es / ru, it
POINT_OF_VIEW: new RegExp( [ // en
'ambox-POV',
'ambox-Advert',
'ambox-autobiography',
'ambox-believerpov',
'ambox-COI',
'ambox-fanpov',
'ambox-globalize',
'ambox-npov-language',
'ambox-fringe-theories',
'ambox-systemic-bias'
].join( '|' ) )
// ..And everything else that doesn't match is mapped to a "SEVERITY" type.
},
// Variants supported by specific types. The "severity icon" supports all severities but the
// type icons only support one each by ResourceLoader.
TYPE_SEVERITY = {
MOVE: 'DEFAULT',
POINT_OF_VIEW: 'MEDIUM'
};
/**
* @param {Element} box
* @return {string} An SEVERITY_SELECTOR key.
*/
function parseSeverity( box ) {
var severity, identified;
identified = Object.keys( SEVERITY_REGEX ).some( function ( key ) {
var 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.
*/
function parseType( box, severity ) {
var identified, identifiedType;
identified = Object.keys( TYPE_REGEX ).some( function ( type ) {
var 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
* @param {string} severity An SEVERITY_LEVEL key.
* @return {string} A severity or type ISSUE_ICON.
*/
function iconName( box, severity ) {
var nameSeverity = parseType( box, severity );
// The icon with color variant as expected by ResourceLoader, {iconName}-{severityColorVariant}.
return nameSeverity.name + '-' + ICON_COLOR[nameSeverity.severity];
}
/**
* @param {PageIssue[]} issues
* @return {string} The greatest SEVERITY_LEVEL key.
*/
function maxSeverity( issues ) {
return issues.reduce( function ( max, issue ) {
return SEVERITY_LEVEL[max] > SEVERITY_LEVEL[issue.severity] ? max : issue.severity;
}, 'DEFAULT' );
}
/**
* @param {Element} box
* @return {PageIssue}
*/
function parse( box ) {
var severity = parseSeverity( box );
return {
severity: severity,
icon: new Icon( {
glyphPrefix: 'minerva',
name: iconName( box, severity )
} )
};
}
/**
* @module skins.minerva.scripts/utils
*/
M.define( 'skins.minerva.scripts/pageIssueParser', {
/**
* Extract an icon for use with the issue.
* @param {JQuery.Object} $box element to extract the icon from
* @return {Icon} representing the icon
*/
parse: parse,
maxSeverity: maxSeverity,
iconName: iconName,
test: {
parseSeverity: parseSeverity,
parseType: parseType
}
} );
}( mw.mobileFrontend ) );

View File

@ -1,44 +0,0 @@
( function ( M ) {
var Icon = M.require( 'mobile.startup/Icon' );
function getIconFromAmbox( $box ) {
var glyph,
names = [
'speedy',
'delete',
'protection',
'pov',
'move',
'style',
'content'
];
// since objects have no concept of ordering we repeat ourselves here
names.forEach( function ( name ) {
if ( !glyph && $box.hasClass( 'ambox-' + name ) ) {
// with a match, exit
glyph = name;
}
} );
glyph = glyph || 'default';
return new Icon( {
glyphPrefix: 'minerva',
name: 'issue-' + glyph
} );
}
/**
* @module skins.minerva.scripts/utils
*/
M.define( 'skins.minerva.scripts/utils', {
/**
* Extract an icon for use with the issue.
* @param {JQuery.Object} $box element to extract the icon from
* @return {Icon} representing the icon
*/
getIconFromAmbox: getIconFromAmbox
} );
}( mw.mobileFrontend ) );

View File

@ -242,19 +242,54 @@
}
},
"skins.minerva.icons.images.scripts": {
"targets": [
"mobile",
"desktop"
],
"dependencies": [
"skins.minerva.icons.images.scripts.misc",
"skins.minerva.icons.page.issues.uncolored",
"skins.minerva.icons.page.issues.default.color",
"skins.minerva.icons.page.issues.medium.color"
]
},
"skins.minerva.icons.images.scripts.misc": {
"class": "ResourceLoaderImageModule",
"selector": ".mw-ui-icon-minerva-{name}:before",
"images": {
"issue-speedy": "resources/skins.minerva.icons.images.scripts/issue-speedy.svg",
"issue-delete": "resources/skins.minerva.icons.images.scripts/issue-delete.svg",
"issue-protection": "resources/skins.minerva.icons.images.scripts/issue-protection.svg",
"issue-default": "resources/skins.minerva.icons.images.scripts/issue-default.svg",
"issue-pov": "resources/skins.minerva.icons.images.scripts/issue-pov.svg",
"issue-style": "resources/skins.minerva.icons.images.scripts/issue-style.svg",
"issue-content": "resources/skins.minerva.icons.images.scripts/issue-content.svg",
"issue-move": "resources/skins.minerva.icons.images.scripts/issue-move.svg",
"download": "resources/skins.minerva.icons.images.scripts/download.svg",
"stop-hand": "resources/skins.minerva.icons.images.scripts/stop-hand.svg"
"download": "resources/skins.minerva.icons.images.scripts.misc/download.svg",
"stop-hand": "resources/skins.minerva.icons.images.scripts.misc/stop-hand.svg"
}
},
"skins.minerva.icons.page.issues.uncolored": {
"class": "ResourceLoaderImageModule",
"selector": ".mw-ui-icon-minerva-{name}:before",
"images": {
"issue-severity-low-lowColor": "resources/skins.minerva.icons.page.issues.uncolored/issue-severity-low.svg",
"issue-type-move-defaultColor": "resources/skins.minerva.icons.page.issues.uncolored/issue-type-move.svg"
}
},
"skins.minerva.icons.page.issues.default.color": {
"class": "ResourceLoaderImageModule",
"selectorWithoutVariant": ".mw-ui-icon-minerva-{name}-defaultColor:before",
"selectorWithVariant": ".mw-ui-icon-minerva-{name}-{variant}:before",
"defaultColor": "#54595d",
"variants": {
"lowColor": { "color": "#fc3", "global": true },
"mediumColor": { "color": "#ff5d01", "global": true },
"highColor": { "color": "#d33", "global": true }
},
"images": {
"issue-generic": "resources/skins.minerva.icons.page.issues.default.color/issue-generic.svg"
}
},
"skins.minerva.icons.page.issues.medium.color": {
"class": "ResourceLoaderImageModule",
"selector": ".mw-ui-icon-minerva-{name}-mediumColor:before",
"defaultColor": "#ff5d01",
"images": {
"issue-severity-medium": "resources/skins.minerva.icons.page.issues.medium.color/issue-severity-medium.svg",
"issue-type-point-of-view": "resources/skins.minerva.icons.page.issues.medium.color/issue-type-point-of-view.svg"
}
},
"skins.minerva.mainPage.styles": {
@ -382,7 +417,7 @@
"resources/skins.minerva.scripts/mobileRedirect.js",
"resources/skins.minerva.scripts/search.js",
"resources/skins.minerva.scripts/references.js",
"resources/skins.minerva.scripts/utils.js",
"resources/skins.minerva.scripts/pageIssueParser.js",
"resources/skins.minerva.scripts/AB.js",
"resources/skins.minerva.scripts/cleanuptemplates.js"
]
@ -519,7 +554,6 @@
"resources/skins.minerva.editor/init.js"
]
},
"skins.minerva.backtotop": {
"targets": [
"mobile",

View File

@ -0,0 +1,124 @@
( function ( M ) {
var pageIssueParser = M.require( 'skins.minerva.scripts/pageIssueParser' );
QUnit.module( 'pageIssueParser' );
/**
* @param {string} className
* @return {Element}
*/
function newBox( className ) {
var box = document.createElement( 'div' );
box.className = className;
return box;
}
QUnit.test( 'parseSeverity', function ( assert ) {
var tests = [
[ '', 'DEFAULT', 'empty' ],
[ 'foo', 'DEFAULT', 'unknown' ],
[ 'ambox-style', 'LOW', 'style' ],
[ 'ambox-content', 'MEDIUM', 'content' ],
[ 'ambox-speedy', 'HIGH', 'speedy' ],
[ 'ambox-delete', 'HIGH', 'delete' ],
// Move has an "unknown" severity and falls into DEFAULT.
[ 'ambox-move', 'DEFAULT', 'move' ],
// Point of view uses ambox-content to identify correct severity.
[ 'ambox-content ambox-POV', 'MEDIUM', 'point of view' ]
// Mixed severities such as 'ambox-style ambox-content' are not prioritized.
];
tests.forEach( function ( params, i ) {
var
className = params[0],
expect = params[1],
test = params[2],
box = newBox( className );
assert.strictEqual(
pageIssueParser.test.parseSeverity( box ),
expect,
'Result should be the correct severity; case ' + i + ' failed: ' + test + '.'
);
} );
} );
QUnit.test( 'parseType', function ( assert ) {
var tests = [
[ '', 'DEFAULT', 'issue-generic', 'empty' ],
[ 'foo', 'DEFAULT', 'issue-generic', 'unknown' ],
[ 'ambox-move', 'DEFAULT', 'issue-type-move', 'move' ],
[ 'ambox-POV', 'MEDIUM', 'issue-type-point-of-view', 'point of view' ],
[ '', 'DEFAULT', 'issue-generic', 'Default severity' ],
[ '', 'LOW', 'issue-severity-low', 'Low severity' ],
[ '', 'MEDIUM', 'issue-severity-medium', 'Medium severity' ],
[ '', 'HIGH', 'issue-generic', 'HIGH severity' ]
];
tests.forEach( function ( params, i ) {
var
className = params[0],
severity = params[1],
expect = {
name: params[2],
severity: severity
},
test = params[3],
box = newBox( className );
assert.propEqual(
pageIssueParser.test.parseType( box, severity ),
expect,
'Result should be the correct icon type; case ' + i + ' failed: ' + test + '.'
);
} );
} );
QUnit.test( 'iconName', function ( assert ) {
var tests = [
[ '', 'DEFAULT', 'issue-generic-defaultColor' ],
[ '', 'LOW', 'issue-severity-low-lowColor' ],
[ '', 'MEDIUM', 'issue-severity-medium-mediumColor' ],
[ '', 'HIGH', 'issue-generic-highColor' ],
[ 'ambox-move', 'DEFAULT', 'issue-type-move-defaultColor' ],
[ 'ambox-POV', 'MEDIUM', 'issue-type-point-of-view-mediumColor' ],
// ResourceLoader only supplies color variants for the generic type. Ensure impossible
// combinations are forbidden.
[ 'ambox-style ambox-POV', 'LOW', 'issue-type-point-of-view-mediumColor' ],
[ 'ambox-content ambox-move', 'MEDIUM', 'issue-type-move-defaultColor' ]
];
tests.forEach( function ( params, i ) {
var
className = params[0],
severity = params[1],
expect = params[2],
box = newBox( className );
assert.strictEqual(
pageIssueParser.iconName( box, severity ),
expect,
'Result should be the correct ResourceLoader icon name; case ' + i + ' failed: ' + severity + '.'
);
} );
} );
QUnit.test( 'maxSeverity', function ( assert ) {
var tests = [
[ [], 'DEFAULT' ],
[ [ 'DEFAULT' ], 'DEFAULT' ],
[ [ 'DEFAULT', 'LOW' ], 'LOW' ],
[ [ 'DEFAULT', 'LOW', 'MEDIUM' ], 'MEDIUM' ],
[ [ 'DEFAULT', 'LOW', 'MEDIUM', 'HIGH' ], 'HIGH' ],
[ [ 'HIGH', 'DEFAULT', 'LOW', 'MEDIUM' ], 'HIGH' ],
[ [ 'DEFAULT', 'HIGH', 'LOW', 'MEDIUM' ], 'HIGH' ]
];
tests.forEach( function ( params, i ) {
var
severities = params[0],
expect = params[1];
assert.strictEqual(
pageIssueParser.maxSeverity( severities.map( function ( severity ) {
return { severity: severity };
} ) ),
expect,
'Result should be the highest severity in the array; case ' + i + ' failed.'
);
} );
} );
}( mw.mobileFrontend ) );

View File

@ -1,47 +0,0 @@
( function ( M ) {
var utils = M.require( 'skins.minerva.scripts/utils' ),
getIconFromAmbox = utils.getIconFromAmbox;
QUnit.module( 'Minerva utils' );
QUnit.test( 'getIconFromAmbox', function ( assert ) {
var tests = [
[
'', 'issue-default'
],
[
'ambox', 'issue-default'
],
[
'ambox-content ambox-speedy', 'issue-speedy'
],
[
'ambox-content ambox-delete', 'issue-delete'
],
[
'ambox-content', 'issue-content'
],
[
'ambox-content ambox-pov', 'issue-pov'
],
[
'ambox-content ambox-style', 'issue-style'
],
[
'ambox-content ambox-move', 'issue-move'
],
[
'ambox-content ambox-protection', 'issue-protection'
]
];
tests.forEach( function ( test, i ) {
var $box = $( '<div>' );
$box.addClass( test[0] );
assert.strictEqual(
getIconFromAmbox( $box ).options.name,
test[1],
i
);
} );
} );
}( mw.mobileFrontend ) );