Passed
Push — master ( a5b8e1...7a57ef )
by Dev
01:13
created

src/helpers.js   F

Complexity

Total Complexity 66
Complexity/F 1.89

Size

Lines of Code 337
Function Count 35

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 180
dl 0
loc 337
rs 3.12
c 0
b 0
f 0
wmc 66
mnd 31
bc 31
fnc 35
bpm 0.8857
cpm 1.8857
noi 11

10 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
F helpers.js ➔ formToSky 0 76 17
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
A helpers.js ➔ imgLazyLoad 0 23 5

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
 * - getBlockFromSky(attr)
5
 * - formToSky(attr)
6
 *
7
 * - responsiveImage(string)    Relative to Liip filters
8
 * - uncloakLinks(attr)
9
 * - convertFormFromRot13(attr)
10
 * - readableEmail(attr)
11
 * - convertImageLinkToWebPLink()
12
 */
13
14
/**
15
 * Fetch (ajax) function permitting to get block via a POST request
16
 * (prevent from spam)
17
 *
18
 * @param {string} attribute
19
 */
20
export function getBlockFromSky(attribute = "data-sky") {
21
  document.querySelectorAll("[" + attribute + "]").forEach(item => {
22
    fetch(item.getAttribute(attribute), {
23
      headers: { "Content-Type": "application/json", Accept: "text/plain" },
24
      method: "POST",
25
      // Later: maybe implement sending data form data-post
26
      // body: JSON.stringify({"contact": (document.getElementById("contact") !== null ? 1: 0)}),
27
      credentials: "same-origin"
28
    })
29
      .then(function(response) {
30
        return response.text();
31
      })
32
      .then(function(body) {
33
        item.removeAttribute("data-sky");
34
        item.innerHTML = body;
35
36
        // add export function to reDo on document dom ready
37
        if (typeof onPageLoaded === "function") {
0 ignored issues
show
Bug introduced by
The variable onPageLoaded seems to be never declared. If this is a global, consider adding a /** global: onPageLoaded */ 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...
38
          onPageLoaded();
39
        }
40
        if (typeof onDomLoaded === "function") {
0 ignored issues
show
Bug introduced by
The variable onDomLoaded seems to be never declared. If this is a global, consider adding a /** global: onDomLoaded */ 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...
41
          onDomLoaded();
42
        }
43
      });
44
  });
45
}
46
47
/**
48
 * ajaxify-form
49
 */
50
export function formToSky(userOptions = {}) {
51
  var options = {
52
    selector: ".ajax-form" // selector for ajax form
53
  };
54
  for (var attrname in userOptions) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
55
    options[attrname] = userOptions[attrname];
56
  }
57
58
  document.querySelectorAll(options.selector).forEach(item => {
59
    if (item.querySelector("form") !== null) {
60
      item.querySelector("form").addEventListener("submit", e => {
61
        e.preventDefault();
62
        sendFormToSky(e);
63
      });
64
    }
65
  });
66
67
  var sendFormToSky = function(form) {
68
    var $submitButton = getSubmitButton(form);
69
    if ($submitButton !== null) {
70
      var initialButton = getSubmitButton(form).outerHTML;
0 ignored issues
show
Unused Code introduced by
The variable initialButton seems to be never used. Consider removing it.
Loading history...
71
      $submitButton.outerHTML = '<i class="fa fa-spinner fa-spin"></i>';
72
    }
73
74
    //var formData = new FormData();
75
    var toSend = "";
76
    for (var i = 0; i < form.srcElement.length; ++i) {
77
      toSend +=
78
        encodeURI(form.srcElement[i].name) +
79
        "=" +
80
        encodeURI(form.srcElement[i].value) +
81
        "&";
82
    }
83
84
    var xmlhttp = new XMLHttpRequest();
85
    xmlhttp.addEventListener(
86
      "load",
87
      function() {
88
        form.srcElement.outerHTML = xmlhttp.responseText;
89
        formToSky();
90
      },
91
      false
92
    );
93
    xmlhttp.open("POST", form.srcElement.action, false);
94
    xmlhttp.setRequestHeader(
95
      "Content-type",
96
      "application/x-www-form-urlencoded"
97
    );
98
    xmlhttp.send(toSend);
99
  };
100
101
  var renderError = function(error) {
0 ignored issues
show
Unused Code introduced by
The variable renderError seems to be never used. Consider removing it.
Loading history...
102
    var msg = "";
103
    for (var key in error) {
104
      if (error.hasOwnProperty(key)) {
105
        var obj = error[key];
106
        for (var prop in obj) {
107
          if (obj.hasOwnProperty(prop)) {
108
            msg += key + " : " + obj[prop] + "<br>";
109
          }
110
        }
111
      }
112
    }
113
    return msg;
114
  };
115
116
  var getSubmitButton = function(form) {
117
    if (form.srcElement.querySelector("[type=submit]") !== null) {
118
      return form.srcElement.querySelector("[type=submit]");
119
    }
120
    if (form.srcElement.getElementsByTagName("button") !== null) {
121
      return form.srcElement.getElementsByTagName("button");
122
    }
123
    return null;
124
  };
125
}
126
127
/**
128
 * Transform image's path (src) produce with Liip to responsive path
129
 *
130
 * @param {string} src
131
 */
132
export function responsiveImage(src) {
133
  var screenWidth = window.innerWidth;
134
  if (screenWidth <= 576) {
135
    src = src.replace("/default/", "/xs/");
136
  } else if (screenWidth <= 768) {
137
    src = src.replace("/default/", "/sm/");
138
  } else if (screenWidth <= 992) {
139
    src = src.replace("/default/", "/md/");
140
  } else if (screenWidth <= 1200) {
141
    src = src.replace("/default/", "/lg/");
142
  } else {
143
    // 1200+
144
    src = src.replace("/default/", "/xl/");
145
  }
146
147
  return src;
148
}
149
150
/**
151
 * Convert elements wich contain attribute (data-href) in normal link (a href)
152
 * You can use a callback function to decrypt the link (eg: rot13ToText ;-))
153
 *
154
 * @param {string}  attribute
155
 */
156
export async function uncloakLinks(attribute = "data-rot") {
157
  var convertLink = function(element) {
158
    // fix "bug" with img
159
    if (element.getAttribute(attribute) === null) {
160
      var element = element.closest("[" + attribute + "]");
161
    }
162
    if (element.getAttribute(attribute) === null) return;
0 ignored issues
show
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...
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...
163
    var link = document.createElement("a");
164
    var href = element.getAttribute(attribute);
165
    element.removeAttribute(attribute);
166
    for (var i = 0, n = element.attributes.length; i < n; i++) {
167
      link.setAttribute(
168
        element.attributes[i].nodeName,
169
        element.attributes[i].nodeValue
170
      );
171
    }
172
    link.innerHTML = element.innerHTML;
173
    link.setAttribute(
174
      "href",
175
      responsiveImage(convertShortchutForLink(rot13ToText(href)))
176
    );
177
    element.parentNode.replaceChild(link, element);
178
    return link;
179
  };
180
181
  var convertThemAll = function(attribute) {
182
    [].forEach.call(document.querySelectorAll("[" + attribute + "]"), function(
183
      element
184
    ) {
185
      convertLink(element);
186
    });
187
  };
188
189
  var fireEventLinksBuilt = async function(element, event) {
190
    await document.dispatchEvent(new Event("linksBuilt"));
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...
191
192
    var clickEvent = new Event(event.type);
193
    element.dispatchEvent(clickEvent);
194
  };
195
196
  var convertLinkOnEvent = async function(event) {
197
    // convert them all if it's an image (thanks this bug), permit to use gallery (baguetteBox)
198
    if (event.target.tagName == "IMG") {
199
      await convertThemAll(attribute);
200
      var element = event.target;
201
    } else {
202
      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 200. 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...
203
    }
204
    fireEventLinksBuilt(element, event);
205
  };
206
207
  [].forEach.call(document.querySelectorAll("[" + attribute + "]"), function(
208
    element
209
  ) {
210
    element.addEventListener(
211
      "touchstart",
212
      function(e) {
213
        convertLinkOnEvent(e);
214
      },
215
      { once: true }
216
    );
217
    element.addEventListener(
218
      "click",
219
      function(e) {
220
        convertLinkOnFly(e);
221
      },
222
      { once: true }
223
    );
224
    element.addEventListener(
225
      "mouseover",
226
      function(e) {
227
        convertInLinksRot13OnFly(e);
228
      },
229
      { once: true }
230
    );
231
  });
232
}
233
234
/**
235
 * Convert action attr encoded in rot 13 to normal action with default attr `data-frot`
236
 *
237
 * @param {string}  attribute
238
 */
239
export function convertFormFromRot13(attribute = "data-frot") {
240
  [].forEach.call(document.querySelectorAll("[" + attribute + "]"), function(
241
    element
242
  ) {
243
    var action = element.getAttribute(attribute);
244
    element.removeAttribute(attribute);
245
    element.setAttribute(
246
      "action",
247
      convertShortchutForLink(rot13ToText(action))
248
    );
249
  });
250
}
251
252
export function convertShortchutForLink(str) {
253
  if (str.charAt(0) == "-") {
254
    return str.replace("-", "http://");
255
  }
256
  if (str.charAt(0) == "_") {
257
    return str.replace("_", "https://");
258
  }
259
  if (str.charAt(0) == "@") {
260
    return str.replace("@", "mailto:");
261
  }
262
  return str;
263
}
264
265
/**
266
 * readableEmail(selector) Transform an email encoded with rot13 in a readable mail (and add mailto:)
267
 *
268
 * @param {string}  text
269
 */
270
export function readableEmail(selector) {
271
  document.querySelectorAll(selector).forEach(function(item) {
272
    var mail = rot13ToText(item.textContent);
273
    item.innerHTML = '<a href="mailto:' + mail + '">' + mail + "</a>";
274
    if (selector.charAt(0) == ".") {
275
      item.classList.remove(selector.substring(1));
276
    }
277
  });
278
}
279
280
/**
281
 * Decode rot13
282
 *
283
 * @param {string}  str
284
 */
285
export function rot13ToText(str) {
286
  return str.replace(/[a-zA-Z]/g, function(c) {
287
    return String.fromCharCode(
288
      (c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26
289
    );
290
  });
291
}
292
293
export function testWebPSupport() {
294
  var elem = document.createElement("canvas");
295
296
  if (elem.getContext && elem.getContext("2d")) {
297
    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...
298
  }
299
300
  return false;
301
}
302
303
/**
304
 * Used in ThemeComponent
305
 */
306
export function convertImageLinkToWebPLink() {
307
  var switchToWebP = function() {
308
    [].forEach.call(document.querySelectorAll("a[dwl]"), function(element) {
309
      var href = responsiveImage(element.getAttribute("dwl"));
310
      element.setAttribute("href", href);
311
      element.removeAttribute("dwl");
312
    });
313
  };
314
315
  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...
316
}
317
318
/**
319
 * Simple Image Lazy Loader
320
 * original from : https://davidwalsh.name/lazyload-image-fade
321
 *
322
 * @param {string}  attribute
323
 *
324
 * @example
325
 * imgLazyLoad()
326
 * <span data-img=/img/me.png>Tagada</span> or <img data-img=/img/me.png alt=Tagada>
327
 *
328
 * will be converted to
329
 *
330
 * <img src=/img/me.png alt=Tagada />
331
 * 
332
 * still used in piedvert. To remove ?!
333
 */
334
export function imgLazyLoad(attribute = "data-img") {
335
  [].forEach.call(document.querySelectorAll("[" + attribute + "]"), function(
336
    img
337
  ) {
338
    var newDomImg = document.createElement("img");
339
    var src = img.getAttribute(attribute);
340
    img.removeAttribute(attribute);
341
    for (var i = 0, n = img.attributes.length; i < n; i++) {
342
      newDomImg.setAttribute(
343
        img.attributes[i].nodeName,
344
        img.attributes[i].nodeValue
345
      );
346
    }
347
    if (newDomImg.getAttribute("alt") === null && img.textContent != "") {
348
      newDomImg.setAttribute("alt", img.textContent);
349
    }
350
    newDomImg.setAttribute(
351
      "src",
352
      typeof responsiveImage === "function" ? responsiveImage(src) : src
353
    );
354
    img.outerHTML = newDomImg.outerHTML;
355
  });
356
}
357