Format JS files using Prettier (Fixes #10468, #10479)

This commit is contained in:
Alex Gibson 2021-10-06 13:18:46 +01:00
Родитель 2ef16dc299
Коммит 7305098445
157 изменённых файлов: 5838 добавлений и 3509 удалений

Просмотреть файл

@ -1,56 +1,23 @@
module.exports = {
env: {
'browser': true,
'commonjs': true,
'jasmine': true
browser: true,
commonjs: true,
jasmine: true
},
extends: [
'eslint:recommended',
'plugin:json/recommended'
],
extends: ['eslint:recommended', 'plugin:json/recommended', 'prettier'],
rules: {
// Require strict mode directive in top level functions
// https://eslint.org/docs/rules/strict
'strict': ['error', 'function'],
// This option sets a specific tab width for your code
// https://eslint.org/docs/rules/indent
'indent': ['error', 4],
// Disallow mixed 'LF' and 'CRLF' as linebreaks
// https://eslint.org/docs/rules/linebreak-style
'linebreak-style': ['error', 'unix'],
// Specify whether double or single quotes should be used
'quotes': ['error', 'single'],
// Require or disallow use of semicolons instead of ASI
'semi': ['error', 'always'],
// Enforce location of semicolons
// https://eslint.org/docs/rules/semi-style
'semi-style': ['error', 'last'],
// Require camel case names
// https://eslint.org/docs/rules/camelcase
'camelcase': ['error', { 'properties': 'always' }],
strict: ['error', 'function'],
// Use type-safe equality operators
// https://eslint.org/docs/rules/eqeqeq
'eqeqeq': ['error', 'always'],
eqeqeq: ['error', 'always'],
// Treat var statements as if they were block scoped
// https://eslint.org/docs/rules/block-scoped-var
'block-scoped-var': 'error',
// Require newlines around variable declarations
// https://eslint.org/docs/rules/one-var-declaration-per-line
'one-var-declaration-per-line': ['error', 'always'],
// Require constructor names to begin with a capital letter
// https://eslint.org/docs/rules/new-cap
'new-cap': 'error',
// Disallow Use of alert, confirm, prompt
// https://eslint.org/docs/rules/no-alert
'no-alert': 'error',
@ -65,7 +32,7 @@ module.exports = {
// Require radix parameter
// https://eslint.org/docs/rules/radix
'radix': 'error',
radix: 'error',
// Disallow the use of `console`
// https://eslint.org/docs/rules/no-console
@ -77,14 +44,12 @@ module.exports = {
overrides: [
{
// JS files transpiled by Babel
files: [
'media/js/**/*.es6.js',
],
files: ['media/js/**/*.es6.js'],
env: {
'es2017': true
es2017: true
},
parserOptions: {
'sourceType': 'module'
sourceType: 'module'
},
rules: {
// Require `let` or `const` instead of `var`
@ -105,7 +70,7 @@ module.exports = {
'tests/unit/**/*.js'
],
env: {
'es2017': true
es2017: true
}
},
{
@ -116,17 +81,17 @@ module.exports = {
'tests/unit/karma.conf.js'
],
env: {
'node': true,
'es2017': true
node: true,
es2017: true
},
rules: {
'strict': ['error', 'global'],
strict: ['error', 'global']
}
}
],
globals: {
'Mozilla': 'writable',
'Mzp': 'writable',
'site': 'writable'
Mozilla: 'writable',
Mzp: 'writable',
site: 'writable'
}
};

Просмотреть файл

@ -1,2 +1,5 @@
# Migrate code style to Black
31943fea7582fa42320b44e796b0e343bfa90f89
# Migrate JS code style to Prettier
af4305055ec7748541c87c7cb035c547fbcb8303

Просмотреть файл

@ -23,6 +23,10 @@ repos:
- id: flake8
# TODO Add this and fix issues found
# additional_dependencies: [flake8-bugbear]
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.4.1
hooks:
- id: prettier
- repo: https://github.com/awebdeveloper/pre-commit-stylelint
rev: 0.0.2
hooks:
@ -36,11 +40,5 @@ repos:
- id: eslint
additional_dependencies:
- "eslint-plugin-json@2.1.1"
exclude: >
(?x)^(
docs
| node_modules
| assets
| static
| media/js/libs
)
- "eslint-config-prettier@8.3.0"
# Additional excludes in /.eslintignore file

25
.prettierignore Normal file
Просмотреть файл

@ -0,0 +1,25 @@
# Ignore artifacts:
.vscode/
assets
data
docs
git-repos
node_modules
static
static_build
static_final
venv
# Ignore external JS libraries
media/js/libs/**/
media/js/ie/libs/**/
# Ignore file types:
# https://github.com/prettier/prettier/issues/6356 blocks formating scss/css.
*.html
*.md
*.scss
*.css
*.yml
*.yaml
*.json

6
.prettierrc.json Normal file
Просмотреть файл

@ -0,0 +1,6 @@
{
"trailingComma": "none",
"tabWidth": 4,
"semi": true,
"singleQuote": true
}

Просмотреть файл

@ -1,40 +1,43 @@
{
"rules": {
"color-no-invalid-hex": true,
"font-family-no-duplicate-names": true,
"font-family-name-quotes": "always-where-recommended",
"function-name-case": "lower",
"function-url-no-scheme-relative": true,
"function-url-quotes": "always",
"number-no-trailing-zeros": true,
"length-zero-no-unit": true,
"unit-case": "lower",
"unit-no-unknown": true,
"property-case": "lower",
"property-no-unknown": true,
"keyframe-declaration-no-important": true,
"declaration-no-important": true,
"declaration-block-no-shorthand-property-overrides": true,
"declaration-block-single-line-max-declarations": 1,
"declaration-block-trailing-semicolon": "always",
"declaration-block-semicolon-newline-after": "always-multi-line",
"block-no-empty": true,
"selector-pseudo-class-no-unknown": true,
"selector-pseudo-element-no-unknown": true,
"selector-pseudo-element-case": "lower",
"selector-type-case": "lower",
"selector-type-no-unknown": true,
"selector-max-empty-lines": 0,
"media-feature-name-case": "lower",
"media-feature-name-no-unknown": [true, {
ignoreMediaFeatureNames: ["min--moz-device-pixel-ratio"]
}],
"comment-no-empty": true,
"max-nesting-depth": 5,
"no-invalid-double-slash-comments": true,
"no-unknown-animations": true,
"no-extra-semicolons": true,
"no-missing-end-of-source-newline": true,
"no-eol-whitespace": true
}
"rules": {
"color-no-invalid-hex": true,
"font-family-no-duplicate-names": true,
"font-family-name-quotes": "always-where-recommended",
"function-name-case": "lower",
"function-url-no-scheme-relative": true,
"function-url-quotes": "always",
"number-no-trailing-zeros": true,
"length-zero-no-unit": true,
"unit-case": "lower",
"unit-no-unknown": true,
"property-case": "lower",
"property-no-unknown": true,
"keyframe-declaration-no-important": true,
"declaration-no-important": true,
"declaration-block-no-shorthand-property-overrides": true,
"declaration-block-single-line-max-declarations": 1,
"declaration-block-trailing-semicolon": "always",
"declaration-block-semicolon-newline-after": "always-multi-line",
"block-no-empty": true,
"selector-pseudo-class-no-unknown": true,
"selector-pseudo-element-no-unknown": true,
"selector-pseudo-element-case": "lower",
"selector-type-case": "lower",
"selector-type-no-unknown": true,
"selector-max-empty-lines": 0,
"media-feature-name-case": "lower",
"media-feature-name-no-unknown": [
true,
{
"ignoreMediaFeatureNames": ["min--moz-device-pixel-ratio"]
}
],
"comment-no-empty": true,
"max-nesting-depth": 5,
"no-invalid-double-slash-comments": true,
"no-unknown-animations": true,
"no-extra-semicolons": true,
"no-missing-end-of-source-newline": true,
"no-eol-whitespace": true
}
}

Просмотреть файл

@ -13,7 +13,7 @@ COPY package.json yarn.lock ./
RUN yarn install --pure-lockfile
# copy supporting files and media
COPY .eslintrc.js .eslintignore .stylelintrc .stylelintignore webpack.config.js webpack.static.config.js ./
COPY .eslintrc.js .eslintignore .stylelintrc .stylelintignore .prettierignore .prettierrc.json webpack.config.js webpack.static.config.js ./
COPY ./media ./media
COPY ./tests/unit ./tests/unit

Просмотреть файл

@ -18,7 +18,8 @@ help:
@echo " fresh-data - pull the latest database and update all external data"
@echo " clean - remove all build, test, coverage and Python artifacts"
@echo " rebuild - force a rebuild of all of the docker images"
@echo " lint - check style with flake8, eslint, and stylelint"
@echo " lint - check style with Flake8, ESlint, Stylelint, and Prettier"
@echo " format - format front-end code using Prettier"
@echo " test - run tests against local files"
@echo " test-image - run tests against files in docker image"
@echo " test-cdn - run CDN tests against TEST_DOMAIN"
@ -97,6 +98,10 @@ lint: .docker-build-pull
${DC} run test flake8
${DC} run assets npm run lint
format: .docker-build-pull
${DC} run assets npm run prettier
${DC} run app black .
test: .docker-build-pull
${DC} run test

Просмотреть файл

@ -514,29 +514,30 @@ location of the user.
<h1>Yay World!</h1>
{% endif %}
Coding Style Guides
-------------------
Coding Style
------------
Bedrock uses the following open source tools to follow coding styles and conventions,
as well as applying automatic code formatting:
* `Black <https://black.readthedocs.io/>`_ for Python code formatting.
* `Flake8 <https://flake8.pycqa.org/>`_ for Python style and code quality rules.
* `Prettier <https://prettier.io/>`_ for JavaScript code formatting.
* `ESLint <https://eslint.org/>`_ for JavaScript code quality rules.
* `Stylelint <https://stylelint.io/>`_ for Sass/CSS style and code quality rules.
For front-end HTML & CSS conventions, bedrock uses Mozilla's Protocol design system for
building components. You can read the `Protocol documentation site <https://protocol.mozilla.org/>`_
for more information.
Mozilla also has some more general coding styleguides available, although some of
these are now rather outdated:
* `Mozilla Python Style Guide <http://mozweb.readthedocs.org/en/latest/reference/python-style.html>`_
* `Mozilla HTML Style Guide <http://mozweb.readthedocs.org/en/latest/reference/html-style.html>`_
* `Mozilla JS Style Guide <http://mozweb.readthedocs.org/en/latest/reference/js-style.html>`_
* `Mozilla CSS Style Guide <http://mozweb.readthedocs.org/en/latest/reference/css-style.html>`_
Use the ``.open-sans``, ``.open-sans-light`` and ``.open-sans-extrabold`` mixins
to specify font families to allow using international fonts. See the :ref:`CSS <l10n>`
section in the l10n doc for details.
Use the ``.font-size()`` mixin to generate root-relative font sizes. You can
declare a font size in pixels and the mixin will convert it to an equivalent
``rem`` (root em) unit while also including the pixel value as a fallback for
older browsers that don't support ``rem``. This is preferable to declaring font
sizes in either fixed units (``px``, ``pt``, etc) or element-relative units (``em``, ``%``).
See `this post by Jonathan Snook <http://snook.ca/archives/html_and_css/font-size-with-rem>`_
for more info.
When including CSS blocks, use ``{% block page_css %}`` for page specific inclusion of CSS.
``{% block site_css %}`` should only be touched in rare cases where base styles need to be overwritten.
Configuring your code editor
----------------------------

Просмотреть файл

@ -2,14 +2,12 @@
// 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/.
(function() {
(function () {
'use strict';
function onLoad() {
window.Mozilla.Banner.init('eu-mr1-banner');
}
window.Mozilla.run(onLoad);
})();

Просмотреть файл

@ -11,15 +11,18 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function() {
(function () {
'use strict';
function onLoad() {
window.Mozilla.Banner.init('firefox-app-store-banner', true);
}
if (window.Mozilla.run && window.site && (window.site.platform === 'android' || window.site.platform === 'ios')) {
if (
window.Mozilla.run &&
window.site &&
(window.site.platform === 'android' || window.site.platform === 'ios')
) {
window.Mozilla.run(onLoad);
}
})();

Просмотреть файл

@ -2,7 +2,7 @@
// 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/.
(function() {
(function () {
'use strict';
function onLoad() {

Просмотреть файл

@ -7,25 +7,25 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function() {
(function () {
'use strict';
var _pageBanner;
var Banner = {};
Banner.setCookie = function(id) {
Banner.setCookie = function (id) {
var date = new Date();
var cookieDuration = 1 * 24 * 60 * 60 * 1000; // 1 day expiration
date.setTime(date.getTime() + cookieDuration); // 1 day expiration
Mozilla.Cookies.setItem(id, true, date.toUTCString(), '/');
};
Banner.hasCookie = function(id) {
Banner.hasCookie = function (id) {
return Mozilla.Cookies.hasItem(id);
};
Banner.close = function() {
Banner.close = function () {
// Remove the banner from the DOM.
_pageBanner.parentNode.removeChild(_pageBanner);
@ -34,14 +34,14 @@ if (typeof window.Mozilla === 'undefined') {
// Track the event in GA.
window.dataLayer.push({
'event': 'in-page-interaction',
'eLabel': 'Banner Dismissal',
event: 'in-page-interaction',
eLabel: 'Banner Dismissal',
'data-banner-name': Banner.id,
'data-banner-dismissal': '1'
});
};
Banner.show = function(renderAtTopOfPage) {
Banner.show = function (renderAtTopOfPage) {
var outerWrapper = document.getElementById('outer-wrapper');
// if for some reason there's no outer-wrapper on the page, do nothing.
@ -63,11 +63,14 @@ if (typeof window.Mozilla === 'undefined') {
_pageBanner.classList.add('c-banner-is-visible');
// wire up close button
_pageBanner.querySelector('.c-banner-close').addEventListener('click', Banner.close, false);
_pageBanner
.querySelector('.c-banner-close')
.addEventListener('click', Banner.close, false);
};
Banner.init = function(id, renderAtTopOfPage) {
var cookiesEnabled = typeof Mozilla.Cookies !== 'undefined' && Mozilla.Cookies.enabled();
Banner.init = function (id, renderAtTopOfPage) {
var cookiesEnabled =
typeof Mozilla.Cookies !== 'undefined' && Mozilla.Cookies.enabled();
_pageBanner = document.getElementById(id);
@ -88,5 +91,4 @@ if (typeof window.Mozilla === 'undefined') {
};
window.Mozilla.Banner = Banner;
})();

Просмотреть файл

@ -5,11 +5,11 @@
/**
* General DOM ready handler applied to all pages in base template.
*/
(function() {
(function () {
'use strict';
if (typeof Mozilla.Utils !== 'undefined') {
Mozilla.Utils.onDocumentReady(function() {
Mozilla.Utils.onDocumentReady(function () {
var utils = Mozilla.Utils;
utils.initMobileDownloadLinks();
@ -21,15 +21,20 @@
var client = Mozilla.Client;
if (client.isFirefoxDesktop) {
client.getFirefoxDetails(utils.maybeSwitchToChinaRepackImages);
client.getFirefoxDetails(
utils.maybeSwitchToChinaRepackImages
);
}
}
});
}
// The `loaded` class is used mostly as a signal for functional tests to run.
window.addEventListener('load', function() {
document.getElementsByTagName('html')[0].classList.add('loaded');
}, false);
window.addEventListener(
'load',
function () {
document.getElementsByTagName('html')[0].classList.add('loaded');
},
false
);
})();

Просмотреть файл

@ -3,25 +3,25 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// init core dataLayer object and push into dataLayer
(function() {
(function () {
'use strict';
var analytics = Mozilla.Analytics;
var client = Mozilla.Client;
var dataLayer = window.dataLayer = window.dataLayer || [];
var dataLayer = (window.dataLayer = window.dataLayer || []);
var firefoxDetailsComplete = false;
var fxaDetailsComplete = false;
function sendCoreDataLayer() {
var dataLayerCore = {
'event': 'core-datalayer-loaded',
'pageHasDownload': analytics.pageHasDownload(),
'pageHasVideo': analytics.pageHasVideo(),
'pageVersion': analytics.getPageVersion(),
event: 'core-datalayer-loaded',
pageHasDownload: analytics.pageHasDownload(),
pageHasVideo: analytics.pageHasVideo(),
pageVersion: analytics.getPageVersion(),
// permitted for www.mozill.org, will always return false on other domains
'testPilotUser': 'testpilotAddon' in navigator ? 'true' : 'false',
'releaseWindowVersion': analytics.getLatestFxVersion(),
'win10SUser': analytics.isWin10S()
testPilotUser: 'testpilotAddon' in navigator ? 'true' : 'false',
releaseWindowVersion: analytics.getLatestFxVersion(),
win10SUser: analytics.isWin10S()
};
dataLayer.push(dataLayerCore);
@ -34,14 +34,14 @@
}
function initCoreDataLayer() {
client.getFxaDetails(function(details) {
client.getFxaDetails(function (details) {
dataLayer.push(analytics.formatFxaDetails(details));
fxaDetailsComplete = true;
checkSendCoreDataLayer();
});
if (client.isFirefoxDesktop || client.isFirefoxAndroid) {
client.getFirefoxDetails(function(details) {
client.getFirefoxDetails(function (details) {
dataLayer.push(details);
firefoxDetailsComplete = true;
checkSendCoreDataLayer();
@ -56,7 +56,7 @@
// Init dataLayer event on DOM Ready.
if (typeof Mozilla.Utils !== 'undefined') {
Mozilla.Utils.onDocumentReady(function() {
Mozilla.Utils.onDocumentReady(function () {
initCoreDataLayer();
// Add GA custom dimension for AMO experiments (Issue 10175).
@ -73,5 +73,4 @@
}
});
}
})();

Просмотреть файл

@ -6,30 +6,39 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function(Mozilla) {
(function (Mozilla) {
'use strict';
// init dataLayer object
var dataLayer = window.dataLayer = window.dataLayer || [];
var dataLayer = (window.dataLayer = window.dataLayer || []);
var Analytics = {};
/** Returns page ID used in Event Category for GA events tracked on page.
* @param {String} path - URL path name fallback if page ID does not exist.
* @return {String} GTM page ID.
*/
Analytics.getPageId = function(path) {
var pageId = document.getElementsByTagName('html')[0].getAttribute('data-gtm-page-id');
* @param {String} path - URL path name fallback if page ID does not exist.
* @return {String} GTM page ID.
*/
Analytics.getPageId = function (path) {
var pageId = document
.getElementsByTagName('html')[0]
.getAttribute('data-gtm-page-id');
var pathName = path ? path : document.location.pathname;
return pageId ? pageId : pathName.replace(/^(\/\w{2}-\w{2}\/|\/\w{2,3}\/)/, '/');
return pageId
? pageId
: pathName.replace(/^(\/\w{2}-\w{2}\/|\/\w{2,3}\/)/, '/');
};
Analytics.getTrafficCopReferrer = function() {
Analytics.getTrafficCopReferrer = function () {
var referrer;
// if referrer cookie exists, store the value and remove the cookie
if (Mozilla.Cookies && Mozilla.Cookies.hasItem('mozilla-traffic-cop-original-referrer')) {
referrer = Mozilla.Cookies.getItem('mozilla-traffic-cop-original-referrer');
if (
Mozilla.Cookies &&
Mozilla.Cookies.hasItem('mozilla-traffic-cop-original-referrer')
) {
referrer = Mozilla.Cookies.getItem(
'mozilla-traffic-cop-original-referrer'
);
// referrer shouldn't persist
Mozilla.Cookies.removeItem('mozilla-traffic-cop-original-referrer');
@ -38,10 +47,10 @@ if (typeof window.Mozilla === 'undefined') {
return referrer;
};
Analytics.buildDataObject = function() {
Analytics.buildDataObject = function () {
var dataObj = {
'event': 'page-id-loaded',
'pageId': Analytics.getPageId()
event: 'page-id-loaded',
pageId: Analytics.getPageId()
};
var referrer = Analytics.getTrafficCopReferrer();

Просмотреть файл

@ -3,46 +3,53 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Utility class for core dataLayer object to track contextual user and page data
*/
* Utility class for core dataLayer object to track contextual user and page data
*/
if (typeof window.Mozilla.Analytics === 'undefined') {
window.Mozilla.Analytics = {};
}
(function() {
(function () {
'use strict';
var analytics = Mozilla.Analytics;
var isModernBrowser = 'querySelector' in document && 'querySelectorAll' in document;
var isModernBrowser =
'querySelector' in document && 'querySelectorAll' in document;
/** Returns whether page has download button.
* @param {String} path - URL path name fallback if page ID does not exist.
* @return {String} string.
*/
analytics.pageHasDownload = function() {
* @param {String} path - URL path name fallback if page ID does not exist.
* @return {String} string.
*/
analytics.pageHasDownload = function () {
if (!isModernBrowser) {
return 'false';
}
return document.querySelector('[data-download-os]') !== null ? 'true' : 'false';
return document.querySelector('[data-download-os]') !== null
? 'true'
: 'false';
};
/** Returns whether page has video.
* @param {String} path - URL path name fallback if page ID does not exist.
* @return {String} string.
*/
analytics.pageHasVideo = function() {
* @param {String} path - URL path name fallback if page ID does not exist.
* @return {String} string.
*/
analytics.pageHasVideo = function () {
if (!isModernBrowser) {
return 'false';
}
return (document.querySelector('video') !== null || document.querySelector('iframe[src^="https://www.youtube"]') !== null) ? 'true' : 'false';
return document.querySelector('video') !== null ||
document.querySelector('iframe[src^="https://www.youtube"]') !==
null
? 'true'
: 'false';
};
/** Returns page version.
* @param {String} path - URL path name fallback if page ID does not exist.
* @return {String} version number from URL.
*/
analytics.getPageVersion = function(path) {
* @param {String} path - URL path name fallback if page ID does not exist.
* @return {String} version number from URL.
*/
analytics.getPageVersion = function (path) {
var pathName = path ? path : document.location.pathname;
var versionResults = /firefox\/(\d+(?:\.\d+)?\.\da?\d?)/.exec(pathName);
@ -50,17 +57,19 @@ if (typeof window.Mozilla.Analytics === 'undefined') {
};
/** Returns latest Fx version.
* @return {String} latest Fx version.
*/
analytics.getLatestFxVersion = function() {
return document.getElementsByTagName('html')[0].getAttribute('data-latest-firefox');
* @return {String} latest Fx version.
*/
analytics.getLatestFxVersion = function () {
return document
.getElementsByTagName('html')[0]
.getAttribute('data-latest-firefox');
};
/** Returns true if user is running Windows 10 in S mode.
* @param {String} ua - User Agent string.
* @return {Boolean}.
*/
analytics.isWin10S = function(ua) {
* @param {String} ua - User Agent string.
* @return {Boolean}.
*/
analytics.isWin10S = function (ua) {
ua = ua || navigator.userAgent;
var isEdge = ua.indexOf('Edge') > -1;
@ -70,30 +79,36 @@ if (typeof window.Mozilla.Analytics === 'undefined') {
}
try {
var mode = JSON.parse(window.external.getHostEnvironmentValue('os-mode'));
var mode = JSON.parse(
window.external.getHostEnvironmentValue('os-mode')
);
if (mode && mode['os-mode'] === '2') {
return true;
}
return false;
} catch(e) {
} catch (e) {
return false;
}
};
analytics.getAMOExperiment = function(params) {
analytics.getAMOExperiment = function (params) {
var allowedExperiment = /^\d{8}_amo_.[\w/.%-]{1,50}$/; // should match the format YYYYMMDD_amo_experiment_name.
var allowedVariation = /^[\w/.%-]{1,50}$/; // allow alpha numeric & common URL encoded chars.
if (Object.prototype.hasOwnProperty.call(params, 'experiment') &&
Object.prototype.hasOwnProperty.call(params, 'variation')) {
if (
Object.prototype.hasOwnProperty.call(params, 'experiment') &&
Object.prototype.hasOwnProperty.call(params, 'variation')
) {
var experiment = decodeURIComponent(params['experiment']);
var variation = decodeURIComponent(params['variation']);
if ((allowedExperiment).test(experiment) && (allowedVariation).test(variation)) {
if (
allowedExperiment.test(experiment) &&
allowedVariation.test(variation)
) {
return {
'experiment': experiment,
'variation': variation
experiment: experiment,
variation: variation
};
}
}
@ -102,17 +117,17 @@ if (typeof window.Mozilla.Analytics === 'undefined') {
};
/** Returns an object containing GA-formatted FxA details
* The specs for this are a combination of:
* - https://bugzilla.mozilla.org/show_bug.cgi?id=1457024#c33
* - https://bugzilla.mozilla.org/show_bug.cgi?id=1457004#c22
* Our implmentation it might deviate from the spec where there was conflicting info in the spec.
*
* Data arrives from Client.getFxaDetails as an object, see getFxaDetails for details.
*
* @param {Object} FxaDetails - object of FxA details returned by getFxaDetails
* @return {Object} FxA details formatted for GA
*/
analytics.formatFxaDetails = function(FxaDetails) {
* The specs for this are a combination of:
* - https://bugzilla.mozilla.org/show_bug.cgi?id=1457024#c33
* - https://bugzilla.mozilla.org/show_bug.cgi?id=1457004#c22
* Our implmentation it might deviate from the spec where there was conflicting info in the spec.
*
* Data arrives from Client.getFxaDetails as an object, see getFxaDetails for details.
*
* @param {Object} FxaDetails - object of FxA details returned by getFxaDetails
* @return {Object} FxA details formatted for GA
*/
analytics.formatFxaDetails = function (FxaDetails) {
// start with empty object
var formatted = {};
@ -134,8 +149,12 @@ if (typeof window.Mozilla.Analytics === 'undefined') {
}
// variables to compare to determine the segments
var mobileDevices = FxaDetails.browserServices.sync ? FxaDetails.browserServices.sync.mobileDevices : null;
var desktopDevices = FxaDetails.browserServices.sync ? FxaDetails.browserServices.sync.desktopDevices : null;
var mobileDevices = FxaDetails.browserServices.sync
? FxaDetails.browserServices.sync.mobileDevices
: null;
var desktopDevices = FxaDetails.browserServices.sync
? FxaDetails.browserServices.sync.desktopDevices
: null;
// set FxAMobileSync
if (mobileDevices > 0) {
@ -165,7 +184,6 @@ if (typeof window.Mozilla.Analytics === 'undefined') {
} else if (desktopDevices > 1) {
formatted.FxASegment = 'Multi-Desktop Sync';
}
} else {
// Not logged into FxA
if (FxaDetails.legacy === true) {
@ -186,15 +204,15 @@ if (typeof window.Mozilla.Analytics === 'undefined') {
};
/** Monkey patch for dataLayer.push
* Adds href stripped of locale to link click objects when pushed to the dataLayer,
* also removes protocol and host if same as parent page from href.
*/
analytics.updateDataLayerPush = function(host) {
var dataLayer = window.dataLayer = window.dataLayer || [];
* Adds href stripped of locale to link click objects when pushed to the dataLayer,
* also removes protocol and host if same as parent page from href.
*/
analytics.updateDataLayerPush = function (host) {
var dataLayer = (window.dataLayer = window.dataLayer || []);
var hostname = host || document.location.hostname;
dataLayer.defaultPush = dataLayer.push;
dataLayer.push = function() {
dataLayer.push = function () {
for (var i = 0; i < arguments.length; i++) {
if (arguments[i].event === 'gtm.linkClick') {
var element = arguments[i]['gtm.element'];
@ -202,8 +220,13 @@ if (typeof window.Mozilla.Analytics === 'undefined') {
if (element.hostname === hostname) {
// remove host and locale from internal links
var path = href.replace(/^(?:https?:\/\/)(?:[^/])*/, '');
var locale = path.match(/^(\/\w{2}-\w{2}\/|\/\w{2,3}\/)/);
var path = href.replace(
/^(?:https?:\/\/)(?:[^/])*/,
''
);
var locale = path.match(
/^(\/\w{2}-\w{2}\/|\/\w{2,3}\/)/
);
path = locale ? path.replace(locale[0], '/') : path;
arguments[i].newClickHref = path;
@ -218,5 +241,4 @@ if (typeof window.Mozilla.Analytics === 'undefined') {
}
};
};
})();

Просмотреть файл

@ -1,6 +1,6 @@
/* 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/. */
* 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/. */
// create namespace
if (typeof window.Mozilla === 'undefined') {
@ -16,17 +16,25 @@ if (typeof window.Mozilla === 'undefined') {
* @params {string} [ua] - An optional mock userAgent string to ease unit testing.
* @returns {boolean} true if enabled else false
*/
Mozilla.dntEnabled = function(dnt, ua) {
Mozilla.dntEnabled = function (dnt, ua) {
'use strict';
// for old version of IE we need to use the msDoNotTrack property of navigator
// on newer versions, and newer platforms, this is doNotTrack but, on the window object
// Safari also exposes the property on the window object.
var dntStatus = dnt || navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
var dntStatus =
dnt ||
navigator.doNotTrack ||
window.doNotTrack ||
navigator.msDoNotTrack;
var userAgent = ua || navigator.userAgent;
// List of Windows versions known to not implement DNT according to the standard.
var anomalousWinVersions = ['Windows NT 6.1', 'Windows NT 6.2', 'Windows NT 6.3'];
var anomalousWinVersions = [
'Windows NT 6.1',
'Windows NT 6.2',
'Windows NT 6.3'
];
var fxMatch = userAgent.match(/Firefox\/(\d+)/);
var ieRegEx = /MSIE|Trident/i;
@ -41,13 +49,17 @@ Mozilla.dntEnabled = function(dnt, ua) {
} else if (fxMatch && parseInt(fxMatch[1], 10) < 32) {
// Can't say for sure if it is 1 or 0, due to Fx bug 887703
dntStatus = 'Unspecified';
} else if (isIE && platform && anomalousWinVersions.indexOf(platform.toString()) !== -1) {
} else if (
isIE &&
platform &&
anomalousWinVersions.indexOf(platform.toString()) !== -1
) {
// default is on, which does not honor the specification
dntStatus = 'Unspecified';
} else {
// sets dntStatus to Disabled or Enabled based on the value returned by the browser.
// If dntStatus is undefined, it will be set to Unspecified
dntStatus = { '0': 'Disabled', '1': 'Enabled' }[dntStatus] || 'Unspecified';
dntStatus = { 0: 'Disabled', 1: 'Enabled' }[dntStatus] || 'Unspecified';
}
return dntStatus === 'Enabled' ? true : false;

Просмотреть файл

@ -4,7 +4,7 @@
// eslint-disable-next-line
(function(){
(function () {
'use strict';
var backLink = document.getElementById('go-back');
@ -18,7 +18,7 @@
backLink.classList.remove('hide-back');
}
backLink.addEventListener('click', function(){
backLink.addEventListener('click', function () {
window.history.back();
});
}());
})();

Просмотреть файл

@ -25,8 +25,20 @@ if (typeof window.Mozilla === 'undefined') {
'https://guardian-dev.herokuapp.com/'
];
var utms = ['utm_source', 'utm_campaign', 'utm_content', 'utm_term', 'utm_medium'];
var fxaParams = ['device_id', 'flow_id', 'flow_begin_time', 'entrypoint_experiment', 'entrypoint_variation'];
var utms = [
'utm_source',
'utm_campaign',
'utm_content',
'utm_term',
'utm_medium'
];
var fxaParams = [
'device_id',
'flow_id',
'flow_begin_time',
'entrypoint_experiment',
'entrypoint_variation'
];
var sameSiteParams = ['source'];
var acceptedParams = utms.concat(fxaParams, sameSiteParams);
var referralCookieID = 'fxa-product-referral-id';
@ -36,7 +48,7 @@ if (typeof window.Mozilla === 'undefined') {
* @param {String} url.
* @returns {String} hostname.
*/
UtmUrl.getHostName = function(url) {
UtmUrl.getHostName = function (url) {
var matches = url.match(/^https?:\/\/(?:[^/?#]+)(?:[/?#]|$)/i);
return matches && matches[0];
};
@ -46,12 +58,12 @@ if (typeof window.Mozilla === 'undefined') {
* @param {Object} params.
* @returns {Boolean}.
*/
UtmUrl.hasUtmParams = function(params) {
UtmUrl.hasUtmParams = function (params) {
if (typeof params !== 'object') {
return false;
}
for (var param in params){
for (var param in params) {
if (Object.prototype.hasOwnProperty.call(params, param)) {
if (param.indexOf('utm_') === 0) {
return true;
@ -61,15 +73,16 @@ if (typeof window.Mozilla === 'undefined') {
return false;
};
UtmUrl.getFxALinkReferralData = function(params) {
var cookiesEnabled = typeof Mozilla.Cookies !== 'undefined' && Mozilla.Cookies.enabled();
UtmUrl.getFxALinkReferralData = function (params) {
var cookiesEnabled =
typeof Mozilla.Cookies !== 'undefined' && Mozilla.Cookies.enabled();
var allowedChars = /^[\w/.%-]+$/;
var data;
if (cookiesEnabled && UtmUrl.hasFxALinkReferralCookie()) {
var campaign = UtmUrl.getFxALinkReferralCookie();
if (typeof campaign === 'string' && (allowedChars).test(campaign)) {
if (typeof campaign === 'string' && allowedChars.test(campaign)) {
var utmSource = 'www.mozilla.org';
if (campaign.indexOf('whatsnew') !== -1) {
@ -81,10 +94,10 @@ if (typeof window.Mozilla === 'undefined') {
}
data = {
'entrypoint': utmSource,
'utm_source': utmSource,
'utm_medium': 'referral',
'utm_campaign': campaign,
entrypoint: utmSource,
utm_source: utmSource,
utm_medium: 'referral',
utm_campaign: campaign
};
}
}
@ -98,29 +111,41 @@ if (typeof window.Mozilla === 'undefined') {
return null;
};
UtmUrl.hasFxALinkReferralCookie = function() {
UtmUrl.hasFxALinkReferralCookie = function () {
return Mozilla.Cookies.hasItem(referralCookieID);
};
UtmUrl.getFxALinkReferralCookie = function() {
UtmUrl.getFxALinkReferralCookie = function () {
return Mozilla.Cookies.getItem(referralCookieID);
};
UtmUrl.setFxALinkReferralCookie = function(id) {
var cookiesEnabled = typeof Mozilla.Cookies !== 'undefined' && Mozilla.Cookies.enabled();
var dntEnabled = typeof Mozilla.dntEnabled === 'function' && Mozilla.dntEnabled();
UtmUrl.setFxALinkReferralCookie = function (id) {
var cookiesEnabled =
typeof Mozilla.Cookies !== 'undefined' && Mozilla.Cookies.enabled();
var dntEnabled =
typeof Mozilla.dntEnabled === 'function' && Mozilla.dntEnabled();
if (id && cookiesEnabled && !dntEnabled && !UtmUrl.hasFxALinkReferralCookie()) {
if (
id &&
cookiesEnabled &&
!dntEnabled &&
!UtmUrl.hasFxALinkReferralCookie()
) {
var date = new Date();
date.setTime(date.getTime() + (1 * 3600 * 1000)); // expiry in 1 hour.
date.setTime(date.getTime() + 1 * 3600 * 1000); // expiry in 1 hour.
var expires = date.toUTCString();
Mozilla.Cookies.setItem('fxa-product-referral-id', id, expires, '/');
Mozilla.Cookies.setItem(
'fxa-product-referral-id',
id,
expires,
'/'
);
}
};
UtmUrl.onFxALinkReferralClick = function(e) {
var newTab = (e.target.target === '_blank' || e.metaKey || e.ctrlKey);
UtmUrl.onFxALinkReferralClick = function (e) {
var newTab = e.target.target === '_blank' || e.metaKey || e.ctrlKey;
var referralId = e.target.getAttribute('data-referral-id');
if (!newTab) {
@ -134,11 +159,17 @@ if (typeof window.Mozilla === 'undefined') {
}
};
UtmUrl.bindFxALinkReferrals = function() {
var ctaLinks = document.querySelectorAll('.js-fxa-product-referral-link');
UtmUrl.bindFxALinkReferrals = function () {
var ctaLinks = document.querySelectorAll(
'.js-fxa-product-referral-link'
);
for (var i = 0; i < ctaLinks.length; i++) {
ctaLinks[i].addEventListener('click', UtmUrl.onFxALinkReferralClick, false);
ctaLinks[i].addEventListener(
'click',
UtmUrl.onFxALinkReferralClick,
false
);
}
};
@ -155,7 +186,7 @@ if (typeof window.Mozilla === 'undefined') {
var acceptedParam = acceptedParams[i];
if (Object.prototype.hasOwnProperty.call(params, acceptedParam)) {
var foundParam = decodeURIComponent(params[acceptedParam]);
if ((allowedChars).test(foundParam)) {
if (allowedChars.test(foundParam)) {
finalParams[acceptedParam] = foundParam;
}
}
@ -167,13 +198,16 @@ if (typeof window.Mozilla === 'undefined') {
* the option of passing a `source` parameter to help connect attribution with FxA link referrals.
*/
if (Object.prototype.hasOwnProperty.call(finalParams, 'source')) {
if (finalParams['source'].indexOf('whatsnew') !== -1 || finalParams['source'].indexOf('welcome') !== -1 || finalParams['source'].indexOf('vpn-info') !== -1) {
if (
finalParams['source'].indexOf('whatsnew') !== -1 ||
finalParams['source'].indexOf('welcome') !== -1 ||
finalParams['source'].indexOf('vpn-info') !== -1
) {
// utm_source and entrypoint should always be consistent and omit a version number.
if (finalParams['source'].indexOf('vpn-info') !== -1 ) {
if (finalParams['source'].indexOf('vpn-info') !== -1) {
finalParams['utm_source'] = 'www.mozilla.org-vpn-info';
finalParams['entrypoint'] = 'www.mozilla.org-vpn-info';
} else if (finalParams['source'].indexOf('whatsnew') !== -1 ) {
} else if (finalParams['source'].indexOf('whatsnew') !== -1) {
finalParams['utm_source'] = 'www.mozilla.org-whatsnew';
finalParams['entrypoint'] = 'www.mozilla.org-whatsnew';
} else {
@ -198,10 +232,19 @@ if (typeof window.Mozilla === 'undefined') {
* Some experiments may redirect people back to the landing page from in-product (e.g. VPN Issue 10209).
* In cases like this we want to support passing through FxA flow params to keep track of the funnel.
*/
if (!Object.prototype.hasOwnProperty.call(finalParams, 'entrypoint_experiment') ||
!Object.prototype.hasOwnProperty.call(finalParams, 'entrypoint_variation')) {
if (Object.prototype.hasOwnProperty.call(finalParams, 'device_id')) {
if (
!Object.prototype.hasOwnProperty.call(
finalParams,
'entrypoint_experiment'
) ||
!Object.prototype.hasOwnProperty.call(
finalParams,
'entrypoint_variation'
)
) {
if (
Object.prototype.hasOwnProperty.call(finalParams, 'device_id')
) {
delete finalParams['device_id'];
}
@ -209,15 +252,33 @@ if (typeof window.Mozilla === 'undefined') {
delete finalParams['flow_id'];
}
if (Object.prototype.hasOwnProperty.call(finalParams, 'flow_begin_time')) {
if (
Object.prototype.hasOwnProperty.call(
finalParams,
'flow_begin_time'
)
) {
delete finalParams['flow_begin_time'];
}
}
// Both utm_source and utm_campaign are considered required, so only pass through referral data if they exist.
// Alternatively, pass through entrypoint_experiment and entrypoint_variation independently.
if ((Object.prototype.hasOwnProperty.call(finalParams, 'utm_source') && Object.prototype.hasOwnProperty.call(finalParams, 'utm_campaign')) ||
(Object.prototype.hasOwnProperty.call(finalParams, 'entrypoint_experiment') && Object.prototype.hasOwnProperty.call(finalParams, 'entrypoint_variation'))) {
if (
(Object.prototype.hasOwnProperty.call(finalParams, 'utm_source') &&
Object.prototype.hasOwnProperty.call(
finalParams,
'utm_campaign'
)) ||
(Object.prototype.hasOwnProperty.call(
finalParams,
'entrypoint_experiment'
) &&
Object.prototype.hasOwnProperty.call(
finalParams,
'entrypoint_variation'
))
) {
return finalParams;
}
@ -236,14 +297,24 @@ if (typeof window.Mozilla === 'undefined') {
var linkParams;
if (url.indexOf('?') > 0) {
linkParams = window._SearchParams.queryStringToObject(url.split('?')[1]);
linkParams = window._SearchParams.queryStringToObject(
url.split('?')[1]
);
// If we have utm parameters then remove them from the target URL,
// as we don't want to muddle data from different campaign sources.
if (Object.prototype.hasOwnProperty.call(data, 'utm_source') && Object.prototype.hasOwnProperty.call(data, 'utm_campaign')) {
if (
Object.prototype.hasOwnProperty.call(data, 'utm_source') &&
Object.prototype.hasOwnProperty.call(data, 'utm_campaign')
) {
for (var i = 0; i < utms.length; i++) {
var utmParam = utms[i];
if (Object.prototype.hasOwnProperty.call(linkParams, utmParam)) {
if (
Object.prototype.hasOwnProperty.call(
linkParams,
utmParam
)
) {
delete linkParams[utmParam];
}
}
@ -251,10 +322,24 @@ if (typeof window.Mozilla === 'undefined') {
// In principle, experiments should never clobber eachother(!). However, if we have
// new entrypoint_* parameters then assume they take precedence in the target URL.
if (Object.prototype.hasOwnProperty.call(data, 'entrypoint_experiment') && Object.prototype.hasOwnProperty.call(data, 'entrypoint_variation')) {
if (
Object.prototype.hasOwnProperty.call(
data,
'entrypoint_experiment'
) &&
Object.prototype.hasOwnProperty.call(
data,
'entrypoint_variation'
)
) {
for (var j = 0; j < fxaParams.length; j++) {
var fxaParam = fxaParams[j];
if (Object.prototype.hasOwnProperty.call(linkParams, fxaParam)) {
if (
Object.prototype.hasOwnProperty.call(
linkParams,
fxaParam
)
) {
delete linkParams[fxaParam];
}
}
@ -265,7 +350,11 @@ if (typeof window.Mozilla === 'undefined') {
finalParams = data;
}
return url.split('?')[0] + '?' + window._SearchParams.objectToQueryString(finalParams);
return (
url.split('?')[0] +
'?' +
window._SearchParams.objectToQueryString(finalParams)
);
};
/**
@ -274,7 +363,9 @@ if (typeof window.Mozilla === 'undefined') {
*/
UtmUrl.init = function (urlParams) {
var params = UtmUrl.getAttributionData(urlParams);
var ctaLinks = document.querySelectorAll('.js-fxa-cta-link, .js-vpn-cta-link');
var ctaLinks = document.querySelectorAll(
'.js-fxa-cta-link, .js-vpn-cta-link'
);
// feature detect support for object modification.
if (typeof Object.assign !== 'function') {
@ -297,25 +388,38 @@ if (typeof window.Mozilla === 'undefined') {
for (var i = 0; i < ctaLinks.length; i++) {
// get the link off the element
var oldAccountsLink = ctaLinks[i].hasAttribute('href') ? ctaLinks[i].href : null ;
var oldAccountsLink = ctaLinks[i].hasAttribute('href')
? ctaLinks[i].href
: null;
if (oldAccountsLink) {
var hostName = UtmUrl.getHostName(oldAccountsLink);
// check if link is in the FxA referral allowedList list.
if (hostName && allowedList.indexOf(hostName) !== -1) {
// get the China repack link, so that can be updated too
var oldMozillaOnlineLink = ctaLinks[i].getAttribute('data-mozillaonline-link');
var oldMozillaOnlineLink = ctaLinks[i].getAttribute(
'data-mozillaonline-link'
);
// append our new UTM param data to create new FxA links.
var newAccountsLink = UtmUrl.appendToDownloadURL(oldAccountsLink, params);
var newAccountsLink = UtmUrl.appendToDownloadURL(
oldAccountsLink,
params
);
// set the FxA button to use the new link.
ctaLinks[i].href = newAccountsLink;
// also handle mozilla-online links for FxA China Repack.
if (oldMozillaOnlineLink) {
var newMozillaOnlineLink = UtmUrl.appendToDownloadURL(oldMozillaOnlineLink, params);
ctaLinks[i].setAttribute('data-mozillaonline-link', newMozillaOnlineLink);
var newMozillaOnlineLink = UtmUrl.appendToDownloadURL(
oldMozillaOnlineLink,
params
);
ctaLinks[i].setAttribute(
'data-mozillaonline-link',
newMozillaOnlineLink
);
}
}
}

Просмотреть файл

@ -2,13 +2,16 @@
* 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/. */
(function() {
(function () {
'use strict';
var GTM_CONTAINER_ID = document.getElementsByTagName('html')[0].getAttribute('data-gtm-container-id');
var GTM_CONTAINER_ID = document
.getElementsByTagName('html')[0]
.getAttribute('data-gtm-container-id');
// If doNotTrack is not enabled, it is ok to add GTM
// @see https://bugzilla.mozilla.org/show_bug.cgi?id=1217896 for more details
// prettier-ignore
if (typeof Mozilla.dntEnabled === 'function' && !Mozilla.dntEnabled() && GTM_CONTAINER_ID) {
(function(w,d,s,l,i,j,f,dl,k,q){
w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});f=d.getElementsByTagName(s)[0];

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
(function(Mzp) {
(function (Mzp) {
'use strict';
var _mqWide = matchMedia('(max-width: 767px)');
@ -10,12 +10,11 @@
if (_mqWide.matches) {
Mzp.Details.init('.side-reference-title');
}
_mqWide.addListener(function(mq) {
_mqWide.addListener(function (mq) {
if (mq.matches) {
Mzp.Details.init('.side-reference-title');
} else {
Mzp.Details.destroy('.side-reference-title');
}
});
})(window.Mzp);

Просмотреть файл

@ -7,7 +7,7 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function() {
(function () {
'use strict';
/**
@ -69,7 +69,11 @@ if (typeof window.Mozilla === 'undefined') {
Client._isFirefoxDesktop = function (ua) {
ua = ua || navigator.userAgent;
return /\sFirefox/.test(ua) && !/Mobile|Tablet|Fennec/.test(ua) && !Client._isLikeFirefox(ua);
return (
/\sFirefox/.test(ua) &&
!/Mobile|Tablet|Fennec/.test(ua) &&
!Client._isLikeFirefox(ua)
);
};
/**
@ -108,7 +112,7 @@ if (typeof window.Mozilla === 'undefined') {
*/
Client._isFirefoxFxOS = function (ua, pf) {
ua = ua || navigator.userAgent;
pf = (pf === '') ? '' : pf || navigator.platform;
pf = pf === '' ? '' : pf || navigator.platform;
return /Firefox/.test(ua) && pf === '';
};
@ -138,7 +142,7 @@ if (typeof window.Mozilla === 'undefined') {
var matches = /Firefox\/(\d+(?:\.\d+){1,2})/.exec(ua);
return (matches && !Client._isLikeFirefox(ua)) ? matches[1] : '0';
return matches && !Client._isLikeFirefox(ua) ? matches[1] : '0';
};
/**
@ -214,22 +218,33 @@ if (typeof window.Mozilla === 'undefined') {
var html = document.documentElement;
if (!html.getAttribute('data-esr-versions') || !html.getAttribute('data-latest-firefox')) {
if (
!html.getAttribute('data-esr-versions') ||
!html.getAttribute('data-latest-firefox')
) {
return false;
}
var versions = isESR ? html.getAttribute('data-esr-versions').split(' ') : [html.getAttribute('data-latest-firefox')];
var versions = isESR
? html.getAttribute('data-esr-versions').split(' ')
: [html.getAttribute('data-latest-firefox')];
var userVerArr = userVer.match(/^(\d+(?:\.\d+){1,2})/)[1].split('.');
var isUpToDate = false;
// Sort product details version so we compare the newer version first
versions.sort(function(a, b) { return parseFloat(a) < parseFloat(b); });
versions.sort(function (a, b) {
return parseFloat(a) < parseFloat(b);
});
// Compare each latest version in product details to the user version.
for (var i = 0; i < versions.length; i++) {
var latestVerArr = versions[i].split('.');
isUpToDate = Client._compareVersion(strict, userVerArr, latestVerArr);
isUpToDate = Client._compareVersion(
strict,
userVerArr,
latestVerArr
);
if (isUpToDate) {
break;
@ -246,12 +261,24 @@ if (typeof window.Mozilla === 'undefined') {
* @param {String} latestVer - Current latest release version number.
* @return {Boolean}
*/
Client.isFirefoxOutOfDate = function(clientVer, majorVer, latestVer) {
Client.isFirefoxOutOfDate = function (clientVer, majorVer, latestVer) {
var clientVersion = parseInt(clientVer, 10);
var latestVersion = typeof latestVer === 'undefined' ? parseInt(document.documentElement.getAttribute('data-latest-firefox'), 10) : parseInt(latestVer, 10);
var latestVersion =
typeof latestVer === 'undefined'
? parseInt(
document.documentElement.getAttribute(
'data-latest-firefox'
),
10
)
: parseInt(latestVer, 10);
var majorVersions = Math.max(parseInt(majorVer, 10), 1); // majorVersions must be at least 1.
if (isNaN(latestVersion) || isNaN(clientVersion) || isNaN(majorVersions)) {
if (
isNaN(latestVersion) ||
isNaN(clientVersion) ||
isNaN(majorVersions)
) {
return false;
}
@ -265,14 +292,29 @@ if (typeof window.Mozilla === 'undefined') {
* @param {String} latestVer - Current latest release version number.
* @return {Boolean}
*/
Client.isFirefoxURLOutOfDate = function(majorVer, pathName, latestVer) {
var path = typeof pathName === 'undefined' ? window.location.pathname : pathName;
var urlVersion = /firefox\/(\d+(?:\.\d+)?\.\da?\d?)/.exec(path);
Client.isFirefoxURLOutOfDate = function (majorVer, pathName, latestVer) {
var path =
typeof pathName === 'undefined'
? window.location.pathname
: pathName;
var urlVersion = /firefox\/(\d+(?:\.\d+)?\.\da?\d?)/.exec(path);
var version = urlVersion ? parseInt(urlVersion[1], 10) : null;
var latestVersion = typeof latestVer === 'undefined' ? parseInt(document.documentElement.getAttribute('data-latest-firefox'), 10) : parseInt(latestVer, 10);
var latestVersion =
typeof latestVer === 'undefined'
? parseInt(
document.documentElement.getAttribute(
'data-latest-firefox'
),
10
)
: parseInt(latestVer, 10);
var majorVersions = Math.max(parseInt(majorVer, 10), 1); // majorVersions must be at least 1.
if (version && latestVersion && (version <= latestVersion - majorVersions)) {
if (
version &&
latestVersion &&
version <= latestVersion - majorVersions
) {
return true;
}
@ -295,37 +337,54 @@ if (typeof window.Mozilla === 'undefined') {
return;
}
var callbackID = Math.random().toString(36).replace(/[^a-z]+/g, '');
var callbackID = Math.random()
.toString(36)
.replace(/[^a-z]+/g, '');
var listener = function (event) {
if (!event.detail || !event.detail.data || event.detail.callbackID !== callbackID) {
if (
!event.detail ||
!event.detail.data ||
event.detail.callbackID !== callbackID
) {
return;
}
window.clearTimeout(timer);
onRetrieved(true, event.detail.data.version, event.detail.data.defaultUpdateChannel, event.detail.data.distribution);
onRetrieved(
true,
event.detail.data.version,
event.detail.data.defaultUpdateChannel,
event.detail.data.distribution
);
};
var onRetrieved = function (accurate, version, channel, distribution) {
document.removeEventListener('mozUITourResponse', listener, false);
var isESR = channel === 'esr';
var isUpToDate = Client._isFirefoxUpToDate(accurate, accurate ? isESR : false, version);
var details = Client.FirefoxDetails = {
'accurate': accurate,
'version': version,
'channel': channel,
'distribution': distribution,
'isUpToDate': isUpToDate,
'isESR': isESR
};
var isUpToDate = Client._isFirefoxUpToDate(
accurate,
accurate ? isESR : false,
version
);
var details = (Client.FirefoxDetails = {
accurate: accurate,
version: version,
channel: channel,
distribution: distribution,
isUpToDate: isUpToDate,
isESR: isESR
});
callback(details);
};
// Prepare fallback function in case the API doesn't work
var userVer = Client._getFirefoxVersion();
var fallback = function () { onRetrieved(false, userVer, 'release', undefined); };
var fallback = function () {
onRetrieved(false, userVer, 'release', undefined);
};
// If Firefox is old or for Android, call the fallback function immediately because the API is not implemented
if (parseFloat(userVer) < 35 || Client._isFirefoxAndroid()) {
@ -339,13 +398,15 @@ if (typeof window.Mozilla === 'undefined') {
// Trigger the API
document.addEventListener('mozUITourResponse', listener, false);
document.dispatchEvent(new CustomEvent('mozUITour', {
'bubbles': true,
'detail': {
'action': 'getConfiguration',
'data': { 'configuration': 'appinfo', 'callbackID': callbackID }
}
}));
document.dispatchEvent(
new CustomEvent('mozUITour', {
bubbles: true,
detail: {
action: 'getConfiguration',
data: { configuration: 'appinfo', callbackID: callbackID }
}
})
);
};
/**
@ -391,16 +452,16 @@ if (typeof window.Mozilla === 'undefined') {
// Set up the object with default values of false
var details = {
'firefox': false,
'legacy': false,
'mobile': false,
'setup': false,
'browserServices': {
'sync': {
'setup': false,
'desktopDevices': false,
'mobileDevices': false,
'totalDevices': false
firefox: false,
legacy: false,
mobile: false,
setup: false,
browserServices: {
sync: {
setup: false,
desktopDevices: false,
mobileDevices: false,
totalDevices: false
}
}
};
@ -433,11 +494,17 @@ if (typeof window.Mozilla === 'undefined') {
}
// callbackID to make sure we're responding to our request
var callbackID = Math.random().toString(36).replace(/[^a-z]+/g, '');
var callbackID = Math.random()
.toString(36)
.replace(/[^a-z]+/g, '');
// UITour API response event handler for 'sync', checks for callbackID
var listenerSync = function (event) {
if (!event.detail || !event.detail.data || event.detail.callbackID !== callbackID) {
if (
!event.detail ||
!event.detail.data ||
event.detail.callbackID !== callbackID
) {
return;
}
@ -445,7 +512,11 @@ if (typeof window.Mozilla === 'undefined') {
// Clear the timeout and remove the event listener.
window.clearTimeout(timer);
document.removeEventListener('mozUITourResponse', listenerSync, false);
document.removeEventListener(
'mozUITourResponse',
listenerSync,
false
);
/**
* Account signed-in state
@ -459,9 +530,24 @@ if (typeof window.Mozilla === 'undefined') {
*/
details.browserServices.sync = {
setup: config.setup,
desktopDevices: Object.prototype.hasOwnProperty.call(config, 'desktopDevices') ? config.desktopDevices : 'unknown',
mobileDevices: Object.prototype.hasOwnProperty.call(config, 'mobileDevices') ? config.mobileDevices : 'unknown',
totalDevices: Object.prototype.hasOwnProperty.call(config, 'totalDevices') ? config.totalDevices : 'unknown'
desktopDevices: Object.prototype.hasOwnProperty.call(
config,
'desktopDevices'
)
? config.desktopDevices
: 'unknown',
mobileDevices: Object.prototype.hasOwnProperty.call(
config,
'mobileDevices'
)
? config.mobileDevices
: 'unknown',
totalDevices: Object.prototype.hasOwnProperty.call(
config,
'totalDevices'
)
? config.totalDevices
: 'unknown'
};
returnFxaDetails();
@ -469,7 +555,11 @@ if (typeof window.Mozilla === 'undefined') {
// UITour API response event handler for 'fxa', checks for callbackID
var listenerFxA = function (event) {
if (!event.detail || !event.detail.data || event.detail.callbackID !== callbackID) {
if (
!event.detail ||
!event.detail.data ||
event.detail.callbackID !== callbackID
) {
return;
}
@ -477,7 +567,11 @@ if (typeof window.Mozilla === 'undefined') {
// Clear the timeout and remove the event listener.
window.clearTimeout(timer);
document.removeEventListener('mozUITourResponse', listenerFxA, false);
document.removeEventListener(
'mozUITourResponse',
listenerFxA,
false
);
// Account signed-in state
details.setup = config.setup;
@ -500,14 +594,23 @@ if (typeof window.Mozilla === 'undefined') {
}
// Trigger the UITour API and start listening for the reponse
document.addEventListener('mozUITourResponse', request.callback, false);
document.dispatchEvent(new CustomEvent('mozUITour', {
'bubbles': true,
'detail': {
'action': 'getConfiguration',
'data': { 'configuration': request.name, 'callbackID': callbackID }
}
}));
document.addEventListener(
'mozUITourResponse',
request.callback,
false
);
document.dispatchEvent(
new CustomEvent('mozUITour', {
bubbles: true,
detail: {
action: 'getConfiguration',
data: {
configuration: request.name,
callbackID: callbackID
}
}
})
);
}
}
@ -521,7 +624,7 @@ if (typeof window.Mozilla === 'undefined') {
var timer = window.setTimeout(returnFxaDetails, 400);
};
Client.getFxaConnections = function(callback) {
Client.getFxaConnections = function (callback) {
// Fire the callback function immediately if FxaDetails are already defined
if (Client.FxaConnections) {
callback(Client.FxaConnections);
@ -530,12 +633,12 @@ if (typeof window.Mozilla === 'undefined') {
// Set up the object with default values of false
var details = {
'setup': false,
'unsupported': false,
'firefox': false,
'numOtherDevices': false,
'numDevicesByType': {},
'accountServices': {}
setup: false,
unsupported: false,
firefox: false,
numOtherDevices: false,
numDevicesByType: {},
accountServices: {}
};
var userVer = parseFloat(Client._getFirefoxVersion());
@ -557,11 +660,17 @@ if (typeof window.Mozilla === 'undefined') {
}
// callbackID to make sure we're responding to our request
var callbackID = Math.random().toString(36).replace(/[^a-z]+/g, '');
var callbackID = Math.random()
.toString(36)
.replace(/[^a-z]+/g, '');
// UITour API response event handler for 'fxaConnections', checks for callbackID
var listener = function (event) {
if (!event.detail || !event.detail.data || event.detail.callbackID !== callbackID) {
if (
!event.detail ||
!event.detail.data ||
event.detail.callbackID !== callbackID
) {
return;
}
@ -579,15 +688,27 @@ if (typeof window.Mozilla === 'undefined') {
// Additional devices types (we're mainly interested in mobile and desktop).
for (var device in config.numDevicesByType) {
if (Object.prototype.hasOwnProperty.call(config.numDevicesByType, device)) {
details.numDevicesByType[device] = config.numDevicesByType[device];
if (
Object.prototype.hasOwnProperty.call(
config.numDevicesByType,
device
)
) {
details.numDevicesByType[device] =
config.numDevicesByType[device];
}
}
// Account services (recently accessed).
for (var service in config.accountServices) {
if (Object.prototype.hasOwnProperty.call(config.accountServices, service)) {
details.accountServices[service] = config.accountServices[service];
if (
Object.prototype.hasOwnProperty.call(
config.accountServices,
service
)
) {
details.accountServices[service] =
config.accountServices[service];
}
}
@ -596,13 +717,18 @@ if (typeof window.Mozilla === 'undefined') {
// Trigger the UITour API and start listening for the reponse
document.addEventListener('mozUITourResponse', listener, false);
document.dispatchEvent(new CustomEvent('mozUITour', {
'bubbles': true,
'detail': {
'action': 'getConfiguration',
'data': { 'configuration': 'fxaConnections', 'callbackID': callbackID }
}
}));
document.dispatchEvent(
new CustomEvent('mozUITour', {
bubbles: true,
detail: {
action: 'getConfiguration',
data: {
configuration: 'fxaConnections',
callbackID: callbackID
}
}
})
);
function returnFxaConnections() {
window.clearTimeout(timer);
@ -630,5 +756,4 @@ if (typeof window.Mozilla === 'undefined') {
Client.isDesktop = !Client.isMobile;
window.Mozilla.Client = Client;
})();

Просмотреть файл

@ -7,12 +7,12 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function() {
(function () {
'use strict';
var Convert = {};
Convert.onLoaded = function(callback) {
Convert.onLoaded = function (callback) {
var timeout;
var pollRetry = 0;
@ -26,7 +26,7 @@ if (typeof window.Mozilla === 'undefined') {
function checkHasLoaded() {
if (window.convert) {
clearTimeout(timeout);
window.convert.$(document).ready(function() {
window.convert.$(document).ready(function () {
callback(window.convert);
});
} else {
@ -43,7 +43,7 @@ if (typeof window.Mozilla === 'undefined') {
checkHasLoaded();
};
Convert.getCurrentExperiment = function(convert) {
Convert.getCurrentExperiment = function (convert) {
/**
* The following code relies on an object constructed by
* a third-party, so let's use a safety net.
@ -54,7 +54,12 @@ if (typeof window.Mozilla === 'undefined') {
// Get the variation key
for (key in convert['currentData']['experiments']) {
if (!Object.prototype.hasOwnProperty.call(convert['currentData']['experiments'], key)) {
if (
!Object.prototype.hasOwnProperty.call(
convert['currentData']['experiments'],
key
)
) {
continue;
}
}
@ -64,9 +69,15 @@ if (typeof window.Mozilla === 'undefined') {
* Then get the experiment name and variation name.
*/
if (key) {
var currentExperiment = convert['currentData']['experiments'][key];
var curExperimentName = refObject[key] && refObject[key].n ? refObject[key].n : null;
var curVariant = currentExperiment['variation_name'] ? currentExperiment['variation_name'] : null;
var currentExperiment =
convert['currentData']['experiments'][key];
var curExperimentName =
refObject[key] && refObject[key].n
? refObject[key].n
: null;
var curVariant = currentExperiment['variation_name']
? currentExperiment['variation_name']
: null;
if (curExperimentName && curVariant) {
var reg = new RegExp('^[0-9]+$');
@ -76,17 +87,21 @@ if (typeof window.Mozilla === 'undefined') {
experimentVariation: curVariant.replace('Var #', '')
};
if (reg.test(data.experimentName) && reg.test(data.experimentVariation)) {
if (
reg.test(data.experimentName) &&
reg.test(data.experimentVariation)
) {
return data;
}
throw new Error('Mozilla.Convert.getCurrentExperiment: data was malformed');
throw new Error(
'Mozilla.Convert.getCurrentExperiment: data was malformed'
);
}
}
return false;
} catch(e) {
} catch (e) {
/* eslint-disable no-console */
// log errors thrown in the console to make debugging easier.
if ('console' in window && typeof console.error === 'function') {
@ -98,5 +113,4 @@ if (typeof window.Mozilla === 'undefined') {
};
window.Mozilla.Convert = Convert;
})();

Просмотреть файл

@ -1,6 +1,6 @@
/* 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/. */
* 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/. */
/*\
|*|
@ -34,24 +34,48 @@ if (typeof window.Mozilla === 'undefined') {
Mozilla.Cookies = {
getItem: function (sKey) {
'use strict';
if (!sKey) { return null; }
return decodeURIComponent(document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + encodeURIComponent(sKey).replace(/[-.+*]/g, '\\$&') + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1')) || null;
if (!sKey) {
return null;
}
return (
decodeURIComponent(
document.cookie.replace(
new RegExp(
'(?:(?:^|.*;)\\s*' +
encodeURIComponent(sKey).replace(
/[-.+*]/g,
'\\$&'
) +
'\\s*\\=\\s*([^;]*).*$)|^.*$'
),
'$1'
)
) || null
);
},
setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure, vSamesite) {
'use strict';
if (!sKey || /^(?:expires|max-age|path|domain|secure|samesite)$/i.test(sKey)) { return false; }
if (
!sKey ||
/^(?:expires|max-age|path|domain|secure|samesite)$/i.test(sKey)
) {
return false;
}
var sExpires = '';
if (vEnd) {
switch (vEnd.constructor) {
case Number:
sExpires = vEnd === Infinity ? '; expires=Fri, 31 Dec 9999 23:59:59 GMT' : '; max-age=' + vEnd;
break;
case String:
sExpires = '; expires=' + vEnd;
break;
case Date:
sExpires = '; expires=' + vEnd.toUTCString();
break;
case Number:
sExpires =
vEnd === Infinity
? '; expires=Fri, 31 Dec 9999 23:59:59 GMT'
: '; max-age=' + vEnd;
break;
case String:
sExpires = '; expires=' + vEnd;
break;
case Date:
sExpires = '; expires=' + vEnd.toUTCString();
break;
}
}
/**
@ -64,10 +88,13 @@ Mozilla.Cookies = {
}
vSamesite = vSamesite.toString().toLowerCase();
if (vSamesite === 'lax' || vSamesite === 'none'|| vSamesite === 'strict') {
if (
vSamesite === 'lax' ||
vSamesite === 'none' ||
vSamesite === 'strict'
) {
return vSamesite;
}
else {
} else {
return 'lax';
}
}
@ -77,27 +104,54 @@ Mozilla.Cookies = {
if (vSamesite === 'none') {
bSecure = true;
}
document.cookie = encodeURIComponent(sKey) + '=' + encodeURIComponent(sValue) + sExpires + (sDomain ? '; domain=' + sDomain : '') + (sPath ? '; path=' + sPath : '') + (bSecure ? '; secure' : '') + (!vSamesite ? '': '; samesite='+ vSamesite);
document.cookie =
encodeURIComponent(sKey) +
'=' +
encodeURIComponent(sValue) +
sExpires +
(sDomain ? '; domain=' + sDomain : '') +
(sPath ? '; path=' + sPath : '') +
(bSecure ? '; secure' : '') +
(!vSamesite ? '' : '; samesite=' + vSamesite);
return true;
},
removeItem: function (sKey, sPath, sDomain) {
'use strict';
if (!this.hasItem(sKey)) { return false; }
document.cookie = encodeURIComponent(sKey) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' + (sDomain ? '; domain=' + sDomain : '') + (sPath ? '; path=' + sPath : '');
if (!this.hasItem(sKey)) {
return false;
}
document.cookie =
encodeURIComponent(sKey) +
'=; expires=Thu, 01 Jan 1970 00:00:00 GMT' +
(sDomain ? '; domain=' + sDomain : '') +
(sPath ? '; path=' + sPath : '');
return true;
},
hasItem: function (sKey) {
'use strict';
if (!sKey) { return false; }
return (new RegExp('(?:^|;\\s*)' + encodeURIComponent(sKey).replace(/[-.+*]/g, '\\$&') + '\\s*\\=')).test(document.cookie);
if (!sKey) {
return false;
}
return new RegExp(
'(?:^|;\\s*)' +
encodeURIComponent(sKey).replace(/[-.+*]/g, '\\$&') +
'\\s*\\='
).test(document.cookie);
},
keys: function () {
'use strict';
var aKeys = document.cookie.replace(/((?:^|\s*;)[^=]+)(?=;|$)|^\s*|\s*(?:=[^;]*)?(?:\1|$)/g, '').split(/\s*(?:=[^;]*)?;\s*/);
for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); }
var aKeys = document.cookie
.replace(
/((?:^|\s*;)[^=]+)(?=;|$)|^\s*|\s*(?:=[^;]*)?(?:\1|$)/g,
''
)
.split(/\s*(?:=[^;]*)?;\s*/);
for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) {
aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]);
}
return aKeys;
},
enabled: function() {
enabled: function () {
'use strict';
/**
* Cookies feature detect lifted from Modernizr
@ -118,10 +172,10 @@ Mozilla.Cookies = {
document.cookie = 'cookietest=1';
var ret = document.cookie.indexOf('cookietest=') !== -1;
// Delete cookie
document.cookie = 'cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT';
document.cookie =
'cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT';
return ret;
}
catch (e) {
} catch (e) {
return false;
}
}

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
(function() {
(function () {
'use strict';
Mozilla.FxaForm.init();

Просмотреть файл

@ -1,13 +1,13 @@
/* 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/. */
* 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/. */
// create namespace
if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function(Mozilla) {
(function (Mozilla) {
'use strict';
var FxaForm = {};
@ -19,7 +19,7 @@ if (typeof window.Mozilla === 'undefined') {
* @param value (String) input value.
* @returns HTML element.
*/
FxaForm.createInput = function(name, value) {
FxaForm.createInput = function (name, value) {
var input = document.createElement('input');
input.type = 'hidden';
input.name = name;
@ -33,7 +33,7 @@ if (typeof window.Mozilla === 'undefined') {
*
* @returns {Object} of utm parameters
*/
FxaForm.getUTMParams = function() {
FxaForm.getUTMParams = function () {
var urlParams = new window._SearchParams().utmParams();
return Mozilla.UtmUrl.getAttributionData(urlParams) || {};
};
@ -42,12 +42,18 @@ if (typeof window.Mozilla === 'undefined') {
* Get tokens from FxA for analytics purposes.
* This is non-critical to the user flow.
*/
FxaForm.fetchTokens = function() {
FxaForm.fetchTokens = function () {
var destURL = formElem.getAttribute('action') + 'metrics-flow';
var entrypoint = document.getElementById('fxa-email-form-entrypoint');
var entrypointExp = document.getElementById('fxa-email-form-entrypoint-experiment');
var entrypointVar = document.getElementById('fxa-email-form-entrypoint-variation');
var utmCampaign = document.getElementById('fxa-email-form-utm-campaign');
var entrypointExp = document.getElementById(
'fxa-email-form-entrypoint-experiment'
);
var entrypointVar = document.getElementById(
'fxa-email-form-entrypoint-variation'
);
var utmCampaign = document.getElementById(
'fxa-email-form-utm-campaign'
);
var utmContent = document.getElementById('fxa-email-form-utm-content');
var utmSource = document.getElementById('fxa-email-form-utm-source');
var utmTerm = document.getElementById('fxa-email-form-utm-term');
@ -77,18 +83,21 @@ if (typeof window.Mozilla === 'undefined') {
destURL += '&entrypoint_variation=' + entrypointVar.value;
}
return fetch(destURL).then(function(resp) {
return resp.json();
}).then(function(r) {
formElem.querySelector('[name="device_id"]').value = r.deviceId;
formElem.querySelector('[name="flow_id"]').value = r.flowId;
formElem.querySelector('[name="flow_begin_time"]').value = r.flowBeginTime;
}).catch(function() {
// silently fail, leaving flow_id and flow_begin_time as default empty value
});
return fetch(destURL)
.then(function (resp) {
return resp.json();
})
.then(function (r) {
formElem.querySelector('[name="device_id"]').value = r.deviceId;
formElem.querySelector('[name="flow_id"]').value = r.flowId;
formElem.querySelector('[name="flow_begin_time"]').value =
r.flowBeginTime;
})
.catch(function () {
// silently fail, leaving flow_id and flow_begin_time as default empty value
});
};
/**
* Intercept event handler for FxA forms, lets the browser drive the FxA Flow using
* the `showFirefoxAccounts` UITour API. Attaches several UTM parameters from the current page
@ -96,13 +105,19 @@ if (typeof window.Mozilla === 'undefined') {
* @param event {Event}
* @private
*/
FxaForm.interceptFxANavigation = function(event) {
FxaForm.interceptFxANavigation = function (event) {
event.preventDefault();
var extraURLParams = FxaForm.getUTMParams();
var entrypointInput = document.getElementById('fxa-email-form-entrypoint');
var entrypointExp = document.getElementById('fxa-email-form-entrypoint-experiment');
var entrypointVar = document.getElementById('fxa-email-form-entrypoint-variation');
var entrypointInput = document.getElementById(
'fxa-email-form-entrypoint'
);
var entrypointExp = document.getElementById(
'fxa-email-form-entrypoint-experiment'
);
var entrypointVar = document.getElementById(
'fxa-email-form-entrypoint-variation'
);
var entrypoint = null;
if (entrypointInput && entrypointInput.value) {
entrypoint = entrypointInput.value;
@ -123,7 +138,9 @@ if (typeof window.Mozilla === 'undefined') {
if (formElem) {
var deviceId = formElem.querySelector('[name="device_id"]');
var flowId = formElem.querySelector('[name="flow_id"]');
var flowBeginTime = formElem.querySelector('[name="flow_begin_time"]');
var flowBeginTime = formElem.querySelector(
'[name="flow_begin_time"]'
);
if (deviceId && deviceId.value) {
extraURLParams['device_id'] = deviceId.value;
}
@ -131,28 +148,39 @@ if (typeof window.Mozilla === 'undefined') {
extraURLParams['flow_id'] = flowId.value;
}
if (flowBeginTime && flowBeginTime.value) {
extraURLParams['flow_begin_time'] = parseInt(flowBeginTime.value, 10);
extraURLParams['flow_begin_time'] = parseInt(
flowBeginTime.value,
10
);
}
}
return Mozilla.UITour.showFirefoxAccounts(extraURLParams, entrypoint, email);
return Mozilla.UITour.showFirefoxAccounts(
extraURLParams,
entrypoint,
email
);
};
/**
* Configures Sync for Firefox browsers.
* Only Firefox < 71 requires `service=sync`.
*/
FxaForm.setServiceContext = function() {
FxaForm.setServiceContext = function () {
var contextField = formElem.querySelector('[name="context"]');
var serviceField = formElem.querySelector('[name="service"]');
var userVer = parseFloat(Mozilla.Client._getFirefoxVersion());
var self = this;
var useUITourForFxA = userVer >= 80 && typeof Mozilla.UITour !== 'undefined';
var useUITourForFxA =
userVer >= 80 && typeof Mozilla.UITour !== 'undefined';
if (useUITourForFxA) {
Mozilla.UITour.ping(function() {
Mozilla.UITour.ping(function () {
// intercept the flow and submit the form using the UITour API instead.
// In the future we should fully migrate to this API for Firefox Desktop login.
formElem.addEventListener('submit', self.interceptFxANavigation);
formElem.addEventListener(
'submit',
self.interceptFxANavigation
);
});
}
/**
@ -177,25 +205,30 @@ if (typeof window.Mozilla === 'undefined') {
* Checks for China repack, before making a metrics-flow request.
* Once completed, then configures Sync `context` and `service` params.
*/
FxaForm.configureRequest = function() {
FxaForm.configureRequest = function () {
var formSubmitButton = document.getElementById('fxa-email-form-submit');
var mozillaonlineAction = formElem.dataset.mozillaonlineAction;
var metrics;
var dist = new window.Promise(function(resolve) {
var dist = new window.Promise(function (resolve) {
// disable form while we configure the distribution.
formSubmitButton.disabled = true;
Mozilla.Client.getFirefoxDetails(function(data) {
Mozilla.Client.getFirefoxDetails(function (data) {
// only switch to China re-pack URL if UITour call is successful
// (marked by data.accurate being true)
if (mozillaonlineAction && data.accurate && data.distribution && data.distribution.toLowerCase() === 'mozillaonline') {
if (
mozillaonlineAction &&
data.accurate &&
data.distribution &&
data.distribution.toLowerCase() === 'mozillaonline'
) {
formElem.action = mozillaonlineAction;
}
formSubmitButton.disabled = false;
metrics = new window.Promise(function(resolve) {
FxaForm.fetchTokens().then(function() {
metrics = new window.Promise(function (resolve) {
FxaForm.fetchTokens().then(function () {
resolve();
});
});
@ -205,30 +238,31 @@ if (typeof window.Mozilla === 'undefined') {
});
// Configure Sync once metrics request has finished.
return window.Promise.all([dist, metrics]).then(function() {
return window.Promise.all([dist, metrics]).then(function () {
FxaForm.setServiceContext();
});
};
FxaForm.isSupported = function() {
FxaForm.isSupported = function () {
return 'Promise' in window && 'fetch' in window;
};
FxaForm.init = function() {
FxaForm.init = function () {
if (!FxaForm.isSupported()) {
return false;
}
formElem = document.getElementById('fxa-email-form');
return new window.Promise(function(resolve, reject) {
return new window.Promise(function (resolve, reject) {
if (formElem) {
// Pass through UTM params from the URL to the form.
var utms = FxaForm.getUTMParams();
Object.keys(utms).forEach(function (i) {
// check if input is available
if (formElem.querySelector('[name="' + i + '"]')) {
formElem.querySelector('[name="' + i + '"]').value = utms[i];
formElem.querySelector('[name="' + i + '"]').value =
utms[i];
} else {
// create input if one is not present
var input = FxaForm.createInput(i, utms[i]);
@ -238,11 +272,11 @@ if (typeof window.Mozilla === 'undefined') {
// Configure Sync for Firefox desktop browsers.
if (Mozilla.Client._isFirefoxDesktop()) {
FxaForm.configureRequest().then(function() {
FxaForm.configureRequest().then(function () {
resolve();
});
} else {
FxaForm.fetchTokens().then(function() {
FxaForm.fetchTokens().then(function () {
resolve();
});
}
@ -253,5 +287,4 @@ if (typeof window.Mozilla === 'undefined') {
};
window.Mozilla.FxaForm = FxaForm;
})(window.Mozilla);

Просмотреть файл

@ -2,9 +2,8 @@
* 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/. */
(function(Mozilla) {
(function (Mozilla) {
'use strict';
Mozilla.FxaState.getStateClassAndDo(Mozilla.FxaState.applyStateToBody);
})(window.Mozilla);

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
(function() {
(function () {
'use strict';
Mozilla.FxaLink.init();

Просмотреть файл

@ -7,7 +7,7 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function() {
(function () {
'use strict';
var FxaLink = {};
@ -26,7 +26,7 @@ if (typeof window.Mozilla === 'undefined') {
* @param href {String}
* @returns href {String}
*/
FxaLink.updateURL = function(href) {
FxaLink.updateURL = function (href) {
var userVer = parseFloat(client._getFirefoxVersion());
var serviceParam = userVer < 71 ? 'service=sync' : null;
var contextParam = 'context=fx_desktop_v3';
@ -46,7 +46,7 @@ if (typeof window.Mozilla === 'undefined') {
* @param {String} url.
* @returns {String} hostname.
*/
FxaLink.getHostName = function(url) {
FxaLink.getHostName = function (url) {
var matches = url.match(/^https?:\/\/(?:[^/?#]+)(?:[/?#]|$)/i);
return matches && matches[0];
};
@ -58,21 +58,31 @@ if (typeof window.Mozilla === 'undefined') {
* @param event {Event}
* @private
*/
FxaLink.interceptFxANavigation = function(event) {
FxaLink.interceptFxANavigation = function (event) {
event.preventDefault();
var search = new URL(event.target.href).search;
var urlParams = new window._SearchParams(search).params;
var extraURLParams = {};
var allowedChars = /^[\w/.%-]+$/;
var knownParams = ['flow_id', 'flow_begin_time', 'device_id',
'entrypoint', 'entrypoint_experiment', 'entrypoint_variation',
'utm_source', 'utm_campaign', 'utm_content', 'utm_term', 'utm_medium'];
var knownParams = [
'flow_id',
'flow_begin_time',
'device_id',
'entrypoint',
'entrypoint_experiment',
'entrypoint_variation',
'utm_source',
'utm_campaign',
'utm_content',
'utm_term',
'utm_medium'
];
for (var i = 0; i < knownParams.length; i++) {
var known = knownParams[i];
if (Object.prototype.hasOwnProperty.call(urlParams, known)) {
var param = decodeURIComponent(urlParams[known]);
if ((allowedChars).test(param)) {
if (allowedChars.test(param)) {
extraURLParams[known] = param;
}
}
@ -87,16 +97,19 @@ if (typeof window.Mozilla === 'undefined') {
* Updates FxA links with Sync params.
* Only applicable for Firefox desktop user agents.
*/
FxaLink.init = function(callback) {
callback = callback || function noop() {
// do nothing
};
FxaLink.init = function (callback) {
callback =
callback ||
function noop() {
// do nothing
};
if (!client._isFirefoxDesktop()) {
return;
}
var userVer = parseFloat(client._getFirefoxVersion());
var useUITourForFxA = userVer >= 80 && typeof Mozilla.UITour !== 'undefined';
var useUITourForFxA =
userVer >= 80 && typeof Mozilla.UITour !== 'undefined';
var self = this;
var fxaSigninLink = document.querySelectorAll('.js-fxa-cta-link');
@ -112,14 +125,19 @@ if (typeof window.Mozilla === 'undefined') {
link.href = FxaLink.updateURL(link.href);
// update china repack URL.
var mozillaOnlineLink = link.getAttribute('data-mozillaonline-link');
var mozillaOnlineLink = link.getAttribute(
'data-mozillaonline-link'
);
if (mozillaOnlineLink) {
link.setAttribute('data-mozillaonline-link', FxaLink.updateURL(mozillaOnlineLink));
link.setAttribute(
'data-mozillaonline-link',
FxaLink.updateURL(mozillaOnlineLink)
);
}
}
if (useUITourForFxA) {
Mozilla.UITour.ping(function() {
Mozilla.UITour.ping(function () {
for (var i = 0; i < fxaSigninLink.length; i++) {
var link = fxaSigninLink[i];
var hostName = FxaLink.getHostName(link.href);
@ -128,12 +146,15 @@ if (typeof window.Mozilla === 'undefined') {
continue;
}
link.setAttribute('role', 'button');
link.oncontextmenu = function(e) {
link.oncontextmenu = function (e) {
e.preventDefault();
};
// intercept the flow and submit the form using the UITour API instead.
// In the future we should fully migrate to this API for Firefox Desktop login.
link.addEventListener('auxclick', self.interceptFxANavigation);
link.addEventListener(
'auxclick',
self.interceptFxANavigation
);
link.addEventListener('click', self.interceptFxANavigation);
}
callback();
@ -144,5 +165,4 @@ if (typeof window.Mozilla === 'undefined') {
};
window.Mozilla.FxaLink = FxaLink;
})();

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
(function() {
(function () {
'use strict';
Mozilla.FxaProductButton.init();

Просмотреть файл

@ -1,13 +1,13 @@
/* 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/. */
* 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/. */
// create namespace
if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function() {
(function () {
'use strict';
var FxaProductButton = {};
@ -31,7 +31,7 @@ if (typeof window.Mozilla === 'undefined') {
* @param {String} url.
* @returns {String} hostname.
*/
FxaProductButton.getHostName = function(url) {
FxaProductButton.getHostName = function (url) {
var matches = url.match(/^https?:\/\/(?:[^/?#]+)(?:[/?#]|$)/i);
return matches && matches[0];
};
@ -40,10 +40,11 @@ if (typeof window.Mozilla === 'undefined') {
* Get tokens from FxA for analytics purposes.
* This is non-critical to the user flow.
*/
FxaProductButton.fetchTokens = function(buttons) {
FxaProductButton.fetchTokens = function (buttons) {
// assume the first button should dictate the metrics flow request
var buttonURL = buttons[0].getAttribute('href');
var metricsURL = buttons[0].getAttribute('data-action') + 'metrics-flow';
var metricsURL =
buttons[0].getAttribute('data-action') + 'metrics-flow';
// strip url to everything after `?`
var buttonURLParams = buttonURL.match(/\?(.*)/)[1];
@ -74,24 +75,29 @@ if (typeof window.Mozilla === 'undefined') {
}
if (params.entrypoint_experiment) {
metricsURL += '&entrypoint_experiment=' + params.entrypoint_experiment;
metricsURL +=
'&entrypoint_experiment=' + params.entrypoint_experiment;
}
if (params.entrypoint_variation) {
metricsURL += '&entrypoint_variation=' + params.entrypoint_variation;
metricsURL +=
'&entrypoint_variation=' + params.entrypoint_variation;
}
return fetch(metricsURL).then(function(resp) {
return resp.json();
}).then(function(r) {
// add retrieved deviceID, flowBeginTime and flowId values to cta url
var flowParams = '&device_id=' + r.deviceId;
flowParams += '&flow_begin_time=' + r.flowBeginTime;
flowParams += '&flow_id=' + r.flowId;
return flowParams;
}).catch(function() {
// silently fail: deviceId, flowBeginTime, flowId are not added to url.
});
return fetch(metricsURL)
.then(function (resp) {
return resp.json();
})
.then(function (r) {
// add retrieved deviceID, flowBeginTime and flowId values to cta url
var flowParams = '&device_id=' + r.deviceId;
flowParams += '&flow_begin_time=' + r.flowBeginTime;
flowParams += '&flow_id=' + r.flowId;
return flowParams;
})
.catch(function () {
// silently fail: deviceId, flowBeginTime, flowId are not added to url.
});
};
/**
@ -99,7 +105,7 @@ if (typeof window.Mozilla === 'undefined') {
* @param {Object} Node List
* @param {String} flowParams
*/
FxaProductButton.updateProductLinks = function(buttons, flowParams) {
FxaProductButton.updateProductLinks = function (buttons, flowParams) {
// if flowParams are undefined (e.g. blocked by CORS), then do nothing.
if (!flowParams) {
return;
@ -111,12 +117,12 @@ if (typeof window.Mozilla === 'undefined') {
var hostName = FxaProductButton.getHostName(href);
// check if link is in the FxA referral allowedListDomains.
if (hostName && allowedList.indexOf(hostName) !== -1) {
// Only add flow params if they do not already exist.
if (href.indexOf('flow_id') === -1 &&
if (
href.indexOf('flow_id') === -1 &&
href.indexOf('flow_begin_time') === -1 &&
href.indexOf('device_id') === -1) {
href.indexOf('device_id') === -1
) {
buttons[i].href += flowParams;
}
}
@ -127,10 +133,14 @@ if (typeof window.Mozilla === 'undefined') {
* Switches FxA links to point to mozillaonline FxA server for China repack.
* @param {Object} Node List
*/
FxaProductButton.switchDistribution = function(buttons) {
FxaProductButton.switchDistribution = function (buttons) {
for (var i = 0; i < buttons.length; i++) {
var mozillaonlineAction = buttons[i].getAttribute('data-mozillaonline-action');
var mozillaonlineLink = buttons[i].getAttribute('data-mozillaonline-link');
var mozillaonlineAction = buttons[i].getAttribute(
'data-mozillaonline-action'
);
var mozillaonlineLink = buttons[i].getAttribute(
'data-mozillaonline-link'
);
if (mozillaonlineAction && mozillaonlineLink) {
buttons[i].href = mozillaonlineLink;
@ -142,28 +152,45 @@ if (typeof window.Mozilla === 'undefined') {
/**
* Checks for China repack, before making a metrics-flow request.
*/
FxaProductButton.configureRequest = function() {
return new window.Promise(function(resolve) {
Mozilla.Client.getFirefoxDetails(function(data) {
var syncButtons = document.querySelectorAll('.js-fxa-product-button[data-mozillaonline-link]');
FxaProductButton.configureRequest = function () {
return new window.Promise(function (resolve) {
Mozilla.Client.getFirefoxDetails(function (data) {
var syncButtons = document.querySelectorAll(
'.js-fxa-product-button[data-mozillaonline-link]'
);
/**
* Only switch to China repack URLs if there are Sync buttons on the page,
* and if UITour call is successful (marked by data.accurate being true)
*/
if (syncButtons.length && data.accurate && data.distribution && data.distribution.toLowerCase() === 'mozillaonline') {
if (
syncButtons.length &&
data.accurate &&
data.distribution &&
data.distribution.toLowerCase() === 'mozillaonline'
) {
FxaProductButton.switchDistribution(syncButtons);
/**
* Rather than waiting on requests from multiple servers,
* only attach metrics params to Sync buttons for China repack
* if there is more than one type of product button on a page.
*/
FxaProductButton.fetchTokens(syncButtons).then(function(flowParams) {
FxaProductButton.updateProductLinks(syncButtons, flowParams);
FxaProductButton.fetchTokens(syncButtons).then(function (
flowParams
) {
FxaProductButton.updateProductLinks(
syncButtons,
flowParams
);
resolve();
});
} else {
FxaProductButton.fetchTokens(_buttons).then(function(flowParams) {
FxaProductButton.updateProductLinks(_buttons, flowParams);
FxaProductButton.fetchTokens(_buttons).then(function (
flowParams
) {
FxaProductButton.updateProductLinks(
_buttons,
flowParams
);
resolve();
});
}
@ -171,11 +198,11 @@ if (typeof window.Mozilla === 'undefined') {
});
};
FxaProductButton.isSupported = function() {
FxaProductButton.isSupported = function () {
return 'Promise' in window && 'fetch' in window;
};
FxaProductButton.init = function() {
FxaProductButton.init = function () {
// Collect all Fxa product buttons
_buttons = document.getElementsByClassName('js-fxa-product-button');
@ -183,16 +210,21 @@ if (typeof window.Mozilla === 'undefined') {
return false;
}
return new window.Promise(function(resolve, reject) {
return new window.Promise(function (resolve, reject) {
if (_buttons.length) {
// Configure Sync for Firefox desktop browsers
if (Mozilla.Client._isFirefoxDesktop()) {
FxaProductButton.configureRequest().then(function() {
FxaProductButton.configureRequest().then(function () {
resolve();
});
} else {
FxaProductButton.fetchTokens(_buttons).then(function(flowParams) {
FxaProductButton.updateProductLinks(_buttons, flowParams);
FxaProductButton.fetchTokens(_buttons).then(function (
flowParams
) {
FxaProductButton.updateProductLinks(
_buttons,
flowParams
);
resolve();
});
}
@ -204,4 +236,3 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla.FxaProductButton = FxaProductButton;
})();

Просмотреть файл

@ -10,21 +10,21 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function(Mozilla) {
(function (Mozilla) {
'use strict';
var FxaState = {
body: document.getElementsByTagName('body')[0],
defaultStateClass : 'state-fxa-default', // only present if added manually to page in HTML
defaultStateClass: 'state-fxa-default' // only present if added manually to page in HTML
};
FxaState.getStateClassAndDo = function(callback) {
Mozilla.Client.getFxaDetails(function(details) {
FxaState.getStateClassAndDo = function (callback) {
Mozilla.Client.getFxaDetails(function (details) {
FxaState.convertFxaDetailsToStateAndDo(details, callback);
});
};
FxaState.convertFxaDetailsToStateAndDo = function(details, callback) {
FxaState.convertFxaDetailsToStateAndDo = function (details, callback) {
var stateClass = '';
if (details.firefox) {
@ -38,7 +38,10 @@ if (typeof window.Mozilla === 'undefined') {
}
} else {
// Query param `signed-in=true` is used for integration testing and demo review only.
if (details.setup || window.location.search.indexOf('signed-in=true') !== -1) {
if (
details.setup ||
window.location.search.indexOf('signed-in=true') !== -1
) {
stateClass = 'state-fxa-supported-signed-in';
} else {
stateClass = 'state-fxa-supported-signed-out';
@ -50,11 +53,10 @@ if (typeof window.Mozilla === 'undefined') {
callback(stateClass);
};
FxaState.applyStateToBody = function(stateClass) {
FxaState.applyStateToBody = function (stateClass) {
FxaState.body.classList.remove(FxaState.defaultStateClass);
FxaState.body.classList.add(stateClass);
};
Mozilla.FxaState = FxaState;
})(window.Mozilla);

Просмотреть файл

@ -1,21 +1,23 @@
/* 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/. */
* 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/. */
if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function() {
(function () {
'use strict';
var LazyLoad = {};
var _selector;
function featureDetect() {
return 'IntersectionObserver' in window &&
'IntersectionObserverEntry' in window &&
'intersectionRatio' in window.IntersectionObserverEntry.prototype;
return (
'IntersectionObserver' in window &&
'IntersectionObserverEntry' in window &&
'intersectionRatio' in window.IntersectionObserverEntry.prototype
);
}
LazyLoad.supportsInsersectionObserver = featureDetect();
@ -25,10 +27,9 @@ if (typeof window.Mozilla === 'undefined') {
* @param changes (Array) - IntersectionObserverEntry objects.
* @param observer (Object) - IntersectionObserver instance.
*/
LazyLoad.observerCallback = function(changes, observer) {
changes.forEach(function(change) {
LazyLoad.observerCallback = function (changes, observer) {
changes.forEach(function (change) {
if (change.intersectionRatio > 0) {
if (change.target.dataset.srcset) {
change.target.srcset = change.target.dataset.srcset;
}
@ -46,7 +47,7 @@ if (typeof window.Mozilla === 'undefined') {
* for intersection events.
* @return (Object) IntersectionObserver instance.
*/
LazyLoad.registerObserver = function() {
LazyLoad.registerObserver = function () {
return new IntersectionObserver(LazyLoad.observerCallback);
};
@ -55,12 +56,14 @@ if (typeof window.Mozilla === 'undefined') {
* @param _selector (String) - CSS selector for target images e.g. '.list-item img'.
* @return observe (Object) IntersectionObserver instance.
*/
LazyLoad.observe = function(_selector) {
LazyLoad.observe = function (_selector) {
var observer = LazyLoad.registerObserver();
var targets = Array.prototype.slice.call(document.querySelectorAll(_selector));
var targets = Array.prototype.slice.call(
document.querySelectorAll(_selector)
);
if (targets.length) {
targets.forEach(function(target) {
targets.forEach(function (target) {
observer.observe(target);
});
}
@ -72,9 +75,9 @@ if (typeof window.Mozilla === 'undefined') {
* Fallback for older browser by simply loading all images upon page load.
* @param _selector (String) - CSS selector for target images e.g. '.list-item img'.
*/
LazyLoad.loadAllFallback = function(_selector) {
LazyLoad.loadAllFallback = function (_selector) {
var nodeList = document.querySelectorAll(_selector);
for(var ni = 0; ni < nodeList.length; ni++) {
for (var ni = 0; ni < nodeList.length; ni++) {
var self = nodeList[ni];
var srcset = self.getAttribute('data-srcset');
@ -91,7 +94,7 @@ if (typeof window.Mozilla === 'undefined') {
* Removes data-src attribute upon lazy loading of an image. This is useful
* as it provides a CSS styling hook to allow images to fade-in.
*/
LazyLoad.onImageLoad = function(e) {
LazyLoad.onImageLoad = function (e) {
e.target.removeAttribute('data-src');
e.target.removeAttribute('data-srcset');
};
@ -100,13 +103,14 @@ if (typeof window.Mozilla === 'undefined') {
* Initiates LazyLoad via feature detecting support for IntersectioObserver.
* @param _selector (String) - CSS selector for target images e.g. '.list-item img'.
*/
LazyLoad.init = function(selector) {
LazyLoad.init = function (selector) {
// Allow passing custom selector if required.
_selector = selector || '.lazy-image-container img';
if (typeof _selector !== 'string') {
throw new Error('Mozilla.LazyLoad.init: custom selector is not a string');
throw new Error(
'Mozilla.LazyLoad.init: custom selector is not a string'
);
}
if (LazyLoad.supportsInsersectionObserver) {

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
(function() {
(function () {
'use strict';
Mozilla.Pixel.init();

Просмотреть файл

@ -7,7 +7,7 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function() {
(function () {
'use strict';
/**
@ -20,11 +20,11 @@ if (typeof window.Mozilla === 'undefined') {
*/
var Pixel = {};
Pixel.getPixelData = function() {
Pixel.getPixelData = function () {
return document.getElementById('strings').getAttribute('data-pixels');
};
Pixel.setPixels = function() {
Pixel.setPixels = function () {
var body = document.querySelector('body');
var pixels = Pixel.getPixelData();
var pixel;
@ -55,7 +55,7 @@ if (typeof window.Mozilla === 'undefined') {
}
};
Pixel.init = function() {
Pixel.init = function () {
// Do not set pixels if visitor has DNT enabled.
if (!Mozilla.dntEnabled()) {
Pixel.setPixels();

Просмотреть файл

@ -7,10 +7,10 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function() {
(function () {
'use strict';
window.Mozilla.run = function(callback) {
window.Mozilla.run = function (callback) {
var isModernBrowser = window.site && window.site.isModernBrowser;
if (isModernBrowser && typeof callback === 'function') {

Просмотреть файл

@ -9,29 +9,30 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
Mozilla.smoothScroll = (function() {
Mozilla.smoothScroll = (function () {
'use strict';
var _smoothScroll;
var _init = function(unitTest) {
var _init = function (unitTest) {
var hasSmoothScroll;
// try to use native smooth scrolling
if (unitTest) {
hasSmoothScroll = (unitTest === 'native') ? true : false;
hasSmoothScroll = unitTest === 'native' ? true : false;
} else {
hasSmoothScroll = 'scrollBehavior' in document.documentElement.style;
hasSmoothScroll =
'scrollBehavior' in document.documentElement.style;
}
// use native smooth scrolling
if (hasSmoothScroll) {
_smoothScroll = function(opts) {
_smoothScroll = function (opts) {
window.scrollTo(opts);
};
// default to regular ol' jump scrolling
// default to regular ol' jump scrolling
} else {
_smoothScroll = function(opts) {
_smoothScroll = function (opts) {
window.scrollTo(opts.top, opts.left);
};
}
@ -45,7 +46,7 @@ Mozilla.smoothScroll = (function() {
At least one of the two axes (top, left) should be specified.
*/
return function(userOpts) {
return function (userOpts) {
// set up defaults
var opts = {
behavior: userOpts.behavior || 'smooth',

Просмотреть файл

@ -20,20 +20,21 @@ Expectations (expressed in logic below) of these kinds of tests:
- Non-matched geo-lookup persists on client for 48 hours
*/
(function(Mozilla) {
(function (Mozilla) {
'use strict';
// Traffic Cop Funnel Cake Geolocation Experiment
var TCFCGeoExp = {};
TCFCGeoExp.init = function(config) {
TCFCGeoExp.init = function (config) {
var experimentConfig = config.experimentConfig;
var countryCode = config.countryCode;
var experimentId = experimentConfig.Id;
var geoNonmatchCookieName = experimentId + '_non' + countryCode;
// check if cookies are enabled
var hasCookies = (typeof Mozilla.Cookies !== 'undefined' || Mozilla.Cookies.enabled());
var hasCookies =
typeof Mozilla.Cookies !== 'undefined' || Mozilla.Cookies.enabled();
// all depends on cookies being enabled/available
if (hasCookies) {
@ -43,29 +44,33 @@ Expectations (expressed in logic below) of these kinds of tests:
// (will send them to the same variation as before)
if (TCFCGeoExp.checkInCohort(experimentId)) {
TCFCGeoExp.runExperiment(experimentConfig);
// if visitor is not already in a cohort, make sure they are
// eligible for the experiment. if so, perform the geo-lookup
// if visitor is not already in a cohort, make sure they are
// eligible for the experiment. if so, perform the geo-lookup
} else if (TCFCGeoExp.preCheckGeo()) {
TCFCGeoExp.geoLookup(countryCode, geoNonmatchCookieName, experimentConfig);
TCFCGeoExp.geoLookup(
countryCode,
geoNonmatchCookieName,
experimentConfig
);
}
}
}
};
// ensures current visitor did not previously fail the geo-lookup
TCFCGeoExp.checkGeoNonmatch = function(geoNonmatchCookieName) {
TCFCGeoExp.checkGeoNonmatch = function (geoNonmatchCookieName) {
// check if user already failed geolookup
return !Mozilla.Cookies.hasItem(geoNonmatchCookieName);
};
// checks to see if visitor was previously entered into a variation
TCFCGeoExp.checkInCohort = function(experimentId) {
TCFCGeoExp.checkInCohort = function (experimentId) {
// check if user already was served a variation
return Mozilla.Cookies.hasItem(experimentId);
};
// checks many environmental factors to verify visitor is eligible
TCFCGeoExp.preCheckGeo = function(ua, platform, search) {
TCFCGeoExp.preCheckGeo = function (ua, platform, search) {
ua = ua || navigator.userAgent;
platform = platform || window.site.platform;
search = search || document.location.search;
@ -74,7 +79,8 @@ Expectations (expressed in logic below) of these kinds of tests:
var isIELT9 = /MSIE\s[1-8]\./.test(ua);
// swiped from mozilla-client.js
var isLikeFirefox = /Iceweasel|IceCat|SeaMonkey|Camino|like Firefox/i.test(ua);
var isLikeFirefox =
/Iceweasel|IceCat|SeaMonkey|Camino|like Firefox/i.test(ua);
var isFirefox = /\s(Firefox|FxiOS)/.test(ua) && !isLikeFirefox;
// check if user is on windows
@ -82,22 +88,29 @@ Expectations (expressed in logic below) of these kinds of tests:
// check if current URL has a funnelcake param (in the unlikely event of navigating directly)
var isFunnelcake = /^.*\?.*f=\d{3}.*/.test(search);
// check if DNT is detectable and off
var dntOk = (typeof Mozilla.dntEnabled === 'function' && !Mozilla.dntEnabled());
var dntOk =
typeof Mozilla.dntEnabled === 'function' && !Mozilla.dntEnabled();
return !isFunnelcake && isWindows && !isIELT9 && !isFirefox && dntOk;
};
// performs AJAX request to get country of current visitor
TCFCGeoExp.geoLookup = function(countryCode, geoNonmatchCookieName, experimentConfig) {
TCFCGeoExp.geoLookup = function (
countryCode,
geoNonmatchCookieName,
experimentConfig
) {
var xhr = new window.XMLHttpRequest();
xhr.onload = function(r) {
xhr.onload = function (r) {
// make sure status is in the acceptable range
if (r.target.status >= 200 && r.target.status < 300) {
var country;
try {
country = JSON.parse(r.target.responseText).country_code.toLowerCase();
country = JSON.parse(
r.target.responseText
).country_code.toLowerCase();
} catch (e) {
country = 'none';
}
@ -121,7 +134,7 @@ Expectations (expressed in logic below) of these kinds of tests:
};
// starts the traffic cop experiment
TCFCGeoExp.runExperiment = function(config) {
TCFCGeoExp.runExperiment = function (config) {
var rawls = new Mozilla.TrafficCop(config);
rawls.init();
};

Просмотреть файл

@ -7,13 +7,13 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function() {
(function () {
'use strict';
var Utils = {};
// Vanilla JS DOM Ready handler
Utils.onDocumentReady = function(callback) {
Utils.onDocumentReady = function (callback) {
if (document.readyState !== 'loading') {
callback();
} else {
@ -26,40 +26,41 @@ if (typeof window.Mozilla === 'undefined') {
* @param {Object} window.site
* @returns {Object} os, name, version
*/
Utils.getDownloadAttributionValues = function(site) {
Utils.getDownloadAttributionValues = function (site) {
var data = {};
var platform = site.platform;
switch(platform) {
case 'windows':
data.os = 'Desktop';
data.name = 'Windows 32-bit';
data.version = 'win';
break;
case 'osx':
data.os = 'Desktop';
data.name = 'macOS';
data.version = 'osx';
break;
case 'linux':
data.os = 'Desktop';
data.name = site.archSize === 64 ? 'Linux 64-bit' : 'Linux 32-bit';
data.version = site.archSize === 64 ? 'linux64': 'linux';
break;
case 'ios':
data.os = 'iOS';
data.name = 'iOS';
data.version = 'ios';
break;
case 'android':
data.os = 'Android';
data.name = 'Android';
data.version = 'android';
break;
default:
data.os = 'Unsupported';
data.name = 'Unsupported';
data.version = 'unsupported';
switch (platform) {
case 'windows':
data.os = 'Desktop';
data.name = 'Windows 32-bit';
data.version = 'win';
break;
case 'osx':
data.os = 'Desktop';
data.name = 'macOS';
data.version = 'osx';
break;
case 'linux':
data.os = 'Desktop';
data.name =
site.archSize === 64 ? 'Linux 64-bit' : 'Linux 32-bit';
data.version = site.archSize === 64 ? 'linux64' : 'linux';
break;
case 'ios':
data.os = 'iOS';
data.name = 'iOS';
data.version = 'ios';
break;
case 'android':
data.os = 'Android';
data.name = 'Android';
data.version = 'android';
break;
default:
data.os = 'Unsupported';
data.name = 'Unsupported';
data.version = 'unsupported';
}
return data;
@ -68,35 +69,44 @@ if (typeof window.Mozilla === 'undefined') {
/**
* Set platfrom specific GA data attributes for download_firefox_thanks() buttons.
*/
Utils.trackDownloadThanksButton = function() {
var downloadButton = document.querySelectorAll('.c-button-download-thanks > .download-link');
Utils.trackDownloadThanksButton = function () {
var downloadButton = document.querySelectorAll(
'.c-button-download-thanks > .download-link'
);
var data = Utils.getDownloadAttributionValues(window.site);
for (var i = 0; i < downloadButton.length; ++i) {
if (data && data.os && data.name && data.version) {
downloadButton[i].setAttribute('data-download-os', data.os);
downloadButton[i].setAttribute('data-display-name', data.name);
downloadButton[i].setAttribute('data-download-version', data.version);
downloadButton[i].setAttribute(
'data-download-version',
data.version
);
}
}
};
// Replace Google Play links on Android devices to let them open the marketplace app
Utils.initMobileDownloadLinks = function() {
Utils.initMobileDownloadLinks = function () {
if (site.platform === 'android') {
var playLinks = document.querySelectorAll('a[href^="https://play.google.com/store/apps/"]');
var playLinks = document.querySelectorAll(
'a[href^="https://play.google.com/store/apps/"]'
);
for (var i = 0; i < playLinks.length; ++i) {
var playLink = playLinks[i];
var oldHref = playLink.getAttribute('href');
var newHref = oldHref.replace('https://play.google.com/store/apps/', 'market://');
var newHref = oldHref.replace(
'https://play.google.com/store/apps/',
'market://'
);
playLink.setAttribute('href', newHref);
}
}
};
// Bug 1264843: link to China build of Fx4A, for display within Fx China repack
Utils.maybeSwitchToChinaRepackImages = function(client) {
Utils.maybeSwitchToChinaRepackImages = function (client) {
if (!client.distribution) {
return;
}
@ -108,16 +118,20 @@ if (typeof window.Mozilla === 'undefined') {
return;
}
var images = document.querySelectorAll('img[data-' + distribution + '-link]');
var images = document.querySelectorAll(
'img[data-' + distribution + '-link]'
);
for (var j = 0; j < images.length; j++) {
var distributionSrc = images[j].getAttribute('data-' + distribution + '-link');
var distributionSrc = images[j].getAttribute(
'data-' + distribution + '-link'
);
images[j].setAttribute('src', distributionSrc);
}
};
// client-side redirects (handy for testing)
Utils.doRedirect = function(destination) {
Utils.doRedirect = function (destination) {
if (destination) {
window.location.href = destination;
}
@ -130,7 +144,7 @@ if (typeof window.Mozilla === 'undefined') {
// to work. After this, you can access all strings defined inside the
// string_data block in JS using Mozilla.Utils.trans('key-of-string'); Thank @mkelly
var _strings = document.getElementById('strings');
Utils.trans = function(stringId) {
Utils.trans = function (stringId) {
if (_strings) {
return _strings.getAttribute('data-' + stringId);
} else {
@ -139,5 +153,4 @@ if (typeof window.Mozilla === 'undefined') {
};
window.Mozilla.Utils = Utils;
})();

Просмотреть файл

@ -76,7 +76,7 @@ Mozilla.VideoPosterHelper.prototype.play = function (e) {
video.load();
video.play();
}
} catch(e) {
} catch (e) {
// fail silently.
}

Просмотреть файл

@ -5,18 +5,18 @@
/**
* Initialize Protocol language switcher.
*/
(function() {
(function () {
'use strict';
if (typeof Mzp === 'undefined' || typeof Mzp.LangSwitcher === 'undefined') {
return;
}
Mzp.LangSwitcher.init(function(previousLanguage, newLanguage) {
Mzp.LangSwitcher.init(function (previousLanguage, newLanguage) {
window.dataLayer.push({
'event': 'change-language',
'languageSelected': newLanguage,
'previousLanguage': previousLanguage
event: 'change-language',
languageSelected: newLanguage,
previousLanguage: previousLanguage
});
});
})();

Просмотреть файл

@ -5,17 +5,24 @@
/**
* Initialize Protocol Navigation.
*/
(function() {
(function () {
'use strict';
if (typeof Mzp === 'undefined' || typeof Mzp.Menu === 'undefined' || typeof Mzp.Navigation === 'undefined') {
if (
typeof Mzp === 'undefined' ||
typeof Mzp.Menu === 'undefined' ||
typeof Mzp.Navigation === 'undefined'
) {
return;
}
var hasMediaQueries = typeof window.matchMedia !== 'undefined';
function handleOnMenuOpen() {
if (!hasMediaQueries || !window.matchMedia('(min-width: 768px)').matches) {
if (
!hasMediaQueries ||
!window.matchMedia('(min-width: 768px)').matches
) {
return;
}
}
@ -26,7 +33,9 @@
}
var nav = document.querySelector('.c-navigation');
var fxaButton = document.querySelector('.c-navigation .c-navigation-fxa-cta');
var fxaButton = document.querySelector(
'.c-navigation .c-navigation-fxa-cta'
);
// Nav should be present on page.
if (!nav) {
@ -38,7 +47,7 @@
var fxaButtonAltHref = fxaButton.getAttribute('data-alt-href');
// Update the button if user is signed in
Mozilla.Client.getFxaDetails(function(details) {
Mozilla.Client.getFxaDetails(function (details) {
if (details.setup) {
nav.classList.add('fxa-signed-in');
fxaButton.href = fxaButtonAltHref;

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
(function() {
(function () {
'use strict';
// check we have global variable
@ -11,10 +11,12 @@
var footerHeadings = '.c-footer-section .c-footer-heading';
// check we have global Supports and Details library
if (typeof Mzp.Supports !== 'undefined' && typeof Mzp.Details !== 'undefined') {
if (
typeof Mzp.Supports !== 'undefined' &&
typeof Mzp.Details !== 'undefined'
) {
// check browser supports matchMedia
if(Mzp.Supports.matchMedia) {
if (Mzp.Supports.matchMedia) {
var _mqWide = matchMedia('(max-width: 479px)');
// initialize details if screen is small
@ -23,7 +25,7 @@
}
// remove details if screen is big
_mqWide.addListener(function(mq) {
_mqWide.addListener(function (mq) {
if (mq.matches) {
Mzp.Details.init(footerHeadings);
} else {

Просмотреть файл

@ -4,7 +4,7 @@
// Copied from Protocol, to be backported along with nav updates.
(function(Mzp) {
(function (Mzp) {
'use strict';
var Menu = {};
@ -25,7 +25,7 @@
* @param {Object} el - DOM element (`.mzp-c-menu-category.mzp-js-expandable`)
* @param {Boolean} animate - show animation when menu panel opens.
*/
Menu.open = function(el, animate) {
Menu.open = function (el, animate) {
if (animate) {
el.classList.add('mzp-is-animated');
}
@ -45,8 +45,10 @@
* Closes all currently open menu panels.
* Note: on small screens more than one menu can be open at the same time.
*/
Menu.close = function() {
var current = document.querySelectorAll('.c-menu-category.mzp-is-selected');
Menu.close = function () {
var current = document.querySelectorAll(
'.c-menu-category.mzp-is-selected'
);
for (var i = 0; i < current.length; i++) {
// The following classes must be removed in the correct order
@ -55,7 +57,9 @@
current[i].classList.remove('mzp-is-selected');
current[i].classList.remove('mzp-is-animated');
current[i].querySelector('.c-menu-title').setAttribute('aria-expanded', false);
current[i]
.querySelector('.c-menu-title')
.setAttribute('aria-expanded', false);
}
_menuOpen = false; // For checking menu state on keyup.
@ -67,7 +71,7 @@
return current.length > 0;
};
Menu.onDocumentKeyUp = function(e) {
Menu.onDocumentKeyUp = function (e) {
if (e.keyCode === 27 && _menuOpen) {
Menu.close();
}
@ -77,7 +81,7 @@
* Menu panel close button `click` event handler.
* @param {Object} e - Event object.
*/
Menu.onCloseButtonClick = function(e) {
Menu.onCloseButtonClick = function (e) {
e.preventDefault();
if (typeof _options.onMenuButtonClose === 'function') {
@ -91,7 +95,7 @@
* Toggles the open/closed state of a menu panel.
* @param {Object} el - DOM element (`.mzp-c-menu-category.mzp-js-expandable`)
*/
Menu.toggle = function(el) {
Menu.toggle = function (el) {
var state = el.classList.contains('mzp-is-selected') ? true : false;
if (!state) {
@ -102,7 +106,10 @@
// https://github.com/mozilla/bedrock/issues/6221 :/
el.classList.remove('mzp-is-selected');
el.classList.remove('mzp-is-animated');
el.querySelector('.c-menu-title').setAttribute('aria-expanded', false);
el.querySelector('.c-menu-title').setAttribute(
'aria-expanded',
false
);
if (typeof _options.onMenuClose === 'function') {
_options.onMenuClose();
@ -116,12 +123,12 @@
* Animates only if a menu panel is not already open.
* @param {Object} e - Event object.
*/
Menu.onMouseEnter = function(e) {
Menu.onMouseEnter = function (e) {
clearTimeout(_hoverTimeout);
_hoverTimeout = setTimeout(function() {
_hoverTimeout = setTimeout(function () {
var current = Menu.close();
var animate = current ? false: true;
var animate = current ? false : true;
Menu.open(e.target, animate);
}, _hoverTimeoutDelay);
@ -131,10 +138,10 @@
* Menu `mouseleave` event handler.
* Closes the menu only when hover intent is shown.
*/
Menu.onMouseLeave = function() {
Menu.onMouseLeave = function () {
clearTimeout(_hoverTimeout);
_hoverTimeout = setTimeout(function() {
_hoverTimeout = setTimeout(function () {
Menu.close();
}, _hoverTimeoutDelay);
};
@ -143,7 +150,7 @@
* Menu `focusout` event handler.
* Closes the menu when focus moves to an alement outside of the currently open panel.
*/
Menu.onFocusOut = function() {
Menu.onFocusOut = function () {
var self = this;
/**
@ -151,9 +158,12 @@
* moving to the next element. A `setTimeout` of `0` circumvents this issue as it
* re-queues the JavaScript to run at the end of the current excecution.
*/
setTimeout(function() {
setTimeout(function () {
// If the menu is open and the newly focused element is not a child, then call close().
if (!self.contains(document.activeElement) && self.classList.contains('mzp-is-selected')) {
if (
!self.contains(document.activeElement) &&
self.classList.contains('mzp-is-selected')
) {
Menu.close();
}
}, 0);
@ -164,7 +174,7 @@
* Closes any currently open menu panels before opening the selected one.
* @param {Object} e - Event object.
*/
Menu.onClickWide = function(e) {
Menu.onClickWide = function (e) {
e.preventDefault();
Menu.close();
Menu.open(e.target.parentNode);
@ -175,7 +185,7 @@
* Toggles the currently selected menu open open/close state.
* @param {Object} e - Event object.
*/
Menu.onClickSmall = function(e) {
Menu.onClickSmall = function (e) {
e.preventDefault();
Menu.toggle(e.target.parentNode);
};
@ -184,17 +194,17 @@
* Convenience function for checking `matchMedia` state.
* @return {Boolean}
*/
Menu.isWideViewport = function() {
Menu.isWideViewport = function () {
return _mqWideNav.matches;
};
/**
* Toggle desktop/mobile navigation using `matchMedia` event handler.
*/
Menu.handleState = function() {
Menu.handleState = function () {
_mqWideNav = matchMedia('(min-width: ' + _wideBreakpoint + ')');
_mqWideNav.addListener(function(mq) {
_mqWideNav.addListener(function (mq) {
Menu.close();
if (mq.matches) {
@ -216,8 +226,10 @@
/**
* Bind events for wide viewports.
*/
Menu.bindEventsWide = function() {
var items = document.querySelectorAll('.c-menu-category.mzp-js-expandable');
Menu.bindEventsWide = function () {
var items = document.querySelectorAll(
'.c-menu-category.mzp-js-expandable'
);
var link;
var close;
@ -240,14 +252,24 @@
/**
* Unbind events for wide viewports.
*/
Menu.unbindEventsWide = function() {
var items = document.querySelectorAll('.c-menu-category.mzp-js-expandable');
Menu.unbindEventsWide = function () {
var items = document.querySelectorAll(
'.c-menu-category.mzp-js-expandable'
);
var link;
var close;
for (var i = 0; i < items.length; i++) {
items[i].removeEventListener('mouseenter', Menu.onMouseEnter, false);
items[i].removeEventListener('mouseleave', Menu.onMouseLeave, false);
items[i].removeEventListener(
'mouseenter',
Menu.onMouseEnter,
false
);
items[i].removeEventListener(
'mouseleave',
Menu.onMouseLeave,
false
);
items[i].removeEventListener('focusout', Menu.onFocusOut, false);
link = items[i].querySelector('.c-menu-title');
@ -263,8 +285,10 @@
/**
* Bind events for small viewports.
*/
Menu.bindEventsSmall = function() {
var items = document.querySelectorAll('.c-menu-category.mzp-js-expandable .c-menu-title');
Menu.bindEventsSmall = function () {
var items = document.querySelectorAll(
'.c-menu-category.mzp-js-expandable .c-menu-title'
);
for (var i = 0; i < items.length; i++) {
items[i].addEventListener('click', Menu.onClickSmall, false);
@ -274,8 +298,10 @@
/**
* Unbind events for small viewports.
*/
Menu.unbindEventsSmall = function() {
var items = document.querySelectorAll('.c-menu-category.mzp-js-expandable .c-menu-title');
Menu.unbindEventsSmall = function () {
var items = document.querySelectorAll(
'.c-menu-category.mzp-js-expandable .c-menu-title'
);
for (var i = 0; i < items.length; i++) {
items[i].removeEventListener('click', Menu.onClickSmall, false);
@ -285,8 +311,10 @@
/**
* Set initial ARIA menu panel states.
*/
Menu.setAria = function() {
var items = document.querySelectorAll('.c-menu-category.mzp-js-expandable .c-menu-title');
Menu.setAria = function () {
var items = document.querySelectorAll(
'.c-menu-category.mzp-js-expandable .c-menu-title'
);
for (var i = 0; i < items.length; i++) {
items[i].setAttribute('aria-expanded', false);
@ -296,7 +324,7 @@
/**
* Enhances the menu for 1st class JS support.
*/
Menu.enhanceJS = function() {
Menu.enhanceJS = function () {
var menu = document.querySelectorAll('.c-menu');
for (var i = 0; i < menu.length; i++) {
@ -308,7 +336,7 @@
/**
* Basic feature detect for 1st class menu JS support.
*/
Menu.isSupported = function() {
Menu.isSupported = function () {
if (typeof Mzp.Supports !== 'undefined') {
return Mzp.Supports.matchMedia && Mzp.Supports.classList;
} else {
@ -320,7 +348,7 @@
* Initialise menu.
* @param {Object} options - configurable options.
*/
Menu.init = function(options) {
Menu.init = function (options) {
if (typeof options === 'object') {
for (var i in options) {
if (options.hasOwnProperty.call(i)) {
@ -337,5 +365,4 @@
};
window.Mzp.Menu = Menu;
})(window.Mzp);

Просмотреть файл

@ -4,7 +4,7 @@
// Copied from Protocol, to be backported along with nav updates.
(function(Mzp) {
(function (Mzp) {
'use strict';
var Navigation = {};
@ -28,7 +28,7 @@
* requirements for sticky behaviour?
* @returns {Boolean}
*/
Navigation.isLargeViewport = function() {
Navigation.isLargeViewport = function () {
return _mqLargeNav.matches;
};
@ -36,13 +36,15 @@
* Feature detect for sticky navigation
* @returns {Boolean}
*/
Navigation.supportsSticky = function() {
Navigation.supportsSticky = function () {
if (typeof Mzp.Supports !== 'undefined') {
return Mzp.Supports.matchMedia &&
Mzp.Supports.classList &&
Mzp.Supports.requestAnimationFrame &&
Mzp.Supports.cssFeatureQueries &&
CSS.supports('position', 'sticky');
return (
Mzp.Supports.matchMedia &&
Mzp.Supports.classList &&
Mzp.Supports.requestAnimationFrame &&
Mzp.Supports.cssFeatureQueries &&
CSS.supports('position', 'sticky')
);
} else {
return false;
}
@ -53,9 +55,11 @@
* operations such as DOM modifications should happen
* here. Instead we throttle using `requestAnimationFrame`.
*/
Navigation.onScroll = function() {
Navigation.onScroll = function () {
if (!_ticking) {
_animationFrameID = window.requestAnimationFrame(Navigation.checkScrollPosition);
_animationFrameID = window.requestAnimationFrame(
Navigation.checkScrollPosition
);
_ticking = true;
}
};
@ -63,16 +67,18 @@
/**
* Create sticky state for the navigation.
*/
Navigation.createSticky = function() {
Navigation.createSticky = function () {
_viewport.classList.add('mzp-has-sticky-navigation');
_animationFrameID = window.requestAnimationFrame(Navigation.checkScrollPosition);
_animationFrameID = window.requestAnimationFrame(
Navigation.checkScrollPosition
);
window.addEventListener('scroll', Navigation.onScroll, false);
};
/**
* Destroy sticky state for the navigation.
*/
Navigation.destroySticky = function() {
Navigation.destroySticky = function () {
_viewport.classList.remove('mzp-has-sticky-navigation');
_navElem.classList.remove('mzp-is-scrolling');
_navElem.classList.remove('mzp-is-hidden');
@ -89,10 +95,16 @@
* Uses `matchMedia` to determine if conditions
* for sticky navigation are satisfied.
*/
Navigation.initSticky = function() {
_mqLargeNav = matchMedia('(min-width: ' + _wideBreakpoint + ') and (min-height: ' + _tallBreakpoint + ')');
Navigation.initSticky = function () {
_mqLargeNav = matchMedia(
'(min-width: ' +
_wideBreakpoint +
') and (min-height: ' +
_tallBreakpoint +
')'
);
_mqLargeNav.addListener(function(mq) {
_mqLargeNav.addListener(function (mq) {
if (mq.matches) {
Navigation.createSticky();
} else {
@ -109,7 +121,7 @@
* Implements sticky navigation behaviour as
* user scrolls up and down the viewport.
*/
Navigation.checkScrollPosition = function() {
Navigation.checkScrollPosition = function () {
// add tyling for when scrolling the viewport
if (window.scrollY > 0) {
_navElem.classList.add('mzp-is-scrolling');
@ -141,8 +153,10 @@
/**
* Event handler for navigation menu button `click` events.
*/
Navigation.onClick = function(e) {
var thisNavItemList = e.target.parentNode.querySelector('.c-navigation-items');
Navigation.onClick = function (e) {
var thisNavItemList = e.target.parentNode.querySelector(
'.c-navigation-items'
);
e.preventDefault();
@ -153,7 +167,9 @@
thisNavItemList.classList.toggle('mzp-is-open');
// Update aria-expended state on menu.
var expanded = thisNavItemList.classList.contains('mzp-is-open') ? true : false;
var expanded = thisNavItemList.classList.contains('mzp-is-open')
? true
: false;
thisNavItemList.setAttribute('aria-expanded', expanded);
if (expanded) {
@ -170,7 +186,7 @@
/**
* Set initial ARIA navigation states.
*/
Navigation.setAria = function() {
Navigation.setAria = function () {
for (var i = 0; i < _navItemsLists.length; i++) {
_navItemsLists[i].setAttribute('aria-expanded', false);
}
@ -179,12 +195,18 @@
/**
* Bind navigation event handlers.
*/
Navigation.bindEvents = function() {
Navigation.bindEvents = function () {
_navItemsLists = document.querySelectorAll('.c-navigation-items');
if (_navItemsLists.length > 0) {
var navButtons = document.querySelectorAll('.c-navigation-menu-button');
var navButtons = document.querySelectorAll(
'.c-navigation-menu-button'
);
for (var i = 0; i < navButtons.length; i++) {
navButtons[i].addEventListener('click', Navigation.onClick, false);
navButtons[i].addEventListener(
'click',
Navigation.onClick,
false
);
}
Navigation.setAria();
}
@ -194,7 +216,7 @@
* Initialise menu.
* @param {Object} options - configurable options.
*/
Navigation.init = function(options) {
Navigation.init = function (options) {
if (typeof options === 'object') {
for (var i in options) {
if (options.hasOwnProperty.call(i)) {
@ -221,5 +243,4 @@
};
window.Mzp.Navigation = Navigation;
})(window.Mzp);

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
(function() {
(function () {
'use strict';
// check we have global variable
@ -11,8 +11,10 @@
var subNavTitle = '.c-sub-navigation .c-sub-navigation-title';
// check we have global Supports and Details library
if (typeof Mzp.Supports !== 'undefined' && typeof Mzp.Details !== 'undefined') {
if (
typeof Mzp.Supports !== 'undefined' &&
typeof Mzp.Details !== 'undefined'
) {
// check browser supports matchMedia
if (Mzp.Supports.matchMedia) {
var _mqWide = matchMedia('(max-width: 767px)');
@ -23,7 +25,7 @@
}
// remove details if screen is big
_mqWide.addListener(function(mq) {
_mqWide.addListener(function (mq) {
if (mq.matches) {
Mzp.Details.init(subNavTitle);
} else {

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
(function() {
(function () {
'use strict';
// Retrieve search params as a object for easier access
@ -20,7 +20,12 @@
for (var param in obj) {
if (Object.prototype.hasOwnProperty.call(obj, param)) {
searchStrings.push([encodeURIComponent(param), encodeURIComponent(obj[param])].join('='));
searchStrings.push(
[
encodeURIComponent(param),
encodeURIComponent(obj[param])
].join('=')
);
}
}
@ -65,11 +70,11 @@
return _SearchParams.objectToQueryString(this.params);
};
_SearchParams.prototype.utmParams = function() {
_SearchParams.prototype.utmParams = function () {
var utms = {};
var params = this.params;
for (var param in params){
for (var param in params) {
if (Object.prototype.hasOwnProperty.call(params, param)) {
if (param.indexOf('utm_') === 0) {
utms[param] = params[param];
@ -80,7 +85,7 @@
return utms;
};
_SearchParams.prototype.utmParamsFxA = function(pathname) {
_SearchParams.prototype.utmParamsFxA = function (pathname) {
pathname = pathname || window.location.pathname || '';
var utms = this.utmParams();
@ -108,7 +113,7 @@
// ensure all values are strings, as no numeric values are allowed
// into UITour.showFirefoxAccounts
Object.keys(utms).forEach(function(key) {
Object.keys(utms).forEach(function (key) {
utms[key] = utms[key].toString();
});
@ -116,5 +121,4 @@
};
window._SearchParams = _SearchParams;
})();

Просмотреть файл

@ -1,6 +1,6 @@
/* 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/. */
* 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/. */
// create namespace
if (typeof window.Mozilla === 'undefined') {
@ -9,11 +9,10 @@ if (typeof window.Mozilla === 'undefined') {
var Spinner = require('../libs/spin.min.js');
(function() {
(function () {
'use strict';
var SendToDevice = function(id) {
var SendToDevice = function (id) {
this.formId = typeof id !== 'undefined' ? id : 'send-to-device';
this.formLoaded = false;
@ -27,14 +26,17 @@ var Spinner = require('../libs/spin.min.js');
}
this.form = this.widget.querySelector('.send-to-device-form');
this.formFields = this.form.querySelector('.send-to-device-form-fields');
this.formFields = this.form.querySelector(
'.send-to-device-form-fields'
);
this.input = this.formFields.querySelector('.send-to-device-input');
this.thankyou = this.widget.querySelectorAll('.thank-you');
this.errorList = this.form.querySelector('.mzp-c-form-errors');
this.spinnerTarget = this.form.querySelector('.loading-spinner');
this.sendAnotherLink = this.form.querySelector('.send-another');
this.formHeading = this.widget.querySelector('.form-heading');
this.spinnerColor = this.widget.getAttribute('data-spinner-color') || '#000';
this.spinnerColor =
this.widget.getAttribute('data-spinner-color') || '#000';
this.spinner = new Spinner({
lines: 12, // The number of lines to draw
@ -55,7 +57,7 @@ var Spinner = require('../libs/spin.min.js');
/**
* Initialise the form messaging and bind events.
*/
SendToDevice.prototype.init = function() {
SendToDevice.prototype.init = function () {
if (this.widget) {
this.formSubmitHandler = this.onFormSubmit.bind(this);
this.sendAnotherHandler = this.sendAnother.bind(this);
@ -66,23 +68,31 @@ var Spinner = require('../libs/spin.min.js');
/**
* Binds form submission and click events
*/
SendToDevice.prototype.bindEvents = function() {
SendToDevice.prototype.bindEvents = function () {
this.form.addEventListener('submit', this.formSubmitHandler, false);
this.sendAnotherLink.addEventListener('click', this.sendAnotherHandler, false);
this.sendAnotherLink.addEventListener(
'click',
this.sendAnotherHandler,
false
);
};
/**
* Remove all form event handlers
*/
SendToDevice.prototype.unbindEvents = function() {
SendToDevice.prototype.unbindEvents = function () {
this.form.removeEventListener('submit', this.formSubmitHandler, false);
this.sendAnotherLink.removeEventListener('click', this.sendAnotherHandler, false);
this.sendAnotherLink.removeEventListener(
'click',
this.sendAnotherHandler,
false
);
};
/**
* Show the form again to send another link
*/
SendToDevice.prototype.sendAnother = function(e) {
SendToDevice.prototype.sendAnother = function (e) {
e.preventDefault();
this.input.value = '';
this.errorList.classList.add('hidden');
@ -102,7 +112,7 @@ var Spinner = require('../libs/spin.min.js');
/**
* Enable form fields and hide loading indicator
*/
SendToDevice.prototype.enableForm = function() {
SendToDevice.prototype.enableForm = function () {
this.input.disabled = false;
this.form.classList.remove('loading');
this.spinnerTarget.style.display = 'none';
@ -111,7 +121,7 @@ var Spinner = require('../libs/spin.min.js');
/**
* Disable form fields and show loading indicator
*/
SendToDevice.prototype.disableForm = function() {
SendToDevice.prototype.disableForm = function () {
this.input.disabled = true;
this.form.classList.add('loading');
this.spinnerTarget.style.display = 'block';
@ -123,16 +133,16 @@ var Spinner = require('../libs/spin.min.js');
* matches built-in validation in Firefox
* @param {email}
*/
SendToDevice.prototype.checkEmailValidity = function(email) {
SendToDevice.prototype.checkEmailValidity = function (email) {
return /\S+@\S+/.test(email);
};
/**
* Helper function to serialize form data for XHR request.
*/
SendToDevice.prototype.serialize = function() {
SendToDevice.prototype.serialize = function () {
var q = [];
for(var i = 0; i < this.form.elements.length; i++) {
for (var i = 0; i < this.form.elements.length; i++) {
var elem = this.form.elements[i];
if (elem.name) {
q.push(elem.name + '=' + encodeURIComponent(elem.value));
@ -146,7 +156,7 @@ var Spinner = require('../libs/spin.min.js');
/**
* Handle form submission via XHR
*/
SendToDevice.prototype.onFormSubmit = function(e) {
SendToDevice.prototype.onFormSubmit = function (e) {
e.preventDefault();
var self = this;
@ -163,7 +173,7 @@ var Spinner = require('../libs/spin.min.js');
var xhr = new XMLHttpRequest();
xhr.onload = function(r) {
xhr.onload = function (r) {
if (r.target.status >= 200 && r.target.status < 300) {
var response = r.target.response || r.target.responseText;
@ -181,20 +191,23 @@ var Spinner = require('../libs/spin.min.js');
}
};
xhr.onerror = function(e) {
xhr.onerror = function (e) {
self.onFormFailure(e);
};
xhr.open('POST', action, true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.setRequestHeader('X-Requested-With','XMLHttpRequest');
xhr.setRequestHeader(
'Content-type',
'application/x-www-form-urlencoded'
);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.timeout = 5000;
xhr.ontimeout = self.onFormFailure;
xhr.responseType = 'json';
xhr.send(formData);
};
SendToDevice.prototype.onFormSuccess = function() {
SendToDevice.prototype.onFormSuccess = function () {
this.errorList.classList.add('hidden');
this.formFields.classList.add('hidden');
@ -209,12 +222,12 @@ var Spinner = require('../libs/spin.min.js');
this.enableForm();
window.dataLayer.push({
'event': 'send-to-device-success',
'input': 'email-address'
event: 'send-to-device-success',
input: 'email-address'
});
};
SendToDevice.prototype.onFormError = function(errors) {
SendToDevice.prototype.onFormError = function (errors) {
var errorClass;
var errorListItems = this.errorList.querySelectorAll('li');
@ -239,7 +252,7 @@ var Spinner = require('../libs/spin.min.js');
this.enableForm();
};
SendToDevice.prototype.onFormFailure = function() {
SendToDevice.prototype.onFormFailure = function () {
var errorListItems = this.errorList.querySelectorAll('li');
for (var i = 0; i < errorListItems.length; i++) {
@ -258,5 +271,4 @@ var Spinner = require('../libs/spin.min.js');
};
window.Mozilla.SendToDevice = SendToDevice;
})();

Просмотреть файл

@ -5,16 +5,20 @@
import * as Sentry from '@sentry/browser';
// Respect Do Not Track
if (typeof window.Mozilla.dntEnabled === 'function' && !window.Mozilla.dntEnabled()) {
if (
typeof window.Mozilla.dntEnabled === 'function' &&
!window.Mozilla.dntEnabled()
) {
// Get Data Source Name (DSN)
const sentryDsn = document.getElementsByTagName('html')[0].getAttribute('data-sentry-dsn');
const sentryDsn = document
.getElementsByTagName('html')[0]
.getAttribute('data-sentry-dsn');
// Configure Sentry SDK
if (sentryDsn) {
Sentry.init({
dsn: sentryDsn,
sampleRate: 0.10,
sampleRate: 0.1,
ignoreErrors: [
'https://plugin.ucads.ucweb.com/api/flow/',
'Non-Error promise rejection captured with value' // issue 10380
@ -28,7 +32,10 @@ if (typeof window.Mozilla.dntEnabled === 'function' && !window.Mozilla.dntEnable
beforeSend(event) {
try {
// https://github.com/getsentry/sentry-javascript/issues/3147
if (event.exception.values[0].stacktrace.frames[0].filename === '<anonymous>') {
if (
event.exception.values[0].stacktrace.frames[0]
.filename === '<anonymous>'
) {
return null;
}
} catch (e) {

Просмотреть файл

@ -9,8 +9,7 @@
pf = pf || navigator.platform;
ua = ua || navigator.userAgent;
if (pf.indexOf('Win32') !== -1 ||
pf.indexOf('Win64') !== -1) {
if (pf.indexOf('Win32') !== -1 || pf.indexOf('Win64') !== -1) {
return 'windows';
}
if (/android/i.test(ua)) {
@ -22,13 +21,19 @@
if (pf.indexOf('MacPPC') !== -1) {
return 'other';
}
if (pf.indexOf('iPhone') !== -1 ||
if (
pf.indexOf('iPhone') !== -1 ||
pf.indexOf('iPad') !== -1 ||
pf.indexOf('iPod') !== -1 ||
pf.indexOf('MacIntel') !== -1 && 'standalone' in navigator) { // iPadOS
(pf.indexOf('MacIntel') !== -1 && 'standalone' in navigator)
) {
// iPadOS
return 'ios';
}
if (ua.indexOf('Mac OS X') !== -1 && !/Mac OS X 10.[0-8]\D/.test(ua)) {
if (
ua.indexOf('Mac OS X') !== -1 &&
!/Mac OS X 10.[0-8]\D/.test(ua)
) {
return 'osx';
}
@ -39,15 +44,16 @@
ua = ua || navigator.userAgent;
// On OS X, Safari and Chrome have underscores instead of dots
var match = ua.match(/Windows NT (\d+\.\d+)/) ||
ua.match(/Mac OS X (\d+[._]\d+)/) ||
ua.match(/Android (\d+\.\d+)/);
var match =
ua.match(/Windows NT (\d+\.\d+)/) ||
ua.match(/Mac OS X (\d+[._]\d+)/) ||
ua.match(/Android (\d+\.\d+)/);
return match ? match[1].replace('_', '.') : undefined;
},
getArchType: function (ua, pf) {
pf = (pf === '') ? '' : pf || navigator.platform;
pf = pf === '' ? '' : pf || navigator.platform;
ua = ua || navigator.userAgent;
var re;
@ -69,7 +75,7 @@
},
getArchSize: function (ua, pf) {
pf = (pf === '') ? '' : pf || navigator.platform;
pf = pf === '' ? '' : pf || navigator.platform;
ua = ua || navigator.userAgent;
var re = /x64|x86_64|Win64|WOW64|aarch64/i;
@ -84,7 +90,10 @@
// Universal feature detect to deliver graded browser support (targets IE 11 and above).
cutsTheMustard: function () {
return 'classList' in document.createElement('div') && 'MutationObserver' in window;
return (
'classList' in document.createElement('div') &&
'MutationObserver' in window
);
},
platform: 'other',
@ -98,8 +107,9 @@
// if other than 'windows', immediately replace the platform classname on the html-element
// to avoid lots of flickering
var platform = window.site.platform = window.site.getPlatform();
var version = window.site.platformVersion = window.site.getPlatformVersion();
var platform = (window.site.platform = window.site.getPlatform());
var version = (window.site.platformVersion =
window.site.getPlatformVersion());
var _version = version ? parseFloat(version) : 0;
if (platform === 'windows') {
@ -111,9 +121,9 @@
}
// Add class to reflect the microprocessor architecture info
var archType = window.site.archType = window.site.getArchType();
var archSize = window.site.archSize = window.site.getArchSize();
var isARM = window.site.isARM = archType.match(/armv(\d+)/);
var archType = (window.site.archType = window.site.getArchType());
var archSize = (window.site.archSize = window.site.getArchSize());
var isARM = (window.site.isARM = archType.match(/armv(\d+)/));
// Used for Linux ARM processor detection.
if (archType !== 'x86') {
@ -130,14 +140,19 @@
}
// Add class to reflect if user agent is Firefox. Cherry-picked from mozilla-client.js.
var isFirefox = /\s(Firefox|FxiOS)/.test(navigator.userAgent) && !/Iceweasel|IceCat|SeaMonkey|Camino|like Firefox/i.test(navigator.userAgent);
var isFirefox =
/\s(Firefox|FxiOS)/.test(navigator.userAgent) &&
!/Iceweasel|IceCat|SeaMonkey|Camino|like Firefox/i.test(
navigator.userAgent
);
if (isFirefox) {
h.className += ' is-firefox';
}
// Add class to reflect browsers that get 1st class JS & CSS support.
var isModernBrowser = window.site.isModernBrowser = window.site.cutsTheMustard();
var isModernBrowser = (window.site.isModernBrowser =
window.site.cutsTheMustard());
if (isModernBrowser) {
h.className += ' is-modern-browser';

Просмотреть файл

@ -2,19 +2,19 @@
* 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/. */
(function() {
(function () {
'use strict';
Mozilla.Convert.onLoaded(function(convert) {
Mozilla.Convert.onLoaded(function (convert) {
if (convert) {
var data = Mozilla.Convert.getCurrentExperiment(convert);
if (data && data.experimentName && data.experimentVariation) {
Mozilla.StubAttribution.experimentName = data.experimentName;
Mozilla.StubAttribution.experimentVariation = data.experimentVariation;
Mozilla.StubAttribution.experimentVariation =
data.experimentVariation;
}
}
Mozilla.StubAttribution.init();
});
})();

Просмотреть файл

@ -2,14 +2,18 @@
* 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/. */
(function() {
(function () {
'use strict';
// This script is run in a conditional comment that only IE understands,
// so all we care about is making sure that window.site.patform === 'windows'
// for the stub attribution check.
window.site = {
platform: (navigator.platform.indexOf('Win32') !== -1 || navigator.platform.indexOf('Win64') !== -1) ? 'windows' : 'other'
platform:
navigator.platform.indexOf('Win32') !== -1 ||
navigator.platform.indexOf('Win64') !== -1
? 'windows'
: 'other'
};
Mozilla.StubAttribution.init();

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
(function() {
(function () {
'use strict';
Mozilla.StubAttribution.init();

Просмотреть файл

@ -7,7 +7,7 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function() {
(function () {
'use strict';
/**
@ -42,55 +42,77 @@ if (typeof window.Mozilla === 'undefined') {
* Determines if session falls within the predefined stub attribution sample rate.
* @return {Boolean}.
*/
StubAttribution.withinAttributionRate = function() {
return (Math.random() < StubAttribution.getAttributionRate()) ? true : false;
StubAttribution.withinAttributionRate = function () {
return Math.random() < StubAttribution.getAttributionRate()
? true
: false;
};
/**
* Returns stub attribution value used for rate limiting.
* @return {Number} float between 0 and 1.
*/
StubAttribution.getAttributionRate = function() {
var rate = document.getElementsByTagName('html')[0].getAttribute('data-stub-attribution-rate');
return (isNaN(rate) || !rate) ? 0 : Math.min(Math.max(parseFloat(rate), 0), 1);
StubAttribution.getAttributionRate = function () {
var rate = document
.getElementsByTagName('html')[0]
.getAttribute('data-stub-attribution-rate');
return isNaN(rate) || !rate
? 0
: Math.min(Math.max(parseFloat(rate), 0), 1);
};
/**
* Returns true if both cookies exist.
* @return {Boolean} data.
*/
StubAttribution.hasCookie = function() {
return Mozilla.Cookies.hasItem(StubAttribution.COOKIE_CODE_ID) && Mozilla.Cookies.hasItem(StubAttribution.COOKIE_SIGNATURE_ID);
StubAttribution.hasCookie = function () {
return (
Mozilla.Cookies.hasItem(StubAttribution.COOKIE_CODE_ID) &&
Mozilla.Cookies.hasItem(StubAttribution.COOKIE_SIGNATURE_ID)
);
};
/**
* Stores a cookie with stub attribution data values.
* @param {Object} data - attribution_code, attribution_sig.
*/
StubAttribution.setCookie = function(data) {
StubAttribution.setCookie = function (data) {
if (!data.attribution_code || !data.attribution_sig) {
return;
}
// set cookie to expire in 24 hours
var date = new Date();
date.setTime(date.getTime() + (1 * 24 * 60 * 60 * 1000));
date.setTime(date.getTime() + 1 * 24 * 60 * 60 * 1000);
var expires = date.toUTCString();
Mozilla.Cookies.setItem(StubAttribution.COOKIE_CODE_ID, data.attribution_code, expires, '/');
Mozilla.Cookies.setItem(StubAttribution.COOKIE_SIGNATURE_ID, data.attribution_sig, expires, '/');
Mozilla.Cookies.setItem(
StubAttribution.COOKIE_CODE_ID,
data.attribution_code,
expires,
'/'
);
Mozilla.Cookies.setItem(
StubAttribution.COOKIE_SIGNATURE_ID,
data.attribution_sig,
expires,
'/'
);
};
/**
* Gets stub attribution data from cookie.
* @return {Object} - attribution_code, attribution_sig.
*/
StubAttribution.getCookie = function() {
StubAttribution.getCookie = function () {
return {
/* eslint-disable camelcase */
attribution_code: Mozilla.Cookies.getItem(StubAttribution.COOKIE_CODE_ID),
attribution_sig: Mozilla.Cookies.getItem(StubAttribution.COOKIE_SIGNATURE_ID)
attribution_code: Mozilla.Cookies.getItem(
StubAttribution.COOKIE_CODE_ID
),
attribution_sig: Mozilla.Cookies.getItem(
StubAttribution.COOKIE_SIGNATURE_ID
)
/* eslint-enable camelcase */
};
};
@ -100,36 +122,56 @@ if (typeof window.Mozilla === 'undefined') {
* stub attribution.
* @param {Object} data - attribution_code, attribution_sig.
*/
StubAttribution.updateBouncerLinks = function(data) {
StubAttribution.updateBouncerLinks = function (data) {
/**
* If data is missing or the browser does not meet requirements for
* stub attribution, then do nothing.
*/
if (!data.attribution_code || !data.attribution_sig || !StubAttribution.meetsRequirements()) {
if (
!data.attribution_code ||
!data.attribution_sig ||
!StubAttribution.meetsRequirements()
) {
return;
}
// target download buttons and other-platforms modal links.
var downloadLinks = document.querySelectorAll('.download-list .download-link, .c-button-download-thanks .download-link, .download-platform-list .download-link');
var downloadLinks = document.querySelectorAll(
'.download-list .download-link, .c-button-download-thanks .download-link, .download-platform-list .download-link'
);
for (var i = 0; i < downloadLinks.length; i++) {
var link = downloadLinks[i];
var version;
var directLink;
// Append stub attribution data to direct download links.
if (link.href && link.href.indexOf('https://download.mozilla.org') !== -1) {
if (
link.href &&
link.href.indexOf('https://download.mozilla.org') !== -1
) {
version = link.getAttribute('data-download-version');
// Append attribution params to Windows 32bit, 64bit, and MSI installer links.
if (version && (/win/.test(version))) {
link.href = Mozilla.StubAttribution.appendToDownloadURL(link.href, data);
if (version && /win/.test(version)) {
link.href = Mozilla.StubAttribution.appendToDownloadURL(
link.href,
data
);
}
} else if (link.href && link.href.indexOf('/firefox/download/thanks/') !== -1) {
} else if (
link.href &&
link.href.indexOf('/firefox/download/thanks/') !== -1
) {
// Append stub data to direct-link data attributes on transitional links for old IE browsers (Issue #9350)
directLink = link.getAttribute('data-direct-link');
if (directLink) {
link.setAttribute('data-direct-link', Mozilla.StubAttribution.appendToDownloadURL(directLink, data));
link.setAttribute(
'data-direct-link',
Mozilla.StubAttribution.appendToDownloadURL(
directLink,
data
)
);
}
}
}
@ -142,8 +184,7 @@ if (typeof window.Mozilla === 'undefined') {
* @param {Object} data - attribution_code, attribution_sig.
* @return {String} url + additional parameters.
*/
StubAttribution.appendToDownloadURL = function(url, data) {
StubAttribution.appendToDownloadURL = function (url, data) {
if (!data.attribution_code || !data.attribution_sig) {
return url;
}
@ -152,7 +193,11 @@ if (typeof window.Mozilla === 'undefined') {
for (var key in data) {
if (Object.prototype.hasOwnProperty.call(data, key)) {
if (key === 'attribution_code' || key === 'attribution_sig') {
url += (url.indexOf('?') > -1 ? '&' : '?') + key + '=' + data[key];
url +=
(url.indexOf('?') > -1 ? '&' : '?') +
key +
'=' +
data[key];
}
}
}
@ -164,8 +209,12 @@ if (typeof window.Mozilla === 'undefined') {
* Handles XHR request from `stub_attribution_code` service.
* @param {Object} data - attribution_code, attribution_sig.
*/
StubAttribution.onRequestSuccess = function(data) {
if (data.attribution_code && data.attribution_sig && !StubAttribution.requestComplete) {
StubAttribution.onRequestSuccess = function (data) {
if (
data.attribution_code &&
data.attribution_sig &&
!StubAttribution.requestComplete
) {
// Update download links on the current page.
StubAttribution.updateBouncerLinks(data);
// Store attribution data in a cookie should the user navigate.
@ -179,7 +228,7 @@ if (typeof window.Mozilla === 'undefined') {
}
};
StubAttribution.onRequestTimeout = function() {
StubAttribution.onRequestTimeout = function () {
if (!StubAttribution.requestComplete) {
StubAttribution.requestComplete = true;
@ -193,13 +242,23 @@ if (typeof window.Mozilla === 'undefined') {
* AJAX request to bedrock service to authenticate stub attribution request.
* @param {Object} data - utm params and referrer.
*/
StubAttribution.requestAuthentication = function(data) {
var SERVICE_URL = window.location.protocol + '//' + window.location.host + '/en-US/firefox/stub_attribution_code/';
StubAttribution.requestAuthentication = function (data) {
var SERVICE_URL =
window.location.protocol +
'//' +
window.location.host +
'/en-US/firefox/stub_attribution_code/';
var xhr = new window.XMLHttpRequest();
var timeoutValue = 10000;
var timeout = setTimeout(StubAttribution.onRequestTimeout, timeoutValue);
var timeout = setTimeout(
StubAttribution.onRequestTimeout,
timeoutValue
);
xhr.open('GET', SERVICE_URL + '?' + window._SearchParams.objectToQueryString(data));
xhr.open(
'GET',
SERVICE_URL + '?' + window._SearchParams.objectToQueryString(data)
);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
// use readystate change over onload for IE8 support.
@ -230,7 +289,7 @@ if (typeof window.Mozilla === 'undefined') {
* @param {String} ua - Optional user agent string to facilitate testing.
* @returns {String} - Browser name.
*/
StubAttribution.getUserAgent = function(ua) {
StubAttribution.getUserAgent = function (ua) {
ua = typeof ua !== 'undefined' ? ua : navigator.userAgent;
if (/MSIE|Trident/i.test(ua)) {
@ -256,7 +315,7 @@ if (typeof window.Mozilla === 'undefined') {
* Gets the client ID from the GA object.
* @returns {String} client ID.
*/
StubAttribution.getGAVisitID = function() {
StubAttribution.getGAVisitID = function () {
try {
return window.ga.getAll()[0].get('clientId');
} catch (e) {
@ -269,7 +328,7 @@ if (typeof window.Mozilla === 'undefined') {
* attempts to retrieve the client ID from the global `ga` object.
* @param {Function} callback
*/
StubAttribution.waitForGoogleAnalytics = function(callback) {
StubAttribution.waitForGoogleAnalytics = function (callback) {
var timeout;
var pollRetry = 0;
var interval = 100;
@ -299,11 +358,13 @@ if (typeof window.Mozilla === 'undefined') {
* @param {String} ref - Optional referrer to facilitate testing.
* @return {Object} - Stub attribution data object.
*/
StubAttribution.getAttributionData = function(ref) {
StubAttribution.getAttributionData = function (ref) {
var params = new window._SearchParams();
var utms = params.utmParams();
var experiment = params.get('experiment') || StubAttribution.experimentName;
var variation = params.get('variation') || StubAttribution.experimentVariation;
var experiment =
params.get('experiment') || StubAttribution.experimentName;
var variation =
params.get('variation') || StubAttribution.experimentVariation;
var referrer = typeof ref !== 'undefined' ? ref : document.referrer;
var ua = StubAttribution.getUserAgent();
var visitID = StubAttribution.getGAVisitID();
@ -315,7 +376,7 @@ if (typeof window.Mozilla === 'undefined') {
utm_campaign: utms.utm_campaign,
utm_content: utms.utm_content,
referrer: referrer,
ua : ua,
ua: ua,
experiment: experiment,
variation: variation,
visit_id: visitID
@ -334,8 +395,11 @@ if (typeof window.Mozilla === 'undefined') {
return data;
};
StubAttribution.hasValidData = function(data) {
if (typeof data.utm_content === 'string' && typeof data.referrer === 'string') {
StubAttribution.hasValidData = function (data) {
if (
typeof data.utm_content === 'string' &&
typeof data.referrer === 'string'
) {
var content = data.utm_content;
var charLimit = 150;
@ -358,7 +422,10 @@ if (typeof window.Mozilla === 'undefined') {
}
// If RTAMO data does not originate from AMO, drop attribution (Issues 10337, 10524).
if ((/^rta:/).test(content) && data.referrer.indexOf('https://addons.mozilla.org') === -1) {
if (
/^rta:/.test(content) &&
data.referrer.indexOf('https://addons.mozilla.org') === -1
) {
return false;
}
}
@ -372,8 +439,9 @@ if (typeof window.Mozilla === 'undefined') {
* want to make the request a dependency on the download starting.
* @return {Boolean}.
*/
StubAttribution.isFirefoxNewScene2 = function(location) {
location = typeof location !== 'undefined' ? location : window.location.href;
StubAttribution.isFirefoxNewScene2 = function (location) {
location =
typeof location !== 'undefined' ? location : window.location.href;
return location.indexOf('/firefox/download/thanks/') > -1;
};
@ -382,11 +450,12 @@ if (typeof window.Mozilla === 'undefined') {
* Stub attribution is only applicable to Windows users who get the stub installer.
* @return {Boolean}.
*/
StubAttribution.meetsRequirements = function() {
if (typeof window.site === 'undefined' ||
StubAttribution.meetsRequirements = function () {
if (
typeof window.site === 'undefined' ||
typeof Mozilla.Cookies === 'undefined' ||
typeof window._SearchParams === 'undefined') {
typeof window._SearchParams === 'undefined'
) {
return false;
}
@ -408,7 +477,7 @@ if (typeof window.Mozilla === 'undefined') {
/**
* Determines whether to make a request to the stub authentication service.
*/
StubAttribution.init = function(successCallback, timeoutCallback) {
StubAttribution.init = function (successCallback, timeoutCallback) {
var data = {};
if (!StubAttribution.meetsRequirements()) {
@ -429,19 +498,21 @@ if (typeof window.Mozilla === 'undefined') {
* else make a request to the service if within attribution rate.
*/
if (StubAttribution.hasCookie()) {
data = StubAttribution.getCookie();
StubAttribution.updateBouncerLinks(data);
// As long as the user is not already on scene2 of the main download page,
// make the XHR request to the stub authentication service.
// As long as the user is not already on scene2 of the main download page,
// make the XHR request to the stub authentication service.
} else if (!StubAttribution.isFirefoxNewScene2()) {
// Wait for GA to load so that we can pass along visit ID.
StubAttribution.waitForGoogleAnalytics(function() {
StubAttribution.waitForGoogleAnalytics(function () {
data = StubAttribution.getAttributionData();
if (data && StubAttribution.withinAttributionRate() && StubAttribution.hasValidData(data)) {
if (
data &&
StubAttribution.withinAttributionRate() &&
StubAttribution.hasValidData(data)
) {
StubAttribution.requestAuthentication(data);
}
});

Просмотреть файл

@ -7,7 +7,7 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function() {
(function () {
'use strict';
// create namespace
@ -36,7 +36,9 @@ if (typeof window.Mozilla === 'undefined') {
}
function _generateCallbackID() {
return Math.random().toString(36).replace(/[^a-z]+/g, '');
return Math.random()
.toString(36)
.replace(/[^a-z]+/g, '');
}
function _waitForCallback(callback) {
@ -60,24 +62,31 @@ if (typeof window.Mozilla === 'undefined') {
Mozilla.UITour.DEFAULT_THEME_CYCLE_DELAY = 10 * 1000;
Mozilla.UITour.registerPageID = function(pageID) {
Mozilla.UITour.registerPageID = function (pageID) {
_sendEvent('registerPageID', {
pageID: pageID
});
};
Mozilla.UITour.showHighlight = function(target, effect) {
Mozilla.UITour.showHighlight = function (target, effect) {
_sendEvent('showHighlight', {
target: target,
effect: effect
});
};
Mozilla.UITour.hideHighlight = function() {
Mozilla.UITour.hideHighlight = function () {
_sendEvent('hideHighlight');
};
Mozilla.UITour.showInfo = function(target, title, text, icon, buttons, options) {
Mozilla.UITour.showInfo = function (
target,
title,
text,
icon,
buttons,
options
) {
var buttonData = [];
if (Array.isArray(buttons)) {
for (var i = 0; i < buttons.length; i++) {
@ -93,7 +102,9 @@ if (typeof window.Mozilla === 'undefined') {
var closeButtonCallbackID;
var targetCallbackID;
if (options && options.closeButtonCallback) {
closeButtonCallbackID = _waitForCallback(options.closeButtonCallback);
closeButtonCallbackID = _waitForCallback(
options.closeButtonCallback
);
}
if (options && options.targetCallback) {
targetCallbackID = _waitForCallback(options.targetCallback);
@ -110,11 +121,11 @@ if (typeof window.Mozilla === 'undefined') {
});
};
Mozilla.UITour.hideInfo = function() {
Mozilla.UITour.hideInfo = function () {
_sendEvent('hideInfo');
};
Mozilla.UITour.previewTheme = function(theme) {
Mozilla.UITour.previewTheme = function (theme) {
_stopCyclingThemes();
_sendEvent('previewTheme', {
@ -122,13 +133,13 @@ if (typeof window.Mozilla === 'undefined') {
});
};
Mozilla.UITour.resetTheme = function() {
Mozilla.UITour.resetTheme = function () {
_stopCyclingThemes();
_sendEvent('resetTheme');
};
Mozilla.UITour.cycleThemes = function(themes, delay, callback) {
Mozilla.UITour.cycleThemes = function (themes, delay, callback) {
_stopCyclingThemes();
if (!delay) {
@ -151,7 +162,7 @@ if (typeof window.Mozilla === 'undefined') {
nextTheme();
};
Mozilla.UITour.showMenu = function(name, callback) {
Mozilla.UITour.showMenu = function (name, callback) {
var showCallbackID;
if (callback) {
showCallbackID = _waitForCallback(callback);
@ -162,32 +173,32 @@ if (typeof window.Mozilla === 'undefined') {
});
};
Mozilla.UITour.hideMenu = function(name) {
Mozilla.UITour.hideMenu = function (name) {
_sendEvent('hideMenu', {
name: name
});
};
Mozilla.UITour.showNewTab = function() {
Mozilla.UITour.showNewTab = function () {
_sendEvent('showNewTab');
};
/**
* Loads about:protections in the tour tab.
* @since 70
*/
Mozilla.UITour.showProtectionReport = function() {
* Loads about:protections in the tour tab.
* @since 70
*/
Mozilla.UITour.showProtectionReport = function () {
_sendEvent('showProtectionReport');
};
Mozilla.UITour.getConfiguration = function(configName, callback) {
Mozilla.UITour.getConfiguration = function (configName, callback) {
_sendEvent('getConfiguration', {
callbackID: _waitForCallback(callback),
configuration: configName
});
};
Mozilla.UITour.setConfiguration = function(configName, configValue) {
Mozilla.UITour.setConfiguration = function (configName, configValue) {
_sendEvent('setConfiguration', {
configuration: configName,
value: configValue
@ -195,21 +206,25 @@ if (typeof window.Mozilla === 'undefined') {
};
/**
* Request the browser open the Firefox Accounts page.
*
* @param {Object} [extraURLParams] - An optional object containing additional
* parameters for the URL opened by the browser for reasons of promotional
* campaign tracking. Each attribute of the object must have a name that
* is a string, is "flow_id", "flow_begin_time", "device_id", "entrypoint_experiment",
* "entrypoint_variation" or begins with `utm_` and contains only only alphanumeric
* characters, dashes or underscores. The values may be any string and will automatically be encoded.
* For Flow metrics, see details at https://mozilla.github.io/ecosystem-platform/docs/fxa-engineering/fxa-metrics#content-server
* @since 79 renamed from `extraURLCampaignParams` to `extraURLParams`
* @param {String} [email] - the optional FxA email value.
* @param {String} [entrypoint] - the optional FxA entrypoint value. If not set, the browser will report `uitour`.
* @since 80 added the "entrypoint" option.
*/
Mozilla.UITour.showFirefoxAccounts = function(extraURLParams, entrypoint, email) {
* Request the browser open the Firefox Accounts page.
*
* @param {Object} [extraURLParams] - An optional object containing additional
* parameters for the URL opened by the browser for reasons of promotional
* campaign tracking. Each attribute of the object must have a name that
* is a string, is "flow_id", "flow_begin_time", "device_id", "entrypoint_experiment",
* "entrypoint_variation" or begins with `utm_` and contains only only alphanumeric
* characters, dashes or underscores. The values may be any string and will automatically be encoded.
* For Flow metrics, see details at https://mozilla.github.io/ecosystem-platform/docs/fxa-engineering/fxa-metrics#content-server
* @since 79 renamed from `extraURLCampaignParams` to `extraURLParams`
* @param {String} [email] - the optional FxA email value.
* @param {String} [entrypoint] - the optional FxA entrypoint value. If not set, the browser will report `uitour`.
* @since 80 added the "entrypoint" option.
*/
Mozilla.UITour.showFirefoxAccounts = function (
extraURLParams,
entrypoint,
email
) {
_sendEvent('showFirefoxAccounts', {
email: email,
entrypoint: entrypoint,
@ -217,50 +232,50 @@ if (typeof window.Mozilla === 'undefined') {
});
};
Mozilla.UITour.resetFirefox = function() {
Mozilla.UITour.resetFirefox = function () {
_sendEvent('resetFirefox');
};
Mozilla.UITour.addNavBarWidget = function(name, callback) {
Mozilla.UITour.addNavBarWidget = function (name, callback) {
_sendEvent('addNavBarWidget', {
name: name,
callbackID: _waitForCallback(callback)
});
};
Mozilla.UITour.setDefaultSearchEngine = function(identifier) {
Mozilla.UITour.setDefaultSearchEngine = function (identifier) {
_sendEvent('setDefaultSearchEngine', {
identifier: identifier
});
};
Mozilla.UITour.setTreatmentTag = function(name, value) {
Mozilla.UITour.setTreatmentTag = function (name, value) {
_sendEvent('setTreatmentTag', {
name: name,
value: value
});
};
Mozilla.UITour.getTreatmentTag = function(name, callback) {
Mozilla.UITour.getTreatmentTag = function (name, callback) {
_sendEvent('getTreatmentTag', {
name: name,
callbackID: _waitForCallback(callback)
});
};
Mozilla.UITour.setSearchTerm = function(term) {
Mozilla.UITour.setSearchTerm = function (term) {
_sendEvent('setSearchTerm', {
term: term
});
};
Mozilla.UITour.openSearchPanel = function(callback) {
Mozilla.UITour.openSearchPanel = function (callback) {
_sendEvent('openSearchPanel', {
callbackID: _waitForCallback(callback)
});
};
Mozilla.UITour.ping = function(callback) {
Mozilla.UITour.ping = function (callback) {
var data = {};
if (callback) {
data.callbackID = _waitForCallback(callback);
@ -279,25 +294,30 @@ if (typeof window.Mozilla === 'undefined') {
notificationListener(event.detail.event, event.detail.params);
}
Mozilla.UITour.observe = function(listener, callback) {
Mozilla.UITour.observe = function (listener, callback) {
notificationListener = listener;
if (listener) {
document.addEventListener('mozUITourNotification', _notificationListener);
document.addEventListener(
'mozUITourNotification',
_notificationListener
);
Mozilla.UITour.ping(callback);
} else {
document.removeEventListener('mozUITourNotification', _notificationListener);
document.removeEventListener(
'mozUITourNotification',
_notificationListener
);
}
};
Mozilla.UITour.openPreferences = function(pane) {
Mozilla.UITour.openPreferences = function (pane) {
_sendEvent('openPreferences', {
pane: pane
});
};
Mozilla.UITour.closeTab = function() {
Mozilla.UITour.closeTab = function () {
_sendEvent('closeTab');
};
})();

Просмотреть файл

@ -1,11 +1,10 @@
/* 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/. */
* 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/. */
(function () {
'use strict';
// Lazyload images
Mozilla.LazyLoad.init();
})();

Просмотреть файл

@ -2,16 +2,25 @@
* 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/. */
(function() {
(function () {
'use strict';
var CONVERT_PROJECT_ID = document.getElementsByTagName('html')[0].getAttribute('data-convert-project-id');
var CONVERT_PROJECT_ID = document
.getElementsByTagName('html')[0]
.getAttribute('data-convert-project-id');
// Load third-party JS async and respect DNT.
if (CONVERT_PROJECT_ID && typeof Mozilla.dntEnabled === 'function' && !Mozilla.dntEnabled()) {
if (
CONVERT_PROJECT_ID &&
typeof Mozilla.dntEnabled === 'function' &&
!Mozilla.dntEnabled()
) {
var newScriptTag = document.createElement('script');
var target = document.getElementsByTagName('script')[0];
newScriptTag.src = 'https://cdn-3.convertexperiments.com/js/' + CONVERT_PROJECT_ID + '.js';
newScriptTag.src =
'https://cdn-3.convertexperiments.com/js/' +
CONVERT_PROJECT_ID +
'.js';
target.parentNode.insertBefore(newScriptTag, target);
}
})();

Просмотреть файл

@ -2,12 +2,12 @@
* 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/. */
(function() {
(function () {
'use strict';
// Prevent double-requesting Flow IDs, inits FxaForm even on non-firefox browsers.
if (Mozilla.Client.isFirefoxDesktop) {
Mozilla.Client.getFxaDetails(function(details) {
Mozilla.Client.getFxaDetails(function (details) {
if (details.setup) {
Mozilla.FxaProductButton.init();
} else {
@ -17,5 +17,4 @@
} else {
Mozilla.FxaForm.init();
}
})(window.Mozilla);

Просмотреть файл

@ -2,14 +2,16 @@
* 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/. */
(function(Mozilla){
(function (Mozilla) {
'use strict';
function onLoad() {
var browserHelpContent = document.getElementById('browser-help');
var browserHelpIcon = document.getElementById('icon-browser-help');
var installerHelpContent = document.getElementById('installer-help');
var installerHelpIcon = document.querySelectorAll('.icon-installer-help');
var installerHelpIcon = document.querySelectorAll(
'.icon-installer-help'
);
function showHelpModal(modalContent, modalTitle, eventLabel) {
Mzp.Modal.createModal(this, modalContent, {
@ -18,29 +20,46 @@
});
window.dataLayer.push({
'event': 'in-page-interaction',
'eAction': 'link click',
'eLabel': eventLabel
event: 'in-page-interaction',
eAction: 'link click',
eLabel: eventLabel
});
}
Mozilla.FirefoxDownloader.init();
// Browser help modal.
browserHelpIcon.addEventListener('click', function(e) {
e.preventDefault();
showHelpModal.call(this, browserHelpContent, browserHelpIcon.textContent, 'Get Browser Help');
}, false);
browserHelpIcon.addEventListener(
'click',
function (e) {
e.preventDefault();
showHelpModal.call(
this,
browserHelpContent,
browserHelpIcon.textContent,
'Get Browser Help'
);
},
false
);
// Installer help modal.
for (var i = 0; i < installerHelpIcon.length; i++) {
installerHelpIcon[i].addEventListener('click', function(e) {
e.preventDefault();
showHelpModal.call(this, installerHelpContent, e.target.textContent, 'Get Installer Help');
}, false);
installerHelpIcon[i].addEventListener(
'click',
function (e) {
e.preventDefault();
showHelpModal.call(
this,
installerHelpContent,
e.target.textContent,
'Get Installer Help'
);
},
false
);
}
}
Mozilla.run(onLoad);
})(window.Mozilla);

Просмотреть файл

@ -2,18 +2,28 @@
* 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/. */
(function(){
(function () {
'use strict';
var form = document.getElementById('product-select-form');
var productSelect = document.getElementById('select-product');
var versionSelect = document.querySelectorAll('.c-selection-version select');
var languageSelect = document.querySelectorAll('.c-selection-language select');
var platformSelect = document.querySelectorAll('.c-selection-platform select');
var versionSelect = document.querySelectorAll(
'.c-selection-version select'
);
var languageSelect = document.querySelectorAll(
'.c-selection-language select'
);
var platformSelect = document.querySelectorAll(
'.c-selection-platform select'
);
var downloadInfo = document.querySelector('.c-download');
var downloadInfoProduct = document.getElementById('download-info-product');
var downloadInfoPlatform = document.getElementById('download-info-platform');
var downloadInfoLanguage = document.getElementById('download-info-language');
var downloadInfoPlatform = document.getElementById(
'download-info-platform'
);
var downloadInfoLanguage = document.getElementById(
'download-info-language'
);
var downloadInfoButton = document.getElementById('download-button-primary');
var FirefoxDownloader = {};
@ -23,10 +33,10 @@
* @param {Object} el dom element.
* @returns {Object} product `id` and `label`.
*/
FirefoxDownloader.getSelectOption = function(el) {
FirefoxDownloader.getSelectOption = function (el) {
return {
'id': el.options[el.selectedIndex].value,
'label': el.options[el.selectedIndex].textContent
id: el.options[el.selectedIndex].value,
label: el.options[el.selectedIndex].textContent
};
};
@ -35,7 +45,7 @@
* @param {String} platform `id`.
* @param {Object} NodeList of <option>'s.
*/
FirefoxDownloader.setSelectOption = function(id, options) {
FirefoxDownloader.setSelectOption = function (id, options) {
for (var i = 0; i < options.length; i++) {
if (options[i].value === id) {
options[i].selected = 'selected';
@ -49,7 +59,7 @@
* @param {String} platform `id`.
* @param {Object} el dom element(s).
*/
FirefoxDownloader.setAllSelectOptions = function(id, el) {
FirefoxDownloader.setAllSelectOptions = function (id, el) {
for (var i = 0; i < el.length; i++) {
FirefoxDownloader.setSelectOption(id, el[i].options);
}
@ -60,7 +70,7 @@
* used to display the appropriate options for each individual product item.
* @param {String} product `id`.
*/
FirefoxDownloader.setFormSelection = function(id) {
FirefoxDownloader.setFormSelection = function (id) {
form.setAttribute('data-current', id);
};
@ -68,7 +78,7 @@
* Get the currently displayed product form.
* @returns {String} product `id`.
*/
FirefoxDownloader.getFormSelection = function() {
FirefoxDownloader.getFormSelection = function () {
return form.getAttribute('data-current');
};
@ -76,7 +86,7 @@
* Get the currently selected product.
* @returns {Object} product `id` and `label`.
*/
FirefoxDownloader.getProductSelection = function() {
FirefoxDownloader.getProductSelection = function () {
var product = FirefoxDownloader.getSelectOption(productSelect);
// ESR can have two versions available but it's listed as a single product in the dropdown.
@ -94,7 +104,7 @@
* Set the product dropdown to a specific value.
* @param {String} product `id`.
*/
FirefoxDownloader.setProductSelection = function(id) {
FirefoxDownloader.setProductSelection = function (id) {
FirefoxDownloader.setSelectOption(id, productSelect.options);
FirefoxDownloader.setFormSelection(id);
};
@ -104,9 +114,13 @@
* @param {String} `product`.
* @returns {Object} product `id` and `label`.
*/
FirefoxDownloader.getVersionSelection = function(product) {
var currentOptions = document.querySelector('.c-selection-options[data-product="' + product.id + '"]');
var currentVersion = currentOptions.querySelector('.c-selection-version select');
FirefoxDownloader.getVersionSelection = function (product) {
var currentOptions = document.querySelector(
'.c-selection-options[data-product="' + product.id + '"]'
);
var currentVersion = currentOptions.querySelector(
'.c-selection-version select'
);
return FirefoxDownloader.getSelectOption(currentVersion);
};
@ -115,30 +129,30 @@
* @param {String} platform.
* @returns {String} OS.
*/
FirefoxDownloader.getPlatform = function(platform) {
FirefoxDownloader.getPlatform = function (platform) {
var system;
/**
* Note: we can't accurately detect 64bit arch via user agent
* alone, so we assume most people want the fastest version.
*/
switch(platform) {
case 'windows':
system = 'win64';
break;
case 'linux':
system = 'linux64';
break;
case 'osx':
system = 'osx';
break;
case 'ios':
system = 'ios';
break;
case 'android':
system = 'android';
break;
default:
system = false;
switch (platform) {
case 'windows':
system = 'win64';
break;
case 'linux':
system = 'linux64';
break;
case 'osx':
system = 'osx';
break;
case 'ios':
system = 'ios';
break;
case 'android':
system = 'android';
break;
default:
system = false;
}
return system;
@ -149,9 +163,13 @@
* @param {String} `product`.
* @returns {Object} platform `id` and platform `label`.
*/
FirefoxDownloader.getPlatformSelection = function(product) {
var currentOptions = document.querySelector('.c-selection-options[data-product="' + product.id + '"]');
var currentPlatform = currentOptions.querySelector('.c-selection-platform select');
FirefoxDownloader.getPlatformSelection = function (product) {
var currentOptions = document.querySelector(
'.c-selection-options[data-product="' + product.id + '"]'
);
var currentPlatform = currentOptions.querySelector(
'.c-selection-platform select'
);
return FirefoxDownloader.getSelectOption(currentPlatform);
};
@ -160,9 +178,13 @@
* @param {String} `product`.
* @returns {Object} language `id` and language `label`.
*/
FirefoxDownloader.getLanguageSelection = function(product) {
var currentOptions = document.querySelector('.c-selection-options[data-product="' + product.id + '"]');
var currentLanguage = currentOptions.querySelector('.c-selection-language select');
FirefoxDownloader.getLanguageSelection = function (product) {
var currentOptions = document.querySelector(
'.c-selection-options[data-product="' + product.id + '"]'
);
var currentLanguage = currentOptions.querySelector(
'.c-selection-language select'
);
return FirefoxDownloader.getSelectOption(currentLanguage);
};
@ -171,8 +193,10 @@
* @param {String} `localeCode` (optional).
* @returns {String} page language.
*/
FirefoxDownloader.getPageLanguage = function(localeCode) {
var lang = localeCode || document.getElementsByTagName('html')[0].getAttribute('lang');
FirefoxDownloader.getPageLanguage = function (localeCode) {
var lang =
localeCode ||
document.getElementsByTagName('html')[0].getAttribute('lang');
if (lang) {
// bedrock uses `en` for `en-US` pages to mark content as region neutral.
@ -189,15 +213,30 @@
* @param {String} language id.
* @returns {String} download URL.
*/
FirefoxDownloader.getDownloadLink = function(product, platform, language) {
FirefoxDownloader.getDownloadLink = function (product, platform, language) {
try {
var productList = document.querySelector('.c-locale-list[data-product="' + product + '"]');
var languageBuild = productList.querySelector('.c-locale-list-item[data-language="' + language + '"]');
var platformLink = languageBuild.querySelector('.c-download-list > li > a[data-download-version="' + platform + '"]');
var productList = document.querySelector(
'.c-locale-list[data-product="' + product + '"]'
);
var languageBuild = productList.querySelector(
'.c-locale-list-item[data-language="' + language + '"]'
);
var platformLink = languageBuild.querySelector(
'.c-download-list > li > a[data-download-version="' +
platform +
'"]'
);
return platformLink.href;
} catch(e) {
var error = new Error('A download link was not found for: ' + product + ', platform: ' + platform + ', language: ' + language);
} catch (e) {
var error = new Error(
'A download link was not found for: ' +
product +
', platform: ' +
platform +
', language: ' +
language
);
FirefoxDownloader.onError(error);
}
};
@ -210,14 +249,20 @@
* @param {Object} language.
* @param {Object} element (optional)
*/
FirefoxDownloader.setDownloadLink = function(url, product, platform, language, element) {
FirefoxDownloader.setDownloadLink = function (
url,
product,
platform,
language,
element
) {
var el = element || downloadInfoButton;
el.href = url;
el.setAttribute('data-display-name', product.label);
el.setAttribute('data-download-version', platform.id);
el.setAttribute('data-download-language', language.id);
if ((/^android/).test(platform.id)) {
if (/^android/.test(platform.id)) {
el.setAttribute('data-download-os', 'Android');
} else {
el.setAttribute('data-download-os', 'Desktop');
@ -227,7 +272,7 @@
/**
* Append Firefox attribution params for windows downloads.
*/
FirefoxDownloader.onDownloadButtonClick = function(e) {
FirefoxDownloader.onDownloadButtonClick = function (e) {
e.preventDefault();
var el = e.target;
var url = e.target.href;
@ -243,11 +288,20 @@
/**
* Format download URL with attribution parameters,
*/
FirefoxDownloader.setAttributionURL = function(url) {
FirefoxDownloader.setAttributionURL = function (url) {
// Get Firefox attribution data from cookie if it exists.
if (typeof Mozilla.StubAttribution !== 'undefined' && typeof Mozilla.Cookies !== 'undefined' && Mozilla.StubAttribution.hasCookie()) {
if (
typeof Mozilla.StubAttribution !== 'undefined' &&
typeof Mozilla.Cookies !== 'undefined' &&
Mozilla.StubAttribution.hasCookie()
) {
var data = Mozilla.StubAttribution.getCookie();
return url += (url.indexOf('?') > -1 ? '&' : '?') + 'attribution_code=' + data.attribution_code + '&attribution_sig=' + data.attribution_sig;
return (url +=
(url.indexOf('?') > -1 ? '&' : '?') +
'attribution_code=' +
data.attribution_code +
'&attribution_sig=' +
data.attribution_sig);
}
return url;
@ -257,7 +311,7 @@
* Display form error message and show fallback locale list.
* @param {Object} instance of `Error`.
*/
FirefoxDownloader.onError = function(e) {
FirefoxDownloader.onError = function (e) {
// show form error and hide download button.
downloadInfo.classList.add('has-error');
downloadInfo.classList.remove('hidden');
@ -273,7 +327,7 @@
/**
* Removes error form state.
*/
FirefoxDownloader.offError = function() {
FirefoxDownloader.offError = function () {
// Remove error message is previously shown.
if (downloadInfo.classList.contains('has-error')) {
downloadInfo.classList.remove('has-error');
@ -285,21 +339,27 @@
* @param {String} url.
* @returns {Boolean}.
*/
FirefoxDownloader.isValidURL = function(url) {
FirefoxDownloader.isValidURL = function (url) {
var bouncerURL = /^https:\/\/download.mozilla.org/;
var stagingURL = /^https:\/\/bouncer-bouncer.stage.mozaws.net/;
return typeof url === 'string' && ((bouncerURL).test(url) || (stagingURL).test(url));
return (
typeof url === 'string' &&
(bouncerURL.test(url) || stagingURL.test(url))
);
};
/**
* Show appropriate download button & Uppdate download URL for the desktop button, based on the current form selection.
*/
FirefoxDownloader.setDownloadButton = function() {
FirefoxDownloader.setDownloadButton = function () {
var product = FirefoxDownloader.getProductSelection();
var platform = FirefoxDownloader.getPlatformSelection(product);
var language = FirefoxDownloader.getLanguageSelection(product);
FirefoxDownloader.setDownloadInfo(product.label, platform.label, language.label);
FirefoxDownloader.setDownloadInfo(
product.label,
platform.label,
language.label
);
if (product.id.indexOf('android') === 0) {
FirefoxDownloader.offError();
@ -308,12 +368,23 @@
} else {
// Use `version.id` as ESR can sometimes offer 2 builds simultaneously.
var version = FirefoxDownloader.getVersionSelection(product);
var downloadURL = FirefoxDownloader.getDownloadLink(version.id, platform.id, language.id);
var downloadURL = FirefoxDownloader.getDownloadLink(
version.id,
platform.id,
language.id
);
if (FirefoxDownloader.isValidURL(downloadURL)) {
FirefoxDownloader.setDownloadLink(downloadURL, product, platform, language);
FirefoxDownloader.setDownloadLink(
downloadURL,
product,
platform,
language
);
FirefoxDownloader.offError();
} else {
var error = new Error('An unrecognised download link was found: ' + downloadURL);
var error = new Error(
'An unrecognised download link was found: ' + downloadURL
);
FirefoxDownloader.onError(error);
}
}
@ -322,7 +393,7 @@
/**
* Set the form info for what the current selection will download.
*/
FirefoxDownloader.setDownloadInfo = function(product, platform, language) {
FirefoxDownloader.setDownloadInfo = function (product, platform, language) {
downloadInfoProduct.textContent = product;
downloadInfoPlatform.textContent = platform;
downloadInfoLanguage.textContent = language;
@ -332,7 +403,7 @@
* Product input <select> handler.
* @param {Object} event object.
*/
FirefoxDownloader.onProductChange = function(e) {
FirefoxDownloader.onProductChange = function (e) {
FirefoxDownloader.setFormSelection(e.target.value);
FirefoxDownloader.setDownloadButton();
FirefoxDownloader.setHash(e.target.value);
@ -342,9 +413,12 @@
* Product ESR input <select> handler.
* @param {Object} event object.
*/
FirefoxDownloader.onVersionChange = function(e) {
FirefoxDownloader.onVersionChange = function (e) {
// ESR can have two versions available in product details.
if (e.target.value === 'desktop_esr' || e.target.value === 'desktop_esr_next') {
if (
e.target.value === 'desktop_esr' ||
e.target.value === 'desktop_esr_next'
) {
FirefoxDownloader.setFormSelection(e.target.value);
}
FirefoxDownloader.setAllSelectOptions(e.target.value, versionSelect);
@ -355,7 +429,7 @@
* Platform input <select> handler.
* @param {Object} event object.
*/
FirefoxDownloader.onPlatformChange = function(e) {
FirefoxDownloader.onPlatformChange = function (e) {
FirefoxDownloader.setAllSelectOptions(e.target.value, platformSelect);
FirefoxDownloader.setDownloadButton();
};
@ -364,7 +438,7 @@
* Language input <select> handler.
* @param {Object} event object.
*/
FirefoxDownloader.onLanguageChange = function(e) {
FirefoxDownloader.onLanguageChange = function (e) {
FirefoxDownloader.setAllSelectOptions(e.target.value, languageSelect);
FirefoxDownloader.setDownloadButton();
};
@ -374,7 +448,7 @@
* @param {Object} el.
* @param {Function} callback.
*/
FirefoxDownloader.initInput = function(el, callback) {
FirefoxDownloader.initInput = function (el, callback) {
if (typeof callback === 'function') {
el.addEventListener('change', callback, false);
}
@ -386,7 +460,7 @@
* @param {Object} el NodeList.
* @param {Function} callback.
*/
FirefoxDownloader.initAllInputs = function(el, callback) {
FirefoxDownloader.initAllInputs = function (el, callback) {
for (var i = 0; i < el.length; i++) {
FirefoxDownloader.initInput(el[i], callback);
}
@ -395,20 +469,40 @@
/**
* Enable form inputs, bind event handlers, and show the product options.
*/
FirefoxDownloader.enableForm = function() {
FirefoxDownloader.initInput(productSelect, FirefoxDownloader.onProductChange);
FirefoxDownloader.initAllInputs(platformSelect, FirefoxDownloader.onPlatformChange);
FirefoxDownloader.initAllInputs(languageSelect, FirefoxDownloader.onLanguageChange);
FirefoxDownloader.initAllInputs(versionSelect, FirefoxDownloader.onVersionChange);
FirefoxDownloader.enableForm = function () {
FirefoxDownloader.initInput(
productSelect,
FirefoxDownloader.onProductChange
);
FirefoxDownloader.initAllInputs(
platformSelect,
FirefoxDownloader.onPlatformChange
);
FirefoxDownloader.initAllInputs(
languageSelect,
FirefoxDownloader.onLanguageChange
);
FirefoxDownloader.initAllInputs(
versionSelect,
FirefoxDownloader.onVersionChange
);
// show product options.
downloadInfo.classList.remove('hidden');
// listen for hash changes to update the product dropdown.
window.addEventListener('hashchange', FirefoxDownloader.onHashChange, false);
window.addEventListener(
'hashchange',
FirefoxDownloader.onHashChange,
false
);
// capture click events on download button for attribution referrals
downloadInfoButton.addEventListener('click', FirefoxDownloader.onDownloadButtonClick, false);
downloadInfoButton.addEventListener(
'click',
FirefoxDownloader.onDownloadButtonClick,
false
);
};
/**
@ -416,7 +510,7 @@
* @param {String} url (optional).
* @returns {String} product `id` if valid.
*/
FirefoxDownloader.getHash = function(url) {
FirefoxDownloader.getHash = function (url) {
var urlString = typeof url === 'string' ? url : window.location.href;
var hash;
@ -425,37 +519,37 @@
hash = urlParts[1];
}
switch(hash) {
case 'product-desktop-release':
hash = 'desktop_release';
break;
case 'product-desktop-beta':
hash = 'desktop_beta';
break;
case 'product-desktop-developer':
hash = 'desktop_developer';
break;
case 'product-desktop-nightly':
hash = 'desktop_nightly';
break;
case 'product-desktop-esr':
hash = 'desktop_esr';
break;
case 'product-android-release':
hash = 'android_release';
break;
case 'product-android-beta':
hash = 'android_beta';
break;
case 'product-android-nightly':
hash = 'android_nightly';
break;
case 'product-ios-release':
hash = 'ios_release';
break;
default:
hash = null;
break;
switch (hash) {
case 'product-desktop-release':
hash = 'desktop_release';
break;
case 'product-desktop-beta':
hash = 'desktop_beta';
break;
case 'product-desktop-developer':
hash = 'desktop_developer';
break;
case 'product-desktop-nightly':
hash = 'desktop_nightly';
break;
case 'product-desktop-esr':
hash = 'desktop_esr';
break;
case 'product-android-release':
hash = 'android_release';
break;
case 'product-android-beta':
hash = 'android_beta';
break;
case 'product-android-nightly':
hash = 'android_nightly';
break;
case 'product-ios-release':
hash = 'ios_release';
break;
default:
hash = null;
break;
}
return hash;
@ -467,7 +561,7 @@
* @param {String} hash (optional).
* @returns {String} id.
*/
FirefoxDownloader.setHash = function(productId, hash) {
FirefoxDownloader.setHash = function (productId, hash) {
var id = typeof hash === 'string' ? hash : window.location.hash;
id = '#product-' + productId.replace(/_/g, '-');
@ -480,7 +574,7 @@
/**
* Updates currently selected product based on window.location.hash
*/
FirefoxDownloader.onHashChange = function() {
FirefoxDownloader.onHashChange = function () {
var id = FirefoxDownloader.getHash();
// Only update the product if the hash is valid.
@ -493,7 +587,7 @@
/**
* Initialize the form and show the default selection.
*/
FirefoxDownloader.init = function() {
FirefoxDownloader.init = function () {
// Set the product if there's a valid hash identifier in the URL.
var hash = FirefoxDownloader.getHash();
@ -505,7 +599,7 @@
var product = FirefoxDownloader.getProductSelection();
var platform = FirefoxDownloader.getPlatform(window.site.platform);
if (platform === 'ios' || platform ==='android' ) {
if (platform === 'ios' || platform === 'android') {
FirefoxDownloader.setProductSelection(platform + '_release');
product = FirefoxDownloader.getProductSelection();
} else if (platform) {
@ -527,5 +621,4 @@
};
window.Mozilla.FirefoxDownloader = FirefoxDownloader;
})();

Просмотреть файл

@ -10,14 +10,13 @@
var version = client._getFirefoxMajorVersion();
if (client.isFirefox && version >= '70') {
var menuItem = document.getElementById('js-lockwise-desktop');
if(menuItem !== null) {
if (menuItem !== null) {
menuItem.classList.remove('hidden');
var lockwiseButton = document.getElementById('lockwise-button');
if(lockwiseButton !== null) {
lockwiseButton.addEventListener('click', function() {
if (lockwiseButton !== null) {
lockwiseButton.addEventListener('click', function () {
Mozilla.UITour.showHighlight('logins');
});
}
@ -26,5 +25,4 @@
// init menus on page
window.Mzp.Details.init('.mzp-c-menu-list-title');
})();

Просмотреть файл

@ -2,9 +2,8 @@
* 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/. */
(function() {
(function () {
'use strict';
window.Mzp.Details.init('.mzp-c-menu-list-title');
})();

Просмотреть файл

@ -7,7 +7,7 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function(Mozilla) {
(function (Mozilla) {
'use strict';
var sendToDevice = document.getElementById('s2d-footer');
@ -16,5 +16,4 @@ if (typeof window.Mozilla === 'undefined') {
var form = new Mozilla.SendToDevice('s2d-footer');
form.init();
}
})(window.Mozilla);

Просмотреть файл

@ -7,5 +7,4 @@
// init menus on page
window.Mzp.Details.init('.mzp-c-menu-list-title');
})();

Просмотреть файл

@ -7,7 +7,7 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function(Mozilla) {
(function (Mozilla) {
'use strict';
var sendToDevice = document.getElementById('s2d-hero');
@ -16,5 +16,4 @@ if (typeof window.Mozilla === 'undefined') {
var form = new Mozilla.SendToDevice('s2d-hero');
form.init();
}
})(window.Mozilla);

Просмотреть файл

@ -1,25 +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/. */
* 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/. */
/*
Image lazy loading
*/
(function() {
(function () {
'use strict';
/**
* Safari on iOS and macOS does not yet support loading="lazy", so make sure that images
* with display: none; in CSS are not loaded wastefully.
*/
var isFirefox = document.getElementsByTagName('html')[0].classList.contains('is-firefox');
var isFirefox = document
.getElementsByTagName('html')[0]
.classList.contains('is-firefox');
var lazyImages = document.querySelectorAll('.c-item-gif');
if (isFirefox) {
lazyImages = document.querySelectorAll('.c-section-unfck-list.cc-firefox .c-item-gif');
lazyImages = document.querySelectorAll(
'.c-section-unfck-list.cc-firefox .c-item-gif'
);
} else {
lazyImages = document.querySelectorAll('.c-section-unfck-list.cc-default .c-item-gif');
lazyImages = document.querySelectorAll(
'.c-section-unfck-list.cc-default .c-item-gif'
);
}
for (var i = 0; i < lazyImages.length; i++) {
@ -37,13 +42,12 @@
}
}
}
})();
/*
Twitter sharing
*/
(function() {
(function () {
'use strict';
// Twitter share
@ -51,33 +55,48 @@
var width = 550;
var height = 420;
var options = {
'scrollbars': 'yes',
'resizable': 'yes',
'toolbar': 'no',
'location': 'yes',
'width': width,
'height': height,
'top': screen.height > height ? Math.round((screen.height / 2) - (height / 2)) : 0,
'left': Math.round((screen.width / 2) - (width / 2))
scrollbars: 'yes',
resizable: 'yes',
toolbar: 'no',
location: 'yes',
width: width,
height: height,
top:
screen.height > height
? Math.round(screen.height / 2 - height / 2)
: 0,
left: Math.round(screen.width / 2 - width / 2)
};
window.open(url, 'twitter_share', window._SearchParams.objectToQueryString(options).replace(/&/g, ',')).focus();
window
.open(
url,
'twitter_share',
window._SearchParams
.objectToQueryString(options)
.replace(/&/g, ',')
)
.focus();
}
// FB Share
function openFacebookSubwin(url) {
open(url, 'fb_share', 'height=380,width=660,resizable=0,toolbar=0,menubar=0,status=0,location=0,scrollbars=0').focus();
open(
url,
'fb_share',
'height=380,width=660,resizable=0,toolbar=0,menubar=0,status=0,location=0,scrollbars=0'
).focus();
}
function handleShareLinkClick(e) {
var linkHref = e.target.href;
var service = '';
if(linkHref.indexOf('twitter') > -1) {
if (linkHref.indexOf('twitter') > -1) {
openTwitterSubwin(linkHref);
service = 'twitter';
e.preventDefault();
} else if(linkHref.indexOf('facebook') > -1) {
} else if (linkHref.indexOf('facebook') > -1) {
openFacebookSubwin(linkHref);
service = 'facebook';
e.preventDefault();
@ -85,9 +104,9 @@
// Track the event in GA
window.dataLayer.push({
'event': 'in-page-interaction',
'eAction': 'share',
'eLabel': 'share to ' + service,
event: 'in-page-interaction',
eAction: 'share',
eLabel: 'share to ' + service
});
}

Просмотреть файл

@ -6,5 +6,4 @@
'use strict';
window.Mzp.Details.init('.mzp-c-menu-list-title');
})();

Просмотреть файл

@ -2,9 +2,8 @@
* 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/. */
(function() {
(function () {
'use strict';
window.Mzp.Details.init('.mzp-c-menu-list-title');
})();

Просмотреть файл

@ -2,14 +2,14 @@
* 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/. */
(function() {
(function () {
'use strict';
function trackVideoInteraction(title, state) {
window.dataLayer.push({
'event': 'video-interaction',
'videoTitle': title,
'interaction': state
event: 'video-interaction',
videoTitle: title,
interaction: state
});
}
@ -20,14 +20,29 @@
return;
}
video.addEventListener('play', function() {
trackVideoInteraction(this.getAttribute('data-ga-label'), 'play');
}, false);
video.addEventListener(
'play',
function () {
trackVideoInteraction(
this.getAttribute('data-ga-label'),
'play'
);
},
false
);
video.addEventListener('pause', function() {
var action = this.currentTime === this.duration ? 'complete' : 'pause';
trackVideoInteraction(this.getAttribute('data-ga-label'), action);
}, false);
video.addEventListener(
'pause',
function () {
var action =
this.currentTime === this.duration ? 'complete' : 'pause';
trackVideoInteraction(
this.getAttribute('data-ga-label'),
action
);
},
false
);
}
function onLoad() {
@ -35,6 +50,4 @@
}
window.Mozilla.run(onLoad);
})();

Просмотреть файл

@ -6,14 +6,14 @@
/* eslint no-unused-vars: [2, { "varsIgnorePattern": "onYouTubeIframeAPIReady" }] */
// YouTube API hook has to be in global scope
window.onYouTubeIframeAPIReady = function() {
window.onYouTubeIframeAPIReady = function () {
'use strict';
// Play the video only once the API is ready.
Mozilla.pipVideoPlay();
};
(function() {
(function () {
'use strict';
var videoLink = document.querySelector('.js-video-play');
@ -27,7 +27,9 @@ window.onYouTubeIframeAPIReady = function() {
}
function isScriptLoaded() {
return document.querySelector('script[src="' + src + '"]') ? true : false;
return document.querySelector('script[src="' + src + '"]')
? true
: false;
}
function playVideo() {
@ -40,11 +42,11 @@ window.onYouTubeIframeAPIReady = function() {
videoId: videoId,
playerVars: {
modestbranding: 1, // hide YouTube logo.
rel: 0, // do not show related videos on end.
rel: 0 // do not show related videos on end.
},
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
onReady: onPlayerReady,
onStateChange: onPlayerStateChange
}
});
@ -55,23 +57,23 @@ window.onYouTubeIframeAPIReady = function() {
function onPlayerStateChange(event) {
var state;
switch(event.data) {
case YT.PlayerState.PLAYING:
state = 'video play';
break;
case YT.PlayerState.PAUSED:
state = 'video paused';
break;
case YT.PlayerState.ENDED:
state = 'video complete';
break;
switch (event.data) {
case YT.PlayerState.PLAYING:
state = 'video play';
break;
case YT.PlayerState.PAUSED:
state = 'video paused';
break;
case YT.PlayerState.ENDED:
state = 'video complete';
break;
}
if (state) {
window.dataLayer.push({
'event': 'video-interaction',
'videoTitle': title,
'interaction': state
event: 'video-interaction',
videoTitle: title,
interaction: state
});
}
}
@ -89,7 +91,7 @@ window.onYouTubeIframeAPIReady = function() {
function init() {
videoLink.setAttribute('role', 'button');
videoLink.addEventListener('click', function(e) {
videoLink.addEventListener('click', function (e) {
e.preventDefault();
initVideoPlayer();
});

Просмотреть файл

@ -6,14 +6,14 @@
/* eslint no-unused-vars: [2, { "varsIgnorePattern": "onYouTubeIframeAPIReady" }] */
// YouTube API hook has to be in global scope, ugh.
window.onYouTubeIframeAPIReady = function() {
window.onYouTubeIframeAPIReady = function () {
'use strict';
// Play the video only once the API is ready.
Mozilla.tipsPageVideoPlay();
};
(function() {
(function () {
'use strict';
var src = 'https://www.youtube.com/iframe_api';
@ -38,12 +38,18 @@ window.onYouTubeIframeAPIReady = function() {
}
function isScriptLoaded() {
return document.querySelector('script[src="' + src + '"]') ? true : false;
return document.querySelector('script[src="' + src + '"]')
? true
: false;
}
function playVideo() {
var title = document.querySelector('.mzp-c-modal-inner > header > h2').innerText;
var videoLink = document.querySelector('.mzp-c-modal-inner .video-play');
var title = document.querySelector(
'.mzp-c-modal-inner > header > h2'
).innerText;
var videoLink = document.querySelector(
'.mzp-c-modal-inner .video-play'
);
var videoId = videoLink.getAttribute('data-id');
player = new YT.Player(videoLink, {
@ -52,11 +58,11 @@ window.onYouTubeIframeAPIReady = function() {
videoId: videoId,
playerVars: {
modestbranding: 1, // hide YouTube logo.
rel: 0, // do not show related videos on end.
rel: 0 // do not show related videos on end.
},
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
onReady: onPlayerReady,
onStateChange: onPlayerStateChange
}
});
@ -67,23 +73,23 @@ window.onYouTubeIframeAPIReady = function() {
function onPlayerStateChange(event) {
var state;
switch(event.data) {
case YT.PlayerState.PLAYING:
state = 'video play';
break;
case YT.PlayerState.PAUSED:
state = 'video paused';
break;
case YT.PlayerState.ENDED:
state = 'video complete';
break;
switch (event.data) {
case YT.PlayerState.PLAYING:
state = 'video play';
break;
case YT.PlayerState.PAUSED:
state = 'video paused';
break;
case YT.PlayerState.ENDED:
state = 'video complete';
break;
}
if (state) {
window.dataLayer.push({
'event': 'video-interaction',
'videoTitle': title,
'interaction': state
event: 'video-interaction',
videoTitle: title,
interaction: state
});
}
}
@ -121,7 +127,9 @@ window.onYouTubeIframeAPIReady = function() {
}
function init() {
var videoCards = document.querySelectorAll('.mzp-c-card.has-video-embed .mzp-c-card-block-link');
var videoCards = document.querySelectorAll(
'.mzp-c-card.has-video-embed .mzp-c-card-block-link'
);
for (var i = 0; i < videoCards.length; i++) {
videoCards[i].addEventListener('click', openVideoModal, false);

Просмотреть файл

@ -2,10 +2,9 @@
* 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/. */
(function() {
(function () {
'use strict';
// Lazyload images
Mozilla.LazyLoad.init();
})();

Просмотреть файл

@ -8,5 +8,4 @@
Mozilla.LazyLoad.init();
window.Mzp.Details.init('.mzp-c-menu-list-title');
})(window.Mozilla);

Просмотреть файл

@ -1,4 +1,4 @@
(function() {
(function () {
'use strict';
var client = window.Mozilla.Client;
@ -12,24 +12,23 @@
firefox70.parentNode.removeChild(firefox70);
firefox69.parentNode.removeChild(firefox69);
nonFirefox.parentNode.removeChild(nonFirefox);
}
else if (!client.isFirefox) {
} else if (!client.isFirefox) {
firefox69.parentNode.removeChild(firefox69);
firefox70.parentNode.removeChild(firefox70);
nonFirefox.classList.remove('hidden');
}
else if (client.isFirefox && version < '70') {
} else if (client.isFirefox && version < '70') {
firefox70.parentNode.removeChild(firefox70);
nonFirefox.parentNode.removeChild(nonFirefox);
firefox69.classList.remove('hidden');
}
else if (client.isFirefox && version >= '70') {
} else if (client.isFirefox && version >= '70') {
firefox69.parentNode.removeChild(firefox69);
nonFirefox.parentNode.removeChild(nonFirefox);
firefox70.classList.remove('hidden');
document.querySelector('#lockwise-button').addEventListener('click', function() {
Mozilla.UITour.showHighlight('logins');
});
document
.querySelector('#lockwise-button')
.addEventListener('click', function () {
Mozilla.UITour.showHighlight('logins');
});
}
})();

Просмотреть файл

@ -2,11 +2,10 @@
* 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/. */
(function() {
(function () {
'use strict';
// initialize send to device widget
var form = new Mozilla.SendToDevice();
form.init();
})();

Просмотреть файл

@ -7,7 +7,7 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function(Mozilla) {
(function (Mozilla) {
'use strict';
var sendToPrimary = document.getElementById('s2d-primary');
var sendToSecondary = document.getElementById('s2d-primary');
@ -19,5 +19,4 @@ if (typeof window.Mozilla === 'undefined') {
var formSecondary = new Mozilla.SendToDevice('s2d-secondary');
formSecondary.init();
}
})(window.Mozilla);

Просмотреть файл

@ -1,11 +1,10 @@
/* 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/. */
* 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/. */
(function () {
'use strict';
// Lazyload images
Mozilla.LazyLoad.init();
})();

Просмотреть файл

@ -2,31 +2,39 @@
* 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/. */
(function() {
(function () {
'use strict';
var client = window.Mozilla.Client;
var otherPlatformsLink = document.querySelector('.js-platform-modal-button');
var otherPlatformsContent = document.querySelector('.other-platforms-content');
var otherPlatformsLink = document.querySelector(
'.js-platform-modal-button'
);
var otherPlatformsContent = document.querySelector(
'.other-platforms-content'
);
var initOtherPlatformsModal = function() {
var initOtherPlatformsModal = function () {
// show the modal cta button
otherPlatformsLink.classList.remove('hidden');
otherPlatformsLink.addEventListener('click', function(e) {
e.preventDefault();
otherPlatformsLink.addEventListener(
'click',
function (e) {
e.preventDefault();
Mzp.Modal.createModal(this, otherPlatformsContent, {
title: otherPlatformsLink.textContent,
className: 'other-platforms-modal'
});
Mzp.Modal.createModal(this, otherPlatformsContent, {
title: otherPlatformsLink.textContent,
className: 'other-platforms-modal'
});
window.dataLayer.push({
'event': 'in-page-interaction',
'eAction': 'link click',
'eLabel': 'Download Firefox for another platform'
});
}, false);
window.dataLayer.push({
event: 'in-page-interaction',
eAction: 'link click',
eLabel: 'Download Firefox for another platform'
});
},
false
);
};
/**
@ -36,5 +44,4 @@
if (otherPlatformsLink && client.isDesktop) {
initOtherPlatformsModal();
}
})();

Просмотреть файл

@ -2,18 +2,23 @@
* 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/. */
(function() {
(function () {
'use strict';
var timeout;
var requestComplete = false;
function beginFirefoxDownload() {
var directDownloadLink = document.getElementById('direct-download-link');
var directDownloadLink = document.getElementById(
'direct-download-link'
);
var downloadURL;
// Only auto-start the download if a supported platform is detected.
if (Mozilla.DownloadThanks.shouldAutoDownload(window.site.platform) && typeof Mozilla.Utils !== 'undefined') {
if (
Mozilla.DownloadThanks.shouldAutoDownload(window.site.platform) &&
typeof Mozilla.Utils !== 'undefined'
) {
downloadURL = Mozilla.DownloadThanks.getDownloadURL(window.site);
if (downloadURL) {
@ -25,8 +30,8 @@
// Start the platform-detected download a second after DOM ready event.
// We don't rely on the window load event as we have third-party tracking pixels.
Mozilla.Utils.onDocumentReady(function() {
setTimeout(function() {
Mozilla.Utils.onDocumentReady(function () {
setTimeout(function () {
window.location.href = downloadURL;
}, 1000);
});
@ -44,9 +49,9 @@
// Fire GA event to log attribution success
window.dataLayer.push({
'event': 'non-interaction',
'eAction': 'amo-exp-attribution',
'eLabel': 'success'
event: 'non-interaction',
eAction: 'amo-exp-attribution',
eLabel: 'success'
});
beginFirefoxDownload();
@ -62,9 +67,9 @@
// Fire GA event to log attribution timeout
window.dataLayer.push({
'event': 'non-interaction',
'eAction': 'amo-exp-attribution',
'eLabel': 'timeout'
event: 'non-interaction',
eAction: 'amo-exp-attribution',
eLabel: 'timeout'
});
beginFirefoxDownload();
@ -76,12 +81,13 @@
* met and the visitor does *not* have a cookie, then attempt to make the attribution
* call before starting the download.
*/
if (typeof Mozilla.StubAttribution !== 'undefined' &&
if (
typeof Mozilla.StubAttribution !== 'undefined' &&
Mozilla.StubAttribution.meetsRequirements() &&
!Mozilla.StubAttribution.hasCookie()) {
!Mozilla.StubAttribution.hasCookie()
) {
// Wait for GA to load so that we can pass along visit ID.
Mozilla.StubAttribution.waitForGoogleAnalytics(function() {
Mozilla.StubAttribution.waitForGoogleAnalytics(function () {
var data = Mozilla.StubAttribution.getAttributionData();
if (data && Mozilla.StubAttribution.withinAttributionRate()) {
@ -101,5 +107,4 @@
// Bug 1354334 - add a hint for test automation that page has loaded.
document.getElementsByTagName('html')[0].classList.add('download-ready');
})();

Просмотреть файл

@ -2,14 +2,17 @@
* 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/. */
(function() {
(function () {
'use strict';
var directDownloadLink = document.getElementById('direct-download-link');
var downloadURL;
// Only auto-start the download if a supported platform is detected.
if (Mozilla.DownloadThanks.shouldAutoDownload(window.site.platform) && typeof Mozilla.Utils !== 'undefined') {
if (
Mozilla.DownloadThanks.shouldAutoDownload(window.site.platform) &&
typeof Mozilla.Utils !== 'undefined'
) {
downloadURL = Mozilla.DownloadThanks.getDownloadURL(window.site);
if (downloadURL) {
@ -21,8 +24,8 @@
// Start the platform-detected download a second after DOM ready event.
// We don't rely on the window load event as we have third-party tracking pixels.
Mozilla.Utils.onDocumentReady(function() {
setTimeout(function() {
Mozilla.Utils.onDocumentReady(function () {
setTimeout(function () {
window.location.href = downloadURL;
}, 1000);
});
@ -31,5 +34,4 @@
// Bug 1354334 - add a hint for test automation that page has loaded.
document.getElementsByTagName('html')[0].classList.add('download-ready');
})();

Просмотреть файл

@ -7,7 +7,7 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function(Mozilla) {
(function (Mozilla) {
'use strict';
var DownloadThanks = {};
@ -17,7 +17,7 @@ if (typeof window.Mozilla === 'undefined') {
* @param {String} platform
* @returns {Boolean}
*/
DownloadThanks.shouldAutoDownload = function(platform) {
DownloadThanks.shouldAutoDownload = function (platform) {
var supportedPlatforms = ['windows', 'osx', 'linux', 'android', 'ios'];
if (supportedPlatforms.indexOf(platform) !== -1) {
@ -32,36 +32,36 @@ if (typeof window.Mozilla === 'undefined') {
* @param {Object} window.site
* @returns {String} download url
*/
DownloadThanks.getDownloadURL = function(site) {
DownloadThanks.getDownloadURL = function (site) {
var prefix = 'thanks-download-button-';
var link;
var url;
switch(site.platform) {
case 'windows':
link = document.getElementById(prefix + 'win');
break;
case 'osx':
link = document.getElementById(prefix + 'osx');
break;
case 'linux':
if (site.isARM) {
// Linux ARM users get SUMO install instructions.
link = null;
} else if (site.archSize === 64) {
// Detect 64bit / 32bit builds for Linux.
link = document.getElementById(prefix + 'linux64');
} else {
link = document.getElementById(prefix + 'linux');
}
switch (site.platform) {
case 'windows':
link = document.getElementById(prefix + 'win');
break;
case 'osx':
link = document.getElementById(prefix + 'osx');
break;
case 'linux':
if (site.isARM) {
// Linux ARM users get SUMO install instructions.
link = null;
} else if (site.archSize === 64) {
// Detect 64bit / 32bit builds for Linux.
link = document.getElementById(prefix + 'linux64');
} else {
link = document.getElementById(prefix + 'linux');
}
break;
case 'android':
link = document.getElementById(prefix + 'android');
break;
case 'ios':
link = document.getElementById(prefix + 'ios');
break;
break;
case 'android':
link = document.getElementById(prefix + 'android');
break;
case 'ios':
link = document.getElementById(prefix + 'ios');
break;
}
if (link && link.href) {
@ -72,5 +72,4 @@ if (typeof window.Mozilla === 'undefined') {
};
Mozilla.DownloadThanks = DownloadThanks;
})(window.Mozilla);

Просмотреть файл

@ -1,17 +1,19 @@
/* 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/. */
* 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/. */
/*
mobile banner
- on mobile, move the mobile banner to the top of the main content area
*/
(function() {
(function () {
'use strict';
// if platform is ios or android
if (/ios/.test(window.site.platform) || /android/.test(window.site.platform)) {
if (
/ios/.test(window.site.platform) ||
/android/.test(window.site.platform)
) {
// move the banner up to the top of main
var mobileBanner = document.getElementById('mobile-banner');
var desktopBanner = document.getElementById('desktop-banner');
@ -20,13 +22,12 @@
}
})();
/*
comparison chart
- show a comparison to the users current browser or their operating system default
- add button listeners to allow changing
*/
(function() {
(function () {
'use strict';
var cells = {
@ -37,8 +38,7 @@
};
var buttons = document.querySelectorAll('.c-compare-button');
var ua = navigator.userAgent;
var compareTo = function() {
var compareTo = (function () {
if (/MSIE|Trident/i.test(ua)) {
return 'edge';
}
@ -67,11 +67,10 @@
}
return 'chrome';
}();
})();
// display chosen browser
function show(browser) {
// hide all comparisons
for (var i = 0; i < cells['all'].length; ++i) {
cells['all'][i].style.display = 'none';
@ -84,7 +83,7 @@
// add active state to button
for (var k = 0; k < buttons.length; ++k) {
if(buttons[k].value === browser) {
if (buttons[k].value === browser) {
buttons[k].setAttribute('aria-pressed', true);
} else {
buttons[k].setAttribute('aria-pressed', false);
@ -97,7 +96,9 @@
// listen to buttons
for (var l = 0; l < buttons.length; ++l) {
buttons[l].addEventListener('click', function(event){ show(event.target.value); });
buttons[l].addEventListener('click', function (event) {
show(event.target.value);
});
}
})();
@ -105,7 +106,7 @@
system requirements
- add target to link so they go to their system's requirements
*/
(function() {
(function () {
'use strict';
var sys = document.getElementById('system-requirements');
@ -118,57 +119,58 @@
} else if (/linux/.test(window.site.platform)) {
sys.href = href + '#linux';
}
})();
/*
scroll animations
- add class to animate
- add observer to trigger animations
*/
(function() {
(function () {
'use strict';
var supportsInsersectionObserver = function() {
return 'IntersectionObserver' in window &&
'IntersectionObserverEntry' in window &&
'intersectionRatio' in window.IntersectionObserverEntry.prototype;
}();
var supportsInsersectionObserver = (function () {
return (
'IntersectionObserver' in window &&
'IntersectionObserverEntry' in window &&
'intersectionRatio' in window.IntersectionObserverEntry.prototype
);
})();
// check for support
if (supportsInsersectionObserver && window.NodeList && NodeList.prototype.forEach) {
if (
supportsInsersectionObserver &&
window.NodeList &&
NodeList.prototype.forEach
) {
// needs a sec to report rect.top right if the page loaded partially scrolled already
setTimeout(function(){
setTimeout(function () {
// define observer behaviour
var observer = new IntersectionObserver(
function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
// trigger animation
entry.target.classList.add('is-animated');
// remove observer after triggering animation
observer.unobserve(entry.target);
}
});
}
);
var observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
// trigger animation
entry.target.classList.add('is-animated');
// remove observer after triggering animation
observer.unobserve(entry.target);
}
});
});
// add observers
document.querySelectorAll('.js-animate').forEach(function(element) {
var rect = element.getBoundingClientRect();
var viewHeight = window.innerHeight;
// check element isn't above user's current position on the page
if(rect.top > viewHeight) {
element.classList.add('has-animate');
observer.observe(element);
}
});
document
.querySelectorAll('.js-animate')
.forEach(function (element) {
var rect = element.getBoundingClientRect();
var viewHeight = window.innerHeight;
// check element isn't above user's current position on the page
if (rect.top > viewHeight) {
element.classList.add('has-animate');
observer.observe(element);
}
});
}, 200);
}
})();
/*
@ -176,7 +178,7 @@
- check for support
- add listener, enable, and show button
*/
(function(Mozilla) {
(function (Mozilla) {
'use strict';
var client = Mozilla.Client;
@ -185,9 +187,9 @@
e.preventDefault();
window.dataLayer.push({
'event': 'in-page-interaction',
'eAction': 'link click',
'eLabel': 'See your protection report'
event: 'in-page-interaction',
eAction: 'link click',
eLabel: 'See your protection report'
});
Mozilla.UITour.showProtectionReport();
@ -196,13 +198,20 @@
if (client.isFirefoxDesktop) {
if (client._getFirefoxMajorVersion() >= 70) {
// show "See what Firefox has blocked for you" links.
document.querySelector('body').classList.add('state-firefox-desktop-70');
document
.querySelector('body')
.classList.add('state-firefox-desktop-70');
// Intercept link clicks to open about:protections page using UITour.
Mozilla.UITour.ping(function() {
document.getElementById('protection-report').addEventListener('click', handleOpenProtectionReport, false);
Mozilla.UITour.ping(function () {
document
.getElementById('protection-report')
.addEventListener(
'click',
handleOpenProtectionReport,
false
);
});
}
}
})(window.Mozilla);

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
(function() {
(function () {
'use strict';
var client = window.Mozilla.Client;
@ -19,23 +19,33 @@
// Count the click in GA
window.dataLayer.push({
'event': 'in-page-interaction',
'eAction': 'link click',
'eLabel': 'Current Firefox user downloading Firefox'
event: 'in-page-interaction',
eAction: 'link click',
eLabel: 'Current Firefox user downloading Firefox'
});
}
var initFxAccountModal = function() {
var downloadLinkPrimary = document.querySelectorAll('.main-download .c-button-download-thanks > .download-link');
var initFxAccountModal = function () {
var downloadLinkPrimary = document.querySelectorAll(
'.main-download .c-button-download-thanks > .download-link'
);
for (var i = 0; i < downloadLinkPrimary.length; i++) {
downloadLinkPrimary[i].addEventListener('click', showFxAModal, false);
downloadLinkPrimary[i].addEventListener(
'click',
showFxAModal,
false
);
}
// Don't trigger the modal for signed in users
client.getFxaDetails(function(details) {
client.getFxaDetails(function (details) {
if (details.setup) {
for (var i = 0; i < downloadLinkPrimary.length; i++) {
downloadLinkPrimary[i].removeEventListener('click', showFxAModal, false);
downloadLinkPrimary[i].removeEventListener(
'click',
showFxAModal,
false
);
}
}
});
@ -45,5 +55,4 @@
if (client.isFirefoxDesktop && client._getFirefoxMajorVersion() >= '57') {
initFxAccountModal();
}
})();

Просмотреть файл

@ -2,9 +2,8 @@
* 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/. */
(function(Mozilla) {
(function (Mozilla) {
'use strict';
Mozilla.Yandex.init();
})(window.Mozilla);

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
(function() {
(function () {
'use strict';
var Yandex = {
@ -15,21 +15,22 @@
var _geoTimeout;
var _requestComplete = false;
Yandex.getLocation = function() {
Yandex.getLocation = function () {
// should /country-code.json be slow to load,
// just show the regular messaging after 3 seconds waiting.
_geoTimeout = setTimeout(Yandex.onRequestComplete, 3000);
var xhr = new window.XMLHttpRequest();
xhr.onload = function(r) {
xhr.onload = function (r) {
var country = 'none';
// make sure status is in the acceptable range
if (r.target.status >= 200 && r.target.status < 300) {
try {
country = JSON.parse(r.target.responseText).country_code.toLowerCase();
country = JSON.parse(
r.target.responseText
).country_code.toLowerCase();
} catch (e) {
country = 'none';
}
@ -44,7 +45,7 @@
xhr.send();
};
Yandex.hasGeoOverride = function(location) {
Yandex.hasGeoOverride = function (location) {
var loc = location || window.location.search;
if (loc.indexOf('geo=') !== -1) {
var urlRe = /geo=([a-z]{2})/i;
@ -57,7 +58,7 @@
return false;
};
Yandex.verifyLocation = function(location) {
Yandex.verifyLocation = function (location) {
if (location) {
return location === Yandex.RUSSIA_COUNTRY_CODE;
}
@ -65,7 +66,7 @@
return false;
};
Yandex.onRequestComplete = function(data) {
Yandex.onRequestComplete = function (data) {
var country = typeof data === 'string' ? data : 'none';
clearTimeout(_geoTimeout);
@ -81,7 +82,7 @@
}
};
Yandex.updatePageContent = function() {
Yandex.updatePageContent = function () {
if (Yandex.shouldShowYandex()) {
Yandex.showYandexContent();
} else {
@ -89,12 +90,14 @@
}
};
Yandex.showYandexContent = function() {
Yandex.showYandexContent = function () {
document.body.classList.add('show-yandex');
// Update page title and description.
document.title = Mozilla.Utils.trans('page-title');
document.querySelector('meta[name="description"]').setAttribute('content', Mozilla.Utils.trans('page-desc'));
document
.querySelector('meta[name="description"]')
.setAttribute('content', Mozilla.Utils.trans('page-desc'));
window.dataLayer.push({
'data-ex-variant': 'yandex-content',
@ -102,43 +105,49 @@
});
};
Yandex.showRegularContent = function() {
Yandex.showRegularContent = function () {
window.dataLayer.push({
'data-ex-variant': 'regular-content',
'data-ex-name': 'firefox-new-ru-yandex'
});
};
Yandex.shouldShowYandex = function() {
Yandex.shouldShowYandex = function () {
// Is user in Russia?
return Yandex.verifyLocation(Yandex.getCookie(Yandex.COOKIE_ID));
};
Yandex.cookieExpiresDate = function(date) {
Yandex.cookieExpiresDate = function (date) {
var d = date || new Date();
d.setTime(d.getTime() + (Yandex.COOKIE_EXPIRATION_DAYS * 24 * 60 * 60 * 1000));
d.setTime(
d.getTime() + Yandex.COOKIE_EXPIRATION_DAYS * 24 * 60 * 60 * 1000
);
return d.toUTCString();
};
Yandex.setCookie = function(country) {
Mozilla.Cookies.setItem(Yandex.COOKIE_ID, country, Yandex.cookieExpiresDate());
Yandex.setCookie = function (country) {
Mozilla.Cookies.setItem(
Yandex.COOKIE_ID,
country,
Yandex.cookieExpiresDate()
);
};
Yandex.getCookie = function(id) {
Yandex.getCookie = function (id) {
return Mozilla.Cookies.getItem(id);
};
Yandex.hasCookie = function() {
Yandex.hasCookie = function () {
return Mozilla.Cookies.hasItem(Yandex.COOKIE_ID);
};
Yandex.init = function() {
var cookiesEnabled = typeof Mozilla.Cookies !== 'undefined' || Mozilla.Cookies.enabled();
Yandex.init = function () {
var cookiesEnabled =
typeof Mozilla.Cookies !== 'undefined' || Mozilla.Cookies.enabled();
var override = Yandex.hasGeoOverride();
// only show Yandex content if on desktop with cookies enabled.
if (_client.isDesktop && cookiesEnabled) {
// if override URL is used, skip doing anything with cookies & show the expected content.
if (override) {
if (Yandex.verifyLocation(override)) {
@ -156,12 +165,10 @@
Yandex.getLocation();
}
}
} else {
Yandex.showRegularContent();
}
};
window.Mozilla.Yandex = Yandex;
})();

Просмотреть файл

@ -2,10 +2,9 @@
* 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/. */
(function() {
(function () {
'use strict';
// Lazyload images
Mozilla.LazyLoad.init();
})();

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
(function() {
(function () {
'use strict';
var client = Mozilla.Client;
@ -11,9 +11,9 @@
e.preventDefault();
window.dataLayer.push({
'event': 'in-page-interaction',
'eAction': 'link click',
'eLabel': 'See what Firefox has blocked for you'
event: 'in-page-interaction',
eAction: 'link click',
eLabel: 'See what Firefox has blocked for you'
});
Mozilla.UITour.showProtectionReport();
@ -22,34 +22,52 @@
if (client.isFirefoxDesktop) {
if (client._getFirefoxMajorVersion() >= 70) {
// show "See what Firefox has blocked for you" links.
document.querySelector('main').classList.add('state-firefox-desktop-70');
document
.querySelector('main')
.classList.add('state-firefox-desktop-70');
// Intercept link clicks to open about:protections page using UITour.
Mozilla.UITour.ping(function() {
var protectionReportLinks = document.querySelectorAll('.js-open-about-protections');
var pictoCardTitles = document.querySelectorAll('.privacy-products-etp .mzp-c-card-picto-title');
Mozilla.UITour.ping(function () {
var protectionReportLinks = document.querySelectorAll(
'.js-open-about-protections'
);
var pictoCardTitles = document.querySelectorAll(
'.privacy-products-etp .mzp-c-card-picto-title'
);
for (var i = 0; i < protectionReportLinks.length; i++) {
protectionReportLinks[i].addEventListener('click', handleOpenProtectionReport, false);
protectionReportLinks[i].addEventListener(
'click',
handleOpenProtectionReport,
false
);
}
for (var j = 0; j < pictoCardTitles.length; j++) {
// Make picto card titles click and keyboard accessible.
pictoCardTitles[j].setAttribute('role', 'link');
pictoCardTitles[j].setAttribute('tabindex', 0);
pictoCardTitles[j].addEventListener('click', handleOpenProtectionReport, false);
pictoCardTitles[j].addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
e.preventDefault();
handleOpenProtectionReport(e);
pictoCardTitles[j].addEventListener(
'click',
handleOpenProtectionReport,
false
);
pictoCardTitles[j].addEventListener(
'keydown',
function (e) {
if (e.key === 'Enter') {
e.preventDefault();
handleOpenProtectionReport(e);
}
}
});
);
}
});
} else {
// show "Update your Firefox browser" links.
document.querySelector('main').classList.add('state-firefox-desktop-old');
document
.querySelector('main')
.classList.add('state-firefox-desktop-old');
}
}
})(window.Mozilla);

Просмотреть файл

@ -1,13 +1,38 @@
/* 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/. */
* 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/. */
(function() {
(function () {
'use strict';
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) { descriptor.writable = true; } Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) { defineProperties(Constructor.prototype, protoProps); } if (staticProps) { defineProperties(Constructor, staticProps); } return Constructor; }; }();
var _createClass = (function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ('value' in descriptor) {
descriptor.writable = true;
}
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) {
defineProperties(Constructor.prototype, protoProps);
}
if (staticProps) {
defineProperties(Constructor, staticProps);
}
return Constructor;
};
})();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError('Cannot call a class as a function');
}
}
var animation = '';
var search = window.location.search;
@ -15,11 +40,15 @@
animation = 'static';
}
var requestAnimFrame = function () {
return window.requestAnimationFrame || window.mozRequestAnimationFrame || function (callback) {
window.setTimeout(callback, 1000 / 60);
};
}();
var requestAnimFrame = (function () {
return (
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
}
);
})();
// Returns a random number between a range.
function range(a, b) {
@ -27,7 +56,12 @@
}
var NUM_CONFETTI = 425;
var COLORS = ['rgb(255,255,255)', 'rgb(255,112,87)', 'rgb(244,239,50)', 'rgb(23,137,147)'];
var COLORS = [
'rgb(255,255,255)',
'rgb(255,112,87)',
'rgb(244,239,50)',
'rgb(23,137,147)'
];
function setupConfetti(id) {
var canvas = document.getElementById(id);
var context = canvas.getContext('2d');
@ -55,7 +89,7 @@
});
// Initial code thanks to https://codepen.io/linrock/pen/Amdhr
var Confetti = function () {
var Confetti = (function () {
function Confetti() {
_classCallCheck(this, Confetti);
@ -66,53 +100,61 @@
this.diff = 0;
}
_createClass(Confetti, [{
key: 'replace',
value: function replace() {
this.opacity = defaultOpacity;
this.x = range(-100, width - confettiSize + 100);
this.y = range(-100, height - confettiSize);
this.xmax = width - confettiSize;
this.ymax = height - confettiSize;
_createClass(Confetti, [
{
key: 'replace',
value: function replace() {
this.opacity = defaultOpacity;
this.x = range(-100, width - confettiSize + 100);
this.y = range(-100, height - confettiSize);
this.xmax = width - confettiSize;
this.ymax = height - confettiSize;
this.dop = range(4, 6);
this.vx = (range(-0.2, 0.2) + xpos) * 200;
this.vy = confettiSize + range(1, 2) * 150;
this.start = Date.now() / 1000;
this.now = this.start;
this.diff = 0;
this.dop = range(4, 6);
this.vx = (range(-0.2, 0.2) + xpos) * 200;
this.vy = confettiSize + range(1, 2) * 150;
this.start = Date.now() / 1000;
this.now = this.start;
this.diff = 0;
}
},
{
key: 'draw',
value: function draw() {
this.now = Date.now() / 1000;
this.diff = this.now - this.start;
this.x += this.vx * this.diff;
this.y += this.vy * this.diff;
this.opacity += this.dop * this.diff;
if (this.opacity > 1) {
this.opacity = 1;
this.dop *= -1;
}
if (this.opacity < 0 || this.y > this.ymax) {
this.replace();
}
if (!(0 < this.x < this.xmax)) {
this.x = (this.x + this.xmax) % this.xmax;
}
context.beginPath();
context.rect(
~~this.x,
~~this.y,
confettiSize,
confettiSize
);
context.globalAlpha = this.opacity;
context.fillStyle = this.rgb;
context.fill();
this.start = Date.now() / 1000;
}
}
}, {
key: 'draw',
value: function draw() {
this.now = Date.now() / 1000;
this.diff = this.now - this.start;
this.x += this.vx * this.diff;
this.y += this.vy * this.diff;
this.opacity += this.dop * this.diff;
if (this.opacity > 1) {
this.opacity = 1;
this.dop *= -1;
}
if (this.opacity < 0 || this.y > this.ymax) {
this.replace();
}
if (!(0 < this.x < this.xmax)) {
this.x = (this.x + this.xmax) % this.xmax;
}
context.beginPath();
context.rect(~~this.x, ~~this.y, confettiSize, confettiSize);
context.globalAlpha = this.opacity;
context.fillStyle = this.rgb;
context.fill();
this.start = Date.now() / 1000;
}
}]);
]);
return Confetti;
}();
})();
var confetti = [];
var pushConfetti = function pushConfetti() {

Просмотреть файл

@ -2,14 +2,14 @@
* 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/. */
(function() {
(function () {
'use strict';
var timer;
function isDefaultBrowser() {
return new window.Promise(function(resolve, reject) {
Mozilla.UITour.getConfiguration('appinfo', function(details) {
return new window.Promise(function (resolve, reject) {
Mozilla.UITour.getConfiguration('appinfo', function (details) {
if (details.defaultBrowser) {
resolve();
} else {
@ -29,19 +29,21 @@
}
function checkForDefaultSwitch() {
isDefaultBrowser().then(function() {
onDefaultSwitch();
clearInterval(timer);
}).catch(function() {
// do nothing.
});
isDefaultBrowser()
.then(function () {
onDefaultSwitch();
clearInterval(timer);
})
.catch(function () {
// do nothing.
});
}
function trackEvent(action, label) {
window.dataLayer.push({
'event': 'in-page-interaction',
'eAction': action,
'eLabel': label
event: 'in-page-interaction',
eAction: action,
eLabel: label
});
}
@ -59,29 +61,31 @@
* If true show a success message.
* If false prompt to switch the default browser.
*/
isDefaultBrowser().then(function() {
document.querySelector('main').classList.add('is-firefox-default');
trackEvent('visited', 'firefox-default');
}).catch(function(canSetDefaultBrowserInBackground) {
/**
* If we can set the default in the background without any user interaction,
* then do so straight away, else poll for when the user sets it manually.
*/
if (canSetDefaultBrowserInBackground) {
trySetDefaultBrowser();
onDefaultSwitch();
} else {
// Give a little time before opening system dialog when the page loads.
window.setTimeout(function() {
isDefaultBrowser()
.then(function () {
document
.querySelector('main')
.classList.add('is-firefox-default');
trackEvent('visited', 'firefox-default');
})
.catch(function (canSetDefaultBrowserInBackground) {
/**
* If we can set the default in the background without any user interaction,
* then do so straight away, else poll for when the user sets it manually.
*/
if (canSetDefaultBrowserInBackground) {
trySetDefaultBrowser();
timer = setInterval(checkForDefaultSwitch, 1000);
}, 1500);
}
trackEvent('visited', 'firefox-not-default');
});
onDefaultSwitch();
} else {
// Give a little time before opening system dialog when the page loads.
window.setTimeout(function () {
trySetDefaultBrowser();
timer = setInterval(checkForDefaultSwitch, 1000);
}, 1500);
}
trackEvent('visited', 'firefox-not-default');
});
}
Mozilla.run(onLoad);
})(window.Mozilla);

Просмотреть файл

@ -1,23 +1,27 @@
/* 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/. */
(function() {
(function () {
'use strict';
// https://davidwalsh.name/javascript-debounce-function
function debounce(func, wait, immediate) {
var timeout;
return function() {
return function () {
var context = this,
args = arguments;
var later = function() {
var later = function () {
timeout = null;
if (!immediate) {func.apply(context, args);}
if (!immediate) {
func.apply(context, args);
}
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) {func.apply(context, args);}
if (callNow) {
func.apply(context, args);
}
};
}
@ -31,9 +35,11 @@
return elementBottom > viewportTop && elementTop < viewportBottom;
}
function onLoad(){
function onLoad() {
// Check if promo exists on the page, or if smaller than tablet, or if user prefers reduced motion.
var matchMediaNoMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var matchMediaNoMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches;
var matchMediaDesktop = window.matchMedia('(min-width: 768px)').matches;
var promo = document.querySelector('.mzp-c-sticky-promo');
@ -45,33 +51,41 @@
var fxUser = document.documentElement.classList.contains('is-firefox');
var hideFromFxUser = promo.classList.contains('hide-from-fx-user');
if ( fxUser && hideFromFxUser) {
if (fxUser && hideFromFxUser) {
return;
}
var StickyPromo = {};
var STICKY_PROMO_COOKIE_ID = 'firefox-sticky-promo';
StickyPromo.bindEvents = function() {
promo.addEventListener('animationend', function() {
promo.classList.add('is-displayed');
}, false);
StickyPromo.bindEvents = function () {
promo.addEventListener(
'animationend',
function () {
promo.classList.add('is-displayed');
},
false
);
};
StickyPromo.hasCookie = function() {
StickyPromo.hasCookie = function () {
return Mozilla.Cookies.hasItem(STICKY_PROMO_COOKIE_ID);
};
StickyPromo.setCookie = function() {
StickyPromo.setCookie = function () {
var date = new Date();
var cookieDuration = 1 * 24 * 60 * 60 * 1000; // 1 day expiration
date.setTime(date.getTime() + cookieDuration); // 1 day expiration
Mozilla.Cookies.setItem(STICKY_PROMO_COOKIE_ID, true, date.toUTCString(), '/');
Mozilla.Cookies.setItem(
STICKY_PROMO_COOKIE_ID,
true,
date.toUTCString(),
'/'
);
};
StickyPromo.show = function (){
function openOnScroll(){
StickyPromo.show = function () {
function openOnScroll() {
// Open promo
Mzp.StickyPromo.open();
document.removeEventListener('scroll', openOnScroll, false);
@ -79,7 +93,7 @@
document.addEventListener('scroll', openOnScroll, false);
var checkForFooterOnScroll = debounce(function() {
var checkForFooterOnScroll = debounce(function () {
// If the footer is in the viewport, fade out the promo.
// Animate it back in when the footer leaves the viewport
// if the user did not dismiss it.
@ -95,20 +109,27 @@
// Add modifier class to the footer to make sure the language selection drop-down is not obscured by the sticky promo
var footer = document.querySelector('.c-footer');
if (footer) {
document.addEventListener('scroll', checkForFooterOnScroll, false);
document.addEventListener(
'scroll',
checkForFooterOnScroll,
false
);
}
// Set Close Button event
var stickyBtnClose = document.querySelector('.mzp-c-sticky-promo-close');
var stickyBtnClose = document.querySelector(
'.mzp-c-sticky-promo-close'
);
stickyBtnClose.addEventListener('click', function(){
stickyBtnClose.addEventListener('click', function () {
StickyPromo.setCookie(STICKY_PROMO_COOKIE_ID);
promo.classList.add('user-dismiss');
});
};
// Check on page load
var cookiesEnabled = typeof Mozilla.Cookies !== 'undefined' && Mozilla.Cookies.enabled();
var cookiesEnabled =
typeof Mozilla.Cookies !== 'undefined' && Mozilla.Cookies.enabled();
if (cookiesEnabled && !StickyPromo.hasCookie()) {
StickyPromo.bindEvents();
@ -117,5 +138,4 @@
}
window.Mozilla.run(onLoad);
})(window.Mozilla);

Просмотреть файл

@ -7,7 +7,7 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function(Mozilla) {
(function (Mozilla) {
'use strict';
var sendTo = document.getElementById('send-to-device');
@ -15,5 +15,4 @@ if (typeof window.Mozilla === 'undefined') {
var form = new Mozilla.SendToDevice();
form.init();
}
})(window.Mozilla);

Просмотреть файл

@ -7,7 +7,7 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function(Mozilla) {
(function (Mozilla) {
'use strict';
var content = document.querySelector('.mzp-u-modal-content');
@ -32,5 +32,4 @@ if (typeof window.Mozilla === 'undefined') {
closeText: window.Mozilla.Utils.trans('global-close')
});
}
})(window.Mozilla);

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
(function() {
(function () {
'use strict';
// used for testing purposes only.
@ -20,21 +20,24 @@
const content = document.querySelector('.mzp-u-modal-content');
const trigger = document.querySelector('.js-modal-link');
trigger.addEventListener('click', (e) => {
e.preventDefault();
Mzp.Modal.createModal(e.target, content, {
closeText: window.Mozilla.Utils.trans('global-close'),
});
trigger.addEventListener(
'click',
(e) => {
e.preventDefault();
Mzp.Modal.createModal(e.target, content, {
closeText: window.Mozilla.Utils.trans('global-close')
});
window.dataLayer.push({
'event': 'in-page-interaction',
'eAction': 'link click',
'eLabel': 'Get Firefox for mobile'
});
}, false);
window.dataLayer.push({
event: 'in-page-interaction',
eAction: 'link click',
eLabel: 'Get Firefox for mobile'
});
},
false
);
// initialize send to device widget
const form = new Mozilla.SendToDevice();
form.init();
})(window.Mozilla);

Просмотреть файл

@ -38,12 +38,11 @@
'v=text': 3,
'v=image': 3,
'v=animation': 3,
'v=header-text': 3,
'v=header-text': 3
}
});
cop.init();
}
};
initTrafficCop();
})(window.Mozilla);

Просмотреть файл

@ -8,9 +8,9 @@
function handleOpenProtectionReport(e) {
e.preventDefault();
window.dataLayer.push({
'event': 'in-page-interaction',
'eAction': 'link click',
'eLabel': 'View your protection report'
event: 'in-page-interaction',
eAction: 'link click',
eLabel: 'View your protection report'
});
Mozilla.UITour.showProtectionReport();
}
@ -18,24 +18,31 @@
function handleOpenProtectionReportLink(e) {
e.preventDefault();
window.dataLayer.push({
'event': 'in-page-interaction',
'eAction': 'link click',
'eLabel': 'See what`s blocked'
event: 'in-page-interaction',
eAction: 'link click',
eLabel: 'See what`s blocked'
});
Mozilla.UITour.showProtectionReport();
}
Mozilla.UITour.ping(function() {
document.querySelectorAll('.protection-report.primary-cta').forEach(
function(button) {
button.addEventListener('click', handleOpenProtectionReport, false);
}
);
document.querySelectorAll('.protection-report:not(.primary-cta)').forEach(
function(button) {
button.addEventListener('click', handleOpenProtectionReportLink, false);
}
);
Mozilla.UITour.ping(function () {
document
.querySelectorAll('.protection-report.primary-cta')
.forEach(function (button) {
button.addEventListener(
'click',
handleOpenProtectionReport,
false
);
});
document
.querySelectorAll('.protection-report:not(.primary-cta)')
.forEach(function (button) {
button.addEventListener(
'click',
handleOpenProtectionReportLink,
false
);
});
});
})(window.Mozilla);

Просмотреть файл

@ -2,15 +2,14 @@
* 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/. */
(function(Mozilla) {
(function (Mozilla) {
'use strict';
Mozilla.Client.getFxaDetails(function(details) {
Mozilla.Client.getFxaDetails(function (details) {
if (details.setup) {
Mozilla.FxaProductButton.init();
} else {
Mozilla.FxaForm.init();
}
});
})(window.Mozilla);

Просмотреть файл

@ -2,10 +2,13 @@
* 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/. */
(function() {
(function () {
'use strict';
if (typeof Mozilla.Client === 'undefined' || typeof Mozilla.UITour === 'undefined') {
if (
typeof Mozilla.Client === 'undefined' ||
typeof Mozilla.UITour === 'undefined'
) {
return;
}
@ -14,18 +17,21 @@
function checkUpToDate() {
// bug 1419573 - only show "Congrats! Youre using the latest version of Firefox." if it's the latest version.
if (client.isFirefoxDesktop) {
client.getFirefoxDetails(function(data) {
client.getFirefoxDetails(function (data) {
if (data.isUpToDate) {
document.querySelector('.c-page-header').classList.add('is-up-to-date');
document
.querySelector('.c-page-header')
.classList.add('is-up-to-date');
} else {
document.querySelector('.c-page-header').classList.add('is-out-of-date');
document
.querySelector('.c-page-header')
.classList.add('is-out-of-date');
}
});
}
}
Mozilla.UITour.ping(function() {
Mozilla.UITour.ping(function () {
checkUpToDate();
});
})();

Просмотреть файл

@ -7,11 +7,10 @@ if (typeof window.Mozilla === 'undefined') {
window.Mozilla = {};
}
(function(Mozilla) {
(function (Mozilla) {
'use strict';
// initialize send to device widget
var form = new Mozilla.SendToDevice();
form.init();
})(window.Mozilla);

Просмотреть файл

@ -6,16 +6,20 @@
/* eslint no-unused-vars: [2, { "varsIgnorePattern": "onYouTubeIframeAPIReady" }] */
// YouTube API hook has to be in global scope
window.onYouTubeIframeAPIReady = function() {
window.onYouTubeIframeAPIReady = function () {
'use strict';
// Play the video only once the API is ready.
if (Mozilla.pipVideoPlay.videoId) {
Mozilla.pipVideoPlay(Mozilla.pipVideoPlay.playerId, Mozilla.pipVideoPlay.videoId, Mozilla.pipVideoPlay.videoTitle);
Mozilla.pipVideoPlay(
Mozilla.pipVideoPlay.playerId,
Mozilla.pipVideoPlay.videoId,
Mozilla.pipVideoPlay.videoTitle
);
}
};
(function() {
(function () {
'use strict';
var src = 'https://www.youtube.com/iframe_api';
@ -28,7 +32,9 @@ window.onYouTubeIframeAPIReady = function() {
}
function isScriptLoaded() {
return document.querySelector('script[src="' + src + '"]') ? true : false;
return document.querySelector('script[src="' + src + '"]')
? true
: false;
}
function playVideo(playerId, videoId, videoTitle) {
@ -38,11 +44,11 @@ window.onYouTubeIframeAPIReady = function() {
videoId: videoId,
playerVars: {
modestbranding: 1, // hide YouTube logo.
rel: 0, // do not show related videos on end.
rel: 0 // do not show related videos on end.
},
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
onReady: onPlayerReady,
onStateChange: onPlayerStateChange
}
});
@ -53,23 +59,23 @@ window.onYouTubeIframeAPIReady = function() {
function onPlayerStateChange(event) {
var state;
switch(event.data) {
case YT.PlayerState.PLAYING:
state = 'video play';
break;
case YT.PlayerState.PAUSED:
state = 'video paused';
break;
case YT.PlayerState.ENDED:
state = 'video complete';
break;
switch (event.data) {
case YT.PlayerState.PLAYING:
state = 'video play';
break;
case YT.PlayerState.PAUSED:
state = 'video paused';
break;
case YT.PlayerState.ENDED:
state = 'video complete';
break;
}
if (state) {
window.dataLayer.push({
'event': 'video-interaction',
'videoTitle': videoTitle,
'interaction': state
event: 'video-interaction',
videoTitle: videoTitle,
interaction: state
});
}
}
@ -88,23 +94,33 @@ window.onYouTubeIframeAPIReady = function() {
var videoLinks = document.querySelectorAll('.js-video-play');
var tryButton = document.getElementById('try-button');
tryButton.addEventListener('click', function(e) {
tryButton.addEventListener('click', function (e) {
Mozilla.pipVideoPlay.playerId = 'player1';
Mozilla.pipVideoPlay.videoId = tryButton.getAttribute('data-id');
Mozilla.pipVideoPlay.videoTitle = tryButton.getAttribute('data-video-title');
Mozilla.pipVideoPlay.videoTitle =
tryButton.getAttribute('data-video-title');
e.preventDefault();
this.setAttribute('disabled', '');
initVideoPlayer(Mozilla.pipVideoPlay.playerId, Mozilla.pipVideoPlay.videoId, Mozilla.pipVideoPlay.videoTitle);
initVideoPlayer(
Mozilla.pipVideoPlay.playerId,
Mozilla.pipVideoPlay.videoId,
Mozilla.pipVideoPlay.videoTitle
);
});
for (var i = 0; i < videoLinks.length; i++) {
videoLinks[i].setAttribute('role', 'button');
videoLinks[i].addEventListener('click', function(e) {
videoLinks[i].addEventListener('click', function (e) {
Mozilla.pipVideoPlay.playerId = this.getAttribute('id');
Mozilla.pipVideoPlay.videoId = this.getAttribute('data-id');
Mozilla.pipVideoPlay.videoTitle = this.getAttribute('data-video-title');
Mozilla.pipVideoPlay.videoTitle =
this.getAttribute('data-video-title');
e.preventDefault();
initVideoPlayer(Mozilla.pipVideoPlay.playerId, Mozilla.pipVideoPlay.videoId, Mozilla.pipVideoPlay.videoTitle);
initVideoPlayer(
Mozilla.pipVideoPlay.playerId,
Mozilla.pipVideoPlay.videoId,
Mozilla.pipVideoPlay.videoTitle
);
});
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше