Composition: DownloadIcon

The DownloadIcon is reduced to a factory function that
returns an instance of Icon

Depends-On: I4d703eef68d51bbe0b03579c5cca0845e17b8c9d
Depends-On: I4a4129b2cac7c7c49559beef0b8780f3211edf9c
Bug: T205592
Change-Id: Ib87390d17bef6f50842f52cd84c9ce2b162aaff0
This commit is contained in:
jdlrobson 2018-11-07 16:06:54 -08:00
parent fef6dd217a
commit c73ff1f7a5
6 changed files with 217 additions and 209 deletions

View File

@ -99,12 +99,12 @@ class MinervaHooks {
'tests/qunit/skins.minerva.scripts/stubs.js',
'resources/skins.minerva.scripts/pageIssuesParser.js',
'resources/skins.minerva.scripts/DownloadIcon.js',
'resources/skins.minerva.scripts/downloadPageAction.js',
'resources/skins.minerva.scripts/AB.js',
'resources/skins.minerva.scripts/PageIssuesOverlay.js',
'resources/skins.minerva.scripts/pageIssues.js',
// test files
'tests/qunit/skins.minerva.scripts/DownloadIcon.test.js',
'tests/qunit/skins.minerva.scripts/downloadPageAction.test.js',
'tests/qunit/skins.minerva.scripts/pageIssuesParser.test.js',
'tests/qunit/skins.minerva.scripts/AB.test.js',
'tests/qunit/skins.minerva.scripts/pageIssues.test.js',

View File

@ -1,151 +0,0 @@
( function ( M, track ) {
var msg = mw.msg,
MAX_PRINT_TIMEOUT = 3000,
GLYPH = 'download',
Icon = M.require( 'mobile.startup/Icon' ),
browser = M.require( 'mobile.startup/Browser' ).getSingleton();
/**
* 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;
}
/**
* A download icon for triggering print functionality
* @class DownloadIcon
* @extends Icon
*
* @param {Skin} skin
* @param {number[]} [supportedNamespaces]
* @param {Window} [windowObj] window object
* @constructor
*/
function DownloadIcon( skin, supportedNamespaces, windowObj ) {
var options = {};
this.skin = skin;
this.window = windowObj || {};
this.supportedNamespaces = supportedNamespaces || [ 0 ];
options.tagName = 'li';
options.glyphPrefix = 'minerva';
options.title = msg( 'minerva-download' );
options.name = GLYPH;
Icon.call( this, options );
}
OO.mfExtend( DownloadIcon, Icon, {
/**
* Checks whether DownloadIcon is available for given user agent
*
* @memberof DownloadIcon
* @instance
* @param {string} userAgent User agent
* @return {boolean}
*/
isAvailable: function ( userAgent ) {
var androidVersion = getAndroidVersion( userAgent ),
chromeVersion = getChromeVersion( userAgent ),
page = this.skin.page;
// Download button is restricted to certain namespaces T181152.
// Defaults to 0, in case cached JS has been served.
if ( this.supportedNamespaces.indexOf( page.getNamespaceId() ) === -1 ||
page.isMainPage() ) {
// namespace is not supported or it's a main page
return false;
}
if ( browser.isIos() || chromeVersion === false ||
this.window.chrome === undefined
) {
// we support only chrome/chromium on desktop/android
return false;
}
if ( ( androidVersion && androidVersion < 5 ) || chromeVersion < 41 ) {
return false;
}
return true;
},
/**
* Replace download icon with a spinner
* @memberof DownloadIcon
* @instance
*/
showSpinner: function () {
// FIXME: There is no spinner icon in Minerva, only in MobileFrontend
// Hopefully when T177432 is resolved this and corresponding change in hideSpinner
// should be unnecessary.
this.options.glyphPrefix = 'mf';
this.options.name = 'spinner';
this.render();
},
/**
* Restore download icon from spinner state
* @memberof DownloadIcon
* @instance
*/
hideSpinner: function () {
this.options.glyphPrefix = 'minerva';
this.options.name = GLYPH;
this.render();
},
/**
* onClick handler for button that invokes print function
* @memberof DownloadIcon
* @instance
*/
onClick: function () {
var self = this,
hideSpinner = this.hideSpinner.bind( this );
function doPrint() {
self.timeout = clearTimeout( self.timeout );
track( 'minerva.downloadAsPDF', {
action: 'callPrint'
} );
window.print();
hideSpinner();
}
function doPrintBeforeTimeout() {
if ( self.timeout ) {
doPrint();
}
}
// The click handler may be invoked multiple times so if a pending print is occurring
// do nothing.
if ( !this.timeout ) {
track( 'minerva.downloadAsPDF', {
action: 'fetchImages'
} );
this.showSpinner();
// If all image downloads are taking longer to load then the MAX_PRINT_TIMEOUT
// abort the spinner and print regardless.
this.timeout = setTimeout( doPrint, MAX_PRINT_TIMEOUT );
this.skin.loadImagesList().then( doPrintBeforeTimeout, doPrintBeforeTimeout );
}
},
events: {
click: 'onClick'
}
} );
M.define( 'skins.minerva.scripts/DownloadIcon', DownloadIcon );
}( mw.mobileFrontend, mw.track ) );

View File

@ -0,0 +1,153 @@
( function ( M, track, msg ) {
var helpers,
MAX_PRINT_TIMEOUT = 3000,
GLYPH = 'download',
icons = M.require( 'mobile.startup/icons' ),
Icon = M.require( 'mobile.startup/Icon' ),
browser = M.require( 'mobile.startup/Browser' ).getSingleton();
/**
* 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;
}
helpers = {
/**
* 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}
*/
isAvailable: function ( 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 {Skin} skin
* @param {Icon} icon
* @param {Icon} spinner
*/
onClick: function ( skin, 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 );
skin.loadImagesList().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 {Skin} skin
* @param {Icon} spinner
* @returns {function}
*/
function getOnClickHandler( skin, spinner ) {
return function () {
helpers.onClick( skin, 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
* @returns {jQuery.Object|null}
*/
function downloadPageAction( skin, supportedNamespaces, windowObj ) {
var icon, spinner = icons.spinner();
if (
helpers.isAvailable(
windowObj, skin.page, navigator.userAgent,
supportedNamespaces
)
) {
icon = new Icon( {
glyphPrefix: 'minerva',
title: msg( 'minerva-download' ),
name: GLYPH,
events: {
// will be bound to `this`
click: getOnClickHandler( skin, spinner )
}
} );
return $( '<li>' ).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', helpers.isAvailable );
M.define( 'skins.minerva.scripts/downloadPageAction', downloadPageAction );
}( mw.mobileFrontend, mw.track, mw.msg ) );

View File

@ -4,7 +4,7 @@
time = M.require( 'mobile.startup/time' ),
skin = M.require( 'mobile.init/skin' ),
issues = M.require( 'skins.minerva.scripts/pageIssues' ),
DownloadIcon = M.require( 'skins.minerva.scripts/DownloadIcon' ),
downloadPageAction = M.require( 'skins.minerva.scripts/downloadPageAction' ),
browser = M.require( 'mobile.startup/Browser' ).getSingleton(),
loader = M.require( 'mobile.startup/rlModuleLoader' ),
router = require( 'mediawiki.router' ),
@ -274,14 +274,15 @@
* @ignore
*/
function appendDownloadButton() {
var downloadIcon = new DownloadIcon( skin, config.get( 'wgMinervaDownloadNamespaces' ), window );
var $downloadAction = downloadPageAction( skin,
config.get( 'wgMinervaDownloadNamespaces', [] ), window );
if ( downloadIcon.isAvailable( navigator.userAgent ) ) {
if ( $downloadAction ) {
// Because the page actions are floated to the right, their order in the
// DOM is reversed in the display. The watchstar is last in the DOM and
// left-most in the display. Since we want the download button to be to
// the left of the watchstar, we put it after it in the DOM.
downloadIcon.$el.insertAfter( '#ca-watch' );
$downloadAction.insertAfter( '#ca-watch' );
track( 'minerva.downloadAsPDF', {
action: 'buttonVisible'
} );

View File

@ -427,7 +427,7 @@
"scripts": [
"resources/skins.minerva.scripts/errorLogging.js",
"resources/skins.minerva.scripts/preInit.js",
"resources/skins.minerva.scripts/DownloadIcon.js",
"resources/skins.minerva.scripts/downloadPageAction.js",
"resources/skins.minerva.scripts/pageIssuesParser.js",
"resources/skins.minerva.scripts/AB.js",
"resources/skins.minerva.scripts/PageIssuesOverlay.js",

View File

@ -2,10 +2,13 @@
var VALID_UA = 'Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Mobile Safari/537.36',
VALID_SUPPORTED_NAMESPACES = [ 0 ],
Skin = M.require( 'mobile.startup/Skin' ),
icons = M.require( 'mobile.startup/icons' ),
Deferred = $.Deferred,
windowChrome = { chrome: true },
downloadIcon = icons.spinner(),
windowNotChrome = {},
DownloadIcon = M.require( 'skins.minerva.scripts/DownloadIcon' ),
getOnClickHandler = M.require( 'skins.minerva.scripts/test/getOnClickHandler' ),
isAvailable = M.require( 'skins.minerva.scripts/test/isAvailable' ),
browser = M.require( 'mobile.startup/Browser' ).getSingleton(),
Page = M.require( 'mobile.startup/Page' );
@ -17,17 +20,20 @@
off: function () {}
}
} );
this.getOnClickHandler = function ( skin ) {
return getOnClickHandler( skin, icons.spinner() ).bind( downloadIcon );
};
}
} );
QUnit.test( '#DownloadIcon (print after image download)', function ( assert ) {
var icon = new DownloadIcon( this.skin ),
QUnit.test( '#getOnClickHandler (print after image download)', function ( assert ) {
var handler = this.getOnClickHandler( this.skin ),
d = Deferred(),
spy = this.sandbox.stub( window, 'print' );
this.sandbox.stub( this.skin, 'loadImagesList' ).returns( d.resolve() );
icon.onClick();
handler();
d.then( function () {
assert.strictEqual( spy.callCount, 1, 'Print occurred.' );
} );
@ -35,8 +41,8 @@
return d;
} );
QUnit.test( '#DownloadIcon (print via timeout)', function ( assert ) {
var icon = new DownloadIcon( this.skin ),
QUnit.test( '#getOnClickHandler (print via timeout)', function ( assert ) {
var handler = this.getOnClickHandler( this.skin ),
d = Deferred(),
spy = this.sandbox.stub( window, 'print' );
@ -46,7 +52,7 @@
d.resolve();
}, 3400 );
icon.onClick();
handler();
d.then( function () {
assert.strictEqual( spy.callCount, 1,
'Print was called once despite loadImagesList resolving after MAX_PRINT_TIMEOUT' );
@ -55,8 +61,8 @@
return d;
} );
QUnit.test( '#DownloadIcon (multiple clicks)', function ( assert ) {
var icon = new DownloadIcon( this.skin ),
QUnit.test( '#getOnClickHandler (multiple clicks)', function ( assert ) {
var handler = this.getOnClickHandler( this.skin ),
d = Deferred(),
spy = this.sandbox.stub( window, 'print' );
@ -66,8 +72,8 @@
d.resolve();
}, 3400 );
icon.onClick();
icon.onClick();
handler();
handler();
d.then( function () {
assert.strictEqual( spy.callCount, 1,
'Print was called once despite multiple clicks' );
@ -76,104 +82,103 @@
return d;
} );
QUnit.module( 'Minerva DownloadIcon.isAvailable()', {
QUnit.module( 'isAvailable()', {
beforeEach: function () {
var page = new Page( {
id: 0,
title: 'Test',
isMainPage: false
} );
this.page = page;
this.skin = new Skin( {
eventBus: {
on: function () {},
off: function () {}
},
page: new Page( {
id: 0,
title: 'Test',
isMainPage: false
} )
page: page
} );
this.isAvailable = function ( ua ) {
return isAvailable( windowChrome, page, ua,
VALID_SUPPORTED_NAMESPACES );
};
this.notChromeIsAvailable = function ( ua ) {
return isAvailable( windowNotChrome, page, ua,
VALID_SUPPORTED_NAMESPACES );
};
}
} );
QUnit.test( 'isAvailable() handles properly correct namespace', function ( assert ) {
var icon = new DownloadIcon( this.skin, VALID_SUPPORTED_NAMESPACES, windowChrome );
assert.ok( icon.isAvailable( VALID_UA ) );
assert.ok( this.isAvailable( VALID_UA ) );
} );
QUnit.test( 'isAvailable() handles properly not supported namespace', function ( assert ) {
var icon = new DownloadIcon( this.skin, [ 9999 ], windowChrome );
assert.notOk( icon.isAvailable( VALID_UA ) );
assert.notOk( isAvailable( windowChrome, this.page, VALID_UA, [ 9999 ] ) );
} );
QUnit.test( 'isAvailable() handles properly main page', function ( assert ) {
var icon;
this.skin.page = new Page( {
var page = new Page( {
id: 0,
title: 'Test',
isMainPage: true
} );
icon = new DownloadIcon( this.skin, VALID_SUPPORTED_NAMESPACES, windowChrome );
assert.notOk( icon.isAvailable( VALID_UA ) );
assert.notOk( isAvailable( windowChrome, page, VALID_UA, VALID_SUPPORTED_NAMESPACES ) );
} );
QUnit.test( 'isAvailable() returns false for iOS', function ( assert ) {
var icon;
this.sandbox.stub( browser, 'isIos' ).returns( true );
icon = new DownloadIcon( this.skin, VALID_SUPPORTED_NAMESPACES, windowChrome );
assert.notOk( icon.isAvailable( VALID_UA ) );
assert.notOk( this.isAvailable( VALID_UA ) );
} );
QUnit.test( 'isAvailable() uses window.chrome to filter certain chrome-like browsers', function ( assert ) {
var icon = new DownloadIcon( this.skin, VALID_SUPPORTED_NAMESPACES, windowNotChrome );
// Dolphin
assert.notOk( icon.isAvailable( ' Mozilla/5.0 (Linux; Android 7.0; SM-G950U1 Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.98 Mobile Safari/537.36' ) );
assert.notOk( this.notChromeIsAvailable( ' Mozilla/5.0 (Linux; Android 7.0; SM-G950U1 Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/61.0.3163.98 Mobile Safari/537.36' ) );
// Opera
assert.notOk( icon.isAvailable( 'Mozilla/5.0 (Linux; Android 7.0; SM-G950U1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36 OPR/44.1.2246.123029' ) );
assert.notOk( this.notChromeIsAvailable( 'Mozilla/5.0 (Linux; Android 7.0; SM-G950U1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Mobile Safari/537.36 OPR/44.1.2246.123029' ) );
// Maxthon
assert.notOk( icon.isAvailable( 'Mozilla/5.0 (Linux; Android 7.0; SM-G950U1 Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36 MxBrowser/4.5.10.1300' ) );
assert.notOk( this.notChromeIsAvailable( 'Mozilla/5.0 (Linux; Android 7.0; SM-G950U1 Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36 MxBrowser/4.5.10.1300' ) );
} );
QUnit.test( 'isAvailable() handles properly browsers', function ( assert ) {
var icon = new DownloadIcon( this.skin, VALID_SUPPORTED_NAMESPACES, windowChrome );
// IPhone 6 Safari
assert.notOk( icon.isAvailable( 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_0_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13A405 Safari/601.1' ) );
assert.notOk( this.isAvailable( 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_0_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13A405 Safari/601.1' ) );
// Nokia Lumia 930 Windows Phone 8.1
assert.notOk( icon.isAvailable( 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; Microsoft; Virtual) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' ) );
assert.notOk( this.isAvailable( 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; Microsoft; Virtual) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' ) );
// Firefox @ Ubuntu
assert.notOk( icon.isAvailable( 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0' ) );
assert.notOk( this.isAvailable( 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0' ) );
} );
QUnit.test( 'isAvailable() handles properly non-chrome browsers', function ( assert ) {
var icon = new DownloadIcon( this.skin, VALID_SUPPORTED_NAMESPACES, windowNotChrome );
// IPhone 6 Safari
assert.notOk( icon.isAvailable( 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_0_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13A405 Safari/601.1' ) );
assert.notOk( this.notChromeIsAvailable( 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_0_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13A405 Safari/601.1' ) );
// Nokia Lumia 930 Windows Phone 8.1
assert.notOk( icon.isAvailable( 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; Microsoft; Virtual) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' ) );
assert.notOk( this.notChromeIsAvailable( 'Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; Microsoft; Virtual) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537' ) );
// Firefox @ Ubuntu
assert.notOk( icon.isAvailable( 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0' ) );
assert.notOk( this.notChromeIsAvailable( 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:56.0) Gecko/20100101 Firefox/56.0' ) );
} );
QUnit.test( 'isAvailable() handles properly old devices', function ( assert ) {
var icon = new DownloadIcon( this.skin, VALID_SUPPORTED_NAMESPACES );
// Samsung Galaxy S5, Android 4.4, Chrome 28
assert.notOk( icon.isAvailable( 'Mozilla/5.0 (Linux; Android 4.4.2; en-us; SAMSUNG SM-G900F Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.6 Chrome/28.0.1500.94 Mobile Safari/537.36' ) );
assert.notOk( this.isAvailable( 'Mozilla/5.0 (Linux; Android 4.4.2; en-us; SAMSUNG SM-G900F Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.6 Chrome/28.0.1500.94 Mobile Safari/537.36' ) );
// Samsung Galaxyu S1, Android 4.2.2 Cyanogenmod + built in Samsung Browser
assert.notOk( icon.isAvailable( 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-ca; GT-I9000 Build/JDQ39E) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 CyanogenMod/10.1.0/galaxysmtd' ) );
assert.notOk( this.isAvailable( 'Mozilla/5.0 (Linux; U; Android 4.2.2; en-ca; GT-I9000 Build/JDQ39E) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 CyanogenMod/10.1.0/galaxysmtd' ) );
// Samsung Galaxy S3
assert.notOk( icon.isAvailable( 'Mozilla/5.0 (Linux; Android 4.3; GT-I9300 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36' ) );
assert.notOk( this.isAvailable( 'Mozilla/5.0 (Linux; Android 4.3; GT-I9300 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36' ) );
} );
QUnit.test( 'isAvailable() handles properly supported browsers', function ( assert ) {
var icon = new DownloadIcon( this.skin, VALID_SUPPORTED_NAMESPACES, windowChrome );
// Samsung Galaxy S7, Android 6, Chrome 44
assert.ok( icon.isAvailable( 'Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G930F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/4.0 Chrome/44.0.2403.133 Mobile Safari/537.36' ) );
assert.ok( this.isAvailable( 'Mozilla/5.0 (Linux; Android 6.0.1; SAMSUNG SM-G930F Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/4.0 Chrome/44.0.2403.133 Mobile Safari/537.36' ) );
// Samsung Galaxy A5, Android 7, Samsung Browser 5.2
assert.ok( icon.isAvailable( 'Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-A510F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.2 Chrome/51.0.2704.106 Mobile Safari/537.36' ) );
assert.ok( this.isAvailable( 'Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-A510F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/5.2 Chrome/51.0.2704.106 Mobile Safari/537.36' ) );
// Galaxy J2, Android 5, Chrome 65
assert.ok( icon.isAvailable( 'Mozilla/5.0 (Linux; Android 5.1.1; SM-J200G Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3320.0 Mobile Safari/537.36' ) );
assert.ok( this.isAvailable( 'Mozilla/5.0 (Linux; Android 5.1.1; SM-J200G Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3320.0 Mobile Safari/537.36' ) );
// Desktop, Chrome 63
assert.ok( icon.isAvailable( 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36' ) );
assert.ok( this.isAvailable( 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36' ) );
// Desktop, Ubuntu, Chromium 61
assert.ok( icon.isAvailable( 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/61.0.3163.100 Chrome/61.0.3163.100 Safari/537.36' ) );
assert.ok( this.isAvailable( 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/61.0.3163.100 Chrome/61.0.3163.100 Safari/537.36' ) );
// Galaxy S8, Android 8, Samsung Browser 6.2
assert.ok( icon.isAvailable( 'Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G950U1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36' ) );
assert.ok( this.isAvailable( 'Mozilla/5.0 (Linux; Android 7.0; SAMSUNG SM-G950U1 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/6.2 Chrome/56.0.2924.87 Mobile Safari/537.36' ) );
} );
}( mw.mobileFrontend ) );