fix(logo): Use the new Firefox logo in Fx Desktop/Android >= 57, iOS >= 10. (#5643) r=@vbudhram, @ryanfeeley
Do some UA sniffing on startup to add the "fx-57" class to the HTML element. If "fx-57" exists, display the new logo. fixes #5588
This commit is contained in:
Родитель
1a520c2136
Коммит
46921fbaee
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 15 KiB |
Двоичные данные
app/favicon.ico
Двоичные данные
app/favicon.ico
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 15 KiB После Ширина: | Высота: | Размер: 66 KiB |
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
После Ширина: | Высота: | Размер: 16 KiB |
|
@ -83,6 +83,7 @@
|
|||
this.addSearchParamStyles();
|
||||
this.addFxiOSSyncStyles();
|
||||
this.addGetUserMediaStyles();
|
||||
this.addFx57Styles();
|
||||
},
|
||||
|
||||
addJSStyle: function () {
|
||||
|
@ -142,6 +143,15 @@
|
|||
} else {
|
||||
this._addClass('no-getusermedia');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the `fx-57` class to the body if in Fx >= 57.
|
||||
*/
|
||||
addFx57Styles: function () {
|
||||
if (this.environment.isFx57OrAbove() || this.environment.isFxiOS10OrAbove()) {
|
||||
this._addClass('fx-57');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -108,6 +108,40 @@
|
|||
return /FxiOS/.test(this.window.navigator.userAgent);
|
||||
},
|
||||
|
||||
/**
|
||||
* Is the user in Firefox for iOS 10 or above?
|
||||
*
|
||||
* @param {String} [userAgent=navigator.userAgent] UA string
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
isFxiOS10OrAbove: function (userAgent) {
|
||||
var fxRegExp = /FxiOS\/(\d{2,}\.\d{1,})/;
|
||||
var matches = fxRegExp.exec(userAgent || this.window.navigator.userAgent);
|
||||
|
||||
if (matches && matches[1]) {
|
||||
return parseFloat(matches[1]) >= 10;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Is the user in Firefox (Desktop or Android) 57 or above?
|
||||
*
|
||||
* @param {String} [userAgent=navigator.userAgent] UA string
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
isFx57OrAbove: function (userAgent) {
|
||||
var fxRegExp = /Firefox\/(\d{2,}\.\d{1,})$/;
|
||||
var matches = fxRegExp.exec(userAgent || this.window.navigator.userAgent);
|
||||
|
||||
if (matches && matches[1]) {
|
||||
return parseFloat(matches[1]) >= 57;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
hasSendBeacon: function () {
|
||||
return typeof this.window.navigator.sendBeacon === 'function';
|
||||
}
|
||||
|
|
|
@ -26,6 +26,14 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
html.fx-57 & {
|
||||
background-image: image-url('firefox-logo.svg');
|
||||
background-position-y: -5px;
|
||||
@include respond-to('small') {
|
||||
background-position-y: -4px;
|
||||
}
|
||||
}
|
||||
|
||||
.static & {
|
||||
opacity: 1;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,14 @@ body.settings #main-content.card {
|
|||
background-repeat: no-repeat;
|
||||
margin: 0;
|
||||
|
||||
html.fx-57 & {
|
||||
background-image: image-url('firefox-logo.svg');
|
||||
background-position-y: -5px;
|
||||
@include respond-to('small') {
|
||||
background-position-y: -4px;
|
||||
}
|
||||
}
|
||||
|
||||
html[dir='ltr'] & {
|
||||
float: left;
|
||||
}
|
||||
|
@ -78,7 +86,6 @@ body.settings #main-content.card {
|
|||
background-position: right 8px;
|
||||
padding-right: 36px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -178,6 +178,40 @@ define(function (require, exports, module) {
|
|||
});
|
||||
});
|
||||
|
||||
describe('addFx57Styles', () => {
|
||||
it('adds `fx-57` if UA is Fx >= 57', () => {
|
||||
sinon.stub(environment, 'isFx57OrAbove').callsFake(() => true);
|
||||
sinon.stub(environment, 'isFxiOS10OrAbove').callsFake(() => false);
|
||||
|
||||
startupStyles.addFx57Styles();
|
||||
assert.isTrue(/fx-57/.test(startupStyles.getClassName()));
|
||||
});
|
||||
|
||||
it('does not add `fx-57` if UA is Fx <= 56', () => {
|
||||
sinon.stub(environment, 'isFx57OrAbove').callsFake(() => false);
|
||||
sinon.stub(environment, 'isFxiOS10OrAbove').callsFake(() => false);
|
||||
|
||||
startupStyles.addFx57Styles();
|
||||
assert.isFalse(/fx-57/.test(startupStyles.getClassName()));
|
||||
});
|
||||
|
||||
it('adds `fx-57` if UA is FxiOS >= 10', () => {
|
||||
sinon.stub(environment, 'isFx57OrAbove').callsFake(() => false);
|
||||
sinon.stub(environment, 'isFxiOS10OrAbove').callsFake(() => true);
|
||||
|
||||
startupStyles.addFx57Styles();
|
||||
assert.isTrue(/fx-57/.test(startupStyles.getClassName()));
|
||||
});
|
||||
|
||||
it('does not add `fx-57` if UA is FxiOS <= 9', () => {
|
||||
sinon.stub(environment, 'isFx57OrAbove').callsFake(() => false);
|
||||
sinon.stub(environment, 'isFxiOS10OrAbove').callsFake(() => false);
|
||||
|
||||
startupStyles.addFx57Styles();
|
||||
assert.isFalse(/fx-57/.test(startupStyles.getClassName()));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('initialize', function () {
|
||||
it('runs all the tests', function () {
|
||||
|
|
|
@ -159,6 +159,40 @@ define(function (require, exports, module) {
|
|||
});
|
||||
});
|
||||
|
||||
describe('isFxiOS10OrAbove', function () {
|
||||
it('returns `false` if on Fx 10 or above, false otw', function () {
|
||||
assert.isFalse(environment.isFxiOS10OrAbove('FxiOS/9.0'));
|
||||
assert.isTrue(environment.isFxiOS10OrAbove('FxiOS/10.0'));
|
||||
assert.isTrue(environment.isFxiOS10OrAbove('FxiOS/11.0'));
|
||||
assert.isFalse(environment.isFxiOS('Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:40.0) Gecko/20100101 Firefox/40.0'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('isFx57OrAbove', () => {
|
||||
it('returns `true` if Fx Desktop 57 or above', () => {
|
||||
assert.isTrue(environment.isFx57OrAbove('Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:57.0) Gecko/20100101 Firefox/57.0'));
|
||||
assert.isTrue(environment.isFx57OrAbove('Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:58.0) Gecko/20100101 Firefox/58.0'));
|
||||
assert.isTrue(environment.isFx57OrAbove('Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:101.0) Gecko/20100101 Firefox/101.0'));
|
||||
assert.isTrue(environment.isFx57OrAbove('Mozilla/5.0 (Windows NT x.y; WOW64; rv:101.0) Gecko/20100101 Firefox/101.0'));
|
||||
});
|
||||
|
||||
it('returns `true` if Fx for Android 57 or above', () => {
|
||||
assert.isTrue(environment.isFx57OrAbove('Mozilla/5.0 (Android 4.4; Mobile; rv:57.0) Gecko/57.0 Firefox/57.0'));
|
||||
assert.isTrue(environment.isFx57OrAbove('Mozilla/5.0 (Android 4.4; Mobile; rv:57.0) Gecko/58.0 Firefox/58.0'));
|
||||
assert.isTrue(environment.isFx57OrAbove('Mozilla/5.0 (Android 4.4; Mobile; rv:57.0) Gecko/999.0 Firefox/999.0'));
|
||||
});
|
||||
|
||||
it('returns `false` otw', () => {
|
||||
assert.isFalse(environment.isFx57OrAbove('Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:40.0) Gecko/20100101 Firefox/40.0'));
|
||||
assert.isFalse(environment.isFx57OrAbove('Mozilla/5.0 (Windows NT x.y; WOW64; rv:10.0) Gecko/20100101 Firefox/10.0'));
|
||||
assert.isFalse(environment.isFx57OrAbove('Mozilla/5.0 (Android; Mobile; rv:40.0) Gecko/40.0 Firefox/40.0'));
|
||||
assert.isFalse(environment.isFx57OrAbove('Mozilla/5.0 (Android 4.4; Mobile; rv:41.0) Gecko/41.0 Firefox/41.0'));
|
||||
assert.isFalse(environment.isFx57OrAbove('Mozilla/5.0 (Android 4.4; Mobile; rv:56.0) Gecko/56.0 Firefox/56.0'));
|
||||
assert.isFalse(environment.isFx57OrAbove(
|
||||
'Mozilla/5.0 (iPod touch; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/1.0 Mobile/12F69 Safari/600.1.4'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasSendBeacon', function () {
|
||||
it('returns `true` if sendBeacon function exists', function () {
|
||||
windowMock.navigator.sendBeacon = function () {};
|
||||
|
|
|
@ -32,6 +32,7 @@ module.exports = function (config, i18n) {
|
|||
// Disable server verification for now due to issues with customs
|
||||
//require('./routes/get-verify-email')(),
|
||||
require('./routes/get-apple-app-site-association')(),
|
||||
require('./routes/get-favicon')(),
|
||||
require('./routes/get-frontend')(),
|
||||
require('./routes/get-terms-privacy')(i18n),
|
||||
require('./routes/get-index')(config),
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Serve up the favicon. A temporary route to serve the Fx 57 logo to
|
||||
* only Fx >= 57 until the logo is publicly released.
|
||||
*/
|
||||
|
||||
const uaParser = require('node-uap');
|
||||
|
||||
function shouldSee57Icon(uaHeader) {
|
||||
const agent = uaParser.parse(uaHeader);
|
||||
return (agent.ua.family === 'Firefox' && parseInt(agent.ua.major, 10) >= 57) ||
|
||||
(agent.ua.family === 'Firefox Mobile' && parseInt(agent.ua.major, 10) >= 57) ||
|
||||
(agent.ua.family === 'Firefox iOS' && parseInt(agent.ua.major, 10) >= 10);
|
||||
}
|
||||
|
||||
module.exports = function () {
|
||||
return {
|
||||
method: 'get',
|
||||
path: '/favicon.ico',
|
||||
process: (req, res, next) => {
|
||||
if (! shouldSee57Icon(req.headers['user-agent'] || '')) {
|
||||
req.url = 'favicon-pre57.ico';
|
||||
}
|
||||
next();
|
||||
}
|
||||
};
|
||||
};
|
|
@ -7,6 +7,8 @@ define([], function () {
|
|||
return {
|
||||
'android_chrome': 'Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19',
|
||||
'android_firefox': 'Mozilla/5.0 (Android 4.4; Mobile; rv:43.0) Gecko/41.0 Firefox/43.0',
|
||||
'android_firefox_56': 'Mozilla/5.0 (Android 4.4; Mobile; rv:56.0) Gecko/56.0 Firefox/56.0',
|
||||
'android_firefox_57': 'Mozilla/5.0 (Android 4.4; Mobile; rv:57.0) Gecko/57.0 Firefox/57.0',
|
||||
'desktop_chrome': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.59 Safari/537.36',
|
||||
'desktop_firefox': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:50.0) Gecko/20100101 Firefox/50.0',
|
||||
'desktop_firefox_55': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:55.0) Gecko/20100101 Firefox/55.0',
|
||||
|
@ -16,6 +18,8 @@ define([], function () {
|
|||
'ios_firefox': 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/1.0 Mobile/12F69 Safari/600.1.4',
|
||||
'ios_firefox_6_0': 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/6.0 Mobile/12F69 Safari/600.1.4',
|
||||
'ios_firefox_6_1': 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/6.1 Mobile/12F69 Safari/600.1.4',
|
||||
'ios_firefox_9': 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/9.0 Mobile/12F69 Safari/600.1.4',
|
||||
'ios_firefox_10': 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/10.0 Mobile/12F69 Safari/600.1.4', // eslint-disable-line
|
||||
'ios_safari': 'Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3'
|
||||
};
|
||||
/*eslint-enable max-len*/
|
||||
|
|
|
@ -33,6 +33,7 @@ define([
|
|||
'tests/server/statsd-collector',
|
||||
'tests/server/raven',
|
||||
'tests/server/routes/get-apple-app-site-association',
|
||||
'tests/server/routes/get-favicon',
|
||||
'tests/server/routes/get-config',
|
||||
'tests/server/routes/get-verify-email',
|
||||
'tests/server/routes/get-fxa-client-configuration',
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
define([
|
||||
'intern!object',
|
||||
'intern/chai!assert',
|
||||
'intern/dojo/node!../../../server/lib/routes/get-favicon',
|
||||
'../../functional/lib/ua-strings',
|
||||
], function (registerSuite, assert, route, uaStrings) {
|
||||
let instance, request, response;
|
||||
|
||||
/*eslint-disable sorting/sort-object-props*/
|
||||
registerSuite({
|
||||
name: 'routes/get-favicon',
|
||||
|
||||
'route interface is correct': function () {
|
||||
assert.isFunction(route);
|
||||
assert.lengthOf(route, 0);
|
||||
},
|
||||
|
||||
'initialise route': {
|
||||
setup: function () {
|
||||
instance = route();
|
||||
},
|
||||
|
||||
'instance interface is correct': function () {
|
||||
assert.isObject(instance);
|
||||
assert.lengthOf(Object.keys(instance), 3);
|
||||
assert.equal(instance.method, 'get');
|
||||
assert.equal(instance.path, '/favicon.ico');
|
||||
assert.isFunction(instance.process);
|
||||
assert.lengthOf(instance.process, 3);
|
||||
},
|
||||
|
||||
'route.process': {
|
||||
'no user-agent header': {
|
||||
setup: function () {
|
||||
request = {
|
||||
headers: {},
|
||||
url: 'favicon.ico'
|
||||
};
|
||||
return new Promise((resolve) => {
|
||||
instance.process(request, response, resolve);
|
||||
});
|
||||
},
|
||||
|
||||
'should see old icon': function () {
|
||||
assert.equal(request.url, 'favicon-pre57.ico');
|
||||
}
|
||||
},
|
||||
|
||||
'Firefox desktop 56': {
|
||||
setup: function () {
|
||||
request = {
|
||||
headers: {
|
||||
'user-agent': uaStrings.desktop_firefox_56
|
||||
},
|
||||
url: 'favicon.ico'
|
||||
};
|
||||
return new Promise((resolve) => {
|
||||
instance.process(request, response, resolve);
|
||||
});
|
||||
},
|
||||
|
||||
'should see old icon': function () {
|
||||
assert.equal(request.url, 'favicon-pre57.ico');
|
||||
}
|
||||
},
|
||||
|
||||
'Firefox desktop 57': {
|
||||
setup: function () {
|
||||
request = {
|
||||
headers: {
|
||||
'user-agent': uaStrings.desktop_firefox_57
|
||||
},
|
||||
url: 'favicon.ico'
|
||||
};
|
||||
return new Promise((resolve) => {
|
||||
instance.process(request, response, resolve);
|
||||
});
|
||||
},
|
||||
|
||||
'should see new icon': function () {
|
||||
assert.equal(request.url, 'favicon.ico');
|
||||
}
|
||||
},
|
||||
|
||||
'Firefox android 56': {
|
||||
setup: function () {
|
||||
request = {
|
||||
headers: {
|
||||
'user-agent': uaStrings.android_firefox_56
|
||||
},
|
||||
url: 'favicon.ico'
|
||||
};
|
||||
return new Promise((resolve) => {
|
||||
instance.process(request, response, resolve);
|
||||
});
|
||||
},
|
||||
|
||||
'should see old icon': function () {
|
||||
assert.equal(request.url, 'favicon-pre57.ico');
|
||||
}
|
||||
},
|
||||
|
||||
'Firefox android 57': {
|
||||
setup: function () {
|
||||
request = {
|
||||
headers: {
|
||||
'user-agent': uaStrings.android_firefox_57
|
||||
},
|
||||
url: 'favicon.ico'
|
||||
};
|
||||
return new Promise((resolve) => {
|
||||
instance.process(request, response, resolve);
|
||||
});
|
||||
},
|
||||
|
||||
'should see new icon': function () {
|
||||
assert.equal(request.url, 'favicon.ico');
|
||||
}
|
||||
},
|
||||
|
||||
'Firefox iOS 9': {
|
||||
setup: function () {
|
||||
request = {
|
||||
headers: {
|
||||
'user-agent': uaStrings.ios_firefox_9
|
||||
},
|
||||
url: 'favicon.ico'
|
||||
};
|
||||
return new Promise((resolve) => {
|
||||
instance.process(request, response, resolve);
|
||||
});
|
||||
},
|
||||
|
||||
'should see old icon': function () {
|
||||
assert.equal(request.url, 'favicon-pre57.ico');
|
||||
}
|
||||
},
|
||||
|
||||
'Firefox iOS 10': {
|
||||
setup: function () {
|
||||
request = {
|
||||
headers: {
|
||||
'user-agent': uaStrings.ios_firefox_10
|
||||
},
|
||||
url: 'favicon.ico'
|
||||
};
|
||||
return new Promise((resolve) => {
|
||||
instance.process(request, response, resolve);
|
||||
});
|
||||
},
|
||||
|
||||
'should see new icon': function () {
|
||||
assert.equal(request.url, 'favicon.ico');
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
/*eslint-enable sorting/sort-object-props*/
|
||||
});
|
Загрузка…
Ссылка в новой задаче