Passed
Push — master ( 9b6a8e...6511c3 )
by Dev
01:31
created

helpers.js ➔ replaceOn   A

Complexity

Conditions 4

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
dl 0
loc 16
rs 9.95
c 0
b 0
f 0
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', event = 'click') {
124
  var loadVideo = function (element) {
125
    var innerHtml = element.getAttribute(attribute);
126
    element.innerHTML = innerHtml;
127
  };
128
129
  document.querySelectorAll('[' + attribute + ']').forEach(function (element) {
130
    element.addEventListener(
131
      event,
132
      function () {
133
        loadVideo(element);
134
      },
135
      { once: true }
136
    );
137
  });
138
}
139
140
/**
141
 *
142
 *
143
 */
144
export function seasonedBackground() {
145
  document.querySelectorAll('[x-hash]').forEach(function (element) {
146
    if (window.location.hash) {
147
      if (element.getAttribute('x-hash') == window.location.hash.substring(1)) {
148
        element.parentNode.parentNode
149
          .querySelectorAll('img')
150
          .forEach(function (img) {
151
            img.style = 'display:none';
152
          });
153
        element.style = 'display:block';
154
      }
155
    }
156
  });
157
}
158
159
/**
160
 * Transform image's path (src) produce with Liip to responsive path
161
 *
162
 * @param {string} src
163
 */
164
export function responsiveImage(src) {
165
  var screenWidth = window.innerWidth;
166
  if (screenWidth <= 576) {
167
    src = src.replace('/default/', '/xs/');
168
  } else if (screenWidth <= 768) {
169
    src = src.replace('/default/', '/sm/');
170
  } else if (screenWidth <= 992) {
171
    src = src.replace('/default/', '/md/');
172
  } else if (screenWidth <= 1200) {
173
    src = src.replace('/default/', '/lg/');
174
  } else {
175
    // 1200+
176
    src = src.replace('/default/', '/xl/');
177
  }
178
179
  return src;
180
}
181
182
/**
183
 * Convert elements wich contain attribute (data-href) in normal link (a href)
184
 * You can use a callback function to decrypt the link (eg: rot13ToText ;-))
185
 *
186
 * @param {string}  attribute
187
 */
188
export async function uncloakLinks(attribute = 'data-rot') {
189
  var convertLink = function (element) {
190
    // fix "bug" with img
191
    if (element.getAttribute(attribute) === null) {
192
      var element = element.closest('[' + attribute + ']');
193
    }
194
    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...
195
    var link = document.createElement('a');
196
    var href = element.getAttribute(attribute);
197
    element.removeAttribute(attribute);
198
    for (var i = 0, n = element.attributes.length; i < n; i++) {
199
      link.setAttribute(
200
        element.attributes[i].nodeName,
201
        element.attributes[i].nodeValue
202
      );
203
    }
204
    link.innerHTML = element.innerHTML;
205
    link.setAttribute(
206
      'href',
207
      responsiveImage(convertShortchutForLink(rot13ToText(href)))
208
    );
209
    element.parentNode.replaceChild(link, element);
210
    return link;
211
  };
212
213
  var convertThemAll = function (attribute) {
214
    [].forEach.call(document.querySelectorAll('[' + attribute + ']'), function (
215
      element
216
    ) {
217
      convertLink(element);
218
    });
219
  };
220
221
  var fireEventLinksBuilt = async function (element, event) {
222
    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...
223
224
    var clickEvent = new Event(event.type);
225
    element.dispatchEvent(clickEvent);
226
  };
227
228
  var convertLinkOnEvent = async function (event) {
229
    // convert them all if it's an image (thanks this bug), permit to use gallery (baguetteBox)
230
    if (event.target.tagName == 'IMG') {
231
      await convertThemAll(attribute);
232
      var element = event.target;
233
    } else {
234
      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 232. 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...
235
    }
236
    fireEventLinksBuilt(element, event);
237
  };
238
239
  [].forEach.call(document.querySelectorAll('[' + attribute + ']'), function (
240
    element
241
  ) {
242
    element.addEventListener(
243
      'touchstart',
244
      function (e) {
245
        convertLinkOnEvent(e);
246
      },
247
      { once: true, passive: true }
248
    );
249
    element.addEventListener(
250
      'click',
251
      function (e) {
252
        convertLinkOnEvent(e);
253
      },
254
      { once: true }
255
    );
256
    element.addEventListener(
257
      'mouseover',
258
      function (e) {
259
        convertLinkOnEvent(e);
260
      },
261
      { once: true }
262
    );
263
  });
264
}
265
266
/**
267
 * Convert action attr encoded in rot 13 to normal action with default attr `data-frot`
268
 *
269
 * @param {string}  attribute
270
 */
271
export function convertFormFromRot13(attribute = 'data-frot') {
272
  [].forEach.call(document.querySelectorAll('[' + attribute + ']'), function (
273
    element
274
  ) {
275
    var action = element.getAttribute(attribute);
276
    element.removeAttribute(attribute);
277
    element.setAttribute(
278
      'action',
279
      convertShortchutForLink(rot13ToText(action))
280
    );
281
  });
282
}
283
284
export function convertShortchutForLink(str) {
285
  if (str.charAt(0) == '-') {
286
    return str.replace('-', 'http://');
287
  }
288
  if (str.charAt(0) == '_') {
289
    return str.replace('_', 'https://');
290
  }
291
  if (str.charAt(0) == '@') {
292
    return str.replace('@', 'mailto:');
293
  }
294
  return str;
295
}
296
297
/**
298
 * readableEmail(selector) Transform an email encoded with rot13 in a readable mail (and add mailto:)
299
 *
300
 * @param {string}  text
301
 */
302
export function readableEmail(selector) {
303
  document.querySelectorAll(selector).forEach(function (item) {
304
    var mail = rot13ToText(item.textContent);
305
    item.innerHTML = '<a href="mailto:' + mail + '">' + mail + '</a>';
306
    if (selector.charAt(0) == '.') {
307
      item.classList.remove(selector.substring(1));
308
    }
309
  });
310
}
311
312
/**
313
 * Decode rot13
314
 *
315
 * @param {string}  str
316
 */
317
export function rot13ToText(str) {
318
  return str.replace(/[a-zA-Z]/g, function (c) {
319
    return String.fromCharCode(
320
      (c <= 'Z' ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26
321
    );
322
  });
323
}
324
325
export function testWebPSupport() {
326
  var elem = document.createElement('canvas');
327
328
  if (elem.getContext && elem.getContext('2d')) {
329
    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...
330
  }
331
332
  return false;
333
}
334
335
/**
336
 * Used in ThemeComponent
337
 */
338
export function convertImageLinkToWebPLink() {
339
  var switchToWebP = function () {
340
    [].forEach.call(document.querySelectorAll('a[dwl]'), function (element) {
341
      var href = responsiveImage(element.getAttribute('dwl'));
342
      element.setAttribute('href', href);
343
      element.removeAttribute('dwl');
344
    });
345
  };
346
347
  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...
348
}
349
350
/**
351
 * Simple Image Lazy Loader
352
 * original from : https://davidwalsh.name/lazyload-image-fade
353
 *
354
 * @param {string}  attribute
355
 *
356
 * @example
357
 * imgLazyLoad()
358
 * <span data-img=/img/me.png>Tagada</span> or <img data-img=/img/me.png alt=Tagada>
359
 *
360
 * will be converted to
361
 *
362
 * <img src=/img/me.png alt=Tagada />
363
 *
364
 * still used in piedvert. To remove ?!
365
 */
366
export function imgLazyLoad(attribute = 'data-img') {
367
  [].forEach.call(document.querySelectorAll('[' + attribute + ']'), function (
368
    img
369
  ) {
370
    var newDomImg = document.createElement('img');
371
    var src = img.getAttribute(attribute);
372
    img.removeAttribute(attribute);
373
    for (var i = 0, n = img.attributes.length; i < n; i++) {
374
      newDomImg.setAttribute(
375
        img.attributes[i].nodeName,
376
        img.attributes[i].nodeValue
377
      );
378
    }
379
    if (newDomImg.getAttribute('alt') === null && img.textContent != '') {
380
      newDomImg.setAttribute('alt', img.textContent);
381
    }
382
    newDomImg.setAttribute(
383
      'src',
384
      typeof responsiveImage === 'function' ? responsiveImage(src) : src
385
    );
386
    img.outerHTML = newDomImg.outerHTML;
387
  });
388
}
389