Passed
Push — master ( d65a30...b630f1 )
by Dev
01:22
created

src/helpers.js   F

Complexity

Total Complexity 74
Complexity/F 1.54

Size

Lines of Code 383
Function Count 48

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 209
dl 0
loc 383
rs 2.48
c 0
b 0
f 0
wmc 74
mnd 26
bc 26
fnc 48
bpm 0.5416
cpm 1.5416
noi 10

11 Functions

Rating   Name   Duplication   Size   Complexity  
A helpers.js ➔ readableEmail 0 9 3
A helpers.js ➔ rot13ToText 0 7 4
F helpers.js ➔ uncloakLinks 0 77 14
A helpers.js ➔ convertFormFromRot13 0 12 2
A helpers.js ➔ imgLazyLoad 0 23 5
A helpers.js ➔ convertShortchutForLink 0 12 4
A helpers.js ➔ responsiveImage 0 17 5
A helpers.js ➔ testWebPSupport 0 9 2
A helpers.js ➔ seasonedBackground 0 14 5
B helpers.js ➔ replaceOn 0 32 5
A helpers.js ➔ convertImageLinkToWebPLink 0 11 4

How to fix   Complexity   

Complexity

Complex classes like src/helpers.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/**
2
 * List of all functions
3
 *
4
 * - liveBlock(attr)
5
 * - liveForm(attr)
6
 *
7
 * -  seasonedBackground
8
 * - responsiveImage(string)    Relative to Liip filters
9
 * - uncloakLinks(attr)
10
 * - convertFormFromRot13(attr)
11
 * - readableEmail(attr)
12
 * - convertImageLinkToWebPLink()
13
 */
14
15
/**
16
 * Live Block Watcher (and button)
17
 *
18
 * Fetch (ajax) function permitting to get block via a POST request
19
 *
20
 * @param {string} attribute
21
 */
22
export function liveBlock(
23
  liveBlockAttribute = 'data-live',
24
  liveFormSelector = '.live-form'
25
) {
26
  var btnToBlock = function (event, btn) {
27
    btn.setAttribute(
28
      liveBlockAttribute,
29
      btn.getAttribute('src-' + liveBlockAttribute)
30
    );
31
    getLiveBlock(btn);
32
  };
33
34
  var getLiveBlock = function (item) {
35
    fetch(item.getAttribute(liveBlockAttribute), {
36
      //headers: { "Content-Type": "application/json", Accept: "text/plain" },
37
      method: 'POST',
38
      credentials: 'include',
39
    })
40
      .then(function (response) {
41
        return response.text();
42
      })
43
      .then(function (body) {
44
        item.removeAttribute(liveBlockAttribute);
45
        item.outerHTML = body;
46
      })
47
      .then(function () {
48
        document.dispatchEvent(new Event('DOMChanged'));
0 ignored issues
show
Bug introduced by
The variable Event seems to be never declared. If this is a global, consider adding a /** global: Event */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
49
      });
50
  };
51
52
  var htmlLoader =
53
    '<div style="width:1em;height:1em;border: 2px solid #222;border-top-color: #fff;border-radius: 50%;  animation: 1s spin linear infinite;"></div><style>@keyframes spin {from{transform:rotate(0deg)}to{transform:rotate(360deg)}}</style>';
54
55
  var setLoader = function (form) {
56
    var $submitButton = getSubmitButton(form);
57
    if ($submitButton !== undefined) {
58
      var initialButton = $submitButton.outerHTML;
0 ignored issues
show
Unused Code introduced by
The variable initialButton seems to be never used. Consider removing it.
Loading history...
59
      $submitButton.innerHTML = '';
60
      $submitButton.outerHTML = htmlLoader;
61
    }
62
  };
63
64
  var sendForm = function (form, liveFormBlock) {
65
    setLoader(form);
66
67
    var formData = new FormData(form.srcElement);
68
    fetch(form.srcElement.action, {
69
      method: 'POST',
70
      body: formData,
71
      credentials: 'include',
72
    })
73
      .then(function (response) {
74
        return response.text();
75
      })
76
      .then(function (body) {
77
        liveFormBlock.outerHTML = body;
78
      })
79
      .then(function () {
80
        document.dispatchEvent(new Event('DOMChanged'));
0 ignored issues
show
Bug introduced by
The variable Event seems to be never declared. If this is a global, consider adding a /** global: Event */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
81
      });
82
  };
83
84
  var getSubmitButton = function (form) {
85
    if (form.srcElement.querySelector('[type=submit]') !== null) {
86
      return form.srcElement.querySelector('[type=submit]');
87
    }
88
    if (form.srcElement.getElementsByTagName('button') !== null) {
89
      return form.srcElement.getElementsByTagName('button')[0];
90
    }
91
    return null;
92
  };
93
94
  // Listen data-live
95
  document.querySelectorAll('[' + liveBlockAttribute + ']').forEach((item) => {
96
    getLiveBlock(item);
97
  });
98
99
  // Listen button src-data-live
100
  document
101
    .querySelectorAll('[src-' + liveBlockAttribute + ']')
102
    .forEach((item) => {
103
      item.addEventListener('click', (event) => {
104
        btnToBlock(event, item);
105
      });
106
    });
107
108
  // Listen live-form
109
  document.querySelectorAll(liveFormSelector).forEach((item) => {
110
    if (item.querySelector('form') !== null) {
111
      item.querySelector('form').addEventListener('submit', (e) => {
112
        e.preventDefault();
113
        sendForm(e, item);
114
      });
115
    }
116
  });
117
}
118
119
/**
120
 * Block to replace Watcher
121
 * On $event on element find via $attribute, set attribute's content in element.innerHTML
122
 */
123
export function replaceOn(attribute = 'replaceBy', eventName = 'click') {
124
  var loadVideo = function (element) {
125
    var content = element.getAttribute(attribute);
126
    if (
127
      element.classList.contains('hero-banner-overlay-lg') &&
128
      element.querySelector('picture') &&
129
      window.innerWidth < 992
130
    ) {
131
      element.querySelector('picture').outerHTML = content;
132
      element.querySelector('.btn-play').outerHTML = ' ';
133
      element.style.zIndex = '2000';
134
    } else {
135
      element.innerHTML = content;
136
    }
137
    element.removeAttribute(attribute);
138
    document.dispatchEvent(new Event('DOMChanged'));
0 ignored issues
show
Bug introduced by
The variable Event seems to be never declared. If this is a global, consider adding a /** global: Event */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
139
  };
140
141
  document
142
    .querySelectorAll('[' + attribute + ']:not([listen])')
143
    .forEach(function (element) {
144
      element.setAttribute('listen', '');
145
      element.addEventListener(
146
        eventName,
147
        function (event) {
148
          loadVideo(event.currentTarget); //event.currentTarget;
149
          element.removeAttribute('listen');
150
        },
151
        { once: true }
152
      );
153
    });
154
}
155
156
/**
157
 *
158
 *
159
 */
160
export function seasonedBackground() {
161
  document.querySelectorAll('[x-hash]').forEach(function (element) {
162
    if (window.location.hash) {
163
      if (element.getAttribute('x-hash') == window.location.hash.substring(1)) {
164
        element.parentNode.parentNode
165
          .querySelectorAll('img')
166
          .forEach(function (img) {
167
            img.style = 'display:none';
168
          });
169
        element.style = 'display:block';
170
      }
171
    }
172
  });
173
}
174
175
/**
176
 * Transform image's path (src) produce with Liip to responsive path
177
 *
178
 * @param {string} src
179
 */
180
export function responsiveImage(src) {
181
  var screenWidth = window.innerWidth;
182
  if (screenWidth <= 576) {
183
    src = src.replace('/default/', '/xs/');
184
  } else if (screenWidth <= 768) {
185
    src = src.replace('/default/', '/sm/');
186
  } else if (screenWidth <= 992) {
187
    src = src.replace('/default/', '/md/');
188
  } else if (screenWidth <= 1200) {
189
    src = src.replace('/default/', '/lg/');
190
  } else {
191
    // 1200+
192
    src = src.replace('/default/', '/xl/');
193
  }
194
195
  return src;
196
}
197
198
/**
199
 * Convert elements wich contain attribute (data-href) in normal link (a href)
200
 * You can use a callback function to decrypt the link (eg: rot13ToText ;-))
201
 *
202
 * @param {string}  attribute
203
 */
204
export async function uncloakLinks(attribute = 'data-rot') {
205
  var convertLink = function (element) {
206
    // fix "bug" with img
207
    if (element.getAttribute(attribute) === null) {
208
      var element = element.closest('[' + attribute + ']');
209
    }
210
    if (element.getAttribute(attribute) === null) return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
211
    var link = document.createElement('a');
212
    var href = element.getAttribute(attribute);
213
    element.removeAttribute(attribute);
214
    for (var i = 0, n = element.attributes.length; i < n; i++) {
215
      link.setAttribute(
216
        element.attributes[i].nodeName,
217
        element.attributes[i].nodeValue
218
      );
219
    }
220
    link.innerHTML = element.innerHTML;
221
    link.setAttribute(
222
      'href',
223
      responsiveImage(convertShortchutForLink(rot13ToText(href)))
224
    );
225
    element.parentNode.replaceChild(link, element);
226
    return link;
227
  };
228
229
  var convertThemAll = function (attribute) {
230
    [].forEach.call(document.querySelectorAll('[' + attribute + ']'), function (
231
      element
232
    ) {
233
      convertLink(element);
234
    });
235
  };
236
237
  var fireEventLinksBuilt = async function (element, event) {
238
    await document.dispatchEvent(new Event('DOMChanged'));
0 ignored issues
show
Bug introduced by
The variable Event seems to be never declared. If this is a global, consider adding a /** global: Event */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
239
240
    var clickEvent = new Event(event.type);
241
    element.dispatchEvent(clickEvent);
242
  };
243
244
  var convertLinkOnEvent = async function (event) {
245
    // convert them all if it's an image (thanks this bug), permit to use gallery (baguetteBox)
246
    if (event.target.tagName == 'IMG') {
247
      await convertThemAll(attribute);
248
      var element = event.target;
249
    } else {
250
      var element = convertLink(event.target);
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable element already seems to be declared on line 248. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
251
    }
252
    fireEventLinksBuilt(element, event);
253
  };
254
255
  [].forEach.call(document.querySelectorAll('[' + attribute + ']'), function (
256
    element
257
  ) {
258
    element.addEventListener(
259
      'touchstart',
260
      function (e) {
261
        convertLinkOnEvent(e);
262
      },
263
      { once: true, passive: true }
264
    );
265
    element.addEventListener(
266
      'click',
267
      function (e) {
268
        convertLinkOnEvent(e);
269
      },
270
      { once: true }
271
    );
272
    element.addEventListener(
273
      'mouseover',
274
      function (e) {
275
        convertLinkOnEvent(e);
276
      },
277
      { once: true }
278
    );
279
  });
280
}
281
282
/**
283
 * Convert action attr encoded in rot 13 to normal action with default attr `data-frot`
284
 *
285
 * @param {string}  attribute
286
 */
287
export function convertFormFromRot13(attribute = 'data-frot') {
288
  [].forEach.call(document.querySelectorAll('[' + attribute + ']'), function (
289
    element
290
  ) {
291
    var action = element.getAttribute(attribute);
292
    element.removeAttribute(attribute);
293
    element.setAttribute(
294
      'action',
295
      convertShortchutForLink(rot13ToText(action))
296
    );
297
  });
298
}
299
300
export function convertShortchutForLink(str) {
301
  if (str.charAt(0) == '-') {
302
    return str.replace('-', 'http://');
303
  }
304
  if (str.charAt(0) == '_') {
305
    return str.replace('_', 'https://');
306
  }
307
  if (str.charAt(0) == '@') {
308
    return str.replace('@', 'mailto:');
309
  }
310
  return str;
311
}
312
313
/**
314
 * readableEmail(selector) Transform an email encoded with rot13 in a readable mail (and add mailto:)
315
 *
316
 * @param {string}  text
317
 */
318
export function readableEmail(selector) {
319
  document.querySelectorAll(selector).forEach(function (item) {
320
    var mail = rot13ToText(item.textContent);
321
    item.innerHTML = '<a href="mailto:' + mail + '">' + mail + '</a>';
322
    if (selector.charAt(0) == '.') {
323
      item.classList.remove(selector.substring(1));
324
    }
325
  });
326
}
327
328
/**
329
 * Decode rot13
330
 *
331
 * @param {string}  str
332
 */
333
export function rot13ToText(str) {
334
  return str.replace(/[a-zA-Z]/g, function (c) {
335
    return String.fromCharCode(
336
      (c <= 'Z' ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26
337
    );
338
  });
339
}
340
341
export function testWebPSupport() {
342
  var elem = document.createElement('canvas');
343
344
  if (elem.getContext && elem.getContext('2d')) {
345
    return elem.toDataURL('image/webp').indexOf('data:image/webp') == 0;
0 ignored issues
show
Best Practice introduced by
Comparing elem.toDataURL("image/we...exOf("data:image/webp") to 0 using the == operator is not safe. Consider using === instead.
Loading history...
346
  }
347
348
  return false;
349
}
350
351
/**
352
 * Used in ThemeComponent
353
 */
354
export function convertImageLinkToWebPLink() {
355
  var switchToWebP = function () {
356
    [].forEach.call(document.querySelectorAll('a[dwl]'), function (element) {
357
      var href = responsiveImage(element.getAttribute('dwl'));
358
      element.setAttribute('href', href);
359
      element.removeAttribute('dwl');
360
    });
361
  };
362
363
  if (testWebPSupport()) switchToWebP();
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
364
}
365
366
/**
367
 * Simple Image Lazy Loader
368
 * original from : https://davidwalsh.name/lazyload-image-fade
369
 *
370
 * @param {string}  attribute
371
 *
372
 * @example
373
 * imgLazyLoad()
374
 * <span data-img=/img/me.png>Tagada</span> or <img data-img=/img/me.png alt=Tagada>
375
 *
376
 * will be converted to
377
 *
378
 * <img src=/img/me.png alt=Tagada />
379
 *
380
 * still used in piedvert. To remove ?!
381
 */
382
export function imgLazyLoad(attribute = 'data-img') {
383
  [].forEach.call(document.querySelectorAll('[' + attribute + ']'), function (
384
    img
385
  ) {
386
    var newDomImg = document.createElement('img');
387
    var src = img.getAttribute(attribute);
388
    img.removeAttribute(attribute);
389
    for (var i = 0, n = img.attributes.length; i < n; i++) {
390
      newDomImg.setAttribute(
391
        img.attributes[i].nodeName,
392
        img.attributes[i].nodeValue
393
      );
394
    }
395
    if (newDomImg.getAttribute('alt') === null && img.textContent != '') {
396
      newDomImg.setAttribute('alt', img.textContent);
397
    }
398
    newDomImg.setAttribute(
399
      'src',
400
      typeof responsiveImage === 'function' ? responsiveImage(src) : src
401
    );
402
    img.outerHTML = newDomImg.outerHTML;
403
  });
404
}
405