Passed
Push — master ( 3643fc...a7d1bd )
by Dev
01:17
created

src/helpers.js   F

Complexity

Total Complexity 64
Complexity/F 1.56

Size

Lines of Code 320
Function Count 41

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 168
dl 0
loc 320
rs 3.28
c 0
b 0
f 0
wmc 64
mnd 23
bc 23
fnc 41
bpm 0.5608
cpm 1.5609
noi 9

9 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 ➔ testWebPSupport 0 9 2
A helpers.js ➔ responsiveImage 0 17 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
 * - responsiveImage(string)    Relative to Liip filters
8
 * - uncloakLinks(attr)
9
 * - convertFormFromRot13(attr)
10
 * - readableEmail(attr)
11
 * - convertImageLinkToWebPLink()
12
 */
13
14
/**
15
 * Live Block Watcher (and button)
16
 * 
17
 * Fetch (ajax) function permitting to get block via a POST request
18
 *
19
 * @param {string} attribute
20
 */
21
export function liveBlock(liveBlockAttribute = "data-live", liveFormSelector = ".live-form") {
22
    
23
  var btnToBlock = function(event, btn) {
24
    btn.setAttribute(liveBlockAttribute, btn.getAttribute("src-"+liveBlockAttribute));
25
    getLiveBlock(btn);
26
  }
27
  
28
  var getLiveBlock = function(item) {
29
    fetch(item.getAttribute(liveBlockAttribute), {
30
      //headers: { "Content-Type": "application/json", Accept: "text/plain" },
31
      method: "POST",
32
      credentials: "include"
33
    })
34
    .then(function(response) {
35
      return response.text();
36
    })
37
    .then(function(body) {
38
      item.removeAttribute(liveBlockAttribute);
39
      item.outerHTML = body;
40
    }).
41
    then(function() {
42
      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...
43
    });
44
  }
45
46
  var htmlLoader = '<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>';
47
  
48
  var setLoader = function (form) {
49
    var $submitButton = getSubmitButton(form);
50
    if ($submitButton !== undefined) {
51
      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...
52
      $submitButton.innerHTML = '';
53
      $submitButton.outerHTML = htmlLoader;
54
    }
55
  }
56
  
57
  var sendForm = function(form, liveFormBlock) {
58
     setLoader(form);
59
     
60
    var formData = new FormData(form.srcElement);
61
    fetch(form.srcElement.action, {
62
      method: "POST",
63
      body: formData,
64
      credentials: "include"
65
    })
66
      .then(function(response) {
67
        return response.text();
68
      })
69
      .then(function(body) {
70
        liveFormBlock.outerHTML = body;
71
      })
72
      .then(function() {
73
        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...
74
      });
75
  };
76
77
  var getSubmitButton = function(form) {
78
    if (form.srcElement.querySelector("[type=submit]") !== null) {
79
      return form.srcElement.querySelector("[type=submit]");
80
    }
81
    if (form.srcElement.getElementsByTagName("button") !== null) {
82
      return form.srcElement.getElementsByTagName("button")[0];
83
    }
84
    return null;
85
  };
86
  
87
  
88
  // Listen data-live
89
  document.querySelectorAll("[" + liveBlockAttribute + "]").forEach(item => {
90
    getLiveBlock(item);
91
  });
92
  
93
  // Listen button src-data-live
94
  document.querySelectorAll("[src-" + liveBlockAttribute + "]").forEach(item => {
95
    item.addEventListener("click", event => {
96
      btnToBlock(event, item);
97
    });
98
  });
99
  
100
  // Listen live-form
101
  document.querySelectorAll(liveFormSelector).forEach(item => {
102
    if (item.querySelector("form") !== null) {
103
      item.querySelector("form").addEventListener("submit", e => {
104
        e.preventDefault();
105
        sendForm(e, item);
106
      });
107
    }
108
  });
109
}
110
111
/**
112
 * Transform image's path (src) produce with Liip to responsive path
113
 *
114
 * @param {string} src
115
 */
116
export function responsiveImage(src) {
117
  var screenWidth = window.innerWidth;
118
  if (screenWidth <= 576) {
119
    src = src.replace("/default/", "/xs/");
120
  } else if (screenWidth <= 768) {
121
    src = src.replace("/default/", "/sm/");
122
  } else if (screenWidth <= 992) {
123
    src = src.replace("/default/", "/md/");
124
  } else if (screenWidth <= 1200) {
125
    src = src.replace("/default/", "/lg/");
126
  } else {
127
    // 1200+
128
    src = src.replace("/default/", "/xl/");
129
  }
130
131
  return src;
132
}
133
134
/**
135
 * Convert elements wich contain attribute (data-href) in normal link (a href)
136
 * You can use a callback function to decrypt the link (eg: rot13ToText ;-))
137
 *
138
 * @param {string}  attribute
139
 */
140
export async function uncloakLinks(attribute = "data-rot") {
141
  var convertLink = function(element) {
142
    // fix "bug" with img
143
    if (element.getAttribute(attribute) === null) {
144
      var element = element.closest("[" + attribute + "]");
145
    }
146
    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...
147
    var link = document.createElement("a");
148
    var href = element.getAttribute(attribute);
149
    element.removeAttribute(attribute);
150
    for (var i = 0, n = element.attributes.length; i < n; i++) {
151
      link.setAttribute(
152
        element.attributes[i].nodeName,
153
        element.attributes[i].nodeValue
154
      );
155
    }
156
    link.innerHTML = element.innerHTML;
157
    link.setAttribute(
158
      "href",
159
      responsiveImage(convertShortchutForLink(rot13ToText(href)))
160
    );
161
    element.parentNode.replaceChild(link, element);
162
    return link;
163
  };
164
165
  var convertThemAll = function(attribute) {
166
    [].forEach.call(document.querySelectorAll("[" + attribute + "]"), function(
167
      element
168
    ) {
169
      convertLink(element);
170
    });
171
  };
172
173
  var fireEventLinksBuilt = async function(element, event) {
174
    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...
175
176
    var clickEvent = new Event(event.type);
177
    element.dispatchEvent(clickEvent);
178
  };
179
180
  var convertLinkOnEvent = async function(event) {
181
    // convert them all if it's an image (thanks this bug), permit to use gallery (baguetteBox)
182
    if (event.target.tagName == "IMG") {
183
      await convertThemAll(attribute);
184
      var element = event.target;
185
    } else {
186
      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 184. 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...
187
    }
188
    fireEventLinksBuilt(element, event);
189
  };
190
191
  [].forEach.call(document.querySelectorAll("[" + attribute + "]"), function(
192
    element
193
  ) {
194
    element.addEventListener(
195
      "touchstart",
196
      function(e) {
197
        convertLinkOnEvent(e);
198
      },
199
      { once: true }
200
    );
201
    element.addEventListener(
202
      "click",
203
      function(e) {
204
        convertLinkOnEvent(e);
205
      },
206
      { once: true }
207
    );
208
    element.addEventListener(
209
      "mouseover",
210
      function(e) {
211
        convertLinkOnEvent(e);
212
      },
213
      { once: true }
214
    );
215
  });
216
}
217
218
/**
219
 * Convert action attr encoded in rot 13 to normal action with default attr `data-frot`
220
 *
221
 * @param {string}  attribute
222
 */
223
export function convertFormFromRot13(attribute = "data-frot") {
224
  [].forEach.call(document.querySelectorAll("[" + attribute + "]"), function(
225
    element
226
  ) {
227
    var action = element.getAttribute(attribute);
228
    element.removeAttribute(attribute);
229
    element.setAttribute(
230
      "action",
231
      convertShortchutForLink(rot13ToText(action))
232
    );
233
  });
234
}
235
236
export function convertShortchutForLink(str) {
237
  if (str.charAt(0) == "-") {
238
    return str.replace("-", "http://");
239
  }
240
  if (str.charAt(0) == "_") {
241
    return str.replace("_", "https://");
242
  }
243
  if (str.charAt(0) == "@") {
244
    return str.replace("@", "mailto:");
245
  }
246
  return str;
247
}
248
249
/**
250
 * readableEmail(selector) Transform an email encoded with rot13 in a readable mail (and add mailto:)
251
 *
252
 * @param {string}  text
253
 */
254
export function readableEmail(selector) {
255
  document.querySelectorAll(selector).forEach(function(item) {
256
    var mail = rot13ToText(item.textContent);
257
    item.innerHTML = '<a href="mailto:' + mail + '">' + mail + "</a>";
258
    if (selector.charAt(0) == ".") {
259
      item.classList.remove(selector.substring(1));
260
    }
261
  });
262
}
263
264
/**
265
 * Decode rot13
266
 *
267
 * @param {string}  str
268
 */
269
export function rot13ToText(str) {
270
  return str.replace(/[a-zA-Z]/g, function(c) {
271
    return String.fromCharCode(
272
      (c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26
273
    );
274
  });
275
}
276
277
export function testWebPSupport() {
278
  var elem = document.createElement("canvas");
279
280
  if (elem.getContext && elem.getContext("2d")) {
281
    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...
282
  }
283
284
  return false;
285
}
286
287
/**
288
 * Used in ThemeComponent
289
 */
290
export function convertImageLinkToWebPLink() {
291
  var switchToWebP = function() {
292
    [].forEach.call(document.querySelectorAll("a[dwl]"), function(element) {
293
      var href = responsiveImage(element.getAttribute("dwl"));
294
      element.setAttribute("href", href);
295
      element.removeAttribute("dwl");
296
    });
297
  };
298
299
  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...
300
}
301
302
/**
303
 * Simple Image Lazy Loader
304
 * original from : https://davidwalsh.name/lazyload-image-fade
305
 *
306
 * @param {string}  attribute
307
 *
308
 * @example
309
 * imgLazyLoad()
310
 * <span data-img=/img/me.png>Tagada</span> or <img data-img=/img/me.png alt=Tagada>
311
 *
312
 * will be converted to
313
 *
314
 * <img src=/img/me.png alt=Tagada />
315
 * 
316
 * still used in piedvert. To remove ?!
317
 */
318
export function imgLazyLoad(attribute = "data-img") {
319
  [].forEach.call(document.querySelectorAll("[" + attribute + "]"), function(
320
    img
321
  ) {
322
    var newDomImg = document.createElement("img");
323
    var src = img.getAttribute(attribute);
324
    img.removeAttribute(attribute);
325
    for (var i = 0, n = img.attributes.length; i < n; i++) {
326
      newDomImg.setAttribute(
327
        img.attributes[i].nodeName,
328
        img.attributes[i].nodeValue
329
      );
330
    }
331
    if (newDomImg.getAttribute("alt") === null && img.textContent != "") {
332
      newDomImg.setAttribute("alt", img.textContent);
333
    }
334
    newDomImg.setAttribute(
335
      "src",
336
      typeof responsiveImage === "function" ? responsiveImage(src) : src
337
    );
338
    img.outerHTML = newDomImg.outerHTML;
339
  });
340
}
341