@pernod-ricard-global-cms/jsutils 1.5.21 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +19 -0
- package/jsutils.js +235 -181
- package/package.json +28 -27
package/.prettierrc
ADDED
package/jsutils.js
CHANGED
|
@@ -2,47 +2,50 @@
|
|
|
2
2
|
/* eslint-disable no-console */
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* This function accepts an html element and returns the position of that element on the page.
|
|
6
|
-
*
|
|
5
|
+
* This function accepts an html element and returns the position of that element on the page.
|
|
6
|
+
*
|
|
7
7
|
* @param {htmlElement} element The element whose position you want to get.
|
|
8
8
|
* @returns {object} An object with the x and y pixel values.
|
|
9
9
|
*/
|
|
10
|
-
export function getPosition(
|
|
10
|
+
export function getPosition(element) {
|
|
11
11
|
const scrollElementTag = document.scrollingElement.tagName;
|
|
12
12
|
let xPosition = 0;
|
|
13
13
|
let yPosition = 0;
|
|
14
|
-
while (
|
|
15
|
-
xPosition +=
|
|
16
|
-
element.offsetLeft - element.scrollLeft + element.clientLeft;
|
|
14
|
+
while (element) {
|
|
15
|
+
xPosition += element.offsetLeft - element.scrollLeft + element.clientLeft;
|
|
17
16
|
yPosition += element.offsetTop - element.scrollTop + element.clientTop;
|
|
18
17
|
element = element.offsetParent;
|
|
19
18
|
}
|
|
20
19
|
// Quirks mode safety - in case of missing DOCTYPE
|
|
21
|
-
if (
|
|
22
|
-
yPosition += document.querySelector(
|
|
20
|
+
if (scrollElementTag === 'BODY') {
|
|
21
|
+
yPosition += document.querySelector('body').scrollTop;
|
|
23
22
|
}
|
|
24
23
|
return { x: xPosition, y: yPosition };
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
/**
|
|
28
|
-
* Adds or removes a 'valid' class to an input and button element depending on whether the value of the input is valid.
|
|
27
|
+
* Adds or removes a 'valid' class to an input and button element depending on whether the value of the input is valid.
|
|
29
28
|
* @param {htmlElement} input The input element to check.
|
|
30
|
-
* @param {htmlElement} button A corresponding button to disable if invalid.
|
|
29
|
+
* @param {htmlElement} button A corresponding button to disable if invalid.
|
|
31
30
|
*/
|
|
32
|
-
export function toggleClassByValidity(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (
|
|
36
|
-
button.classList.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
input.classList.
|
|
31
|
+
export function toggleClassByValidity(input, button) {
|
|
32
|
+
try {
|
|
33
|
+
input.addEventListener('input', () => {
|
|
34
|
+
if (input.validity.valid && input.value) {
|
|
35
|
+
if (!button.classList.contains('valid')) {
|
|
36
|
+
button.classList.add('valid');
|
|
37
|
+
}
|
|
38
|
+
if (!input.classList.contains('valid')) {
|
|
39
|
+
input.classList.add('valid');
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
button.classList.remove('valid');
|
|
43
|
+
input.classList.remove('valid');
|
|
40
44
|
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
} );
|
|
45
|
+
});
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.error('jsutils.js ~ toggleClassByValidity ~ error', error);
|
|
48
|
+
}
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
/**
|
|
@@ -51,10 +54,13 @@ export function toggleClassByValidity( input, button ) {
|
|
|
51
54
|
* @param {string} assetKey The assetkey string of the block.
|
|
52
55
|
* @returns {boolean}
|
|
53
56
|
*/
|
|
54
|
-
export function inCriticalCssConfig(
|
|
57
|
+
export function inCriticalCssConfig(assetKey) {
|
|
58
|
+
if (!globalThis.criticalConfig) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
55
61
|
if (
|
|
56
62
|
globalThis.criticalConfig &&
|
|
57
|
-
globalThis.criticalConfig.indexOf(
|
|
63
|
+
globalThis.criticalConfig.indexOf(assetKey) === -1
|
|
58
64
|
) {
|
|
59
65
|
return false;
|
|
60
66
|
}
|
|
@@ -67,16 +73,16 @@ export function inCriticalCssConfig( assetKey ) {
|
|
|
67
73
|
* @param {object} options The options object which will at the very least contain the css property set to true.
|
|
68
74
|
* @returns {promise}
|
|
69
75
|
*/
|
|
70
|
-
export function loadCss(
|
|
71
|
-
const promise = new Promise(
|
|
72
|
-
if (
|
|
76
|
+
export function loadCss(assetKey, options = { css: true }) {
|
|
77
|
+
const promise = new Promise((resolve) => {
|
|
78
|
+
if (options.css === true && !inCriticalCssConfig(assetKey)) {
|
|
73
79
|
import(
|
|
74
|
-
/* webpackChunkName: "[request]" */ `Assets/scss/components/blocks/${
|
|
75
|
-
).then(
|
|
80
|
+
/* webpackChunkName: "[request]" */ `Assets/scss/components/blocks/${assetKey}.scss`
|
|
81
|
+
).then(() => resolve(true));
|
|
76
82
|
} else {
|
|
77
|
-
return resolve(
|
|
83
|
+
return resolve(true);
|
|
78
84
|
}
|
|
79
|
-
}
|
|
85
|
+
});
|
|
80
86
|
return promise;
|
|
81
87
|
}
|
|
82
88
|
|
|
@@ -86,101 +92,106 @@ export function loadCss( assetKey, options = { css: true } ) {
|
|
|
86
92
|
export function checkDevice() {
|
|
87
93
|
try {
|
|
88
94
|
const deviceAgent = navigator.userAgent.toLowerCase();
|
|
89
|
-
const htmlElement = document.querySelector(
|
|
90
|
-
if (
|
|
91
|
-
|
|
95
|
+
const htmlElement = document.querySelector('html');
|
|
96
|
+
if (
|
|
97
|
+
'ontouchstart' in globalThis &&
|
|
98
|
+
window.screen.width * window.devicePixelRatio >= 2048 &&
|
|
99
|
+
window.screen.width < window.screen.height
|
|
100
|
+
) {
|
|
101
|
+
htmlElement.classList.add('highResTabletPortrait');
|
|
102
|
+
}
|
|
103
|
+
if ('ontouchstart' in globalThis) {
|
|
104
|
+
htmlElement.classList.add('touch');
|
|
92
105
|
}
|
|
93
|
-
if (
|
|
94
|
-
htmlElement.classList.add(
|
|
106
|
+
if (navigator.connection) {
|
|
107
|
+
htmlElement.classList.add(navigator.connection.effectiveType);
|
|
95
108
|
}
|
|
96
|
-
if (
|
|
109
|
+
if (navigator.platform) {
|
|
97
110
|
let platform = navigator.platform.toLowerCase();
|
|
98
111
|
let platformArray = [platform];
|
|
99
|
-
if (
|
|
112
|
+
if (platform.search('-')) {
|
|
100
113
|
platformArray = platform.split('-');
|
|
101
114
|
}
|
|
102
|
-
if (
|
|
115
|
+
if (platform.search(' ')) {
|
|
103
116
|
platformArray = platform.split(' ');
|
|
104
117
|
}
|
|
105
|
-
htmlElement.classList.add(
|
|
118
|
+
htmlElement.classList.add(...platformArray);
|
|
106
119
|
}
|
|
107
|
-
if (
|
|
108
|
-
htmlElement.classList.add(
|
|
109
|
-
htmlElement.classList.add(
|
|
120
|
+
if (deviceAgent.match(/(iphone|ipod|ipad)/)) {
|
|
121
|
+
htmlElement.classList.add('ios');
|
|
122
|
+
htmlElement.classList.add('mobile');
|
|
110
123
|
}
|
|
111
|
-
if (deviceAgent.match(
|
|
112
|
-
|
|
124
|
+
if (deviceAgent.match(/(windows)/)) {
|
|
125
|
+
htmlElement.classList.add('windows');
|
|
113
126
|
}
|
|
114
|
-
if (deviceAgent.match(
|
|
115
|
-
|
|
127
|
+
if (deviceAgent.match(/(macintosh)/)) {
|
|
128
|
+
htmlElement.classList.add('mac');
|
|
116
129
|
}
|
|
117
|
-
if (deviceAgent.match(
|
|
118
|
-
|
|
130
|
+
if (deviceAgent.match(/(android)/)) {
|
|
131
|
+
htmlElement.classList.add('android');
|
|
119
132
|
}
|
|
120
|
-
if (
|
|
121
|
-
htmlElement.classList.add(
|
|
122
|
-
} else if (
|
|
123
|
-
htmlElement.classList.add(
|
|
124
|
-
} else if (
|
|
125
|
-
htmlElement.classList.add(
|
|
126
|
-
} else if (
|
|
127
|
-
htmlElement.classList.add(
|
|
133
|
+
if (navigator.userAgent.search('MSIE') >= 0) {
|
|
134
|
+
htmlElement.classList.add('ie');
|
|
135
|
+
} else if (navigator.userAgent.search('Edge') >= 0) {
|
|
136
|
+
htmlElement.classList.add('edge-legacy');
|
|
137
|
+
} else if (navigator.userAgent.search('Chrome') >= 0) {
|
|
138
|
+
htmlElement.classList.add('chrome');
|
|
139
|
+
} else if (navigator.userAgent.search('Firefox') >= 0) {
|
|
140
|
+
htmlElement.classList.add('firefox');
|
|
128
141
|
} else if (
|
|
129
|
-
navigator.userAgent.search(
|
|
130
|
-
navigator.userAgent.search(
|
|
142
|
+
navigator.userAgent.search('Safari') >= 0 &&
|
|
143
|
+
navigator.userAgent.search('Chrome') < 0
|
|
131
144
|
) {
|
|
132
|
-
htmlElement.classList.add(
|
|
133
|
-
} else if (
|
|
134
|
-
htmlElement.classList.add(
|
|
145
|
+
htmlElement.classList.add('safari');
|
|
146
|
+
} else if (navigator.userAgent.search('Opera') >= 0) {
|
|
147
|
+
htmlElement.classList.add('opera');
|
|
135
148
|
}
|
|
136
149
|
} catch (error) {
|
|
137
|
-
console.error(error)
|
|
150
|
+
console.error(error);
|
|
138
151
|
}
|
|
139
152
|
}
|
|
140
153
|
|
|
141
154
|
/**
|
|
142
|
-
* Check and possibly wait for an image to have downloaded before running an optional function.
|
|
155
|
+
* Check and possibly wait for an image to have downloaded before running an optional function.
|
|
143
156
|
* Returns a resolved promise when the load event has fired.
|
|
144
157
|
* @param {htmlElement} img The image element you want to wait for.
|
|
145
|
-
* @param {function} delayedFunction The optional function you want to run when/if the image has downloaded.
|
|
158
|
+
* @param {function} delayedFunction The optional function you want to run when/if the image has downloaded.
|
|
146
159
|
* @returns {promise}
|
|
147
160
|
*/
|
|
148
|
-
export async function waitForLoad(
|
|
149
|
-
const loaded = new Promise(
|
|
150
|
-
if (
|
|
151
|
-
if (
|
|
161
|
+
export async function waitForLoad(img, delayedFunction) {
|
|
162
|
+
const loaded = new Promise((resolve) => {
|
|
163
|
+
if (img.complete) {
|
|
164
|
+
if (typeof delayedFunction === 'function') {
|
|
152
165
|
delayedFunction();
|
|
153
166
|
}
|
|
154
|
-
return resolve(
|
|
167
|
+
return resolve(true);
|
|
155
168
|
}
|
|
156
169
|
img.addEventListener(
|
|
157
170
|
'load',
|
|
158
171
|
() => {
|
|
159
|
-
if (
|
|
172
|
+
if (typeof delayedFunction === 'function') {
|
|
160
173
|
delayedFunction();
|
|
161
174
|
}
|
|
162
|
-
return resolve(
|
|
175
|
+
return resolve(true);
|
|
163
176
|
},
|
|
164
177
|
{ once: true }
|
|
165
178
|
);
|
|
166
|
-
}
|
|
167
|
-
console.log( error, 'could not load the image', img )
|
|
168
|
-
);
|
|
179
|
+
}).catch((error) => console.log(error, 'could not load the image', img));
|
|
169
180
|
return loaded;
|
|
170
181
|
}
|
|
171
182
|
|
|
172
183
|
/**
|
|
173
|
-
* Check whether the current environment supports the webp image format.
|
|
174
|
-
* Returns true if it does.
|
|
184
|
+
* Check whether the current environment supports the webp image format.
|
|
185
|
+
* Returns true if it does.
|
|
175
186
|
* @returns {boolean}
|
|
176
187
|
*/
|
|
177
188
|
export async function supportsWebp() {
|
|
178
189
|
// eslint-disable-next-line no-restricted-globals
|
|
179
|
-
if (
|
|
190
|
+
if (!self.createImageBitmap) return false;
|
|
180
191
|
const webpData =
|
|
181
192
|
'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=';
|
|
182
|
-
const blob = await fetch(
|
|
183
|
-
return createImageBitmap(
|
|
193
|
+
const blob = await fetch(webpData).then((r) => r.blob());
|
|
194
|
+
return createImageBitmap(blob).then(
|
|
184
195
|
() => true,
|
|
185
196
|
() => false
|
|
186
197
|
);
|
|
@@ -193,30 +204,28 @@ export async function supportsWebp() {
|
|
|
193
204
|
// } )();
|
|
194
205
|
|
|
195
206
|
/**
|
|
196
|
-
* DEPRECATED!! footerIntersection will be removed in a future version.
|
|
207
|
+
* DEPRECATED!! footerIntersection will be removed in a future version.
|
|
197
208
|
*/
|
|
198
|
-
export function footerIntersection(
|
|
199
|
-
entries.forEach(
|
|
200
|
-
if (
|
|
201
|
-
if (
|
|
209
|
+
export function footerIntersection(entries, element) {
|
|
210
|
+
entries.forEach((entry) => {
|
|
211
|
+
if (element) {
|
|
212
|
+
if (entry.isIntersecting) {
|
|
202
213
|
const { height } = entry.boundingClientRect;
|
|
203
|
-
element.style.bottom = `${
|
|
214
|
+
element.style.bottom = `${height}px`;
|
|
204
215
|
} else {
|
|
205
216
|
element.style.bottom = '0px';
|
|
206
217
|
}
|
|
207
218
|
}
|
|
208
|
-
}
|
|
219
|
+
});
|
|
209
220
|
}
|
|
210
221
|
|
|
211
222
|
/**
|
|
212
|
-
* Dynamically retrieves the swiper css and js and returns a resolved promise when they have both been successfully fetched.
|
|
223
|
+
* Dynamically retrieves the swiper css and js and returns a resolved promise when they have both been successfully fetched.
|
|
213
224
|
* @returns {promise}
|
|
214
225
|
*/
|
|
215
226
|
export function getSwiperAssets() {
|
|
216
227
|
const getSwiperJs = () =>
|
|
217
|
-
import(
|
|
218
|
-
/* webpackChunkName: 'swiper' */ '../../swiper/swiper-bundle.js'
|
|
219
|
-
);
|
|
228
|
+
import(/* webpackChunkName: 'swiper' */ '../../swiper/swiper-bundle.js');
|
|
220
229
|
|
|
221
230
|
const getSwiperCss = () =>
|
|
222
231
|
import(
|
|
@@ -224,8 +233,8 @@ export function getSwiperAssets() {
|
|
|
224
233
|
'../../swiper/swiper-bundle.min.css'
|
|
225
234
|
);
|
|
226
235
|
|
|
227
|
-
const promisedJs = Promise.all(
|
|
228
|
-
(
|
|
236
|
+
const promisedJs = Promise.all([getSwiperJs(), getSwiperCss()]).then(
|
|
237
|
+
(values) => {
|
|
229
238
|
return values;
|
|
230
239
|
}
|
|
231
240
|
);
|
|
@@ -233,11 +242,11 @@ export function getSwiperAssets() {
|
|
|
233
242
|
}
|
|
234
243
|
|
|
235
244
|
/**
|
|
236
|
-
* Dynamically retrieves the jQuery and returns a resolved promise when it has been successfully fetched.
|
|
245
|
+
* Dynamically retrieves the jQuery and returns a resolved promise when it has been successfully fetched.
|
|
237
246
|
* @returns {promise}
|
|
238
247
|
*/
|
|
239
248
|
export function getJquery() {
|
|
240
|
-
if (
|
|
249
|
+
if (!window.jQuery) {
|
|
241
250
|
const importCode = () =>
|
|
242
251
|
import(
|
|
243
252
|
/* webpackChunkName: 'jquery' */ '../../jquery/dist/jquery.min.js'
|
|
@@ -248,29 +257,25 @@ export function getJquery() {
|
|
|
248
257
|
}
|
|
249
258
|
|
|
250
259
|
/**
|
|
251
|
-
* Dynamically retrieves GSAP and the scrolltrigger plugin and returns a resolved promise when they have both been successfully fetched.
|
|
260
|
+
* Dynamically retrieves GSAP and the scrolltrigger plugin and returns a resolved promise when they have both been successfully fetched.
|
|
252
261
|
* @returns {promise}
|
|
253
262
|
*/
|
|
254
263
|
export function getGsap() {
|
|
255
264
|
const gsapCore = () =>
|
|
256
|
-
import(
|
|
265
|
+
import('../../gsap/dist/gsap.min.js').then((gsapObj) => {
|
|
257
266
|
const { gsap } = gsapObj;
|
|
258
267
|
return gsap;
|
|
259
|
-
}
|
|
268
|
+
});
|
|
260
269
|
|
|
261
270
|
const gsapPlugin = () =>
|
|
262
|
-
import(
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
( values ) => {
|
|
271
|
-
return values;
|
|
272
|
-
}
|
|
273
|
-
);
|
|
271
|
+
import('../../gsap/dist/ScrollTrigger.min.js').then((scrollObj) => {
|
|
272
|
+
const ScrollTrigger = scrollObj;
|
|
273
|
+
return ScrollTrigger;
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
const prom = Promise.all([gsapCore(), gsapPlugin()]).then((values) => {
|
|
277
|
+
return values;
|
|
278
|
+
});
|
|
274
279
|
return prom;
|
|
275
280
|
}
|
|
276
281
|
|
|
@@ -279,7 +284,7 @@ export function getGsap() {
|
|
|
279
284
|
* @param {*} userAgent Pass the value of navigator.userAgent.
|
|
280
285
|
* @returns {boolean}
|
|
281
286
|
*/
|
|
282
|
-
export function isTablet(
|
|
287
|
+
export function isTablet(userAgent) {
|
|
283
288
|
return /(ipad|tablet|(android(?!.*mobile))|(windows(?!.*phone)(.*touch))|kindle|playbook|silk|(puffin(?!.*(IP|AP|WP))))/.test(
|
|
284
289
|
userAgent.toLowerCase()
|
|
285
290
|
);
|
|
@@ -287,35 +292,45 @@ export function isTablet( userAgent ) {
|
|
|
287
292
|
|
|
288
293
|
/**
|
|
289
294
|
* Returns true if the device is a mobile device. Checks navigator.userAgent||navigator.vendor||window.opera.
|
|
290
|
-
* @returns {boolean}
|
|
295
|
+
* @returns {boolean}
|
|
291
296
|
*/
|
|
292
|
-
export function mobileCheck
|
|
297
|
+
export function mobileCheck() {
|
|
293
298
|
let check = false;
|
|
294
|
-
(function
|
|
299
|
+
(function (a) {
|
|
300
|
+
if (
|
|
301
|
+
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(
|
|
302
|
+
a
|
|
303
|
+
) ||
|
|
304
|
+
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
|
|
305
|
+
a.substr(0, 4)
|
|
306
|
+
)
|
|
307
|
+
)
|
|
308
|
+
check = true;
|
|
309
|
+
})(navigator.userAgent || navigator.vendor || window.opera);
|
|
295
310
|
return check;
|
|
296
|
-
|
|
311
|
+
}
|
|
297
312
|
|
|
298
313
|
/**
|
|
299
|
-
* Run a function after a window resize event, but only after the alloted time has ended.
|
|
314
|
+
* Run a function after a window resize event, but only after the alloted time has ended.
|
|
300
315
|
* If another resize even occurs it resets the time window.
|
|
301
316
|
* @param {function} debouncedFunction The function you want to run after a window resize event.
|
|
302
317
|
* @param {number} time The time in ms.
|
|
303
|
-
*/
|
|
304
|
-
export function resizeDebouncer(
|
|
318
|
+
*/
|
|
319
|
+
export function resizeDebouncer(debouncedFunction, time = 250) {
|
|
305
320
|
let resizeTimer;
|
|
306
|
-
window.addEventListener(
|
|
307
|
-
clearTimeout(
|
|
308
|
-
resizeTimer = setTimeout(
|
|
321
|
+
window.addEventListener('resize', () => {
|
|
322
|
+
clearTimeout(resizeTimer);
|
|
323
|
+
resizeTimer = setTimeout(() => {
|
|
309
324
|
debouncedFunction();
|
|
310
|
-
}, time
|
|
311
|
-
}
|
|
325
|
+
}, time);
|
|
326
|
+
});
|
|
312
327
|
}
|
|
313
328
|
|
|
314
329
|
/**
|
|
315
|
-
* General purpose utility for running a function after a particular event fires on a specified element. The function only fires after the alloted time has ended.
|
|
330
|
+
* General purpose utility for running a function after a particular event fires on a specified element. The function only fires after the alloted time has ended.
|
|
316
331
|
* If another resize even occurs it resets the time window.
|
|
317
332
|
* @param {htmlElement} element The element that emits the event.
|
|
318
|
-
* @param {string} eventType The type of event to listen for.
|
|
333
|
+
* @param {string} eventType The type of event to listen for.
|
|
319
334
|
* @param {function} debouncedFunction The function to run after the event.
|
|
320
335
|
* @param {number} time The time in ms.
|
|
321
336
|
*/
|
|
@@ -326,49 +341,49 @@ export function eventListenerDebouncer(
|
|
|
326
341
|
time = 250
|
|
327
342
|
) {
|
|
328
343
|
let timer;
|
|
329
|
-
element.addEventListener(
|
|
330
|
-
clearTimeout(
|
|
331
|
-
timer = setTimeout(
|
|
332
|
-
debouncedFunction(
|
|
333
|
-
}, time
|
|
334
|
-
}
|
|
344
|
+
element.addEventListener(eventType, (event) => {
|
|
345
|
+
clearTimeout(timer);
|
|
346
|
+
timer = setTimeout(() => {
|
|
347
|
+
debouncedFunction(event);
|
|
348
|
+
}, time);
|
|
349
|
+
});
|
|
335
350
|
}
|
|
336
351
|
|
|
337
352
|
/**
|
|
338
353
|
* Injects the youtube iframe api script and waits for the YT object to be instantiated before resolving the promise
|
|
339
|
-
* @returns {promise} Resolves once the YT object is available.
|
|
354
|
+
* @returns {promise} Resolves once the YT object is available.
|
|
340
355
|
*/
|
|
341
356
|
export function injectYouTubeIframeScript() {
|
|
342
|
-
const prom = new Promise(
|
|
343
|
-
if (
|
|
357
|
+
const prom = new Promise((resolve) => {
|
|
358
|
+
if (globalThis.YT) {
|
|
344
359
|
return resolve();
|
|
345
360
|
}
|
|
346
|
-
const tag = document.createElement(
|
|
361
|
+
const tag = document.createElement('script');
|
|
347
362
|
tag.id = 'iframe-api';
|
|
348
363
|
tag.src = 'https://www.youtube.com/iframe_api';
|
|
349
364
|
|
|
350
|
-
const firstScriptTag = document.getElementsByTagName(
|
|
351
|
-
firstScriptTag.parentNode.insertBefore(
|
|
365
|
+
const firstScriptTag = document.getElementsByTagName('script')[0];
|
|
366
|
+
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
|
|
352
367
|
|
|
353
|
-
tag.addEventListener(
|
|
368
|
+
tag.addEventListener('load', () => {
|
|
354
369
|
if (!YT.loaded) {
|
|
355
370
|
const loadingCheck = setInterval(() => {
|
|
356
371
|
if (YT.loaded) {
|
|
357
372
|
clearInterval(loadingCheck);
|
|
358
|
-
return resolve(
|
|
373
|
+
return resolve(true);
|
|
359
374
|
}
|
|
360
375
|
}, 50);
|
|
361
376
|
} else {
|
|
362
|
-
return resolve(
|
|
377
|
+
return resolve(true);
|
|
363
378
|
}
|
|
364
|
-
}
|
|
365
|
-
}
|
|
379
|
+
});
|
|
380
|
+
});
|
|
366
381
|
|
|
367
382
|
return prom;
|
|
368
383
|
}
|
|
369
384
|
|
|
370
|
-
export function fallbackCopyToClipboard(
|
|
371
|
-
const textArea = document.createElement(
|
|
385
|
+
export function fallbackCopyToClipboard(text) {
|
|
386
|
+
const textArea = document.createElement('textarea');
|
|
372
387
|
textArea.value = text;
|
|
373
388
|
|
|
374
389
|
// Avoid scrolling to bottom
|
|
@@ -376,58 +391,55 @@ export function fallbackCopyToClipboard( text ) {
|
|
|
376
391
|
textArea.style.left = '0';
|
|
377
392
|
textArea.style.position = 'fixed';
|
|
378
393
|
|
|
379
|
-
document.body.appendChild(
|
|
394
|
+
document.body.appendChild(textArea);
|
|
380
395
|
textArea.focus();
|
|
381
396
|
textArea.select();
|
|
382
397
|
|
|
383
398
|
try {
|
|
384
|
-
const successful = document.execCommand(
|
|
399
|
+
const successful = document.execCommand('copy');
|
|
385
400
|
const msg = successful ? 'successful' : 'unsuccessful';
|
|
386
|
-
console.log(
|
|
387
|
-
} catch (
|
|
388
|
-
console.error(
|
|
401
|
+
console.log(`Fallback: Copying text command was ${msg}`);
|
|
402
|
+
} catch (err) {
|
|
403
|
+
console.error('Fallback: Oops, unable to copy', err);
|
|
389
404
|
}
|
|
390
405
|
|
|
391
|
-
document.body.removeChild(
|
|
406
|
+
document.body.removeChild(textArea);
|
|
392
407
|
}
|
|
393
408
|
|
|
394
|
-
|
|
395
409
|
export function copyToClipboard() {
|
|
396
|
-
const copyLinks = document.querySelectorAll(
|
|
410
|
+
const copyLinks = document.querySelectorAll('.copy-to-clipboard');
|
|
397
411
|
let timeout;
|
|
398
|
-
copyLinks.forEach(
|
|
399
|
-
link.addEventListener(
|
|
412
|
+
copyLinks.forEach((link) => {
|
|
413
|
+
link.addEventListener('click', function () {
|
|
400
414
|
const copyToClipboardDone = link.nextElementSibling;
|
|
401
|
-
if (
|
|
402
|
-
fallbackCopyToClipboard(
|
|
415
|
+
if (!navigator.clipboard) {
|
|
416
|
+
fallbackCopyToClipboard(this.dataset.url);
|
|
403
417
|
return;
|
|
404
418
|
}
|
|
405
419
|
|
|
406
|
-
navigator.clipboard.writeText(
|
|
420
|
+
navigator.clipboard.writeText(this.dataset.url).then(
|
|
407
421
|
function () {
|
|
408
|
-
console.log(
|
|
422
|
+
console.log('Copying to clipboard was successful!');
|
|
409
423
|
},
|
|
410
|
-
function (
|
|
411
|
-
console.error(
|
|
424
|
+
function (err) {
|
|
425
|
+
console.error('Could not copy text: ', err);
|
|
412
426
|
}
|
|
413
427
|
);
|
|
414
428
|
|
|
415
429
|
if (
|
|
416
430
|
copyToClipboardDone &&
|
|
417
431
|
copyToClipboardDone.classList &&
|
|
418
|
-
copyToClipboardDone.classList.contains(
|
|
419
|
-
'sharing__clipboard-done'
|
|
420
|
-
)
|
|
432
|
+
copyToClipboardDone.classList.contains('sharing__clipboard-done')
|
|
421
433
|
) {
|
|
422
|
-
clearTimeout(
|
|
423
|
-
copyToClipboardDone.classList.remove(
|
|
434
|
+
clearTimeout(timeout);
|
|
435
|
+
copyToClipboardDone.classList.remove('hidden');
|
|
424
436
|
|
|
425
|
-
timeout = setTimeout(
|
|
426
|
-
copyToClipboardDone.classList.add(
|
|
427
|
-
}, 2000
|
|
437
|
+
timeout = setTimeout(() => {
|
|
438
|
+
copyToClipboardDone.classList.add('hidden');
|
|
439
|
+
}, 2000);
|
|
428
440
|
}
|
|
429
|
-
}
|
|
430
|
-
}
|
|
441
|
+
});
|
|
442
|
+
});
|
|
431
443
|
}
|
|
432
444
|
|
|
433
445
|
/**
|
|
@@ -436,21 +448,25 @@ export function copyToClipboard() {
|
|
|
436
448
|
* @returns {boolean} True if visible and false if not.
|
|
437
449
|
*/
|
|
438
450
|
export function isInViewport(element) {
|
|
439
|
-
|
|
440
|
-
|
|
451
|
+
const position = element.getBoundingClientRect();
|
|
452
|
+
return (
|
|
453
|
+
(position.top >= 0 && position.bottom <= window.innerHeight) ||
|
|
454
|
+
(position.top < window.innerHeight && position.bottom >= 0)
|
|
455
|
+
);
|
|
441
456
|
}
|
|
442
457
|
|
|
443
458
|
/* eslint-disable-next-line */
|
|
444
|
-
const emailRegex =
|
|
459
|
+
const emailRegex =
|
|
460
|
+
/^[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~](\.?[-!#$%&'*+\/0-9=?A-Z^_a-z`{|}~])*@[a-zA-Z0-9](-*\.?[a-zA-Z0-9])*\.[a-zA-Z](-?[a-zA-Z0-9])+$/;
|
|
445
461
|
|
|
446
462
|
/**
|
|
447
463
|
* Checks to make sure a passed string has a valid email address structure and characters.
|
|
448
464
|
* @param {RegExp} email - The email address as a string.
|
|
449
465
|
* @returns {boolean} True if valid and false if not.
|
|
450
466
|
*/
|
|
451
|
-
export function isEmailValid(
|
|
452
|
-
return emailRegex.test(
|
|
453
|
-
}
|
|
467
|
+
export function isEmailValid(email) {
|
|
468
|
+
return emailRegex.test(email);
|
|
469
|
+
}
|
|
454
470
|
|
|
455
471
|
/**
|
|
456
472
|
* Get the value of a css property on a specific element.
|
|
@@ -520,9 +536,7 @@ export function detectSwipe(element, callback, removeHandlers = false) {
|
|
|
520
536
|
function (event) {
|
|
521
537
|
touchendX = event.changedTouches[0].screenX;
|
|
522
538
|
touchendY = event.changedTouches[0].screenY;
|
|
523
|
-
callback(
|
|
524
|
-
handleGesture(touchstartX, touchstartY, touchendX, touchendY)
|
|
525
|
-
);
|
|
539
|
+
callback(handleGesture(touchstartX, touchstartY, touchendX, touchendY));
|
|
526
540
|
},
|
|
527
541
|
false
|
|
528
542
|
);
|
|
@@ -533,6 +547,44 @@ export function detectSwipe(element, callback, removeHandlers = false) {
|
|
|
533
547
|
}
|
|
534
548
|
}
|
|
535
549
|
|
|
550
|
+
/**
|
|
551
|
+
* Function for getting the ios operating system version
|
|
552
|
+
*
|
|
553
|
+
* @returns {number} the ios version
|
|
554
|
+
*/
|
|
555
|
+
export function checkIosVersion() {
|
|
556
|
+
const agent = window.navigator.userAgent,
|
|
557
|
+
start = agent.indexOf('OS ');
|
|
558
|
+
if (
|
|
559
|
+
(agent.indexOf('iPhone') > -1 || agent.indexOf('iPad') > -1) &&
|
|
560
|
+
start > -1
|
|
561
|
+
) {
|
|
562
|
+
return window.Number(agent.substr(start + 3, 3).replace('_', '.'));
|
|
563
|
+
}
|
|
564
|
+
return 0;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Function for adding a link tag with preconnect to the head of the document. Very useful if you need to add this dynamically.
|
|
569
|
+
* @param {string} domain The domain you wish to preconnect to.
|
|
570
|
+
* @returns {void} The preconnect will be appended to the head tag.
|
|
571
|
+
*/
|
|
572
|
+
export function appendPreconnect(domain) {
|
|
573
|
+
try {
|
|
574
|
+
if (!domain) {
|
|
575
|
+
console.log('The domain was missing or broken...');
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
const link = document.createElement('link');
|
|
579
|
+
link.rel = 'preconnect';
|
|
580
|
+
link.href = domain;
|
|
581
|
+
document.head.appendChild(link);
|
|
582
|
+
return;
|
|
583
|
+
} catch (error) {
|
|
584
|
+
console.error(error);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
536
588
|
const api = {
|
|
537
589
|
copyToClipboard,
|
|
538
590
|
checkDevice,
|
|
@@ -555,6 +607,8 @@ const api = {
|
|
|
555
607
|
toggleClassByValidity,
|
|
556
608
|
waitForLoad,
|
|
557
609
|
getElementStyles,
|
|
558
|
-
getPercent
|
|
610
|
+
getPercent,
|
|
611
|
+
checkIosVersion,
|
|
612
|
+
appendPreconnect
|
|
559
613
|
};
|
|
560
614
|
export default api;
|
package/package.json
CHANGED
|
@@ -1,29 +1,30 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
2
|
+
"name": "@pernod-ricard-global-cms/jsutils",
|
|
3
|
+
"version": "1.7.0",
|
|
4
|
+
"description": "Handy collection of Javascript utility functions",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "jsutils.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "jasmine"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/Chivas-Brothers/jsUtils.git"
|
|
13
|
+
},
|
|
14
|
+
"author": "",
|
|
15
|
+
"license": "ISC",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/Chivas-Brothers/jsUtils/issues"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/Chivas-Brothers/jsUtils#readme",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"gsap": "^3.7.1",
|
|
22
|
+
"jquery": "^3.6.0",
|
|
23
|
+
"prettier": "^2.5.1",
|
|
24
|
+
"swiper": "^6.8.3"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"jasmine": "^3.9.0",
|
|
28
|
+
"jsdoc": "^3.6.7"
|
|
29
|
+
}
|
|
29
30
|
}
|