зеркало из https://github.com/mozilla/bedrock.git
Родитель
2ef16dc299
Коммит
7305098445
69
.eslintrc.js
69
.eslintrc.js
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"trailingComma": "none",
|
||||
"tabWidth": 4,
|
||||
"semi": true,
|
||||
"singleQuote": true
|
||||
}
|
79
.stylelintrc
79
.stylelintrc
|
@ -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
|
||||
|
||||
|
|
7
Makefile
7
Makefile
|
@ -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! You’re 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
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче