зеркало из https://github.com/mozilla/bedrock.git
Add Babel as a transpiling option for JS bundles (Fixes #10467)
This commit is contained in:
Родитель
89fd76c83b
Коммит
6f93237cdb
28
.eslintrc.js
28
.eslintrc.js
|
@ -4,7 +4,6 @@ module.exports = {
|
|||
'commonjs': true
|
||||
},
|
||||
extends: [
|
||||
'@mozilla-protocol/eslint-config',
|
||||
'plugin:json/recommended'
|
||||
],
|
||||
/**
|
||||
|
@ -12,18 +11,27 @@ module.exports = {
|
|||
* */
|
||||
overrides: [
|
||||
{
|
||||
// JS files transpiled by Babel
|
||||
files: [
|
||||
'media/js/firefox/welcome/**/*.js',
|
||||
'media/js/firefox/whatsnew/**/*.js'
|
||||
'media/js/**/*.es6.js',
|
||||
],
|
||||
env: {
|
||||
'es6': true
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaVersion: 8
|
||||
'es2017': true
|
||||
}
|
||||
},
|
||||
{
|
||||
// JS files served only to Firefox browsers.
|
||||
files: [
|
||||
'media/js/firefox/welcome/**/*.js',
|
||||
'media/js/firefox/whatsnew/**/*.js',
|
||||
'media/js/firefox/firstrun/**/*.js',
|
||||
],
|
||||
env: {
|
||||
'es2017': true
|
||||
}
|
||||
},
|
||||
{
|
||||
// JS build files for local dev.
|
||||
files: [
|
||||
'webpack.config.js',
|
||||
'webpack.static.config.js',
|
||||
|
@ -31,10 +39,7 @@ module.exports = {
|
|||
],
|
||||
env: {
|
||||
'node': true,
|
||||
'es6': true
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaVersion: 8
|
||||
'es2017': true
|
||||
},
|
||||
rules: {
|
||||
'strict': ['error', 'global'],
|
||||
|
@ -43,6 +48,7 @@ module.exports = {
|
|||
],
|
||||
globals: {
|
||||
'Mozilla': 'writable',
|
||||
'Mzp': 'writable',
|
||||
'site': 'writable'
|
||||
}
|
||||
};
|
||||
|
|
170
docs/coding.rst
170
docs/coding.rst
|
@ -101,6 +101,42 @@ Once you define a bundle in ``static-bundles.json``, the ``webpack.config.js``
|
|||
file will use these as entrypoints for compiling JS and CSS and watching for
|
||||
changes.
|
||||
|
||||
Writing JavaScript
|
||||
------------------
|
||||
|
||||
Bedrock's Webpack configuration supports some different options for writing
|
||||
JavaScript:
|
||||
|
||||
Default configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Write `example-script.js` using ES5 syntax and features. Webpack will bundle
|
||||
the JS as-is, without any additional pre-processing.
|
||||
|
||||
Babel configuration
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Write `example-script.es6.js` using ES2015+ syntax. Webpack will transpile
|
||||
the code to ES5 using `Babel <https://babeljs.io/>`_. This is useful when
|
||||
you want to write modern syntax but still support older browsers.
|
||||
|
||||
.. important::
|
||||
|
||||
Whilst Babel will transpile most modern JS syntax to ES5 when suitable
|
||||
fallbacks exist, it won't automatically include custom polyfills for
|
||||
everything since these can start to greatly increase bundle size. If you
|
||||
want to use ``Promise`` or ``async/await`` functions for example, then
|
||||
you will need to load polyfills for those. This can be done either at
|
||||
the page level, or globally in ``lib.js`` if it's something that multiple
|
||||
pages would benefit from. But please pick and choose wisely, and be
|
||||
concious of performance.
|
||||
|
||||
For pages that are served to Firefox browsers only, such as ``/whatsnew``, it is
|
||||
also possible to write native ES2015+ syntax and serve that directly in production.
|
||||
Here there is no need to include the `.es6.js` file extension. Instead, you can
|
||||
simply use `.js` instead. The rules that which files you can do this in are defined
|
||||
in our `ESLint config <https://github.com/mozilla/bedrock/blob/master/.eslintrc.js>`_.
|
||||
|
||||
Writing URL Patterns
|
||||
--------------------
|
||||
|
||||
|
@ -526,7 +562,7 @@ Picto
|
|||
- title
|
||||
String indicating heading text (usually a translation id wrapped in ftl function)
|
||||
|
||||
Default: None
|
||||
Default: None
|
||||
|
||||
Example: ``title=ftl('misinformation-why-trust-firefox')``
|
||||
|
||||
|
@ -565,14 +601,14 @@ Picto
|
|||
|
||||
Example: ``class='trust'``
|
||||
|
||||
- image_width
|
||||
- image_width
|
||||
Number indicating width of image.
|
||||
|
||||
Default: 64
|
||||
|
||||
Example: ``image_width='153px'``
|
||||
|
||||
- include_highres_image
|
||||
- include_highres_image
|
||||
Boolean that determines whether the image can also appear in high res.
|
||||
|
||||
Default: False
|
||||
|
@ -609,30 +645,30 @@ Call out
|
|||
- desc
|
||||
String indicating paragraph text (usually a translation id wrapped in ftl function).
|
||||
|
||||
Default: None
|
||||
Default: None
|
||||
|
||||
Example: ``desc=ftl('firefox-channel-test-beta-versions-of-firefox-ios')``
|
||||
|
||||
- class
|
||||
String adding class(es) to the section tag.
|
||||
|
||||
Default: None
|
||||
Default: None
|
||||
|
||||
Example: ``class='mzp-t-firefox ' + product_class``
|
||||
Example: ``class='mzp-t-firefox ' + product_class``
|
||||
|
||||
- include_cta
|
||||
- include_cta
|
||||
Boolean indicating whether or not to include the body of the macro call (usually a mix of text and html).
|
||||
|
||||
Default: None
|
||||
Default: None
|
||||
|
||||
Example: ``include_cta=True``
|
||||
Example: ``include_cta=True``
|
||||
|
||||
- heading_level
|
||||
Number indicating heading level for title text. Should be based on semantic meaning, not presentational styling.
|
||||
|
||||
Default: 2
|
||||
|
||||
Example: ``heading_level=1``
|
||||
Example: ``heading_level=1``
|
||||
|
||||
|
||||
Split
|
||||
|
@ -641,7 +677,7 @@ Split
|
|||
- block_id
|
||||
String providing id to the section tag (usually if it needs to be used as an in-page link).
|
||||
|
||||
Default: None
|
||||
Default: None
|
||||
|
||||
Example: ``id='nextgen``
|
||||
|
||||
|
@ -655,35 +691,35 @@ Split
|
|||
- block_class
|
||||
String providing class(es) to the section tag.
|
||||
|
||||
Default: None
|
||||
Default: None
|
||||
|
||||
Example: ``block_class='mzp-l-split-reversed mzp-l-split-center-on-sm-md``
|
||||
|
||||
- theme_class
|
||||
String providing theme class(es) to a container div tag inside the section.
|
||||
|
||||
Default: None
|
||||
Default: None
|
||||
|
||||
Example: ``theme_class='mzp-t-dark'``
|
||||
Example: ``theme_class='mzp-t-dark'``
|
||||
|
||||
- body_class
|
||||
String providing class(es) to the body (text content) div inside the section.
|
||||
|
||||
Default: None
|
||||
Default: None
|
||||
|
||||
Example: ``Not currently in use``
|
||||
Example: ``Not currently in use``
|
||||
|
||||
- image_url
|
||||
Path to image location.
|
||||
|
||||
Default: None
|
||||
Default: None
|
||||
|
||||
Example: ``image_url=’img/firefox/accounts/trailhead/value-respect.jpg’``
|
||||
Example: ``image_url=’img/firefox/accounts/trailhead/value-respect.jpg’``
|
||||
|
||||
- media_class
|
||||
String providing class(es) to the media div inside the section.
|
||||
|
||||
Default: None
|
||||
Default: None
|
||||
|
||||
Example: ``media_class='mzp-l-split-h-center'``
|
||||
|
||||
|
@ -692,35 +728,35 @@ Split
|
|||
|
||||
Default: False
|
||||
|
||||
Example: ``include_highres_image=True``
|
||||
Example: ``include_highres_image=True``
|
||||
|
||||
- l10n_image
|
||||
- l10n_image
|
||||
Boolean to indicate if image has translatable text.
|
||||
|
||||
Default: False
|
||||
|
||||
Example: ``l10n_image=True``
|
||||
Example: ``l10n_image=True``
|
||||
|
||||
- image_alt
|
||||
String providing alt text to the image.
|
||||
|
||||
Default: ''
|
||||
Default: ''
|
||||
|
||||
Example: ``Not currently in use``
|
||||
Example: ``Not currently in use``
|
||||
|
||||
- media_after
|
||||
- media_after
|
||||
Boolean to determine if image appears before or after text when stacked on mobile size screens.
|
||||
|
||||
Default: False
|
||||
|
||||
Example: ``media_after=True``
|
||||
Example: ``media_after=True``
|
||||
|
||||
- media_include
|
||||
Path to video media.
|
||||
|
||||
Default: None
|
||||
Default: None
|
||||
|
||||
Example: ``media_include='firefox/facebookcontainer/includes/video.html'``
|
||||
Example: ``media_include='firefox/facebookcontainer/includes/video.html'``
|
||||
|
||||
|
||||
Billboard
|
||||
|
@ -731,63 +767,63 @@ Billboard
|
|||
|
||||
Default: N/A
|
||||
|
||||
Example: ``title=ftl('about-the-mozilla-manifesto')``
|
||||
Example: ``title=ftl('about-the-mozilla-manifesto')``
|
||||
|
||||
- ga_title
|
||||
**Required**. String providing value for data-link-name attribute on cta.
|
||||
|
||||
Default: N/A
|
||||
|
||||
Example: ``ga_title='The Mozilla Manifesto'``
|
||||
Example: ``ga_title='The Mozilla Manifesto'``
|
||||
|
||||
- desc
|
||||
- desc
|
||||
**Required**.String indicating paragraph text (usually a translation id wrapped in ftl function).
|
||||
|
||||
Default: N/A
|
||||
|
||||
Example: ``desc=ftl('about-the-principles-we-wrote-in')``
|
||||
Example: ``desc=ftl('about-the-principles-we-wrote-in')``
|
||||
|
||||
- link_cta
|
||||
**Required**. String indicating link text (usually a translation id wrapped in an ftl function).
|
||||
**Required**. String indicating link text (usually a translation id wrapped in an ftl function).
|
||||
|
||||
Default: N/A
|
||||
|
||||
Example: ``link_cta=ftl('about-read-the-manifesto')``
|
||||
|
||||
- link_url
|
||||
**Required**. String or url helper function provides href value for cta link.
|
||||
**Required**. String or url helper function provides href value for cta link.
|
||||
|
||||
Default: N/A
|
||||
|
||||
Example: ``link_url=url('mozorg.about.manifesto')``
|
||||
Example: ``link_url=url('mozorg.about.manifesto')``
|
||||
|
||||
- image_url
|
||||
- image_url
|
||||
**Required**. Path to image location.
|
||||
|
||||
Default: N/A
|
||||
|
||||
Example: ``image_url='img/home/2018/billboard-healthy-internet.png'``
|
||||
Example: ``image_url='img/home/2018/billboard-healthy-internet.png'``
|
||||
|
||||
- include_highres_image
|
||||
- include_highres_image
|
||||
Boolean that determines whether the image can also appear in high res.
|
||||
|
||||
Default: False
|
||||
|
||||
Example: ``include_highres_image=True``
|
||||
Example: ``include_highres_image=True``
|
||||
|
||||
- reverse
|
||||
Uses default layout: mzp-l-billboard-rightReverse will switch to billboard (text) left.
|
||||
- reverse
|
||||
Uses default layout: mzp-l-billboard-rightReverse will switch to billboard (text) left.
|
||||
|
||||
Default: False
|
||||
|
||||
Example: ``reverse=True``
|
||||
Example: ``reverse=True``
|
||||
|
||||
- heading_level
|
||||
- heading_level
|
||||
Number indicating heading level for title text. Should be based on semantic meaning, not presentational styling.
|
||||
|
||||
Default: 2
|
||||
Default: 2
|
||||
|
||||
Example: ``heading_level=1``
|
||||
Example: ``heading_level=1``
|
||||
|
||||
|
||||
Feature Card
|
||||
|
@ -800,7 +836,7 @@ Feature Card
|
|||
|
||||
Example: ``title=ftl('firefox-home-firefox-browser')``
|
||||
|
||||
- ga_title
|
||||
- ga_title
|
||||
String used as an identifying name on a link for google analytics. Only used if link_url and link_cta are provided as well.
|
||||
|
||||
Default: None
|
||||
|
@ -812,21 +848,21 @@ Feature Card
|
|||
|
||||
Default: N/A
|
||||
|
||||
Example: ``image_url=’img/firefox/accounts/trailhead/value-respect.jpg’``
|
||||
Example: ``image_url=’img/firefox/accounts/trailhead/value-respect.jpg’``
|
||||
|
||||
- class
|
||||
String adding class(es) to the section tag.
|
||||
|
||||
Default: None
|
||||
|
||||
Example: ``class=’mzp-l-card-feature-left-half t-mozvpn’``
|
||||
Example: ``class=’mzp-l-card-feature-left-half t-mozvpn’``
|
||||
|
||||
- link_url
|
||||
String or url helper function provides href value for cta link. Only used if link_cta is provided as well.
|
||||
|
||||
Default: None
|
||||
|
||||
Example: ``link_url=url('firefox.privacy.index')``
|
||||
Example: ``link_url=url('firefox.privacy.index')``
|
||||
|
||||
- link_cta
|
||||
String indicating link text (usually a translation id wrapped in an ftl function). Only used if link_url is provided as well.
|
||||
|
@ -840,35 +876,35 @@ Feature Card
|
|||
|
||||
Default: False
|
||||
|
||||
Example: ``include_highres_image=True``
|
||||
Example: ``include_highres_image=True``
|
||||
|
||||
- l10n_image
|
||||
- l10n_image
|
||||
Boolean to indicate if image has translatable text.
|
||||
|
||||
Default: False
|
||||
|
||||
Example: ``l10n_image=True``
|
||||
Example: ``l10n_image=True``
|
||||
|
||||
- aspect_ratio
|
||||
aspect_ratio String with an mzp class name indicating desired aspect ratio (adds class to section tag).
|
||||
|
||||
Default: False
|
||||
|
||||
Example: ``aspect_ratio='mzp-has-aspect-3-2'``
|
||||
Example: ``aspect_ratio='mzp-has-aspect-3-2'``
|
||||
|
||||
- heading_level
|
||||
- heading_level
|
||||
Number indicating heading level for title text. Should be based on semantic meaning, not presentational styling.
|
||||
|
||||
Default: 2
|
||||
|
||||
Example: ``heading_level=3``
|
||||
Example: ``heading_level=3``
|
||||
|
||||
- media_after
|
||||
- media_after
|
||||
Boolean to determine if image appears before or after text when stacked on mobile size screens.
|
||||
|
||||
Default: False
|
||||
|
||||
Example: ``media_after=True``
|
||||
Example: ``media_after=True``
|
||||
|
||||
|
||||
Card
|
||||
|
@ -888,7 +924,7 @@ Card
|
|||
|
||||
Example: ``title=ftl('about-the-mozilla-manifesto')``
|
||||
|
||||
- ga_title
|
||||
- ga_title
|
||||
**Required**. String providing value for data-link-name attribute on cta.
|
||||
|
||||
Default: N/A
|
||||
|
@ -900,23 +936,23 @@ Card
|
|||
|
||||
Default: N/A
|
||||
|
||||
Example: ``desc=ftl('about-the-principles-we-wrote-in')``
|
||||
Example: ``desc=ftl('about-the-principles-we-wrote-in')``
|
||||
|
||||
- aspect_ratio
|
||||
String indicating size/aspect ratio of the card (make sure to have it even if it’s in a defined Card Layout.
|
||||
String indicating size/aspect ratio of the card (make sure to have it even if it’s in a defined Card Layout.
|
||||
|
||||
Default: N/A
|
||||
|
||||
Example: ``aspect_ratio=’mzp-has-aspect-16-9’``
|
||||
Example: ``aspect_ratio=’mzp-has-aspect-16-9’``
|
||||
|
||||
- link_url
|
||||
**Required**. String or url helper function provides href value for cta link.
|
||||
|
||||
Default: N/A
|
||||
|
||||
Example: ``link_url=url('mozorg.about.manifesto')``
|
||||
Example: ``link_url=url('mozorg.about.manifesto')``
|
||||
|
||||
- image_url
|
||||
- image_url
|
||||
**Required**. Path to image location.
|
||||
|
||||
Default: N/A
|
||||
|
@ -928,18 +964,18 @@ Card
|
|||
|
||||
Default: N/A
|
||||
|
||||
Example: ``include_highres_image=True``
|
||||
Example: ``include_highres_image=True``
|
||||
|
||||
- l10n_image
|
||||
- l10n_image
|
||||
Boolean to indicate if image has translatable text.
|
||||
|
||||
Default: False
|
||||
|
||||
Example: ``l10n_image=True``
|
||||
Example: ``l10n_image=True``
|
||||
|
||||
- heading_level
|
||||
Number indicating heading level for title text. Should be based on semantic meaning, not presentational styling.
|
||||
|
||||
Default: 3
|
||||
|
||||
Example: ``heading_level=2``
|
||||
Example: ``heading_level=2``
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
/* 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/. */
|
||||
|
||||
'use strict';
|
||||
|
||||
// Lazyload images
|
||||
window.Mozilla.LazyLoad.init();
|
||||
|
||||
const modalContainers = document.getElementsByClassName('has-modal');
|
||||
const content = document.querySelector('.mzp-u-modal-content');
|
||||
const articleArray = document.querySelectorAll('[data-modal-id]');
|
||||
|
||||
const modalNextButtonFragment =
|
||||
`<div class="c-modal-next">
|
||||
<button type="button" class="c-modal-button-next" title="Next">
|
||||
Next
|
||||
</button>
|
||||
</div>`;
|
||||
|
||||
const modalPrevButtonFragment =
|
||||
`<div class="c-modal-prev">
|
||||
<button type="button" class="c-modal-button-prev" title="Previous">
|
||||
Previous
|
||||
</button>
|
||||
</div>`;
|
||||
|
||||
// Set to true when a listener it set, as to not set it multiple times.
|
||||
// Resets when the modal is closed.
|
||||
let kbInit = null;
|
||||
|
||||
function keyboardListenerInit() {
|
||||
|
||||
if (kbInit) {
|
||||
return;
|
||||
// Turn Off
|
||||
}
|
||||
|
||||
document.addEventListener('keyup', keyboardNextPrev, false);
|
||||
kbInit = true;
|
||||
}
|
||||
|
||||
function keyboardNextPrev(event) {
|
||||
if (!kbInit) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.keyCode) {
|
||||
case 37: // Left arrow
|
||||
prevModalArticle();
|
||||
break;
|
||||
case 38: // Up arrow
|
||||
prevModalArticle();
|
||||
break;
|
||||
case 39: // Right arrow
|
||||
nextModalArticle();
|
||||
break;
|
||||
case 40: // Down arrow
|
||||
nextModalArticle();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function modalInit() {
|
||||
// Lazy load images in the modal
|
||||
const modalImage = document.querySelector('.mzp-c-modal-overlay-contents .mzp-c-card-image');
|
||||
|
||||
if (modalImage) {
|
||||
const srcset = modalImage.getAttribute('data-srcset');
|
||||
|
||||
if (srcset) {
|
||||
modalImage.srcset = srcset;
|
||||
}
|
||||
|
||||
modalImage.src = modalImage.getAttribute('data-src');
|
||||
modalImage.removeAttribute('data-src');
|
||||
modalImage.removeAttribute('data-srcset');
|
||||
}
|
||||
|
||||
const modalNextButton = document.querySelector('.c-modal-next');
|
||||
const modalPrevButton = document.querySelector('.c-modal-prev');
|
||||
|
||||
modalNextButton.removeEventListener('click', nextModalArticle, false);
|
||||
modalPrevButton.removeEventListener('click', prevModalArticle, false);
|
||||
|
||||
modalNextButton.addEventListener('click', nextModalArticle, false);
|
||||
modalPrevButton.addEventListener('click', prevModalArticle, false);
|
||||
|
||||
keyboardListenerInit();
|
||||
}
|
||||
|
||||
function getCurrentModalIndex() {
|
||||
const modalContent = document.querySelector('.mzp-u-modal-content.mzp-c-modal-overlay-contents');
|
||||
const newArticleIndex = parseInt(modalContent.getAttribute('data-current-index'), 10);
|
||||
return newArticleIndex;
|
||||
}
|
||||
|
||||
function updateModalArticle(index) {
|
||||
const modalContent = document.querySelector('.mzp-u-modal-content.mzp-c-modal-overlay-contents');
|
||||
let newArticleId = articleArray[index].getAttribute('data-modal-id');
|
||||
const newModalContent = document.querySelector(`[data-modal-parent="${newArticleId}"]`).cloneNode(true);
|
||||
const currentModalContent = modalContent.firstElementChild;
|
||||
|
||||
window.location.hash = newArticleId;
|
||||
|
||||
modalContent.replaceChild(newModalContent, currentModalContent);
|
||||
modalContent.setAttribute('data-current-index', index);
|
||||
|
||||
modalInit();
|
||||
}
|
||||
|
||||
function nextModalArticle() {
|
||||
let newArticleIndex = getCurrentModalIndex();
|
||||
newArticleIndex++;
|
||||
|
||||
// If at the end of the gallery, start over
|
||||
if (newArticleIndex === (articleArray.length)) {
|
||||
newArticleIndex = 0;
|
||||
}
|
||||
|
||||
updateModalArticle(newArticleIndex);
|
||||
}
|
||||
|
||||
function prevModalArticle() {
|
||||
let newArticleIndex = getCurrentModalIndex();
|
||||
newArticleIndex--;
|
||||
|
||||
// If at the beginning of the gallery, start over
|
||||
if (newArticleIndex < 0) {
|
||||
newArticleIndex = articleArray.length - 1;
|
||||
}
|
||||
|
||||
updateModalArticle(newArticleIndex);
|
||||
}
|
||||
|
||||
for (let i = 0; i < modalContainers.length; i++) {
|
||||
const modalContainer = modalContainers[i];
|
||||
|
||||
modalContainer.setAttribute('aria-role', 'button');
|
||||
modalContainer.setAttribute('data-current-index', i);
|
||||
|
||||
modalContainer.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const modalId = this.getAttribute('data-modal-id');
|
||||
const currentIndex = parseInt(this.getAttribute('data-current-index'), 10);
|
||||
const modalContent = document.querySelector(`[data-modal-parent="${modalId}"]`).cloneNode(true);
|
||||
window.location.hash = modalId;
|
||||
|
||||
modalContent.removeAttribute('id');
|
||||
modalContent.setAttribute('aria-role', 'article');
|
||||
|
||||
window.Mzp.Modal.createModal(this, content, {
|
||||
allowScroll: false,
|
||||
closeText: window.Mozilla.Utils.trans('global-close'),
|
||||
onCreate: () => {
|
||||
content.appendChild(modalContent);
|
||||
|
||||
content.setAttribute('data-current-index', currentIndex);
|
||||
|
||||
const modalCloseButton = document.querySelector('.mzp-c-modal-close');
|
||||
modalCloseButton.insertAdjacentHTML('beforebegin', modalNextButtonFragment);
|
||||
modalCloseButton.insertAdjacentHTML('beforebegin', modalPrevButtonFragment);
|
||||
|
||||
// Lazy load images in the modal and set next/prev listeners
|
||||
modalInit();
|
||||
},
|
||||
onDestroy: () => {
|
||||
if (window.history) {
|
||||
window.history.replaceState('', '', window.location.pathname);
|
||||
}
|
||||
|
||||
kbInit = false;
|
||||
|
||||
// Recache the current modal content which may have changed via next/prev buttons
|
||||
const modalParent = document.querySelector('.mzp-u-modal-content.mzp-c-modal-overlay-contents');
|
||||
const currentModalContent = modalParent.firstElementChild;
|
||||
|
||||
modalParent.removeChild(currentModalContent);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// trigger modal on page load if hash is present and matches a person with a bio
|
||||
if (window.location.hash) {
|
||||
const target = document.getElementById(window.location.hash.substr(1));
|
||||
|
||||
if (target && target.classList.contains('has-modal')) {
|
||||
target.click();
|
||||
}
|
||||
}
|
|
@ -1,206 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
// create namespace
|
||||
if (typeof window.Mozilla === 'undefined') {
|
||||
window.Mozilla = {};
|
||||
}
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// Lazyload images
|
||||
Mozilla.LazyLoad.init();
|
||||
|
||||
var modalContainers = document.getElementsByClassName('has-modal');
|
||||
var content = document.querySelector('.mzp-u-modal-content');
|
||||
|
||||
var modalNextButtonFragment =
|
||||
'<div class="c-modal-next">' +
|
||||
' <button type="button" class="c-modal-button-next" title="Next">' +
|
||||
' Next' +
|
||||
' </button>' +
|
||||
'</div>';
|
||||
|
||||
var modalPrevButtonFragment =
|
||||
'<div class="c-modal-prev">' +
|
||||
' <button type="button" class="c-modal-button-prev" title="Previous">' +
|
||||
' Previous' +
|
||||
' </button>' +
|
||||
'</div>';
|
||||
|
||||
var articleArray = document.querySelectorAll('[data-modal-id]');
|
||||
|
||||
// Set to true when a listener it set, as to not set it multiple times.
|
||||
// Resets when the modal is closed.
|
||||
var kbInit = null;
|
||||
|
||||
function keyboardListenerInit() {
|
||||
|
||||
if (kbInit) {
|
||||
return;
|
||||
// Turn Off
|
||||
}
|
||||
|
||||
document.addEventListener('keyup', keyboardNextPrev, false);
|
||||
|
||||
|
||||
kbInit = true;
|
||||
}
|
||||
|
||||
function keyboardNextPrev(event) {
|
||||
if (!kbInit) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.keyCode) {
|
||||
case 37: // Left arrow
|
||||
prevModalArticle();
|
||||
break;
|
||||
case 38: // Up arrow
|
||||
prevModalArticle();
|
||||
break;
|
||||
case 39: // Right arrow
|
||||
nextModalArticle();
|
||||
break;
|
||||
case 40: // Down arrow
|
||||
nextModalArticle();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function modalInit() {
|
||||
// Lazy load images in the modal
|
||||
var modalImage = document.querySelector('.mzp-c-modal-overlay-contents .mzp-c-card-image');
|
||||
|
||||
if (modalImage) {
|
||||
var srcset = modalImage.getAttribute('data-srcset');
|
||||
|
||||
if (srcset) {
|
||||
modalImage.srcset = srcset;
|
||||
}
|
||||
|
||||
modalImage.src = modalImage.getAttribute('data-src');
|
||||
modalImage.removeAttribute('data-src');
|
||||
modalImage.removeAttribute('data-srcset');
|
||||
}
|
||||
|
||||
var modalNextButton = document.querySelector('.c-modal-next');
|
||||
var modalPrevButton = document.querySelector('.c-modal-prev');
|
||||
|
||||
modalNextButton.removeEventListener('click', nextModalArticle, false);
|
||||
modalPrevButton.removeEventListener('click', prevModalArticle, false);
|
||||
|
||||
modalNextButton.addEventListener('click', nextModalArticle, false);
|
||||
modalPrevButton.addEventListener('click', prevModalArticle, false);
|
||||
|
||||
keyboardListenerInit();
|
||||
|
||||
}
|
||||
|
||||
function getCurrentModalIndex(){
|
||||
var modalContent = document.querySelector('.mzp-u-modal-content.mzp-c-modal-overlay-contents');
|
||||
var newArticleIndex = parseInt(modalContent.dataset.currentIndex, 10);
|
||||
return newArticleIndex;
|
||||
}
|
||||
|
||||
function updateModalArticle(index) {
|
||||
var modalContent = document.querySelector('.mzp-u-modal-content.mzp-c-modal-overlay-contents');
|
||||
var newArticleId = newArticleId = articleArray[index].dataset.modalId;
|
||||
var newModalContent = document.querySelector('[data-modal-parent="' + newArticleId + '"]').cloneNode(true);
|
||||
var currentModalContent = modalContent.firstElementChild;
|
||||
|
||||
window.location.hash = newArticleId;
|
||||
|
||||
modalContent.replaceChild(newModalContent, currentModalContent);
|
||||
modalContent.dataset.currentIndex = index;
|
||||
|
||||
modalInit();
|
||||
}
|
||||
|
||||
function nextModalArticle() {
|
||||
var newArticleIndex = getCurrentModalIndex();
|
||||
newArticleIndex++;
|
||||
|
||||
// If at the end of the gallery, start over
|
||||
if (newArticleIndex === (articleArray.length)) {
|
||||
newArticleIndex = 0;
|
||||
}
|
||||
|
||||
updateModalArticle(newArticleIndex);
|
||||
}
|
||||
|
||||
function prevModalArticle() {
|
||||
var newArticleIndex = getCurrentModalIndex();
|
||||
newArticleIndex--;
|
||||
|
||||
// If at the beginning of the gallery, start over
|
||||
if (newArticleIndex < 0) {
|
||||
newArticleIndex = articleArray.length - 1;
|
||||
}
|
||||
|
||||
updateModalArticle(newArticleIndex);
|
||||
}
|
||||
|
||||
for (var i = 0; i < modalContainers.length; i++) {
|
||||
var modalContainer = modalContainers[i];
|
||||
modalContainer.setAttribute('aria-role', 'button');
|
||||
|
||||
modalContainer.dataset.currentIndex = i;
|
||||
|
||||
modalContainer.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var modalId = this.dataset.modalId;
|
||||
var currentIndex = parseInt(this.dataset.currentIndex, 10);
|
||||
var modalContent = document.querySelector('[data-modal-parent="' + modalId + '"]').cloneNode(true);
|
||||
window.location.hash = modalId;
|
||||
|
||||
modalContent.removeAttribute('id');
|
||||
modalContent.setAttribute('aria-role', 'article');
|
||||
|
||||
Mzp.Modal.createModal(this, content, {
|
||||
allowScroll: false,
|
||||
closeText: window.Mozilla.Utils.trans('global-close'),
|
||||
onCreate: function() {
|
||||
content.appendChild(modalContent);
|
||||
|
||||
content.dataset.currentIndex = currentIndex;
|
||||
|
||||
var modalCloseButton = document.querySelector('.mzp-c-modal-close');
|
||||
modalCloseButton.insertAdjacentHTML('beforebegin', modalNextButtonFragment);
|
||||
modalCloseButton.insertAdjacentHTML('beforebegin', modalPrevButtonFragment);
|
||||
|
||||
// Lazy load images in the modal and set next/prev listeners
|
||||
modalInit();
|
||||
|
||||
},
|
||||
onDestroy: function() {
|
||||
if (window.history) {
|
||||
window.history.replaceState('', '', window.location.pathname);
|
||||
}
|
||||
|
||||
kbInit = false;
|
||||
|
||||
// Recache the current modal content which may have changed via next/prev buttons
|
||||
var modalParent = document.querySelector('.mzp-u-modal-content.mzp-c-modal-overlay-contents');
|
||||
var currentModalContent = modalParent.firstElementChild;
|
||||
|
||||
modalParent.removeChild(currentModalContent);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// trigger modal on page load if hash is present and matches a person with a bio
|
||||
if (window.location.hash) {
|
||||
var target = document.getElementById(window.location.hash.substr(1));
|
||||
|
||||
if (target && target.classList.contains('has-modal')) {
|
||||
target.click();
|
||||
}
|
||||
}
|
||||
|
||||
})(window.Mozilla);
|
|
@ -1555,7 +1555,7 @@
|
|||
"files": [
|
||||
"protocol/js/protocol-modal.js",
|
||||
"js/base/mozilla-lazy-load.js",
|
||||
"js/foundation/annual-report-2019.js"
|
||||
"js/foundation/annual-report-2019.es6.js"
|
||||
],
|
||||
"name": "annual_report_2019"
|
||||
},
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
"description": "Making mozilla.org awesome, one pebble at a time",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.15.5",
|
||||
"@babel/preset-env": "^7.15.6",
|
||||
"@mozilla-protocol/core": "14.0.3",
|
||||
"@mozilla-protocol/eslint-config": "^1.1.0",
|
||||
"@sentry/browser": "^6.12.0",
|
||||
"babel-loader": "^8.2.2",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"copy-webpack-plugin": "9.0.1",
|
||||
"css-loader": "6.2.0",
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
var webpackConfig = require('../../webpack.config');
|
||||
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
// Karma configuration
|
||||
|
@ -82,7 +80,29 @@ module.exports = function(config) {
|
|||
},
|
||||
|
||||
webpack: {
|
||||
devtool: 'inline-source-map'
|
||||
devtool: 'inline-source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.es6\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env', {
|
||||
targets: {
|
||||
ie: '10'
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
proxies: {
|
||||
|
|
|
@ -51,6 +51,28 @@ const jsConfig = {
|
|||
path: path.resolve(__dirname, 'assets/'),
|
||||
publicPath: '/media/',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.es6\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env', {
|
||||
targets: {
|
||||
ie: '10'
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
watchOptions: {
|
||||
aggregateTimeout: 600,
|
||||
ignored: './node_modules/'
|
||||
|
|
1064
yarn.lock
1064
yarn.lock
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче