@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.
Files changed (3) hide show
  1. package/.prettierrc +19 -0
  2. package/jsutils.js +235 -181
  3. package/package.json +28 -27
package/.prettierrc ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "useTabs": true,
3
+ "overrides": [
4
+ {
5
+ "files": "*.test.js",
6
+ "options": {
7
+ "semi": true
8
+ }
9
+ },
10
+ {
11
+ "files": ["*.js"],
12
+ "options": {
13
+ "semi": true,
14
+ "singleQuote": true,
15
+ "trailingComma": "none"
16
+ }
17
+ }
18
+ ]
19
+ }
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( element ) {
10
+ export function getPosition(element) {
11
11
  const scrollElementTag = document.scrollingElement.tagName;
12
12
  let xPosition = 0;
13
13
  let yPosition = 0;
14
- while ( element ) {
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 ( scrollElementTag === 'BODY' ) {
22
- yPosition += document.querySelector( 'body' ).scrollTop;
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( input, button ) {
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' );
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
- } else {
42
- button.classList.remove( 'valid' );
43
- input.classList.remove( 'valid' );
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( assetKey ) {
57
+ export function inCriticalCssConfig(assetKey) {
58
+ if (!globalThis.criticalConfig) {
59
+ return false;
60
+ }
55
61
  if (
56
62
  globalThis.criticalConfig &&
57
- globalThis.criticalConfig.indexOf( assetKey ) === -1
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( assetKey, options = { css: true } ) {
71
- const promise = new Promise( ( resolve ) => {
72
- if ( options.css === true && ! inCriticalCssConfig( assetKey ) ) {
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/${ assetKey }.scss`
75
- ).then( () => resolve( true ) );
80
+ /* webpackChunkName: "[request]" */ `Assets/scss/components/blocks/${assetKey}.scss`
81
+ ).then(() => resolve(true));
76
82
  } else {
77
- return resolve( true );
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( 'html' );
90
- if ( 'ontouchstart' in globalThis ) {
91
- htmlElement.classList.add( 'touch' );
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 ( navigator.connection ) {
94
- htmlElement.classList.add( navigator.connection.effectiveType );
106
+ if (navigator.connection) {
107
+ htmlElement.classList.add(navigator.connection.effectiveType);
95
108
  }
96
- if ( navigator.platform ) {
109
+ if (navigator.platform) {
97
110
  let platform = navigator.platform.toLowerCase();
98
111
  let platformArray = [platform];
99
- if ( platform.search('-') ) {
112
+ if (platform.search('-')) {
100
113
  platformArray = platform.split('-');
101
114
  }
102
- if ( platform.search(' ') ) {
115
+ if (platform.search(' ')) {
103
116
  platformArray = platform.split(' ');
104
117
  }
105
- htmlElement.classList.add( ...platformArray );
118
+ htmlElement.classList.add(...platformArray);
106
119
  }
107
- if ( deviceAgent.match( /(iphone|ipod|ipad)/ ) ) {
108
- htmlElement.classList.add( 'ios' );
109
- htmlElement.classList.add( 'mobile' );
120
+ if (deviceAgent.match(/(iphone|ipod|ipad)/)) {
121
+ htmlElement.classList.add('ios');
122
+ htmlElement.classList.add('mobile');
110
123
  }
111
- if (deviceAgent.match( /(windows)/ )) {
112
- htmlElement.classList.add( 'windows' );
124
+ if (deviceAgent.match(/(windows)/)) {
125
+ htmlElement.classList.add('windows');
113
126
  }
114
- if (deviceAgent.match( /(macintosh)/ )) {
115
- htmlElement.classList.add( 'mac' );
127
+ if (deviceAgent.match(/(macintosh)/)) {
128
+ htmlElement.classList.add('mac');
116
129
  }
117
- if (deviceAgent.match( /(android)/ )) {
118
- htmlElement.classList.add( 'android' );
130
+ if (deviceAgent.match(/(android)/)) {
131
+ htmlElement.classList.add('android');
119
132
  }
120
- if ( navigator.userAgent.search( 'MSIE' ) >= 0 ) {
121
- htmlElement.classList.add( 'ie' );
122
- } else if ( navigator.userAgent.search( 'Edge' ) >= 0 ) {
123
- htmlElement.classList.add( 'edge-legacy' );
124
- } else if ( navigator.userAgent.search( 'Chrome' ) >= 0 ) {
125
- htmlElement.classList.add( 'chrome' );
126
- } else if ( navigator.userAgent.search( 'Firefox' ) >= 0 ) {
127
- htmlElement.classList.add( 'firefox' );
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( 'Safari' ) >= 0 &&
130
- navigator.userAgent.search( 'Chrome' ) < 0
142
+ navigator.userAgent.search('Safari') >= 0 &&
143
+ navigator.userAgent.search('Chrome') < 0
131
144
  ) {
132
- htmlElement.classList.add( 'safari' );
133
- } else if ( navigator.userAgent.search( 'Opera' ) >= 0 ) {
134
- htmlElement.classList.add( 'opera' );
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( img, delayedFunction ) {
149
- const loaded = new Promise( ( resolve ) => {
150
- if ( img.complete ) {
151
- if ( typeof delayedFunction === 'function' ) {
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( true );
167
+ return resolve(true);
155
168
  }
156
169
  img.addEventListener(
157
170
  'load',
158
171
  () => {
159
- if ( typeof delayedFunction === 'function' ) {
172
+ if (typeof delayedFunction === 'function') {
160
173
  delayedFunction();
161
174
  }
162
- return resolve( true );
175
+ return resolve(true);
163
176
  },
164
177
  { once: true }
165
178
  );
166
- } ).catch( ( error ) =>
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 ( ! self.createImageBitmap ) return false;
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( webpData ).then( ( r ) => r.blob() );
183
- return createImageBitmap( blob ).then(
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( entries, element ) {
199
- entries.forEach( ( entry ) => {
200
- if ( element ) {
201
- if ( entry.isIntersecting ) {
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 = `${ height }px`;
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( [ getSwiperJs(), getSwiperCss() ] ).then(
228
- ( values ) => {
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 ( ! window.jQuery ) {
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( '../../gsap/dist/gsap.min.js' ).then( ( gsapObj ) => {
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( '../../gsap/dist/ScrollTrigger.min.js' ).then(
263
- ( scrollObj ) => {
264
- const ScrollTrigger = scrollObj;
265
- return ScrollTrigger;
266
- }
267
- );
268
-
269
- const prom = Promise.all( [ gsapCore(), gsapPlugin() ] ).then(
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( userAgent ) {
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(a){if(/(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(a)||/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(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
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( debouncedFunction, time = 250 ) {
318
+ */
319
+ export function resizeDebouncer(debouncedFunction, time = 250) {
305
320
  let resizeTimer;
306
- window.addEventListener( 'resize', () => {
307
- clearTimeout( resizeTimer );
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( eventType, ( event ) => {
330
- clearTimeout( timer );
331
- timer = setTimeout( () => {
332
- debouncedFunction( event );
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( ( resolve ) => {
343
- if ( globalThis.YT ) {
357
+ const prom = new Promise((resolve) => {
358
+ if (globalThis.YT) {
344
359
  return resolve();
345
360
  }
346
- const tag = document.createElement( 'script' );
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( 'script' )[ 0 ];
351
- firstScriptTag.parentNode.insertBefore( tag, firstScriptTag );
365
+ const firstScriptTag = document.getElementsByTagName('script')[0];
366
+ firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
352
367
 
353
- tag.addEventListener( 'load', () => {
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( true );
373
+ return resolve(true);
359
374
  }
360
375
  }, 50);
361
376
  } else {
362
- return resolve( true );
377
+ return resolve(true);
363
378
  }
364
- } );
365
- } );
379
+ });
380
+ });
366
381
 
367
382
  return prom;
368
383
  }
369
384
 
370
- export function fallbackCopyToClipboard( text ) {
371
- const textArea = document.createElement( 'textarea' );
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( textArea );
394
+ document.body.appendChild(textArea);
380
395
  textArea.focus();
381
396
  textArea.select();
382
397
 
383
398
  try {
384
- const successful = document.execCommand( 'copy' );
399
+ const successful = document.execCommand('copy');
385
400
  const msg = successful ? 'successful' : 'unsuccessful';
386
- console.log( `Fallback: Copying text command was ${ msg }` );
387
- } catch ( err ) {
388
- console.error( 'Fallback: Oops, unable to copy', err );
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( textArea );
406
+ document.body.removeChild(textArea);
392
407
  }
393
408
 
394
-
395
409
  export function copyToClipboard() {
396
- const copyLinks = document.querySelectorAll( '.copy-to-clipboard' );
410
+ const copyLinks = document.querySelectorAll('.copy-to-clipboard');
397
411
  let timeout;
398
- copyLinks.forEach( ( link ) => {
399
- link.addEventListener( 'click', function () {
412
+ copyLinks.forEach((link) => {
413
+ link.addEventListener('click', function () {
400
414
  const copyToClipboardDone = link.nextElementSibling;
401
- if ( ! navigator.clipboard ) {
402
- fallbackCopyToClipboard( this.dataset.url );
415
+ if (!navigator.clipboard) {
416
+ fallbackCopyToClipboard(this.dataset.url);
403
417
  return;
404
418
  }
405
419
 
406
- navigator.clipboard.writeText( this.dataset.url ).then(
420
+ navigator.clipboard.writeText(this.dataset.url).then(
407
421
  function () {
408
- console.log( 'Copying to clipboard was successful!' );
422
+ console.log('Copying to clipboard was successful!');
409
423
  },
410
- function ( err ) {
411
- console.error( 'Could not copy text: ', err );
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( timeout );
423
- copyToClipboardDone.classList.remove( 'hidden' );
434
+ clearTimeout(timeout);
435
+ copyToClipboardDone.classList.remove('hidden');
424
436
 
425
- timeout = setTimeout( () => {
426
- copyToClipboardDone.classList.add( 'hidden' );
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
- const position = element.getBoundingClientRect();
440
- return ( position.top >= 0 && position.bottom <= window.innerHeight ) || ( position.top < window.innerHeight && position.bottom >= 0 );
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 = /^[-!#$%&'*+\/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])+$/;
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( email ) {
452
- return emailRegex.test( email );
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
- "name": "@pernod-ricard-global-cms/jsutils",
3
- "version": "1.5.21",
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
- "swiper": "^6.8.3"
24
- },
25
- "devDependencies": {
26
- "jasmine": "^3.9.0",
27
- "jsdoc": "^3.6.7"
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
  }