PageSourceSearch

http://www.comptoirduscrap.fr/js1776270319/design/paniercommande.js

js comptoirduscrap.fr collected 2026-09-26 12:02:47 UTC 322,620 bytes, 8,789 lines download raw bytes

1/******/ (function() { // webpackBootstrap
2/******/ 	"use strict";
3/******/ 	var __webpack_modules__ = ({
4
5/***/ "./js/components/SwiperEditorConfig.js":
6/*!*********************************************!*\
7  !*** ./js/components/SwiperEditorConfig.js ***!
8  \*********************************************/
9/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
10
11/* harmony export */ __webpack_require__.d(__webpack_exports__, {
12/* harmony export */   getSliderParams: function() { return /* binding */ getSliderParams; }
13/* harmony export */ });
14/* harmony import */ var _helper_CSS__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../helper/CSS */ "./js/helper/CSS.js");
15
16function getSliderParams(widget) {
17  let slidesPerViewInline = widget.style.getPropertyValue('--slides-per-view');
18  let slidesPerView = slidesPerViewInline !== "" ? parseInt(slidesPerViewInline) : getComputedStyle(widget).getPropertyValue('--slides-per-view');
19  let spaceBetween = getComputedStyle(widget).getPropertyValue('--slides-space-between');
20  let autoplay = getComputedStyle(widget).getPropertyValue('--autoplay');
21  slidesPerView = slidesPerView ? parseInt(slidesPerView) : 3;
22  spaceBetween = spaceBetween ? parseInt(spaceBetween) : 30;
23  let autoplayConfig = false;
24  if (autoplay && autoplay !== 'false') {
25    if (/s/.test(autoplay)) {
26      const valueInfo = (0,_helper_CSS__WEBPACK_IMPORTED_MODULE_0__.getValueInfos)(autoplay);
27      autoplay = (0,_helper_CSS__WEBPACK_IMPORTED_MODULE_0__.convertUnitByInfo)(valueInfo.value, 'ms', {
28        computed: valueInfo.value,
29        ...valueInfo
30      });
31    }
32    autoplay = parseInt(autoplay);
33    if (autoplay < 1000) {
34      autoplay *= 1000;
35    }
36    autoplayConfig = {
37      delay: autoplay
38    };
39  }
40  return {
41    slidesPerView,
42    spaceBetween,
43    autoplayConfig,
44    autoplayRaw: autoplay,
45    // On garde la valeur brute pour comparaison
46    isInline: !!slidesPerViewInline
47  };
48}
49
50
51/***/ }),
52
53/***/ "./js/helper/CSS.js":
54/*!**************************!*\
55  !*** ./js/helper/CSS.js ***!
56  \**************************/
57/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
58
59/* harmony export */ __webpack_require__.d(__webpack_exports__, {
60/* harmony export */   convertUnitByInfo: function() { return /* binding */ convertUnitByInfo; },
61/* harmony export */   getValueInfos: function() { return /* binding */ getValueInfos; }
62/* harmony export */ });
63/* unused harmony exports cleanValuePropsCSS, getFontNameFromFontFamily, getValueOnEm, getValueOnRem, getBackgroundImageValue, DEFAULT_CLIP_TEXT_GRADIENT, convertBackgroundPositionToString, getPseudoFormatByName, getDefaultValueCss, cssComputedCache, getShortValueCss, getDecodeShortValue, expandShorthandToLonghands, isTargetedShorthand, normalizeDeclarations, normalizeCSSRuleStore, getInfoFromMultiProps, getUnit, getPropRefForPercent, getComputedByInfo, getTranslateValues, getPercentFromTwoValue, getValueWithoutPrefix, verifAndGetValueWithPrefix, getBorderColor, getBorderStyle, getDefaultUnit, addHistoryRemoveFromProps, getCSSQuery, getCSSQueryAllStatus, getCSSQuerySaveKeys, getStatusToClassAndPseudoClass, generatePositionValue, getInitialValue, convertTime, calcMsToUnit, calcToMs, getValueViewWidth, getDefaultDisplayValue, getMediaQuery, getMediaQueryCss, getBackgroundPositionInfo, getBackgroundPositionString, getBackgroundSizeInfo, hasInitialValue, getDefaultTransformItem, getTransformValue, generateTransformValue, decomposeMatrix2d, getTransformOriginValue, generateTransformOriginValue, parseGradient, generateGradient, getBackgroundLayers, generateBackgroundLonghands, getShadowValue, generateShadowValue, getDefaultShadowItem */
64/* harmony import */ var _Math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Math */ "./js/helper/Math.js");
65/* harmony import */ var _String__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./String */ "./js/helper/String.js");
66
67
68
69
70const regexFunctionCss = /([a-z]{3,}\((?:(?:\()[a-z]{3,}\([^\)]*\)|[^()]+)\)|([a-z]{3,}\(.*\)))|([^\s]+)/;
71const regexFunctionCssGlobal = new RegExp(regexFunctionCss.source, 'g');
72const minisite = document.querySelector('#minisite');
73function pxToEm(valuePixel, fontSize) {
74  return parseFloat(valuePixel) / parseFloat(fontSize).toFixed(2);
75}
76function emToPx(valueEm, fontSize) {
77  return parseFloat(valueEm) * parseFloat(fontSize);
78}
79
80/**
81 *
82 * @param elementSelector
83 * @param value
84 * @returns {*}
85 */
86const getValueOnEm = function (elementSelector, value) {
87  let valueFontSize = window.getComputedStyle(elementSelector, null).getPropertyValue('font-size');
88  if (/px/.test(value)) {
89    value = pxToEm(value, valueFontSize);
90  }
91  return secureValueShow(value, 0);
92};
93const getValueOnRem = function (elementSelector, value) {
94  let valueFontSize = window.getComputedStyle(elementSelector.ownerDocument.documentElement, null).getPropertyValue('font-size');
95  if (/px/.test(value)) {
96    value = pxToEm(value, valueFontSize);
97  }
98  return secureValueShow(value, 0);
99};
100const getValueWithoutPrefix = function (value) {
101  let match = /((?:[-0-9.]+)?|auto)[\S]+/.exec(value);
102  if (match) {
103    value = _Math__WEBPACK_IMPORTED_MODULE_0__["default"].cleanFloatValue(parseFloat(match[1]));
104  }
105  return value;
106};
107const getValueViewWidth = function (value, context) {
108  const valueInfo = getValueInfos(value.computed);
109  const valuepx = convertUnitByInfo(valueInfo.value, 'px', value);
110  const width100vwInPx = context.width;
111
112  // vw
113  return valuepx / width100vwInPx * 100;
114};
115const getFontNameFromFontFamily = function (value) {
116  let regexFontFamily = /(?:"?([\w\d][\w\d-\s]+[\w\d])"?,?)/gm;
117  let fontArray = regexFontFamily.exec(value);
118  let font = value;
119  if (fontArray) {
120    font = fontArray[1];
121  }
122  return font;
123};
124const cleanValuePropsCSS = function (propName, value) {
125  switch (propName) {
126    case 'font-family':
127      value = getFontNameFromFontFamily(value);
128      break;
129    case 'letter-spacing':
130      if (/normal/.test(value)) {
131        value = '0em';
132      }
133      break;
134    case 'line-height':
135      if (/normal/.test(value)) {
136        value = '1.2';
137      }
138      break;
139  }
140  return value;
141};
142const propDontViewport = ['line-height'];
143
144/**
145 * Cache pour les valeurs CSS computées.
146 * Stocke les résultats de getComputedStyle par élément et par état DOM
147 * pour éviter les reflows répétés (layout thrashing).
148 *
149 * Supporte plusieurs éléments actifs simultanément (Map<element, session>),
150 * pour pouvoir batcher également les lectures parent/offsetParent.
151 *
152 * Usage :
153 *   cssComputedCache.begin(element, null, props)   — ouvre une session pour un élément
154 *   getDefaultValueCss(...)                        — utilise le cache automatiquement
155 *   cssComputedCache.end(element)                  — ferme la session de cet élément
156 *   cssComputedCache.end()                         — ferme TOUTES les sessions actives
157 */
158const cssComputedCache = (() => {
159  // Map<element, sessionState>
160  // sessionState = { pseudo, props, cache, windowWidthInfo, windowHeightInfo, windowHeightAuto }
161  const _sessions = new Map();
162
163  /**
164   * Lit toutes les props enregistrées pour un état donné.
165   * Appelé une seule fois par état (lazy, au premier get() pour cet état).
166   * = 1 seul reflow par état, quel que soit le nombre de props.
167   */
168  function _readState(element, pseudo, state) {
169    const session = _sessions.get(element);
170    if (!session) return;
171    if (session.cache[state]) return; // déjà lu
172
173    const props = session.props;
174    session.cache[state] = {};
175    switch (state) {
176      case 'normal':
177        {
178          const computed = window.getComputedStyle(element, pseudo);
179          props.forEach(p => {
180            session.cache[state][p] = computed.getPropertyValue(p);
181          });
182          break;
183        }
184      case 'hidden':
185        {
186          element.style.display = 'none';
187          const computed = window.getComputedStyle(element, pseudo);
188          props.forEach(p => {
189            session.cache[state][p] = computed.getPropertyValue(p);
190          });
191          element.style.removeProperty('display');
192          break;
193        }
194      case 'vw':
195        {
196          session.windowWidthInfo = session.windowWidthInfo || getValueInfos(document.body.style.getPropertyValue('--minisite-width'));
197          document.body.style.setProperty('--minisite-width', session.windowWidthInfo.value - 2 + 'px');
198          const computed = window.getComputedStyle(element, pseudo);
199          props.forEach(p => {
200            session.cache[state][p] = computed.getPropertyValue(p);
201          });
202          document.body.style.setProperty('--minisite-width', session.windowWidthInfo.value + 'px');
203          break;
204        }
205      case 'vh':
206        {
207          session.windowHeightInfo = session.windowHeightInfo || getValueInfos(document.body.style.getPropertyValue('--minisite-height'));
208          session.windowHeightAuto = session.windowHeightInfo.value !== '';
209          if (session.windowHeightAuto) {
210            document.body.style.setProperty('--minisite-height', session.windowHeightInfo.value - 2 + 'px');
211          } else {
212            document.body.style.setProperty('--minisite-height', window.innerHeight - 2 + 'px');
213          }
214          const computed = window.getComputedStyle(element, pseudo);
215          props.forEach(p => {
216            session.cache[state][p] = computed.getPropertyValue(p);
217          });
218          if (session.windowHeightAuto) {
219            document.body.style.setProperty('--minisite-height', session.windowHeightInfo.value + 'px');
220          } else {
221            document.body.style.removeProperty('--minisite-height');
222          }
223          break;
224        }
225    }
226  }
227  return {
228    /**
229     * Ouvre une session de cache pour un élément.
230     * Lazy : aucune lecture DOM n'est faite ici.
231     * Plusieurs éléments peuvent être actifs simultanément.
232     */
233    begin(element, pseudoElement = null, props = []) {
234      if (!element) return;
235      _sessions.set(element, {
236        pseudo: pseudoElement,
237        props: props,
238        cache: {},
239        windowWidthInfo: null,
240        windowHeightInfo: null,
241        windowHeightAuto: false
242      });
243    },
244    /**
245     * Ferme la session de cache.
246     * end(element) : ferme la session de cet élément spécifique.
247     * end() : ferme TOUTES les sessions actives.
248     */
249    end(element) {
250      if (typeof element === 'undefined') {
251        _sessions.clear();
252      } else {
253        _sessions.delete(element);
254      }
255    },
256    /**
257     * Vérifie si le cache est actif pour cet élément.
258     */
259    isActive(element) {
260      return _sessions.has(element);
261    },
262    /**
263     * Invalide le cache des valeurs lues (les états seront re-lus au prochain get).
264     * À appeler quand l'état DOM de l'élément change (ajout/retrait de classe, etc.).
265     * invalidate(element) : invalide une session spécifique.
266     * invalidate() : invalide toutes les sessions.
267     */
268    invalidate(element) {
269      const reset = session => {
270        session.cache = {};
271        session.windowWidthInfo = null;
272        session.windowHeightInfo = null;
273        session.windowHeightAuto = false;
274      };
275      if (typeof element === 'undefined') {
276        _sessions.forEach(reset);
277      } else {
278        const session = _sessions.get(element);
279        if (session) reset(session);
280      }
281    },
282    /**
283     * Récupère une valeur depuis le cache pour un état donné.
284     * Au premier appel pour un état, lit TOUTES les props en une passe (1 reflow).
285     * Les appels suivants pour le même état sont gratuits.
286     */
287    get(element, pseudoElement, prop, state = 'normal') {
288      const session = _sessions.get(element);
289      if (!session) return null;
290
291      // Lazy : lire toutes les props pour cet état si pas encore fait
292      if (!session.cache[state]) {
293        _readState(element, pseudoElement, state);
294      }
295
296      // Si la prop est dans le cache, la retourner
297      if (prop in session.cache[state]) {
298        return session.cache[state][prop];
299      }
300
301      // Prop pas dans la liste initiale : lecture individuelle (fallback)
302      switch (state) {
303        case 'hidden':
304          element.style.display = 'none';
305          session.cache[state][prop] = window.getComputedStyle(element, pseudoElement).getPropertyValue(prop);
306          element.style.removeProperty('display');
307          break;
308        case 'vw':
309          session.windowWidthInfo = session.windowWidthInfo || getValueInfos(document.body.style.getPropertyValue('--minisite-width'));
310          document.body.style.setProperty('--minisite-width', session.windowWidthInfo.value - 2 + 'px');
311          session.cache[state][prop] = window.getComputedStyle(element, pseudoElement).getPropertyValue(prop);
312          document.body.style.setProperty('--minisite-width', session.windowWidthInfo.value + 'px');
313          break;
314        case 'vh':
315          session.windowHeightInfo = session.windowHeightInfo || getValueInfos(document.body.style.getPropertyValue('--minisite-height'));
316          session.windowHeightAuto = session.windowHeightInfo.value !== '';
317          if (session.windowHeightAuto) {
318            document.body.style.setProperty('--minisite-height', session.windowHeightInfo.value - 2 + 'px');
319          } else {
320            document.body.style.setProperty('--minisite-height', window.innerHeight - 2 + 'px');
321          }
322          session.cache[state][prop] = window.getComputedStyle(element, pseudoElement).getPropertyValue(prop);
323          if (session.windowHeightAuto) {
324            document.body.style.setProperty('--minisite-height', session.windowHeightInfo.value + 'px');
325          } else {
326            document.body.style.removeProperty('--minisite-height');
327          }
328          break;
329        default:
330          session.cache[state][prop] = window.getComputedStyle(element, pseudoElement).getPropertyValue(prop);
331          break;
332      }
333      return session.cache[state][prop];
334    }
335  };
336})();
337
338/**
339 * Whitelist des props pour lesquelles `getDefaultValueCss(..., origin=true)`
340 * apporte une vraie valeur (détection vw/vh, lecture en display:none).
341 * Les autres props (color, font-family, font-weight, etc.) ont une valeur
342 * identique en mode origin et normal — la version origin=true ouvre la
343 * branche hidden+vw+vh qui force des reflows inutiles (Option I).
344 */
345const viewportConvertibleProps = new Set([
346// Dimensions
347'width', 'height', 'min-width', 'max-width', 'min-height', 'max-height',
348// Positionnement
349'top', 'left', 'bottom', 'right',
350// Espacement
351'margin-top', 'margin-right', 'margin-bottom', 'margin-left', 'padding-top', 'padding-right', 'padding-bottom', 'padding-left', 'gap', 'row-gap', 'column-gap',
352// Typographie sensible aux unités
353'font-size', 'line-height', 'letter-spacing', 'word-spacing', 'text-indent',
354// Bordures
355'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width', 'border-top-left-radius', 'border-top-right-radius', 'border-bottom-left-radius', 'border-bottom-right-radius',
356// Autres
357'outline-width', 'outline-offset', 'background-position', 'background-position-x', 'background-position-y', 'background-size', 'transform', 'transform-origin']);
358const getDefaultValueCss = function (element, pseudoElement, prop, origin = false) {
359  while (element && element.nodeName !== "HTML") {
360    // Si le cache est actif pour cet élément, utiliser le cache
361    if (cssComputedCache.isActive(element)) {
362      let value;
363      if (origin && prop !== 'display') {
364        // Lire la valeur avec display:none (pour récupérer les %)
365        value = cssComputedCache.get(element, pseudoElement, prop, 'hidden');
366      } else {
367        value = cssComputedCache.get(element, pseudoElement, prop, 'normal');
368      }
369      if (origin) {
370        if (/px/.test(value) && !/\s/.test(value) && !/calc\(/.test(value) && propDontViewport.indexOf(prop) === -1) {
371          let valueTemp = cssComputedCache.get(element, pseudoElement, prop, 'normal');
372          let valueViewWidth = cssComputedCache.get(element, pseudoElement, prop, 'vw');
373          let valueInfos = getValueInfos(valueTemp, prop);
374          let valueViewWidthInfos = getValueInfos(valueViewWidth, prop);
375          let isCalculate = false;
376          if (valueViewWidth !== 'auto' && valueTemp !== valueViewWidth && (0,_Math__WEBPACK_IMPORTED_MODULE_0__.valueEqualtoWithinOnePercent)(valueInfos.value, valueViewWidthInfos.value)) {
377            value = convertUnit(element, pseudoElement, prop, valueInfos, 'vw') + 'vw';
378            isCalculate = true;
379          }
380          if (!isCalculate) {
381            let valueViewHeight = cssComputedCache.get(element, pseudoElement, prop, 'vh');
382            let valueViewHeightInfos = getValueInfos(valueViewHeight, prop);
383            if (valueViewHeight !== 'auto' && valueTemp !== valueViewHeight && (0,_Math__WEBPACK_IMPORTED_MODULE_0__.valueEqualtoWithinOnePercent)(valueInfos.value, valueViewHeightInfos.value)) {
384              value = convertUnit(element, pseudoElement, prop, valueInfos, 'vh') + 'vh';
385            }
386          }
387        }
388      }
389      if (deviceRatioProps.includes(prop)) {
390        value = convertDevicePixelRatio(value);
391      }
392      return cleanValuePropsCSS(prop, value);
393    }
394
395    // Pas de cache actif : comportement original
396    if (origin && prop !== 'display') {
397      element.style.display = 'none';
398    }
399    let value = window.getComputedStyle(element, pseudoElement).getPropertyValue(prop);
400    if (origin) {
401      element.style.removeProperty('display');
402      if (/px/.test(value) && !/\s/.test(value) && !/calc\(/.test(value) && propDontViewport.indexOf(prop) === -1) {
403        let windowWidthInfo = getValueInfos(document.body.style.getPropertyValue('--minisite-width'));
404        let windowHeightInfo = getValueInfos(document.body.style.getPropertyValue('--minisite-height'));
405        let valueTemp = window.getComputedStyle(element, pseudoElement).getPropertyValue(prop);
406        document.body.style.setProperty('--minisite-width', windowWidthInfo.value - 2 + 'px');
407        // minisite.style.width = window.innerWidth - 2 + 'px';
408        let valueViewWidth = window.getComputedStyle(element, pseudoElement).getPropertyValue(prop);
409        let valueInfos = getValueInfos(valueTemp, prop);
410        let valueViewWidthInfos = getValueInfos(valueViewWidth, prop);
411        let isCalculate = false;
412        // vérifier si value à un valeur proche de valueViewWidth à 2% près
413
414        if (valueViewWidth !== 'auto' && valueTemp !== valueViewWidth && (0,_Math__WEBPACK_IMPORTED_MODULE_0__.valueEqualtoWithinOnePercent)(valueInfos.value, valueViewWidthInfos.value)) {
415          // convertir en viewport
416          value = convertUnit(element, pseudoElement, prop, valueInfos, 'vw') + 'vw';
417          isCalculate = true;
418        }
419        document.body.style.setProperty('--minisite-width', windowWidthInfo.value + 'px');
420        // minisite.style.width = '';
421
422        const windowHeightAuto = windowHeightInfo.value !== '';
423        if (windowHeightAuto) {
424          document.body.style.setProperty('--minisite-height', windowHeightInfo.value - 2 + 'px');
425        } else {
426          document.body.style.setProperty('--minisite-height', window.innerHeight - 2 + 'px');
427        }
428        let valueViewHeight = window.getComputedStyle(element, pseudoElement).getPropertyValue(prop);
429        let valueViewHeightInfos = getValueInfos(valueViewHeight, prop);
430        if (!isCalculate && valueViewHeight !== 'auto' && valueTemp !== valueViewHeight && (0,_Math__WEBPACK_IMPORTED_MODULE_0__.valueEqualtoWithinOnePercent)(valueInfos.value, valueViewHeightInfos.value)) {
431          // convertir en viewport
432          value = convertUnit(element, pseudoElement, prop, valueInfos, 'vh') + 'vh';
433        }
434        if (windowHeightAuto) {
435          document.body.style.setProperty('--minisite-height', windowHeightInfo.value + 'px');
436        } else {
437          document.body.style.removeProperty('--minisite-height');
438        }
439      }
440    }
441    if (deviceRatioProps.includes(prop)) {
442      value = convertDevicePixelRatio(value);
443    }
444    return cleanValuePropsCSS(prop, value);
445  }
446  return '';
447};
448const deviceRatioProps = ['border-width'];
449function convertDevicePixelRatio(computedValue) {
450  if (/px/.test(computedValue) && !/\s/.test(computedValue) && !/calc\(/.test(computedValue) && window.devicePixelRatio !== 1) {
451    const valueInfoOnRatio = getValueInfos(computedValue);
452    computedValue = (0,_Math__WEBPACK_IMPORTED_MODULE_0__.cleanFloatValueForView)(valueInfoOnRatio.value * window.devicePixelRatio) + valueInfoOnRatio.unit;
453  }
454  return computedValue;
455}
456const regexMultiProps = {
457  'border': /^(border)-(color|width|style|radius)/,
458  'margin': /^(margin)/,
459  'padding': /^(padding)/,
460  'inset': /^(inset)/,
461  'borderImage': /^(border-image-(outset|slice|width))/
462};
463const positionProps = ['top', 'left', 'bottom', 'right'];
464const anglePositionProps = ['top-left', 'top-right', 'bottom-right', 'bottom-left'];
465function getInfoFromMultiProps(prop) {
466  let poss = positionProps;
467  let propWithPos = prop;
468  let listProps = [];
469  let match = null;
470  switch (true) {
471    case regexMultiProps.border.test(prop):
472      match = regexMultiProps.border.exec(prop);
473      propWithPos = match[1] + '-' + '{{pos}}' + '-' + match[2];
474      if (match[2] === "radius") {
475        poss = anglePositionProps;
476      }
477      break;
478    case regexMultiProps.margin.test(prop):
479      propWithPos = 'margin' + '-' + '{{pos}}';
480      break;
481    case regexMultiProps.padding.test(prop):
482      propWithPos = 'padding' + '-' + '{{pos}}';
483      break;
484    case regexMultiProps.borderImage.test(prop):
485      propWithPos = 'border-image' + '-' + '{{pos}}';
486      break;
487    case regexMultiProps.inset.test(prop):
488      propWithPos = '{{pos}}';
489      break;
490    default:
491      poss = [''];
492      propWithPos = prop;
493      break;
494  }
495  listProps = poss.map(x => propWithPos.replace('{{pos}}', x));
496  return {
497    'positions': poss,
498    'propWithPos': propWithPos,
499    'props': listProps
500  };
501}
502function getAllValuePos(element, pseudoElement, prop) {
503  let p = 0;
504  let value = '';
505  let valueRender = '';
506  let infosMulti = getInfoFromMultiProps(prop);
507  let propWithPos = infosMulti.propWithPos;
508  let poss = infosMulti.positions;
509  let match = null;
510  let unit = null;
511  let parentComputed = '';
512  let othersProps = {};
513
514  // Construire la liste des props à lire (ex: margin-top, margin-right, etc.)
515  let allProps = poss.map(p => propWithPos.replace('{{pos}}', p));
516
517  // === Phase 1 : lectures sans modification DOM (état normal) ===
518  // Un seul getComputedStyle pour toutes les positions
519  const computedNormal = window.getComputedStyle(element, pseudoElement);
520  let fontSize = computedNormal.getPropertyValue('font-size');
521
522  // Lire toutes les valeurs en px (état normal = visible)
523  let normalValues = {};
524  allProps.forEach(p => {
525    let val = computedNormal.getPropertyValue(p);
526    if (deviceRatioProps.includes(prop)) {
527      val = convertDevicePixelRatio(val);
528    }
529    normalValues[p] = val;
530  });
531  if (prop !== 'inset') {
532    parentComputed = computedNormal.getPropertyValue(getPropRefForPercent(prop));
533    parentComputed = convertDevicePixelRatio(parentComputed);
534  }
535  if (prop === 'inset') {
536    othersProps['transform'] = getTranslateValues(element);
537    othersProps['transformTranslateX'] = getPercentFromTwoValue(othersProps['transform'].x, element.offsetWidth) + '%';
538  }
539
540  // === Phase 2 : lecture avec display:none (valeurs d'origine, %) ===
541  // Un seul toggle display:none pour toutes les positions
542  element.style.display = 'none';
543  const computedHidden = window.getComputedStyle(element, pseudoElement);
544  let hiddenValues = {};
545  allProps.forEach(p => {
546    let val = computedHidden.getPropertyValue(p);
547    if (deviceRatioProps.includes(prop)) {
548      val = convertDevicePixelRatio(val);
549    }
550    hiddenValues[p] = val;
551  });
552  element.style.removeProperty('display');
553
554  // === Phase 3 : traitement des résultats (sans reflow) ===
555  let unitValues = null,
556    PosvalueInfos = {};
557  poss.forEach(function (p) {
558    let thisProps = propWithPos.replace('{{pos}}', p);
559    let valuePos = hiddenValues[thisProps]; // valeur avec display:none (%)
560    let valuePosPixel = normalValues[thisProps]; // valeur normale (px)
561
562    if (prop === 'inset') {
563      if (element.offsetParent !== null) {
564        const positionElement = getDefaultValueCss(element, null, getPropRefForPercent('position'));
565        let offsetParent = element.parentNode;
566        switch (positionElement) {
567          case 'static':
568          case 'relative':
569            offsetParent = element.parentNode;
570            break;
571          default:
572            offsetParent = element.offsetParent;
573            break;
574        }
575        const sizeParent = window.getComputedStyle(offsetParent, null).getPropertyValue(getPropRefForPercent(thisProps));
576        switch (true) {
577          case thisProps === 'left':
578          case thisProps === 'right':
579            const paddingLeft = getValueInfos(getDefaultValueCss(offsetParent, null, 'padding-left'));
580            const paddingRight = getValueInfos(getDefaultValueCss(offsetParent, null, 'padding-right'));
581            const parentWidth = getValueInfos(sizeParent);
582            parentComputed += (parentComputed === '' ? '' : ' ') + (parentWidth.value - paddingLeft.value - paddingRight.value) + parentWidth.unit;
583            break;
584          case thisProps === 'top':
585          case thisProps === 'bottom':
586            const paddingTop = getValueInfos(getDefaultValueCss(offsetParent, null, 'padding-top'));
587            const paddingBottom = getValueInfos(getDefaultValueCss(offsetParent, null, 'padding-bottom'));
588            const parentHeight = getValueInfos(sizeParent);
589            parentComputed += (parentComputed === '' ? '' : ' ') + (parentHeight.value - paddingTop.value - paddingBottom.value) + parentHeight.unit;
590            break;
591          default:
592            parentComputed += (parentComputed === '' ? '' : ' ') + sizeParent;
593            break;
594        }
595      }
596    }
597    // on se base sur la premier unité trouvé (px, em, %)
598    let valueInfos = getValueInfos(valuePos, prop);
599    if (valueInfos.unit !== null && unitValues === null) {
600      unitValues = valueInfos.unit;
601    }
602    PosvalueInfos[thisProps] = {
603      'valueInfos': valueInfos,
604      'value': valuePos,
605      'valuePx': valuePosPixel
606    };
607  });
608  unitValues = unitValues === null ? 'px' : unitValues;
609  for (let p in PosvalueInfos) {
610    let valueInfos = PosvalueInfos[p].valueInfos;
611    let valuePosPixel = PosvalueInfos[p].valuePx;
612    if (valueInfos.unit === null) {
613      valueInfos.unit = unitValues;
614    }
615    switch (true) {
616      default:
617        value += (value === '' ? '' : ' ') + valueInfos.origin;
618        break;
619    }
620    valueRender += (valuePosPixel === '' ? '' : ' ') + valuePosPixel;
621  }
622  return {
623    'origin': value,
624    'computed': valueRender,
625    'fontSize': fontSize,
626    'parentComputed': parentComputed,
627    'othersProps': othersProps
628  };
629}
630const getShortValueCss = function (element, pseudoElement, prop, unitDefault = null) {
631  switch (true) {
632    case /border|margin$|padding$|inset$/.test(prop):
633      return getAllValuePos(element, pseudoElement, prop);
634    default:
635      let value = getDefaultValueCss(element, pseudoElement, prop);
636      let parentComputed;
637      let parentWidth;
638      let parentHeight;
639      const positionElement = getDefaultValueCss(element, null, getPropRefForPercent('position'));
640      let offsetParent = element.parentNode;
641      switch (positionElement) {
642        case 'static':
643        case 'relative':
644          offsetParent = element.parentNode;
645          break;
646        default:
647          offsetParent = element.offsetParent;
648          break;
649      }
650      switch (prop) {
651        case 'top':
652        case 'bottom':
653          const paddingTop = getValueInfos(getDefaultValueCss(offsetParent, null, 'padding-top'));
654          const paddingBottom = getValueInfos(getDefaultValueCss(offsetParent, null, 'padding-bottom'));
655          parentHeight = getValueInfos(parentComputed);
656          parentComputed = parentHeight.value - paddingTop.value - paddingBottom.value + parentHeight.unit;
657          break;
658        case 'left':
659        case 'right':
660          const paddingLeft = getValueInfos(getDefaultValueCss(offsetParent, null, 'padding-left'));
661          const paddingRight = getValueInfos(getDefaultValueCss(offsetParent, null, 'padding-right'));
662          parentWidth = getValueInfos(parentComputed);
663          parentComputed = parentWidth.value - paddingLeft.value - paddingRight.value + parentWidth.unit;
664          break;
665        default:
666          parentComputed = getDefaultValueCss(element.nodeName === 'BODY' ? element : element.parentNode, null, getPropRefForPercent(prop));
667          break;
668      }
669      let fontSize = getDefaultValueCss(element, pseudoElement, 'font-size');
670
671      // Option I : seuls les props convertibles en viewport (px → vw/vh)
672      // nécessitent la branche origin=true (qui lit en display:none + states vw/vh).
673      // Pour color/font-family/etc., origin === value → on évite N reflows inutiles.
674      let origin;
675      if (viewportConvertibleProps.has(prop)) {
676        origin = getDefaultValueCss(element, pseudoElement, prop, true);
677      } else {
678        origin = value;
679      }
680      let originInfo = getValueInfos(origin, prop);
681      if (unitDefault !== null && originInfo.unit !== unitDefault) {
682        origin = convertUnit(element, pseudoElement, prop, value, unitDefault) + unitDefault;
683      }
684      return {
685        'origin': origin,
686        'computed': value,
687        'fontSize': fontSize,
688        'parentComputed': parentComputed,
689        'othersProps': {}
690      };
691  }
692};
693function getValuesByPosition(prop, value) {
694  let p = 0;
695  let infosMulti = getInfoFromMultiProps(prop);
696  let propWithPos = infosMulti.propWithPos;
697  let poss = infosMulti.positions;
698  let values = {};
699  if (typeof value === "undefined" || value === '' || value === null) {
700    value = '0 0 0 0';
701  }
702  value = value.trim();
703  let splitValue = [];
704  if (regexFunctionCss.test(value)) {
705    splitValue = value.match(regexFunctionCssGlobal);
706  } else {
707    splitValue = value.split(' ');
708  }
709  let matchValue = new Array(4);
710  splitValue.forEach(function (val, index) {
711    matchValue[index] = val;
712  });
713
714  // on nettoie les valeurs pour être sur de ne pas avoir de valeur indéfini
715  // Boucle indexée obligatoire : `new Array(4)` est un tableau CREUX et forEach
716  // saute les trous — la complétion ci-dessous ne s'exécutait donc jamais pour
717  // les positions absentes, et la fonction renvoyait moins de 4 clés (d'où un
718  // panneau rendu avec 2 inputs au lieu de 4).
719  // Borne sur `poss` et non sur 4 : une prop non positionnelle a poss = [''] et
720  // ne doit produire qu'une seule clé, comme avant.
721  for (let index = 0; index < poss.length; index++) {
722    let x = matchValue[index];
723    if (typeof x === "undefined") {
724      if (index) {
725        switch (index) {
726          case 1:
727            // Si les valeurs la valeur suivante et indéfini, on prend la premiere valeur
728            // Pour la simplifier du type : padding: 20px;
729            matchValue[index] = typeof matchValue[2] === "undefined" ? matchValue[0] : 0;
730            break;
731          case 2:
732            matchValue[index] = matchValue[0];
733            break;
734          case 3:
735            matchValue[index] = matchValue[1];
736            break;
737        }
738      } else {
739        matchValue[index] = 0;
740      }
741    }
742    let propName = propWithPos.replace('{{pos}}', poss[index]);
743    values[propName] = matchValue[index];
744  }
745  return values;
746}
747const getDecodeShortValue = function (prop, value) {
748  return getValuesByPosition(prop, value);
749};
750
751/* ────────────────────────────────────────────────────────────────────────────
752 * Expansion des shorthands CSS en longhands
753 *
754 * Le panneau design repose sur un invariant : le store (CSSRule/CSSRuleTemp) ne
755 * contient que des longhands. Une clé shorthand (`border`, `margin`…) y est
756 * orpheline : aucun tool ne la vise, `propReset` ne peut pas l'effacer et le
757 * `delete` du commit — qui opère par clé exacte — ne l'atteint jamais. Elle est
758 * donc régénérée indéfiniment. Ces helpers rétablissent l'invariant.
759 *
760 * ⚠️ Ne PAS confondre avec getValuesByPosition ci-dessus : celui-ci décode le
761 * format *interne* de l'éditeur, dont l'ordre est celui de `positionProps`
762 * (top/left/bottom/right). Les fonctions qui suivent parsent du CSS *réel*,
763 * dont l'ordre est top/right/bottom/left. Les deux ordres diffèrent : réutiliser
764 * l'un pour l'autre intervertit gauche et droite.
765 * ──────────────────────────────────────────────────────────────────────────── */
766
767// Ordres du CSS réel (≠ positionProps / anglePositionProps, qui sont internes)
768const cssSidesOrder = ['top', 'right', 'bottom', 'left'];
769const cssCornersOrder = ['top-left', 'top-right', 'bottom-right', 'bottom-left'];
770
771// Mots-clés de border-style : seul discriminant fiable des composants d'un `border:`
772const borderStyleKeywords = new Set(['none', 'hidden', 'solid', 'dashed', 'dotted', 'double', 'groove', 'ridge', 'inset', 'outset']);
773const borderWidthKeywords = new Set(['thin', 'medium', 'thick']);
774
775// Valeurs globales : expansion impossible sans connaître le contexte de cascade
776const cssGlobalValues = new Set(['inherit', 'initial', 'unset', 'revert', 'revert-layer']);
777
778// Shorthands positionnels : une valeur, quatre côtés/coins de la MÊME propriété
779const positionalShorthands = {
780  'margin': {
781    'template': 'margin-{{pos}}',
782    'order': cssSidesOrder
783  },
784  'padding': {
785    'template': 'padding-{{pos}}',
786    'order': cssSidesOrder
787  },
788  'inset': {
789    'template': '{{pos}}',
790    'order': cssSidesOrder
791  },
792  'border-width': {
793    'template': 'border-{{pos}}-width',
794    'order': cssSidesOrder
795  },
796  'border-radius': {
797    'template': 'border-{{pos}}-radius',
798    'order': cssCornersOrder
799  },
800  // border-color / border-style sont positionnels en CSS, mais le panneau les
801  // édite via un tool ATOMIQUE (clé littérale, appliquée aux 4 côtés). Ils ne
802  // sont éclatés que si la valeur est réellement non-uniforme : cf. _expandBorderSideProp.
803  'border-color': {
804    'template': 'border-{{pos}}-color',
805    'order': cssSidesOrder
806  },
807  'border-style': {
808    'template': 'border-{{pos}}-style',
809    'order': cssSidesOrder
810  }
811};
812
813/**
814 * Découpe une valeur CSS en tokens sans casser les fonctions (rgba(), var(), calc()…).
815 * @param {string} value
816 * @returns {string[]}
817 */
818function tokenizeCssValue(value) {
819  const tokens = String(value).trim().match(regexFunctionCssGlobal);
820  return tokens === null ? [] : tokens.filter(token => token !== '');
821}
822
823/**
824 * Applique la règle CSS 1/2/3/4 valeurs, en ordre CSS réel (top right bottom left).
825 * @param {string[]} tokens
826 * @returns {string[]|null} les 4 valeurs, ou null si le nombre de tokens est invalide
827 */
828function spreadPositionalTokens(tokens) {
829  switch (tokens.length) {
830    case 1:
831      return [tokens[0], tokens[0], tokens[0], tokens[0]];
832    case 2:
833      return [tokens[0], tokens[1], tokens[0], tokens[1]];
834    case 3:
835      return [tokens[0], tokens[1], tokens[2], tokens[1]];
836    case 4:
837      return [tokens[0], tokens[1], tokens[2], tokens[3]];
838    default:
839      return null;
840  }
841}
842
843/**
844 * Nature d'un token d'un shorthand `border` : 'width', 'style', 'color' ou null si ambigu.
845 * @param {string} token
846 * @returns {string|null}
847 */
848function getBorderComponentType(token) {
849  const lower = token.toLowerCase();
850  if (borderStyleKeywords.has(lower)) {
851    return 'style';
852  }
853  if (borderWidthKeywords.has(lower)) {
854    return 'width';
855  }
856  // var() peut porter aussi bien une largeur qu'une couleur : indécidable ici
857  if (/^var\(/i.test(lower)) {
858    return null;
859  }
860  if (/^calc\(/i.test(lower)) {
861    return 'width';
862  }
863  // Longueur : un nombre suivi d'une unité valide (ou nu, cas du 0)
864  const matchUnit = regexUnit.exec(token);
865  if (matchUnit !== null && typeof matchUnit[1] !== "undefined" && (typeof matchUnit[2] === "undefined" || isValidCSSUnit(matchUnit[2]))) {
866    return 'width';
867  }
868  if (/^(#[0-9a-f]{3,8}|(rgba?|hsla?|color|color-mix)\(|transparent$|currentcolor$|[a-z]+$)/i.test(lower)) {
869    return 'color';
870  }
871  return null;
872}
873
874/**
875 * Expanse un `border-color` / `border-style` isolé.
876 * Collapse vers la clé atomique quand les 4 côtés sont identiques : c'est ce
877 * qu'écrit le tool du panneau, et le seul format qu'il sait relire et réinitialiser.
878 * @param {string} prop
879 * @param {string} value
880 * @returns {object|null}
881 */
882function expandBorderSideProp(prop, value) {
883  const tokens = tokenizeCssValue(value);
884  const spread = spreadPositionalTokens(tokens);
885  if (spread === null) {
886    return null;
887  }
888  if (new Set(spread).size === 1) {
889    const atomic = {};
890    atomic[prop] = spread[0];
891    return atomic;
892  }
893  const config = positionalShorthands[prop];
894  const expanded = {};
895  config.order.forEach(function (pos, index) {
896    expanded[config.template.replace('{{pos}}', pos)] = spread[index];
897  });
898  return expanded;
899}
900
901/**
902 * Vrai si la propriété est un shorthand du périmètre traité (familles éditées en
903 * longhand par le panneau design). Sert à ne signaler que les cas pertinents.
904 * @param {string} prop
905 * @returns {boolean}
906 */
907function isTargetedShorthand(prop) {
908  if (typeof prop !== 'string') {
909    return false;
910  }
911  return /^border(-(top|right|bottom|left))?$/.test(prop) || positionalShorthands.hasOwnProperty(prop);
912}
913
914/**
915 * Décompose une propriété CSS shorthand en ses longhands.
916 *
917 * Périmètre : les familles que le panneau design édite en longhand — `border`,
918 * `border-<côté>`, `border-width`, `border-style`, `border-color`, `border-radius`,
919 * `margin`, `padding`, `inset`. Volontairement pas `background`/`font`/`flex`.
920 *
921 * Renvoie null (et non une expansion approximative) dès qu'un doute existe :
922 * valeur globale, rayons elliptiques, token indécidable, composant en double.
923 * L'appelant conserve alors la déclaration telle quelle plutôt que de la fausser.
924 *
925 * @param {string} prop
926 * @param {string} value
927 * @returns {object|null} map longhand → valeur, ou null si non décomposable
928 */
929function expandShorthandToLonghands(prop, value) {
930  if (typeof prop !== 'string' || typeof value !== 'string') {
931    return null;
932  }
933  const cleanValue = value.trim();
934  if (cleanValue === '' || cleanValue === 'remove' || cssGlobalValues.has(cleanValue.toLowerCase())) {
935    return null;
936  }
937
938  // border-color / border-style : atomiques tant que la valeur est uniforme
939  if (prop === 'border-color' || prop === 'border-style') {
940    return expandBorderSideProp(prop, cleanValue);
941  }
942
943  // Shorthands positionnels
944  if (positionalShorthands.hasOwnProperty(prop)) {
945    // Rayons elliptiques (`border-radius: 10px / 20px`) : hors périmètre
946    if (prop === 'border-radius' && cleanValue.indexOf('/') !== -1) {
947      return null;
948    }
949    const spread = spreadPositionalTokens(tokenizeCssValue(cleanValue));
950    if (spread === null) {
951      return null;
952    }
953    const config = positionalShorthands[prop];
954    const expanded = {};
955    config.order.forEach(function (pos, index) {
956      expanded[config.template.replace('{{pos}}', pos)] = spread[index];
957    });
958    return expanded;
959  }
960
961  // Shorthands composites `border` / `border-<côté>` : width | style | color, ordre libre
962  const matchBorderSide = /^border(?:-(top|right|bottom|left))?$/.exec(prop);
963  if (matchBorderSide === null) {
964    return null;
965  }
966  const components = {};
967  const tokens = tokenizeCssValue(cleanValue);
968  if (tokens.length === 0 || tokens.length > 3) {
969    return null;
970  }
971  const ambiguous = [];
972  for (const token of tokens) {
973    const type = getBorderComponentType(token);
974    if (type === null) {
975      ambiguous.push(token);
976      continue;
977    }
978    // Deux tokens de même nature : valeur mal formée, on ne devine pas
979    if (components.hasOwnProperty(type)) {
980      return null;
981    }
982    components[type] = token;
983  }
984
985  // Un token indécidable (typiquement var()) se résout par élimination, mais
986  // seulement s'il ne reste qu'une seule nature possible.
987  if (ambiguous.length) {
988    const remaining = ['width', 'style', 'color'].filter(type => !components.hasOwnProperty(type));
989    if (ambiguous.length !== 1 || remaining.length !== 1) {
990      return null;
991    }
992    components[remaining[0]] = ambiguous[0];
993  }
994  const expanded = {};
995  const side = matchBorderSide[1];
996  if (side) {
997    // Un seul côté concerné : les trois longhands existent tels quels
998    Object.keys(components).forEach(function (type) {
999      expanded['border-' + side + '-' + type] = components[type];
1000    });
1001    return expanded;
1002  }
1003
1004  // `border` uniforme : la largeur s'écrit par côté (format du tool border-width),
1005  // le style et la couleur restent atomiques (format de leurs tools respectifs).
1006  if (components.hasOwnProperty('width')) {
1007    cssSidesOrder.forEach(function (pos) {
1008      expanded['border-' + pos + '-width'] = components.width;
1009    });
1010  }
1011  if (components.hasOwnProperty('style')) {
1012    expanded['border-style'] = components.style;
1013  }
1014  if (components.hasOwnProperty('color')) {
1015    expanded['border-color'] = components.color;
1016  }
1017  return expanded;
1018}
1019
1020/**
1021 * Normalise les déclarations d'un sélecteur : expanse les shorthands du périmètre
1022 * et supprime leur clé, de sorte que seuls des longhands subsistent.
1023 *
1024 * La cascade est reproduite par l'ordre d'insertion des clés — le même que celui
1025 * utilisé pour générer le CSS final (`for (let prop in …)` dans _saveStyleSheet),
1026 * donc le seul qui reflète quelle déclaration l'emporte réellement. Réaffecter une
1027 * clé existante en JS change sa valeur sans déplacer sa position : une passe unique
1028 * suffit à obtenir « dernière déclaration gagne ».
1029 *
1030 * Ex. {margin:'10px', margin-top:'0', margin-right:'0'} → top 0, right 0, bottom 10px, left 10px.
1031 * À l'inverse, un longhand placé AVANT le shorthand est écrasé par celui-ci : ce
1032 * n'est pas un défaut, c'est la cascade CSS rendue fidèlement.
1033 *
1034 * Une déclaration non décomposable est conservée intacte (on ne perd jamais de style).
1035 *
1036 * @param {object} declarations map prop → valeur d'un sélecteur
1037 * @returns {object} nouvelle map, longhands uniquement
1038 */
1039function normalizeDeclarations(declarations) {
1040  if (declarations === null || typeof declarations !== 'object' || Array.isArray(declarations)) {
1041    return declarations;
1042  }
1043  const normalized = {};
1044  for (const prop in declarations) {
1045    if (!declarations.hasOwnProperty(prop)) {
1046      continue;
1047    }
1048    const value = declarations[prop];
1049    const expanded = isTargetedShorthand(prop) ? expandShorthandToLonghands(prop, value) : null;
1050    if (expanded === null) {
1051      normalized[prop] = value;
1052      continue;
1053    }
1054    for (const longhand in expanded) {
1055      if (expanded.hasOwnProperty(longhand)) {
1056        normalized[longhand] = expanded[longhand];
1057      }
1058    }
1059  }
1060  return normalized;
1061}
1062
1063/**
1064 * Applique normalizeDeclarations à un store complet CSSRule[taille][sélecteur].
1065 * Mute l'objet reçu (les stores sont partagés par référence) et le retourne.
1066 * @param {object} cssRule
1067 * @returns {object} le store normalisé
1068 */
1069function normalizeCSSRuleStore(cssRule) {
1070  if (cssRule === null || typeof cssRule !== 'object') {
1071    return cssRule;
1072  }
1073  for (const sizeResponsive in cssRule) {
1074    if (!cssRule.hasOwnProperty(sizeResponsive) || cssRule[sizeResponsive] === null || typeof cssRule[sizeResponsive] !== 'object') {
1075      continue;
1076    }
1077    for (const selector in cssRule[sizeResponsive]) {
1078      if (!cssRule[sizeResponsive].hasOwnProperty(selector)) {
1079        continue;
1080      }
1081      cssRule[sizeResponsive][selector] = normalizeDeclarations(cssRule[sizeResponsive][selector]);
1082    }
1083  }
1084  return cssRule;
1085}
1086
1087/**
1088 *
1089 * @param value
1090 * @returns {{yOffset: string, xOffset: string, yPos: string, xPos: string}}
1091 */
1092const getBackgroundPositionInfo = function (value) {
1093  let regexValueOneWord = /^([a-z]+)$/gi;
1094  let regexValueAll = /^(?:(?<xPos>[a-z]+)?\s?(?<xOffset>[0-9-.]+[a-z%]{0,5})?)\s(?:(?<yPos>[a-z]+)?\s?(?<yOffset>[0-9-.]+[a-z%]{0,5})?)/gi;
1095  let m = regexValueAll.exec(value);
1096  let info = {
1097    xPos: '',
1098    xOffset: '',
1099    yPos: '',
1100    yOffset: ''
1101  };
1102  if (m) {
1103    let values = m.groups;
1104    let positionX = null,
1105      positionY = null;
1106    let newValue = '';
1107    if (!values.xPos && values.xOffset) {
1108      switch (values.xOffset) {
1109        case '0%':
1110          positionX = 'left';
1111          values.xOffset = '';
1112          break;
1113        case '50%':
1114          positionX = 'center';
1115          values.xOffset = '';
1116          break;
1117        case '100%':
1118          positionX = 'right';
1119          values.xOffset = '';
1120          break;
1121      }
1122    }
1123    if (positionX === null) {
1124      positionX = values.xPos ?? 'left';
1125    }
1126    if (!values.yPos && values.yOffset) {
1127      switch (values.yOffset) {
1128        case '0%':
1129          positionY = 'top';
1130          values.yOffset = '';
1131          break;
1132        case '50%':
1133          positionY = 'center';
1134          values.yOffset = '';
1135          break;
1136        case '100%':
1137          positionY = 'bottom';
1138          values.yOffset = '';
1139          break;
1140      }
1141    }
1142    if (positionY === null) {
1143      positionY = values.yPos ?? 'top';
1144    }
1145    info.xPos = positionX;
1146    info.xOffset = values.xOffset ?? '';
1147    info.yPos = positionY;
1148    info.yOffset = values.yOffset ?? '';
1149  } else {
1150    m = regexValueOneWord.exec(value);
1151    if (m) {
1152      info.xPos = info.yPos = m[1];
1153    }
1154  }
1155  return info;
1156};
1157function getBackgroundPositionString(info) {
1158  let value = '';
1159  if (info.xPos) {
1160    value += info.xPos;
1161    if (info.xOffset) {
1162      value += ' ' + info.xOffset;
1163    }
1164  }
1165  if (info.yPos) {
1166    value += ' ' + info.yPos;
1167    if (info.yOffset) {
1168      value += ' ' + info.yOffset;
1169    }
1170  }
1171  return value;
1172}
1173
1174/**
1175 * Valeur CSS de Background Position
1176 * Permet de concervertir par exemple "0% 0%" en "left top"
1177 * @param value
1178 * @returns {string}
1179 */
1180const convertBackgroundPositionToString = function (value) {
1181  let info = getBackgroundPositionInfo(value);
1182  return info.xPos + ' ' + info.yPos;
1183};
1184
1185/**
1186 *
1187 * @param value
1188 * @returns {{ySize: string, xSize: string, keyword: string}}
1189 */
1190const getBackgroundSizeInfo = function (value) {
1191  let regexValueAll = /^(?:(?<xSize>(?:(?:[0-9-.]+[a-z%]{0,5})|auto))?\s(?:(?<ySize>(?:(?:[0-9-.]+[a-z%]{0,5})|auto))?)|(?<keyword>contain|cover)|(?:(?<xySize>(?:(?:[0-9-.]+[a-z%]{0,5})|auto))?))$/gi;
1192  let m = regexValueAll.exec(value);
1193  let info = {
1194    xSize: 'auto',
1195    ySize: 'auto',
1196    keyword: ''
1197  };
1198  if (m) {
1199    let values = m.groups;
1200    info.xSize = values.xSize ?? 'auto';
1201    info.ySize = values.ySize ?? 'auto';
1202    info.keyword = values.keyword ?? '';
1203    if (values.xySize) {
1204      info.xSize = info.ySize = values.xySize;
1205    }
1206    return info;
1207  }
1208  return info;
1209};
1210
1211/**
1212 * Dégradé par défaut appliqué au fond quand l'outil ToolsDesign "background-clip"
1213 * (rognage du texte) est activé sans fond image existant.
1214 * @type {string}
1215 */
1216const DEFAULT_CLIP_TEXT_GRADIENT = 'linear-gradient(90deg, rgb(148, 225, 198) 11%, rgb(72, 61, 139) 32%, rgb(148, 225, 198) 54%, rgb(72, 61, 139) 77%, rgb(148, 225, 198) 100%)';
1217
1218/**
1219 * Récupére les différentes valeurs d'un valeur Background Image
1220 * @param {string} originalValue
1221 * @returns {Array}
1222 */
1223const getBackgroundImageValue = function (originalValue) {
1224  if (!originalValue || !originalValue.trim()) return [];
1225
1226  // Découpe top-level en respectant la profondeur de parenthèses (gradient()/rgba()/url()).
1227  // splitTopLevel (déclaré plus bas, hoisté) remplace l'ancienne regex qui tronquait
1228  // le dernier calque contenant un rgba(...) suivi d'autres stops.
1229  const parts = splitTopLevel(originalValue, ',').map(function (s) {
1230    return s.trim();
1231  }).filter(Boolean);
1232  const results = [];
1233  parts.forEach(function (part) {
1234    const match = part.match(/^([a-zA-Z-]+)\(([\s\S]*)\)$/);
1235    if (!match) return;
1236    // value = contenu interne ; on retire d'éventuels guillemets (cas url("...")).
1237    const value = match[2].trim().replace(/^["']|["']$/g, '');
1238    results.push({
1239      'origin': part,
1240      'type': match[1],
1241      'value': value
1242    });
1243  });
1244  return results;
1245};
1246
1247/**
1248 * Utilitaire interne : split top-level.
1249 * Découpe `str` sur `sep` en ignorant les séparateurs à l'intérieur de parenthèses.
1250 * Exemple : splitTopLevel("rgba(0,0,0,.5) 0%, red 100%") → ["rgba(0,0,0,.5) 0%", " red 100%"]
1251 * @param {string} str
1252 * @param {string} sep séparateur (default ',')
1253 * @returns {string[]}
1254 */
1255function splitTopLevel(str, sep = ',') {
1256  const parts = [];
1257  let depth = 0;
1258  let current = '';
1259  for (let i = 0; i < str.length; i++) {
1260    const ch = str[i];
1261    if (ch === '(') {
1262      depth++;
1263      current += ch;
1264    } else if (ch === ')') {
1265      depth--;
1266      current += ch;
1267    } else if (depth === 0 && str.startsWith(sep, i)) {
1268      parts.push(current);
1269      current = '';
1270      i += sep.length - 1;
1271    } else {
1272      current += ch;
1273    }
1274  }
1275  parts.push(current);
1276  return parts;
1277}
1278
1279/**
1280 * Parse les stops d'un gradient.
1281 * Chaque stop est "<color> <pos>" ou "<color>" (pos optionnel).
1282 * Gère les couleurs fonctionnelles (rgba(...), hsl(...), etc.) via splitTopLevel.
1283 * @param {string[]} rawStops segments top-level déjà splittés
1284 * @returns {{color: string, pos: string}[]}
1285 */
1286function parseGradientStops(rawStops) {
1287  return rawStops.map(function (stop) {
1288    const s = stop.trim();
1289    // Cherche une position à la fin : <nombre><unité> ou <nombre>% (éventuellement précédé d'un espace)
1290    const posMatch = s.match(/\s+([\d.]+(?:%|px|em|rem|vw|vh|pt|cm|mm|in|turn|deg|grad|rad))\s*$/i);
1291    if (posMatch) {
1292      return {
1293        color: s.slice(0, s.length - posMatch[0].length).trim(),
1294        pos: posMatch[1]
1295      };
1296    }
1297    return {
1298      color: s,
1299      pos: ''
1300    };
1301  });
1302}
1303
1304/**
1305 * Parse la valeur intérieure d'un gradient CSS (ce qu'il y a entre les parenthèses).
1306 * Reçoit une entrée {type, value} issue de getBackgroundImageValue où type est *-gradient.
1307 *
1308 * Retourne pour linear-gradient  : {angle, stops}
1309 * Retourne pour radial-gradient  : {shape, size, position, stops}
1310 * Retourne pour conic-gradient   : {angle, position, stops}
1311 *
1312 * Heuristique pour distinguer le préfixe géométrique des stops :
1313 *   - linear  : 1er segment top-level est l'angle s'il matche /^(to\s|[\d.]+(deg|grad|rad|turn))/i
1314 *   - radial  : 1er segment est le préfixe s'il contient circle|ellipse|at |from |closest|farthest
1315 *               ET ne commence pas par une syntaxe de couleur
1316 *   - conic   : même heuristique que radial (from … at …)
1317 *
1318 * @param {{type: string, value: string}} typedEntry
1319 * @returns {Object}
1320 */
1321const parseGradient = function (typedEntry) {
1322  const type = typedEntry.type;
1323  const segments = splitTopLevel(typedEntry.value, ',');
1324  if (type === 'linear-gradient') {
1325    // Heuristique : le 1er segment est l'angle s'il matche to <dir> ou une valeur angulaire
1326    const first = segments[0].trim();
1327    const isAngle = /^(to\s|[\d.]+(deg|grad|rad|turn))/i.test(first);
1328    let angle = '180deg';
1329    let stopSegments;
1330    if (isAngle) {
1331      angle = first;
1332      stopSegments = segments.slice(1);
1333    } else {
1334      stopSegments = segments;
1335    }
1336    return {
1337      angle,
1338      stops: parseGradientStops(stopSegments)
1339    };
1340  }
1341  if (type === 'radial-gradient') {
1342    // Heuristique : 1er segment est le préfixe géométrique s'il contient des mots-clés de forme/taille/position
1343    const first = segments[0].trim();
1344    const isGeometric = /^(circle|ellipse)\b/i.test(first) || /\bat\b/i.test(first) || /^(closest-side|closest-corner|farthest-side|farthest-corner)\b/i.test(first);
1345    let stopSegments;
1346    let shape = 'ellipse';
1347    let size = '';
1348    let position = '';
1349    if (isGeometric) {
1350      stopSegments = segments.slice(1);
1351      // Sépare la partie avant "at" (shape + size) de la position après "at"
1352      const atIdx = first.search(/\bat\b/i);
1353      let shapeSize = atIdx !== -1 ? first.slice(0, atIdx).trim() : first;
1354      if (atIdx !== -1) {
1355        position = first.slice(atIdx + 2).trim();
1356      }
1357      // shape = circle | ellipse (premier mot si présent)
1358      const shapeMatch = shapeSize.match(/^(circle|ellipse)/i);
1359      if (shapeMatch) {
1360        shape = shapeMatch[1].toLowerCase();
1361        shapeSize = shapeSize.slice(shapeMatch[0].length).trim();
1362      }
1363      // size = tout ce qui reste après le shape (longueur explicite ou mot-clé, ex "1000px 600px", "closest-side", "")
1364      size = shapeSize.trim();
1365    } else {
1366      stopSegments = segments;
1367    }
1368    return {
1369      shape,
1370      size,
1371      position,
1372      stops: parseGradientStops(stopSegments)
1373    };
1374  }
1375  if (type === 'conic-gradient') {
1376    const first = segments[0].trim();
1377    const isGeometric = /\bfrom\b/i.test(first) || /\bat\b/i.test(first);
1378    let stopSegments;
1379    let angle = '';
1380    let position = '';
1381    if (isGeometric) {
1382      stopSegments = segments.slice(1);
1383      // from <angle>
1384      const fromMatch = first.match(/\bfrom\s+([\d.]+(?:deg|grad|rad|turn))/i);
1385      if (fromMatch) {
1386        angle = fromMatch[1];
1387      }
1388      // at <position>
1389      const atMatch = first.match(/\bat\s+(.+)$/i);
1390      if (atMatch) {
1391        position = atMatch[1].trim();
1392      }
1393    } else {
1394      stopSegments = segments;
1395    }
1396    return {
1397      angle,
1398      position,
1399      stops: parseGradientStops(stopSegments)
1400    };
1401  }
1402
1403  // Type inconnu : retour minimal
1404  return {
1405    stops: []
1406  };
1407};
1408
1409/**
1410 * Génère la chaîne CSS complète d'un gradient depuis un objet calque.
1411 * Inverse de parseGradient — garantit un round-trip stable.
1412 *
1413 * @param {{type: string, angle?: string, shape?: string, size?: string, position?: string, stops: {color: string, pos: string}[]}} layer
1414 * @returns {string} ex: "linear-gradient(90deg, red 0%, blue 100%)"
1415 */
1416const generateGradient = function (layer) {
1417  const sortedStops = (layer.stops || []).slice().sort(function (a, b) {
1418    return (parseFloat(a.pos) || 0) - (parseFloat(b.pos) || 0);
1419  });
1420  const stopsStr = sortedStops.map(function (stop) {
1421    return stop.pos ? stop.color + ' ' + stop.pos : stop.color;
1422  }).join(', ');
1423  if (layer.type === 'linear-gradient') {
1424    const anglePart = layer.angle ? layer.angle + ', ' : '';
1425    return 'linear-gradient(' + anglePart + stopsStr + ')';
1426  }
1427  if (layer.type === 'radial-gradient') {
1428    const parts = [];
1429    if (layer.shape) parts.push(layer.shape);
1430    if (layer.size) parts.push(layer.size);
1431    if (layer.position) parts.push('at ' + layer.position);
1432    const prefix = parts.length ? parts.join(' ') + ', ' : '';
1433    return 'radial-gradient(' + prefix + stopsStr + ')';
1434  }
1435  if (layer.type === 'conic-gradient') {
1436    const parts = [];
1437    if (layer.angle) parts.push('from ' + layer.angle);
1438    if (layer.position) parts.push('at ' + layer.position);
1439    const prefix = parts.length ? parts.join(' ') + ', ' : '';
1440    return 'conic-gradient(' + prefix + stopsStr + ')';
1441  }
1442  return '';
1443};
1444
1445/**
1446 * Décompose les propriétés CSS background multi-calques en un tableau de calques alignés.
1447 * Chaque calque contient les infos image (type, url ou données gradient parsées)
1448 * et les options communes (position, size, repeat, attachment).
1449 *
1450 * Le nombre de calques est déterminé par le nombre d'entrées de background-image.
1451 * Les autres listes sont allongées/tronquées en conséquence avec des défauts CSS.
1452 *
1453 * @param {{
1454 *   'background-image'?: string,
1455 *   'background-position'?: string,
1456 *   'background-size'?: string,
1457 *   'background-repeat'?: string,
1458 *   'background-attachment'?: string
1459 * }} values
1460 * @returns {Object[]}
1461 */
1462const getBackgroundLayers = function (values, opts) {
1463  const rawImages = !!(opts && opts.rawImages);
1464  const imageEntries = getBackgroundImageValue(values['background-image'] || '');
1465
1466  // Nombre de calques = nombre d'images (minimum 1 si tout est vide)
1467  const count = imageEntries.length || 1;
1468
1469  // Découpe top-level des autres props (peut être multi-valeurs séparées par virgule)
1470  const splitProp = function (rawValue) {
1471    if (!rawValue) return [];
1472    return splitTopLevel(rawValue, ',').map(function (s) {
1473      return s.trim();
1474    });
1475  };
1476  const positions = splitProp(values['background-position']);
1477  const sizes = splitProp(values['background-size']);
1478  const repeats = splitProp(values['background-repeat']);
1479  const attachments = splitProp(values['background-attachment']);
1480  const getAt = function (arr, i, fallback) {
1481    return arr[i] !== undefined && arr[i] !== '' ? arr[i] : fallback;
1482  };
1483  const layers = [];
1484  for (let i = 0; i < count; i++) {
1485    const entry = imageEntries[i];
1486    const posStr = getAt(positions, i, 'left top');
1487    const sizeStr = getAt(sizes, i, 'auto');
1488    const layer = {
1489      type: entry ? entry.type : 'url',
1490      positionInfo: getBackgroundPositionInfo(posStr),
1491      sizeInfo: getBackgroundSizeInfo(sizeStr),
1492      repeat: getAt(repeats, i, 'no-repeat'),
1493      attachment: getAt(attachments, i, 'scroll')
1494    };
1495    if (entry) {
1496      const isKnownGradient = /^(linear|radial|conic)-gradient$/.test(entry.type);
1497      if (entry.type === 'url') {
1498        layer.url = entry.value;
1499      } else if (rawImages || !isKnownGradient) {
1500        // Image non décomposable (repeating-*, formes complexes, ou mode forcé) :
1501        // on conserve la chaîne d'origine telle quelle pour un rendu fidèle.
1502        layer.type = 'raw';
1503        layer.rawImage = entry.origin;
1504      } else {
1505        // Gradient connu : merge des propriétés parsées dans le calque
1506        const gradientData = parseGradient(entry);
1507        Object.assign(layer, gradientData);
1508      }
1509    } else {
1510      layer.url = '';
1511    }
1512    layers.push(layer);
1513  }
1514  return layers;
1515};
1516
1517/**
1518 * Génère les 5 propriétés CSS background longhand depuis un tableau de calques.
1519 * INVARIANT : les 5 listes ont exactement layers.length entrées (CSS sinon répète/tronque silencieusement).
1520 * Inverse de getBackgroundLayers — garantit un round-trip stable.
1521 *
1522 * @param {Object[]} layers tableau de calques (la clé `uid` est ignorée)
1523 * @returns {{
1524 *   'background-image': string,
1525 *   'background-position': string,
1526 *   'background-size': string,
1527 *   'background-repeat': string,
1528 *   'background-attachment': string
1529 * }}
1530 */
1531const generateBackgroundLonghands = function (layers) {
1532  const images = [];
1533  const positions = [];
1534  const sizesList = [];
1535  const repeatsList = [];
1536  const attachList = [];
1537  for (let i = 0; i < layers.length; i++) {
1538    const layer = layers[i];
1539
1540    // --- background-image ---
1541    if (layer.type === 'url') {
1542      images.push('url("' + (layer.url || '') + '")');
1543    } else if (layer.type === 'raw') {
1544      images.push(layer.rawImage || '');
1545    } else {
1546      images.push(generateGradient(layer));
1547    }
1548
1549    // --- background-position ---
1550    const posStr = layer.positionInfo ? getBackgroundPositionString(layer.positionInfo) : '0% 0%';
1551    positions.push(posStr || '0% 0%');
1552
1553    // --- background-size ---
1554    let sizeStr = 'auto';
1555    if (layer.sizeInfo) {
1556      if (layer.sizeInfo.keyword) {
1557        sizeStr = layer.sizeInfo.keyword;
1558      } else {
1559        const x = layer.sizeInfo.xSize || 'auto';
1560        const y = layer.sizeInfo.ySize || 'auto';
1561        sizeStr = x + ' ' + y;
1562      }
1563    }
1564    sizesList.push(sizeStr);
1565
1566    // --- background-repeat ---
1567    repeatsList.push(layer.repeat || 'no-repeat');
1568
1569    // --- background-attachment ---
1570    attachList.push(layer.attachment || 'scroll');
1571  }
1572  return {
1573    'background-image': images.join(', '),
1574    'background-position': positions.join(', '),
1575    'background-size': sizesList.join(', '),
1576    'background-repeat': repeatsList.join(', '),
1577    'background-attachment': attachList.join(', ')
1578  };
1579};
1580const defaultPositionType = {
1581  "top": 0,
1582  "right": 0,
1583  "bottom": 0,
1584  "left": 0
1585};
1586const generatePositionValue = function (data) {
1587  let value = '';
1588  let first = true;
1589  const values = Object.assign({
1590    ...defaultPositionType
1591  }, data);
1592  value += Object.values(values).join(' ');
1593  return value;
1594};
1595const PSEUDO_ELEMENT = ['after', 'backdrop', 'before', 'cue', 'first-letter', 'first-line', 'grammar-error', 'marker', 'part', 'placeholder', 'selection', 'slotted', 'spelling-error'];
1596const PSEUDO_CLASS = ['active', 'any-link', 'blank', 'checked', 'current', 'default', 'defined', 'dir', 'disabled', 'drop', 'empty', 'enabled', 'first', 'first-child', 'first-of-type', 'fullscreen', 'future', 'focus', 'focus-visible', 'focus-within', 'has', 'host', 'host-context', 'hover', 'inderterminate', 'in-range', 'invalid', 'is', 'lang', 'last-child', 'last-of-type', 'left', 'link', 'local-link', 'not', 'nth-child', 'nth-col', 'nth-last-child', 'nth-last-col', 'nth-last-of-type', 'nth-of-type', 'only-child', 'only-of-type', 'optional', 'out-of-range', 'past', 'placeholder-shown', 'read-only', 'read-write', 'required', 'right', 'root', 'scope', 'target', 'target-within', 'user-invalid', 'valid', 'visited', 'where'];
1597const DISPLAY_VALUES = ['block', 'inline', 'run-in', 'flow', 'flow-root', 'table', 'flex', 'grid', 'list-item', 'table-row-group', 'table-header-group', 'table-footer-group', 'table-row', 'table-cell', 'table-cell', 'table-column-group', 'table-column', 'table-caption', 'contents', 'none', 'inline-block', 'inline-table', 'inline-flex', 'inline-grid'];
1598const regexDisplayValue = new RegExp(DISPLAY_VALUES.join('|'));
1599function getDefaultDisplayValue(originalValue) {
1600  switch (true) {
1601    case typeof originalValue === 'string' && regexDisplayValue.test(originalValue):
1602      return originalValue;
1603    case typeof originalValue === 'object' && originalValue.hasOwnProperty('display'):
1604      return originalValue.display;
1605    default:
1606      return 'block';
1607  }
1608}
1609const regexPseudoElement = new RegExp(PSEUDO_ELEMENT.join('|'));
1610const regexPseudoClass = new RegExp(PSEUDO_CLASS.join('|'));
1611
1612/**
1613 *
1614 * @param pseudo string
1615 * @returns string
1616 */
1617function getPseudoFormatByName(pseudo) {
1618  switch (true) {
1619    case regexPseudoElement.test(pseudo):
1620      return '::' + pseudo;
1621    case regexPseudoClass.test(pseudo):
1622      return ':' + pseudo;
1623    default:
1624      return false;
1625  }
1626}
1627const regexUnit = /(?:^([-0-9.,]+)([^0-9.,-]+)?)|(auto)/;
1628
1629// Unités CSS valides (longueur, temps, fréquence, résolution, pourcentage, sans unité)
1630const validCSSUnits = new Set([
1631// Longueur absolue
1632'px', 'cm', 'mm', 'in', 'pt', 'pc', 'Q',
1633// Longueur relative
1634'em', 'rem', 'ex', 'rex', 'cap', 'rcap', 'ch', 'rch', 'ic', 'ric', 'lh', 'rlh', 'vw', 'vh', 'vmin', 'vmax', 'vi', 'vb', 'svw', 'svh', 'lvw', 'lvh', 'dvw', 'dvh', 'cqw', 'cqh', 'cqi', 'cqb', 'cqmin', 'cqmax',
1635// Pourcentage
1636'%',
1637// Temps
1638's', 'ms',
1639// Fréquence
1640'Hz', 'kHz',
1641// Résolution
1642'dpi', 'dpcm', 'dppx', 'x',
1643// Angle
1644'deg', 'grad', 'rad', 'turn',
1645// Flex
1646'fr',
1647// Sans unité (interne éditeur)
1648'ratio', 'int']);
1649function isValidCSSUnit(unit) {
1650  return typeof unit === 'string' && validCSSUnits.has(unit);
1651}
1652
1653/**
1654 * Trouvé l'unité d'une valeur, exemple : '12px', renvoie 'px';
1655 * @param value
1656 * @returns {string|null}
1657 */
1658function getUnit(value) {
1659  let match = regexUnit.exec(value);
1660  if (match && isValidCSSUnit(match[2])) {
1661    return match[2];
1662  }
1663  return 'px';
1664}
1665function getValueInfos(value, prop, unitDefault) {
1666  if (typeof value === 'object' && value.hasOwnProperty('computed')) {
1667    value = value.origin;
1668  }
1669  if (typeof value === 'object' && value.hasOwnProperty('value')) {
1670    value = value.value;
1671  }
1672  let defaultUnit = typeof unitDefault === "undefined" ? getDefaultUnit(prop) : unitDefault;
1673  value = typeof value === "undefined" ? '' : value;
1674  let match = regexUnit.exec(value);
1675  if (match !== null) {
1676    let unit = typeof match[2] === "undefined" || !isValidCSSUnit(match[2]) ? defaultUnit : match[2];
1677    return {
1678      'value': typeof match[1] === "undefined" ? match[3] : _Math__WEBPACK_IMPORTED_MODULE_0__["default"].cleanStringInputToNumber(match[1]),
1679      'unit': unit,
1680      'origin': _Math__WEBPACK_IMPORTED_MODULE_0__["default"].cleanStringInputToNumber(match[0])
1681    };
1682  }
1683  return {
1684    'value': value,
1685    'unit': defaultUnit,
1686    'origin': value
1687  };
1688}
1689function getPercentFromTwoValue(value, compareValue) {
1690  let valuePercent = parseFloat(value / compareValue * 100).toFixed(2);
1691  return valuePercent == parseInt(valuePercent) ? parseInt(valuePercent) : valuePercent;
1692}
1693function convertUnit(element, pseudoElement, prop, valueInfos, unit, withUnit = false) {
1694  valueInfos = typeof valueInfos === "string" ? getValueInfos(valueInfos, prop) : valueInfos;
1695  let returnValue = 0;
1696  switch (valueInfos.origin) {
1697    case 'auto':
1698      return valueInfos.origin;
1699      // removed by dead control flow
1700{}
1701  }
1702  if (valueInfos === null) return 0;
1703  if (parseFloat(valueInfos.value) === 0) return 0;
1704
1705  // On récupére la valeur calculé par le navigateur
1706  // Si l'élément est bien dans le DOM est visible, on aura la valeur en pixel
1707  let valueOnPx = window.getComputedStyle(element, pseudoElement).getPropertyValue(prop);
1708  let propRef, parentOnPx;
1709  switch (unit) {
1710    case 'px':
1711      returnValue = valueOnPx;
1712      break;
1713    case 'em':
1714      switch (valueInfos.unit) {
1715        case 'px':
1716          returnValue = getValueOnEm(element, valueInfos.origin);
1717          break;
1718        case '%':
1719          returnValue = getValueOnEm(element, valueOnPx);
1720          break;
1721      }
1722      break;
1723    case 'rem':
1724      switch (valueInfos.unit) {
1725        case 'px':
1726          returnValue = getValueOnRem(element, valueInfos.origin);
1727          break;
1728        case '%':
1729          returnValue = getValueOnRem(element, valueOnPx);
1730          break;
1731      }
1732      break;
1733    case '%':
1734      propRef = getPropRefForPercent(prop);
1735      parentOnPx = window.getComputedStyle(element.parentNode, pseudoElement).getPropertyValue(propRef);
1736      parentOnPx = getValueWithoutPrefix(parentOnPx);
1737      returnValue = getPercentFromTwoValue(getValueWithoutPrefix(valueOnPx), parentOnPx);
1738      break;
1739    case 'vh':
1740      const viewHeight = element.ownerDocument.defaultView.innerHeight;
1741      returnValue = getPercentFromTwoValue(getValueWithoutPrefix(valueOnPx), viewHeight);
1742      break;
1743    case 'vw':
1744      const viewWidth = element.ownerDocument.defaultView.innerWidth;
1745      returnValue = getPercentFromTwoValue(getValueWithoutPrefix(valueOnPx), viewWidth);
1746      break;
1747  }
1748  return secureValueShow(returnValue);
1749}
1750function secureValueShow(value, valueDefault) {
1751  valueDefault = typeof valueDefault === "undefined" ? 0 : valueDefault;
1752  switch (true) {
1753    case isNaN(value):
1754      return valueDefault;
1755    case !isFinite(value):
1756      return valueDefault;
1757    default:
1758      return value;
1759  }
1760}
1761let infosDataDefault = {
1762  'unit': '',
1763  'computed': '',
1764  'fontSize': '',
1765  'parentComputed': '',
1766  'othersProps': {},
1767  'viewHeight': 0,
1768  'viewWidth': 0,
1769  'fontSizeHtml': '16px'
1770};
1771function convertUnitByInfo(value, unit, data, prop) {
1772  let infos = Object.assign(infosDataDefault, data);
1773  prop = typeof prop === "undefined" ? false : prop;
1774  switch (value) {
1775    case 'auto':
1776      return value;
1777      // removed by dead control flow
1778{}
1779  }
1780  value = parseFloat(value);
1781  if (isNaN(value)) return 0;
1782  if (value === 0) return 0;
1783  let computedInfo = getValueInfos(infos.computed, prop);
1784  let computed = getValueWithoutPrefix(infos.computed);
1785  switch (unit) {
1786    case 'px':
1787      switch (computedInfo.unit) {
1788        case 'px':
1789          return computedInfo.value;
1790        case 'em':
1791          return emToPx(computedInfo.value, getValueWithoutPrefix(infos.fontSize));
1792        case 'rem':
1793          return emToPx(computedInfo.value, getValueWithoutPrefix(infos.fontSizeHtml));
1794      }
1795      break;
1796    case 'em':
1797      switch (prop) {
1798        case 'font-size':
1799          return pxToEm(computed, getValueWithoutPrefix(infos.parentComputed));
1800        default:
1801          return pxToEm(computed, getValueWithoutPrefix(infos.fontSize));
1802      }
1803    case 'rem':
1804      return pxToEm(computed, getValueWithoutPrefix(infos.fontSizeHtml));
1805    case '%':
1806      return getPercentFromTwoValue(computed, getValueWithoutPrefix(infos.parentComputed));
1807    case 'vh':
1808      return getPercentFromTwoValue(computed, infos.viewHeight);
1809    case 'vw':
1810      return getPercentFromTwoValue(computed, infos.viewHeight);
1811    case 'ms':
1812    case 's':
1813      return convertTime(value, data.unit, unit);
1814  }
1815  return 0;
1816}
1817function calcToMs(value, unit) {
1818  switch (unit) {
1819    case 's':
1820      return value * 1000;
1821    case 'ms':
1822      return value;
1823  }
1824}
1825function calcMsToUnit(valueMs, unit) {
1826  switch (unit) {
1827    case 's':
1828      return valueMs / 1000;
1829    case 'ms':
1830      return valueMs;
1831  }
1832}
1833function convertTime(value, fromUnit, toUnit) {
1834  const valueMs = calcToMs(value, fromUnit);
1835  return calcMsToUnit(valueMs, toUnit);
1836}
1837function getComputedByInfo(newValue, data, prop) {
1838  let infos = Object.assign(infosDataDefault, data);
1839  switch (newValue) {
1840    case 'auto':
1841      return newValue;
1842      // removed by dead control flow
1843{}
1844  }
1845  let value = parseFloat(newValue);
1846  let oldValue = null;
1847  let computed = getValueWithoutPrefix(infos.computed);
1848  if (isNaN(value)) return newValue;
1849  if (value === 0) return 0;
1850  if (infos.unit === null || infos.unit === '') return infos.origin;
1851  let newComputed = 0;
1852  switch (infos.unit) {
1853    case '%':
1854      oldValue = getPercentFromTwoValue(computed, getValueWithoutPrefix(infos.parentComputed));
1855      newComputed = _Math__WEBPACK_IMPORTED_MODULE_0__["default"].cleanFloatValue(parseFloat(value / oldValue * computed).toFixed(2));
1856      return newComputed + 'px';
1857    case 'vw':
1858      oldValue = getPercentFromTwoValue(computed, infos.viewWidth);
1859      newComputed = _Math__WEBPACK_IMPORTED_MODULE_0__["default"].cleanFloatValue(parseFloat(value / oldValue * computed).toFixed(2));
1860      return newComputed + 'px';
1861    case 'vh':
1862      oldValue = getPercentFromTwoValue(computed, infos.viewHeight);
1863      newComputed = _Math__WEBPACK_IMPORTED_MODULE_0__["default"].cleanFloatValue(parseFloat(value / oldValue * computed).toFixed(2));
1864      return newComputed + 'px';
1865    case 'em':
1866      switch (prop) {
1867        case 'font-size':
1868          oldValue = pxToEm(computed, getValueWithoutPrefix(infos.parentComputed));
1869          break;
1870        default:
1871          oldValue = pxToEm(computed, getValueWithoutPrefix(infos.fontSize));
1872          break;
1873      }
1874      newComputed = _Math__WEBPACK_IMPORTED_MODULE_0__["default"].cleanFloatValue(parseFloat(value / oldValue * computed).toFixed(2));
1875      return newComputed + 'px';
1876    case 'rem':
1877      oldValue = emToPx(value, getValueWithoutPrefix(infos.fontSizeHtml));
1878      return oldValue + 'px';
1879    default:
1880      return _Math__WEBPACK_IMPORTED_MODULE_0__["default"].cleanFloatValue(value) + 'px';
1881  }
1882  return 0;
1883}
1884function getPropRefForPercent(prop) {
1885  switch (true) {
1886    case regexMultiProps.margin.test(prop):
1887    case regexMultiProps.padding.test(prop):
1888    case prop === 'left':
1889    case prop === 'right':
1890      return 'width';
1891    case prop === 'top':
1892    case prop === 'bottom':
1893      return 'height';
1894    default:
1895      return prop;
1896  }
1897}
1898
1899/**
1900 * https://zellwk.com/blog/css-translate-values-in-javascript/
1901 * Gets computed translate values
1902 * @param {HTMLElement} element
1903 * @returns {Object}
1904 */
1905function getTranslateValues(element) {
1906  const style = window.getComputedStyle(element);
1907  const matrix = style['transform'] || style.webkitTransform || style.mozTransform;
1908
1909  // No transform property. Simply return 0 values.
1910  if (matrix === 'none' || typeof matrix === 'undefined') {
1911    return {
1912      x: 0,
1913      y: 0,
1914      z: 0
1915    };
1916  }
1917
1918  // Can either be 2d or 3d transform
1919  const matrixType = matrix.includes('3d') ? '3d' : '2d';
1920  const matrixValues = matrix.match(/matrix.*\((.+)\)/)[1].split(', ');
1921
1922  // 2d matrices have 6 values
1923  // Last 2 values are X and Y.
1924  // 2d matrices does not have Z value.
1925  if (matrixType === '2d') {
1926    return {
1927      x: matrixValues[4],
1928      y: matrixValues[5],
1929      z: 0
1930    };
1931  }
1932
1933  // 3d matrices have 16 values
1934  // The 13th, 14th, and 15th values are X, Y, and Z
1935  if (matrixType === '3d') {
1936    return {
1937      x: matrixValues[12],
1938      y: matrixValues[13],
1939      z: matrixValues[14]
1940    };
1941  }
1942}
1943
1944// --- Transform (outil ToolsDesign) ---
1945
1946const defaultTransformItems = {
1947  'rotate': {
1948    type: 'rotate',
1949    angle: '0deg'
1950  },
1951  'translate': {
1952    type: 'translate',
1953    x: '0px',
1954    y: '0px',
1955    z: '0px'
1956  },
1957  'scale': {
1958    type: 'scale',
1959    value: '1'
1960  }
1961};
1962
1963/**
1964 * Item transform par défaut pour un type donné (rotate | translate | scale)
1965 * @param {string} type
1966 * @returns {Object}
1967 */
1968function getDefaultTransformItem(type) {
1969  return Object.assign({}, defaultTransformItems[type]);
1970}
1971
1972/**
1973 * Normalise une composante de longueur/angle : nombre + unité, NaN → 0
1974 * @param {string} value ex: '10px', '45', '-50%'
1975 * @param {string} defaultUnit unité si absente
1976 * @returns {string} ex: '10px', '45deg', '0px'
1977 */
1978function normalizeTransformLength(value, defaultUnit = 'px') {
1979  const infos = getValueInfos(value, null, defaultUnit);
1980  const num = parseFloat(infos.value);
1981  if (isNaN(num)) {
1982    return '0' + defaultUnit;
1983  }
1984  return num + infos.unit;
1985}
1986
1987/**
1988 * Décompose une matrice 2D en items translate + rotate + scale.
1989 * Décomposition NORMALISANTE : ordre fixe, skew ignoré, scale uniforme.
1990 * Matrice dégénérée (déterminant 0) → [].
1991 * @param {Array<number>} values [a, b, c, d, e, f]
1992 * @returns {Array<Object>}
1993 */
1994function decomposeMatrix2d(values) {
1995  const [a, b, c, d, e, f] = values;
1996  const det = a * d - b * c;
1997  if (det === 0 || isNaN(det)) {
1998    return [];
1999  }
2000  const items = [];
2001  if (e !== 0 || f !== 0) {
2002    items.push({
2003      type: 'translate',
2004      x: (0,_Math__WEBPACK_IMPORTED_MODULE_0__.cleanFloatValueForView)(e) + 'px',
2005      y: (0,_Math__WEBPACK_IMPORTED_MODULE_0__.cleanFloatValueForView)(f) + 'px',
2006      z: '0px'
2007    });
2008  }
2009  const angle = Math.atan2(b, a) * (180 / Math.PI);
2010  if (angle !== 0) {
2011    items.push({
2012      type: 'rotate',
2013      angle: (0,_Math__WEBPACK_IMPORTED_MODULE_0__.cleanFloatValueForView)(angle) + 'deg'
2014    });
2015  }
2016  const scaleX = Math.sqrt(a * a + b * b);
2017  const scaleY = det / scaleX;
2018  // Scale uniforme : moyenne si égaux à 1 % près, sinon scaleX
2019  const scale = (0,_Math__WEBPACK_IMPORTED_MODULE_0__.valueEqualtoWithinOnePercent)(scaleX, scaleY) ? (scaleX + scaleY) / 2 : scaleX;
2020  if (!(0,_Math__WEBPACK_IMPORTED_MODULE_0__.valueEqualtoWithinOnePercent)(scale, 1)) {
2021    items.push({
2022      type: 'scale',
2023      value: String((0,_Math__WEBPACK_IMPORTED_MODULE_0__.cleanFloatValueForView)(scale))
2024    });
2025  }
2026  return items;
2027}
2028
2029/**
2030 * Parse une valeur CSS transform en tableau d'items {type, ...}.
2031 * - liste de fonctions → items (rotate/rotateZ, translate*, scale/scale3d)
2032 * - matrix(…) → décomposition 2D (fallback lossy)
2033 * - matrix3d(…) → translate seul
2034 * - none / vide / fonctions inconnues → ignoré
2035 * @param {string} value
2036 * @returns {Array<Object>}
2037 */
2038function getTransformValue(value) {
2039  if (typeof value !== 'string' || value === '' || value === 'none') {
2040    return [];
2041  }
2042  const items = [];
2043  const regex = /([a-zA-Z0-9]+)\(([^)]*)\)/g;
2044  let m;
2045  while ((m = regex.exec(value)) !== null) {
2046    const fn = m[1];
2047    const args = m[2].split(',').map(arg => arg.trim());
2048    switch (fn) {
2049      case 'rotate':
2050      case 'rotateZ':
2051        items.push({
2052          type: 'rotate',
2053          angle: normalizeTransformLength(args[0], 'deg')
2054        });
2055        break;
2056      case 'translate':
2057        items.push({
2058          type: 'translate',
2059          x: normalizeTransformLength(args[0]),
2060          y: normalizeTransformLength(args.length > 1 ? args[1] : '0px'),
2061          z: '0px'
2062        });
2063        break;
2064      case 'translateX':
2065        items.push({
2066          type: 'translate',
2067          x: normalizeTransformLength(args[0]),
2068          y: '0px',
2069          z: '0px'
2070        });
2071        break;
2072      case 'translateY':
2073        items.push({
2074          type: 'translate',
2075          x: '0px',
2076          y: normalizeTransformLength(args[0]),
2077          z: '0px'
2078        });
2079        break;
2080      case 'translateZ':
2081        items.push({
2082          type: 'translate',
2083          x: '0px',
2084          y: '0px',
2085          z: normalizeTransformLength(args[0])
2086        });
2087        break;
2088      case 'translate3d':
2089        items.push({
2090          type: 'translate',
2091          x: normalizeTransformLength(args[0]),
2092          y: normalizeTransformLength(args[1]),
2093          z: normalizeTransformLength(args[2])
2094        });
2095        break;
2096      case 'scale':
2097      case 'scale3d':
2098        {
2099          const num = parseFloat(args[0]);
2100          items.push({
2101            type: 'scale',
2102            value: isNaN(num) ? '1' : String(num)
2103          });
2104          break;
2105        }
2106      case 'matrix':
2107        items.push(...decomposeMatrix2d(args.map(arg => parseFloat(arg))));
2108        break;
2109      case 'matrix3d':
2110        {
2111          // Translate seul (composantes 13-15) ; rotation/scale 3D non représentables dans l'UI
2112          const x = parseFloat(args[12]) || 0;
2113          const y = parseFloat(args[13]) || 0;
2114          const z = parseFloat(args[14]) || 0;
2115          if (x !== 0 || y !== 0 || z !== 0) {
2116            items.push({
2117              type: 'translate',
2118              x: (0,_Math__WEBPACK_IMPORTED_MODULE_0__.cleanFloatValueForView)(x) + 'px',
2119              y: (0,_Math__WEBPACK_IMPORTED_MODULE_0__.cleanFloatValueForView)(y) + 'px',
2120              z: (0,_Math__WEBPACK_IMPORTED_MODULE_0__.cleanFloatValueForView)(z) + 'px'
2121            });
2122          }
2123          break;
2124        }
2125      default:
2126        // Fonction non gérée (skew, rotateX/Y, perspective…) : ignorée silencieusement
2127        break;
2128    }
2129  }
2130  return items;
2131}
2132
2133/**
2134 * Sérialise un tableau d'items en valeur CSS transform.
2135 * Tableau vide → 'none'. Jamais de CSS invalide (NaN → défauts).
2136 * @param {Array<Object>} items
2137 * @returns {string}
2138 */
2139function generateTransformValue(items) {
2140  if (!Array.isArray(items) || items.length === 0) {
2141    return 'none';
2142  }
2143  const value = items.map(item => {
2144    switch (item.type) {
2145      case 'rotate':
2146        return 'rotate(' + normalizeTransformLength(item.angle, 'deg') + ')';
2147      case 'translate':
2148        return 'translate3d(' + normalizeTransformLength(item.x) + ', ' + normalizeTransformLength(item.y) + ', ' + normalizeTransformLength(item.z) + ')';
2149      case 'scale':
2150        {
2151          const num = parseFloat(item.value);
2152          return 'scale(' + (isNaN(num) ? 1 : num) + ')';
2153        }
2154      default:
2155        return '';
2156    }
2157  }).filter(fn => fn !== '').join(' ');
2158  return value === '' ? 'none' : value;
2159}
2160
2161// --- Shadow (box-shadow / text-shadow, outil ToolsDesign) ---
2162
2163/**
2164 * Tokenise un segment d'ombre sur les espaces, en ignorant ceux à l'intérieur
2165 * des parenthèses (ex. 'rgba(0, 0, 0, .5) 2px 2px 4px' → 4 tokens, pas 7).
2166 * @param {string} str
2167 * @returns {string[]}
2168 */
2169function splitShadowTokens(str) {
2170  const tokens = [];
2171  let depth = 0;
2172  let current = '';
2173  for (let i = 0; i < str.length; i++) {
2174    const ch = str[i];
2175    if (ch === '(') {
2176      depth++;
2177      current += ch;
2178    } else if (ch === ')') {
2179      depth--;
2180      current += ch;
2181    } else if (depth === 0 && /\s/.test(ch)) {
2182      if (current !== '') {
2183        tokens.push(current);
2184        current = '';
2185      }
2186    } else {
2187      current += ch;
2188    }
2189  }
2190  if (current !== '') {
2191    tokens.push(current);
2192  }
2193  return tokens;
2194}
2195const shadowLengthTokenRegex = /^-?(\d+\.?\d*|\.\d+)[a-z%]*$/i;
2196
2197/**
2198 * Un token ressemble-t-il à une longueur CSS ('2px', '-3', '.5em', '10%') ?
2199 * Tout ce qui n'est ni 'inset' ni une longueur est classé comme couleur.
2200 * @param {string} token
2201 * @returns {boolean}
2202 */
2203function isShadowLengthToken(token) {
2204  return shadowLengthTokenRegex.test(token);
2205}
2206
2207/**
2208 * Normalise une composante de longueur d'ombre : nombre + unité, NaN → '0' + unité par défaut.
2209 * @param {string} value
2210 * @param {string} defaultUnit
2211 * @returns {string}
2212 */
2213function normalizeShadowLength(value, defaultUnit = 'px') {
2214  const infos = getValueInfos(value, null, defaultUnit);
2215  const num = parseFloat(infos.value);
2216  if (isNaN(num)) {
2217    return '0' + defaultUnit;
2218  }
2219  return num + infos.unit;
2220}
2221
2222/**
2223 * Item d'ombre par défaut (pour « Ajouter une ombre » et pour compléter les
2224 * composantes absentes lors du parsing).
2225 * @param {string} mode 'box' | 'text'
2226 * @returns {Object}
2227 */
2228function getDefaultShadowItem(mode = 'box') {
2229  const base = {
2230    'offset-x': '0px',
2231    'offset-y': '0px',
2232    'blur-radius': '0px',
2233    'color': 'rgba(0,0,0,0.5)'
2234  };
2235  if (mode === 'box') {
2236    base['spread-radius'] = '0px';
2237    base.inset = false;
2238  }
2239  return base;
2240}
2241
2242/**
2243 * Parse une valeur CSS box-shadow / text-shadow en tableau d'items.
2244 * Tokenizer robuste par classification (pas par position fixe) : gère la
2245 * couleur en tête (legacy) ou en fin (standard), et 'inset' en tête ou en fin.
2246 * '' / 'none' / non-string → [].
2247 * @param {string} value
2248 * @param {{mode?: string}} options mode: 'box' (défaut) | 'text'
2249 * @returns {Array<Object>}
2250 */
2251function getShadowValue(value, options = {}) {
2252  const mode = options.mode === 'text' ? 'text' : 'box';
2253
2254  // '' / 'none' / 'remove' (sentinelle de réinitialisation ToolsDesign) → aucune ombre.
2255  if (typeof value !== 'string' || value.trim() === '' || value.trim() === 'none' || value.trim() === 'remove') {
2256    return [];
2257  }
2258  const segments = splitTopLevel(value.trim(), ',').map(segment => segment.trim()).filter(segment => segment !== '');
2259  const lengthKeys = mode === 'text' ? ['offset-x', 'offset-y', 'blur-radius'] : ['offset-x', 'offset-y', 'blur-radius', 'spread-radius'];
2260  return segments.map(segment => {
2261    const tokens = splitShadowTokens(segment);
2262    const lengths = [];
2263    let color = '';
2264    let inset = false;
2265    tokens.forEach(token => {
2266      if (/^inset$/i.test(token)) {
2267        // Mot-clé 'inset' : pris en compte en mode box, ignoré (pas la couleur) en mode text.
2268        if (mode === 'box') {
2269          inset = true;
2270        }
2271        return;
2272      }
2273      if (isShadowLengthToken(token)) {
2274        lengths.push(token);
2275        return;
2276      }
2277      // Ni 'inset' ni une longueur : couleur (#hex, rgb/rgba/hsl/hsla(...), var(...), nom CSS…)
2278      color = token;
2279    });
2280    const item = Object.assign({}, getDefaultShadowItem(mode));
2281    lengthKeys.forEach((key, index) => {
2282      if (typeof lengths[index] !== 'undefined') {
2283        item[key] = normalizeShadowLength(lengths[index]);
2284      }
2285    });
2286    if (color !== '') {
2287      item.color = color;
2288    }
2289    if (mode === 'box') {
2290      item.inset = inset;
2291    }
2292    return item;
2293  });
2294}
2295
2296/**
2297 * Sérialise un tableau d'items en valeur CSS box-shadow / text-shadow.
2298 * Tableau vide → 'none'. Ordre canonique :
2299 *   text → offset-x offset-y blur-radius [color]
2300 *   box  → [inset ]offset-x offset-y blur-radius spread-radius [color]
2301 * @param {Array<Object>} items
2302 * @param {{mode?: string}} options mode: 'box' (défaut) | 'text'
2303 * @returns {string}
2304 */
2305function generateShadowValue(items, options = {}) {
2306  const mode = options.mode === 'text' ? 'text' : 'box';
2307
2308  // Aucune ombre → chaîne vide (le composant écrira la sentinelle 'remove' pour
2309  // SUPPRIMER la propriété plutôt que forcer une valeur 'none').
2310  if (!Array.isArray(items) || items.length === 0) {
2311    return '';
2312  }
2313  const value = items.map(item => {
2314    const offsetX = normalizeShadowLength(item['offset-x']);
2315    const offsetY = normalizeShadowLength(item['offset-y']);
2316    const blur = normalizeShadowLength(item['blur-radius']);
2317    const color = item.color || '';
2318    if (mode === 'text') {
2319      const parts = [offsetX, offsetY, blur];
2320      if (color !== '') {
2321        parts.push(color);
2322      }
2323      return parts.join(' ');
2324    }
2325    const spread = normalizeShadowLength(item['spread-radius']);
2326    const parts = [];
2327    if (item.inset) {
2328      parts.push('inset');
2329    }
2330    parts.push(offsetX, offsetY, blur, spread);
2331    if (color !== '') {
2332      parts.push(color);
2333    }
2334    return parts.join(' ');
2335  }).join(', ');
2336  return value;
2337}
2338const transformOriginKeywordX = {
2339  'left': '0%',
2340  'center': '50%',
2341  'right': '100%'
2342};
2343const transformOriginKeywordY = {
2344  'top': '0%',
2345  'center': '50%',
2346  'bottom': '100%'
2347};
2348
2349/**
2350 * Parse une valeur CSS transform-origin en {x, y}.
2351 * Mots-clés convertis en %, valeurs px/% gardées. Défaut : 50% 50%.
2352 * @param {string} value ex: '50% 50%', 'top left', '100px 20px'
2353 * @returns {{x: string, y: string}}
2354 */
2355function getTransformOriginValue(value) {
2356  const origin = {
2357    x: '50%',
2358    y: '50%'
2359  };
2360  if (typeof value !== 'string' || value.trim() === '') {
2361    return origin;
2362  }
2363  let parts = value.trim().split(/\s+/).slice(0, 2);
2364
2365  // Mot-clé seul d'axe vertical : 'top' → '50% 0%'
2366  if (parts.length === 1 && /^(top|bottom)$/.test(parts[0])) {
2367    parts = ['center', parts[0]];
2368  }
2369
2370  // Mots-clés donnés dans l'ordre inverse : 'top left' → 'left top'
2371  if (parts.length === 2 && (/^(top|bottom)$/.test(parts[0]) || /^(left|right)$/.test(parts[1]))) {
2372    parts = [parts[1], parts[0]];
2373  }
2374  const rawX = parts[0];
2375  const rawY = parts.length > 1 ? parts[1] : '50%';
2376  origin.x = transformOriginKeywordX.hasOwnProperty(rawX) ? transformOriginKeywordX[rawX] : normalizeTransformLength(rawX, '%');
2377  origin.y = transformOriginKeywordY.hasOwnProperty(rawY) ? transformOriginKeywordY[rawY] : normalizeTransformLength(rawY, '%');
2378  return origin;
2379}
2380
2381/**
2382 * Sérialise {x, y} en valeur CSS transform-origin.
2383 * @param {{x: string, y: string}} origin
2384 * @returns {string}
2385 */
2386function generateTransformOriginValue(origin) {
2387  const values = Object.assign({
2388    x: '50%',
2389    y: '50%'
2390  }, origin);
2391  return normalizeTransformLength(values.x, '%') + ' ' + normalizeTransformLength(values.y, '%');
2392}
2393
2394/**
2395 *
2396 * @param value
2397 * @param unit
2398 * @returns {*}
2399 * @todo rajouter les calc
2400 */
2401function verifAndGetValueWithPrefix(value, unit) {
2402  switch (value) {
2403    case 'auto':
2404      return value;
2405    case '':
2406      return value;
2407    default:
2408      switch (unit) {
2409        case 'ratio':
2410        case 'int':
2411          return value;
2412        default:
2413          return value + unit;
2414          // removed by dead control flow
2415{}
2416      }
2417  }
2418}
2419function getBorderColor(element, pseudoElement) {
2420  let p = 0,
2421    value = '';
2422  let color = window.getComputedStyle(element, pseudoElement).getPropertyValue('color');
2423  let values = [];
2424  do {
2425    values.push(window.getComputedStyle(element, pseudoElement).getPropertyValue('border-' + positionProps[p] + '-color'));
2426    p++;
2427  } while (p < positionProps.length);
2428  let setValues = new Set(values);
2429  if (setValues.size > 1) {
2430    // on supprime la couleur de typographie, qui est hérité sur les border-color
2431    setValues.delete(color);
2432    // on supprime les 'none'
2433    setValues.delete('none');
2434
2435    // Si il y a plus de valeur, c'est que c'était la couleur de police à minima
2436    if (setValues.size) {
2437      // on récupére ensuite la première couleur en ignorant les autres
2438      let itV = setValues.values();
2439      value = itV.next().value;
2440    } else {
2441      value = color;
2442    }
2443  } else {
2444    value = values.shift();
2445  }
2446  return value;
2447}
2448function getBorderStyle(element, pseudoElement) {
2449  let p = 0,
2450    value = '';
2451  p = 0;
2452  do {
2453    value = window.getComputedStyle(element, pseudoElement).getPropertyValue('border-' + positionProps[p] + '-style');
2454    if (value !== '' && value !== 'none') {
2455      break;
2456    } // si on trouve une valeur on s'arrete là
2457    p++;
2458  } while (p < positionProps.length);
2459  return value;
2460}
2461const propUnitDefault = {
2462  'number': 'ratio',
2463  'number-int': 'int',
2464  'opacity': 'ratio',
2465  'border-image-slice': 'ratio',
2466  'line-height': 'ratio',
2467  'z-index': 'ratio',
2468  'order': 'ratio',
2469  'letter-spacing': 'em',
2470  'border-width': 'px',
2471  'width': 'px',
2472  'min-width': 'px',
2473  'max-width': 'px',
2474  'height': 'px',
2475  'min-height': 'px',
2476  'max-height': 'px',
2477  'margin': 'px',
2478  'padding': 'px',
2479  'font-size': 'px',
2480  'box-shadow': 'px',
2481  'background-size': '%',
2482  'background-size-x': '%',
2483  'background-size-y': '%',
2484  'time': 'ms'
2485};
2486function getDefaultUnit(prop) {
2487  if (!!prop && propUnitDefault.hasOwnProperty(prop)) {
2488    return propUnitDefault[prop];
2489  } else {
2490    return 'px';
2491  }
2492}
2493function addHistoryRemoveFromProps(newJSONOrigin, oldJSONOrigin) {
2494  let oldJSON = Object.assign({}, oldJSONOrigin);
2495  let newJSON = Object.assign({}, newJSONOrigin);
2496
2497  // Media Query ?
2498  for (let sizeResponsive in oldJSON) {
2499    if (!(sizeResponsive in newJSON)) {
2500      newJSON[sizeResponsive] = {};
2501    }
2502    for (let selector in oldJSON[sizeResponsive]) {
2503      if (!(selector in newJSON[sizeResponsive])) {
2504        newJSON[sizeResponsive][selector] = {};
2505      }
2506      for (let prop in oldJSON[sizeResponsive][selector]) {
2507        if (!(prop in newJSON[sizeResponsive][selector])) {
2508          newJSON[sizeResponsive][selector][prop] = 'remove';
2509        }
2510      }
2511    }
2512  }
2513  return newJSON;
2514}
2515function getStatusToClassAndPseudoClass(status) {
2516  let regex = /(?<selector>(?:(?::scope)|\.?[^:\s>]+)+)|(?<pseudoClass>:{1,2}(?<pseudoClassName>[^.:()\s]+(?:\([^\)]+\))?))|(?<child>[\s>])/g;
2517  let result = null;
2518  const returnValue = {
2519    'selector': '',
2520    'selectorWithScope': status,
2521    'pseudo-class': '',
2522    'original': status,
2523    'with-child': false
2524  };
2525  let withChild = false;
2526  let beforeSelector = '';
2527  let beforeType = 'selector';
2528  while ((result = regex.exec(status)) !== null) {
2529    // This is necessary to avoid infinite loops with zero-width matches
2530    if (result.index === regex.lastIndex) {
2531      regex.lastIndex++;
2532    }
2533    const pseudoClassGood = typeof result.groups.pseudoClassName === 'undefined' ? '' : getPseudoFormatByName(result.groups.pseudoClassName);
2534    const pseudoClass = typeof result.groups.pseudoClass === 'undefined' ? '' : result.groups.pseudoClass;
2535    const isLoopChild = typeof result.groups.child !== 'undefined' && (result.groups.child === ' ' || result.groups.child === '>');
2536    if (isLoopChild) {
2537      withChild = true;
2538      returnValue['selector'] += result.groups.child;
2539    }
2540
2541    // on corrige le pseudo élement ou pseudo class
2542    if (pseudoClass !== '') {
2543      status = status.replace(pseudoClass, pseudoClassGood);
2544    }
2545    returnValue['selector'] += typeof result.groups.selector === 'undefined' || result.groups.selector === '' ? '' : result.groups.selector;
2546    returnValue['pseudo-class'] = pseudoClassGood === '' ? returnValue['pseudo-class'] : pseudoClassGood;
2547    if (pseudoClassGood !== '' && /selector|pseudoClass/.test(beforeType)) {
2548      returnValue['pseudo-class-selector'] = pseudoClassGood === '' && /selector|pseudoClass/.test(beforeType) ? '' : beforeSelector;
2549    }
2550    beforeSelector = typeof result.groups.selector === 'undefined' || result.groups.selector === '' ? beforeSelector : result.groups.selector;
2551    beforeType = 'selector';
2552    if (isLoopChild) {
2553      beforeType = 'child';
2554    }
2555    if (pseudoClass !== '') {
2556      beforeType = 'pseudoClass';
2557    }
2558  }
2559  returnValue['with-child'] = withChild;
2560  return returnValue;
2561}
2562;
2563function getCSSQueryAllStatus(CSSquery, allStatus = false) {
2564  if (allStatus) {
2565    switch (typeof allStatus) {
2566      case "object":
2567        let query = '';
2568        let separator = '';
2569        for (let type in allStatus) {
2570          if (allStatus.hasOwnProperty(type)) {
2571            query += separator + getCSSQuery(CSSquery, allStatus[type], type);
2572            separator = ',';
2573          }
2574        }
2575        return query;
2576      default:
2577        const status = CSSHelper.getStatusToClassAndPseudoClass(allStatus);
2578        return getCSSQuery(CSSquery, status);
2579    }
2580  } else {
2581    return getCSSQuery(CSSquery, allStatus);
2582  }
2583}
2584function getCSSQuery(CSSquery, statusQuery = false, type = 'element', onlyElement = false) {
2585  let selectorsArray = CSSquery.split(',');
2586  let selectors = CSSquery;
2587  let statusArray = [];
2588  switch (typeof statusQuery) {
2589    case "string":
2590      statusArray = statusQuery.split(',');
2591      break;
2592    case "object":
2593      if (statusQuery === null) {
2594        statusArray.push('');
2595      } else {
2596        statusArray.push(statusQuery);
2597      }
2598      break;
2599  }
2600  if (statusQuery) {
2601    selectors = '';
2602    let separator = '';
2603    selectorsArray.forEach(function (selector) {
2604      statusArray.forEach(function (thisStatus) {
2605        let status = typeof thisStatus === "string" ? getStatusToClassAndPseudoClass(thisStatus) : thisStatus;
2606        const statusType = onlyElement ? 'selector' : 'original';
2607        switch (type) {
2608          case 'parent':
2609            let selectorParent = (status ? status[statusType].trim() : '') + ' ' + selector;
2610            const classesParentSelector = status.selector.match(/[#.][^#.\s]+/g) || [];
2611            if (classesParentSelector.length > 0) {
2612              classesParentSelector.forEach(part => {
2613                const regex = new RegExp((0,_String__WEBPACK_IMPORTED_MODULE_1__.escapeRegExp)(part));
2614                if (regex.test(selector)) {
2615                  selectorParent = selector.replace(regex, status[statusType].trim());
2616                }
2617              });
2618            }
2619            selectors += separator + selectorParent;
2620            break;
2621          case 'child':
2622            if (status && status[statusType].includes(':scope')) {
2623              selectors += separator + status[statusType].replace(':scope', selector).trim();
2624            } else {
2625              selectors += separator + selector + (status ? ' ' + status[statusType].trim() : '');
2626            }
2627            break;
2628          case 'custom':
2629            selectors += separator + (status ? status[statusType] : '');
2630            break;
2631          case 'element':
2632          default:
2633            const thisStatus = status ? status[statusType].trim().replace(':scope', '') : '';
2634            selectors += separator + selector + thisStatus;
2635            break;
2636        }
2637        separator = ',';
2638      });
2639    });
2640  }
2641  return selectors;
2642}
2643
2644/**
2645 * Clés de sélecteur sous lesquelles addChangeCssByType/_saveStyleLive enregistrent les valeurs
2646 * utilisateur (CSSRule/CSSRuleTemp) : une clé par type de status ET par sous-status (split sur ','),
2647 * chacune passée par getCSSQuery. Sans status, la clé est le sélecteur de base.
2648 * Toute relecture d'une valeur utilisateur doit interroger CES clés (pas le sélecteur de base seul),
2649 * sinon un onglet d'état (ex. « Survolé ») relit la valeur de l'état normal.
2650 * @param {string} CSSquery
2651 * @param {object|string|false} allStatus
2652 * @returns {string[]}
2653 */
2654function getCSSQuerySaveKeys(CSSquery, allStatus = false) {
2655  const keys = [];
2656  const pushKeysForStatus = function (statusString, type) {
2657    String(statusString).split(',').forEach(function (thisStatus) {
2658      keys.push(thisStatus === '' ? CSSquery : getCSSQuery(CSSquery, thisStatus, type));
2659    });
2660  };
2661  switch (typeof allStatus) {
2662    case "object":
2663      if (allStatus !== null) {
2664        for (let type in allStatus) {
2665          if (allStatus.hasOwnProperty(type)) {
2666            pushKeysForStatus(allStatus[type], type);
2667          }
2668        }
2669      }
2670      break;
2671    case "string":
2672      if (allStatus !== '') {
2673        pushKeysForStatus(allStatus, 'element');
2674      }
2675      break;
2676  }
2677  if (!keys.length) {
2678    keys.push(CSSquery);
2679  }
2680  return keys;
2681}
2682const initialValueByProps = {
2683  'background': 'none',
2684  'background-image': 'none',
2685  'background-color': 'transparent',
2686  'border-image-source': 'none',
2687  'color': 'inherit'
2688};
2689function hasInitialValue(prop) {
2690  return initialValueByProps.hasOwnProperty(prop);
2691}
2692function getInitialValue(prop, context = document.body) {
2693  if (initialValueByProps.hasOwnProperty(prop)) {
2694    return initialValueByProps[prop];
2695  } else {
2696    return window.getComputedStyle(document.body, null).getPropertyValue(prop);
2697  }
2698}
2699function getMediaQueryCss(min, max, type = 'up') {
2700  return '@media ' + getMediaQuery(min, max, type);
2701}
2702function getMediaQuery(min, max, type = 'up') {
2703  switch (type) {
2704    case 'up':
2705      return "(min-width:" + min + ")";
2706    case 'down':
2707      return "(max-width:" + max + ")";
2708    case 'only':
2709      return "(min-width:" + min + ") and (max-width:" + max + ")";
2710    case 'all':
2711      return "screen";
2712  }
2713}
2714
2715const CSSHelper = {
2716  cleanValuePropsCSS,
2717  getFontNameFromFontFamily,
2718  getValueOnEm,
2719  getValueOnREm: getValueOnRem,
2720  getBackgroundImageValue,
2721  convertBackgroundPositionToString,
2722  getPseudoFormatByName,
2723  getDefaultValueCss,
2724  cssComputedCache,
2725  getShortValueCss,
2726  getDecodeShortValue,
2727  expandShorthandToLonghands,
2728  isTargetedShorthand,
2729  normalizeDeclarations,
2730  normalizeCSSRuleStore,
2731  getInfoFromMultiProps,
2732  getUnit,
2733  getValueInfos,
2734  getPropRefForPercent,
2735  convertUnitByInfo,
2736  getComputedByInfo,
2737  getTranslateValues,
2738  getPercentFromTwoValue,
2739  getValueWithoutPrefix,
2740  verifAndGetValueWithPrefix,
2741  getBorderColor,
2742  getBorderStyle,
2743  getDefaultUnit,
2744  addHistoryRemoveFromProps,
2745  getCSSQuery,
2746  getCSSQueryAllStatus,
2747  getCSSQuerySaveKeys,
2748  getStatusToClassAndPseudoClass,
2749  generatePositionValue,
2750  getInitialValue,
2751  convertTime,
2752  calcMsToUnit,
2753  calcToMs,
2754  getValueViewWidth,
2755  getDefaultDisplayValue,
2756  getDefaultTransformItem,
2757  getTransformValue,
2758  generateTransformValue,
2759  decomposeMatrix2d,
2760  getTransformOriginValue,
2761  generateTransformOriginValue,
2762  parseGradient,
2763  generateGradient,
2764  getBackgroundLayers,
2765  generateBackgroundLonghands,
2766  getShadowValue,
2767  generateShadowValue,
2768  getDefaultShadowItem
2769};
2770/* unused harmony default export */ var __WEBPACK_DEFAULT_EXPORT__ = (CSSHelper);
2771
2772/***/ }),
2773
2774/***/ "./js/helper/Math.js":
2775/*!***************************!*\
2776  !*** ./js/helper/Math.js ***!
2777  \***************************/
2778/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
2779
2780/* harmony export */ __webpack_require__.d(__webpack_exports__, {
2781/* harmony export */   cleanFloatValueForView: function() { return /* binding */ cleanFloatValueForView; },
2782/* harmony export */   valueEqualtoWithinOnePercent: function() { return /* binding */ valueEqualtoWithinOnePercent; }
2783/* harmony export */ });
2784/* unused harmony exports cleanFloatValue, cleanStringInputToNumber, parseFloatCssValue, getPercent, toFixedCeil, toFixedFloor, ROUND_TYPE_ROUND, ROUND_TYPE_UP, ROUND_TYPE_DOWN */
2785function cleanFloatValue(value) {
2786  return value == parseInt(value) ? parseInt(value) : parseFloat(value);
2787}
2788const ROUND_TYPE_ROUND = 'round';
2789const ROUND_TYPE_UP = 'up';
2790const ROUND_TYPE_DOWN = 'down';
2791function cleanFloatValueForView(value, fractionDigits = 2, typeRound = ROUND_TYPE_ROUND) {
2792  if (value === "") {
2793    return value;
2794  }
2795  if (Number.isInteger(value)) {
2796    return value;
2797  } else {
2798    switch (typeRound) {
2799      case ROUND_TYPE_ROUND:
2800        return cleanFloatValue(parseFloat(value).toFixed(fractionDigits));
2801      case ROUND_TYPE_UP:
2802        return cleanFloatValue(toFixedFloor(parseFloat(value), fractionDigits));
2803      case ROUND_TYPE_DOWN:
2804        return cleanFloatValue(toFixedCeil(parseFloat(value), fractionDigits));
2805    }
2806  }
2807}
2808
2809/**
2810 *
2811 * @param value string
2812 * @returns string
2813 */
2814function cleanStringInputToNumber(value) {
2815  if (typeof value === 'string' && /,/.test(value)) {
2816    return value.replace(',', '.');
2817  }
2818  return value;
2819}
2820
2821/**
2822 *
2823 * @param value string
2824 * @returns string
2825 */
2826function parseFloatCssValue(value) {
2827  let parseValue = parseFloat(value);
2828  if (isNaN(parseValue)) {
2829    parseValue = 0;
2830  }
2831  return parseValue;
2832}
2833function getPercent(value, base, fractionDigits = 4) {
2834  return cleanFloatValueForView(value / base * 100, fractionDigits);
2835}
2836function toFixedCeil(number, n) {
2837  var k = Math.pow(10, n);
2838  return Math.ceil(number * k) / k;
2839}
2840function toFixedFloor(number, n) {
2841  var k = Math.pow(10, n);
2842  return Math.floor(number * k) / k;
2843}
2844function valueEqualtoWithinOnePercent(value1, value2) {
2845  const difference = Math.abs(value1 - value2);
2846  const OnePercentValue1 = 0.01 * Math.abs(value1);
2847  return difference < OnePercentValue1;
2848}
2849
2850const MathHelper = {
2851  cleanFloatValue: cleanFloatValue,
2852  cleanFloatValueForView: cleanFloatValueForView,
2853  cleanStringInputToNumber: cleanStringInputToNumber,
2854  parseFloatCssValue: parseFloatCssValue
2855};
2856/* harmony default export */ __webpack_exports__["default"] = (MathHelper);
2857
2858/***/ }),
2859
2860/***/ "./js/helper/String.js":
2861/*!*****************************!*\
2862  !*** ./js/helper/String.js ***!
2863  \*****************************/
2864/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
2865
2866/* harmony export */ __webpack_require__.d(__webpack_exports__, {
2867/* harmony export */   escapeRegExp: function() { return /* binding */ escapeRegExp; }
2868/* harmony export */ });
2869/* unused harmony exports camelize, decamelize, unicodeToHtml, safeBase64Encode, safeBase64Decode */
2870function escapeRegExp(string) {
2871  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2872}
2873
2874/**
2875 * Camelize a string, cutting the string by multiple separators like
2876 * hyphens, underscores and spaces.
2877 *
2878 * @param {text} string Text to camelize
2879 * @return string Camelized text
2880 */
2881function camelize(text) {
2882  return text.replace(/^([A-Z])|[\s-_]+(\w)/g, function (match, p1, p2, offset) {
2883    if (p2) return p2.toUpperCase();
2884    return p1.toLowerCase();
2885  });
2886}
2887
2888/**
2889 * Decamelizes a string with/without a custom separator (underscore by default).
2890 *
2891 * @param str String in camelcase
2892 * @param separator Separator for the new decamelized string.
2893 */
2894function decamelize(str, separator = '-') {
2895  return str.replace(/([a-z\d])([A-Z])/g, '$1' + separator + '$2').replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + separator + '$2').toLowerCase();
2896}
2897function unicodeToHtml(unicode) {
2898  var html = '';
2899  // On supprime l'anti-slash de l'unicode
2900  // convertie l'unicode Hexa en decimal
2901  var unicodeDecimal = parseInt(unicode, 16);
2902  // cree le caractere html
2903  html += '&#' + unicodeDecimal + ';';
2904  return html;
2905}
2906
2907// Fonctions utilitaires sécurisées pour l'encodage Base64 avec Unicode
2908function safeBase64Encode(str) {
2909  try {
2910    // Méthode moderne avec TextEncoder (supporte Unicode)
2911    if (typeof TextEncoder !== 'undefined') {
2912      const encoder = new TextEncoder();
2913      const bytes = encoder.encode(str);
2914      return btoa(String.fromCharCode(...bytes));
2915    }
2916
2917    // Fallback : encoder en UTF-8 puis base64
2918    return btoa(unescape(encodeURIComponent(str)));
2919  } catch (error) {
2920    console.error(error);
2921    // Fallback ultime : JSON.stringify + btoa (peut échouer avec émojis)
2922    try {
2923      return btoa(JSON.stringify(str));
2924    } catch (fallbackError) {
2925      console.error('Fallback encodage échoué:', fallbackError);
2926      return btoa('ERROR_ENCODING');
2927    }
2928  }
2929}
2930function safeBase64Decode(str) {
2931  try {
2932    // Méthode moderne avec TextDecoder (supporte Unicode)
2933    if (typeof TextDecoder !== 'undefined') {
2934      const decoded = atob(str);
2935      const bytes = new Uint8Array(decoded.length);
2936      for (let i = 0; i < decoded.length; i++) {
2937        bytes[i] = decoded.charCodeAt(i);
2938      }
2939      const decoder = new TextDecoder();
2940      return decoder.decode(bytes);
2941    }
2942
2943    // Fallback : decoder base64 puis UTF-8
2944    return decodeURIComponent(escape(atob(str)));
2945  } catch (error) {
2946    console.error(error);
2947    // Fallback ultime : JSON.parse + atob
2948    try {
2949      return JSON.parse(atob(str));
2950    } catch (fallbackError) {
2951      console.error('Fallback decodage échoué:', fallbackError);
2952      return 'ERROR_DECODING';
2953    }
2954  }
2955}
2956
2957const StringHelper = {
2958  "escapeRegExp": escapeRegExp,
2959  "camelize": camelize,
2960  "decamelize": decamelize
2961};
2962/* unused harmony default export */ var __WEBPACK_DEFAULT_EXPORT__ = (StringHelper);
2963
2964/***/ }),
2965
vendor: 4,214 bytes, lines 2966-3106
2966/***/ "./node_modules/beekube-dom/BaseApp/Component.js":
2967/*!*******************************************************!*\
2968  !*** ./node_modules/beekube-dom/BaseApp/Component.js ***!
2969  \*******************************************************/
2970/***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
2971
2972/* harmony import */ var _DOMModule_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./DOMModule.js */ "./node_modules/beekube-dom/BaseApp/DOMModule.js");
2973/* harmony import */ var _Helper_Object_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Helper/Object.js */ "./node_modules/beekube-dom/Helper/Object.js");
2974/* harmony import */ var js_struct_compare__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! js-struct-compare */ "./node_modules/js-struct-compare/src/index.mjs");
2975
2976
2977
2978
2979
2980/**
2981 * A node in the DOM tree.
2982 *
2983 * @external Node
2984 * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Node Node}
2985 */
2986
2987/**
2988 * Composent, permet de générer un template à partir d'un JSON qu'il faut retourner dans la fonction "render"
2989 *
2990 */
2991class Component {
2992    DOMModule = null;
2993    states = {};
2994
2995    /**
2996     * @param {object} states état initial du composant
2997     * @param {external:Node} element nœud parent dans lequel monter le composant
2998     * @param {number|null} index position d'insertion (null = append)
2999     */
3000    constructor(states, element, index = null) {
3001
3002        this.states = Object.assign(this.states, states);
3003        this.renderTemplate = (0,_DOMModule_js__WEBPACK_IMPORTED_MODULE_0__.getAssignKeyTemplate)(this.render());
3004
3005        this.beforeMount();
3006
3007        this.DOMModule = new _DOMModule_js__WEBPACK_IMPORTED_MODULE_0__["default"]({
3008            parentNode: element,
3009            index: index
3010        }, this.renderTemplate, this.states);
3011
3012        this.afterMount();
3013    }
3014
3015    getProp(variable, index) {
3016        let prop = function () {
3017            return (typeof index !== "undefined" ? this.props[variable][index] : this.props[variable]);
3018        };
3019        return prop.bind(this);
3020    }
3021
3022    /**
3023     *
3024     * @param value Object
3025     */
3026    set props(value) {
3027        let cloneStatesModule = (0,_Helper_Object_js__WEBPACK_IMPORTED_MODULE_1__.cloneObject)(this.states);
3028        Object.assign(cloneStatesModule, value);
3029
3030        for (let nameProps in cloneStatesModule) {
3031            if (cloneStatesModule.hasOwnProperty(nameProps)) {
3032                this.DOMModule.variables[nameProps] = cloneStatesModule[nameProps];
3033            }
3034        }
3035
3036        try {
3037            this.beforeRender();
3038
3039            let thisRender = (0,_DOMModule_js__WEBPACK_IMPORTED_MODULE_0__.getAssignKeyTemplate)(this.render());
3040            let templateCompare = (0,js_struct_compare__WEBPACK_IMPORTED_MODULE_2__["default"])(this.renderTemplate, thisRender);
3041
3042            this.DOMModule.render(null, {'compare': templateCompare, 'template': thisRender});
3043
3044            // On ne mémorise le nouveau template de référence qu'APRÈS une mise à jour
3045            // réussie : si render() lève, on évite de désynchroniser template et DOM.
3046            this.renderTemplate = thisRender;
3047
3048            this.afterRender();
3049        } catch (error) {
3050            // Garde de fiabilité : une exception dans render()/diff ne doit pas
3051            // casser l'ensemble de l'application. Le DOM est conservé en l'état.
3052            console.error('[beekube-dom] Échec de la mise à jour du composant ; DOM conservé en l\'état.', error);
3053        }
3054    }
3055
3056    get props() {
3057        return Object.assign({}, this.states);
3058    }
3059
3060    render() {
3061        return [];
3062    }
3063
3064    beforeRender() {
3065
3066    }
3067
3068    afterRender() {
3069
3070    }
3071
3072    beforeMount() {
3073
3074    }
3075
3076    afterMount() {
3077
3078    }
3079
3080    beforeDestroy() {
3081
3082    }
3083
3084    destroy() {
3085
3086        this.beforeDestroy();
3087
3088        // Remove All DOM
3089        if (this.DOMModule) {
3090            this.DOMModule.deleteDOM();
3091            // On libère la référence au module (le `delete this` précédent était un no-op).
3092            this.DOMModule = null;
3093        }
3094    }
3095
3096    setProps(states) {
3097        this.props = states;
3098    }
3099
3100}
3101
3102/* harmony default export */ __webpack_exports__["default"] = (Component);
3103
3104
3105/***/ }),
3106
vendor: 36,032 bytes, lines 3107-4167
3107/***/ "./node_modules/beekube-dom/BaseApp/DOMModule.js":
3108/*!*******************************************************!*\
3109  !*** ./node_modules/beekube-dom/BaseApp/DOMModule.js ***!
3110  \*******************************************************/
3111/***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
3112
3113/* harmony export */ __webpack_require__.d(__webpack_exports__, {
3114/* harmony export */   getAssignKeyTemplate: function() { return /* binding */ getAssignKeyTemplate; }
3115/* harmony export */ });
3116/* harmony import */ var _DOM_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../DOM.js */ "./node_modules/beekube-dom/DOM.js");
3117/* harmony import */ var _Helper_Object_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Helper/Object.js */ "./node_modules/beekube-dom/Helper/Object.js");
3118/* harmony import */ var _Helper_String_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../Helper/String.js */ "./node_modules/beekube-dom/Helper/String.js");
3119/* harmony import */ var js_struct_compare__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! js-struct-compare */ "./node_modules/js-struct-compare/src/index.mjs");
3120/* harmony import */ var _Component_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Component.js */ "./node_modules/beekube-dom/BaseApp/Component.js");
3121
3122
3123
3124
3125
3126
3127/**
3128 * Permet de générer du DOM HTML à partir d'une template JSON
3129 * Les événements sont pris également en compte et appliquer
3130 * Le paramètre parent indique dans quel élement du DOM, il sera insérer
3131 *
3132 * Les Variables sont une simple JSON (nom, valeur), exemple : {"name": "Damien"}
3133 *
3134 * Voici un exemple de template :
3135 * [{
3136        'p': {
3137            'textContent': 'Bonjour {{name}}'
3138        },
3139    }, {
3140        'div': {
3141            'children': [
3142                {
3143                    "label": {
3144                        "textContent": "Nom"
3145                    },
3146                    "input": {
3147                        "type": "text",
3148                        "value": "{{name}}",
3149                        "change": {
3150                            'listener': this.onChange,
3151                            'useCapture': false
3152                        },
3153                        "keyup": this.onChange
3154                    }
3155                }
3156            ]
3157        }
3158        }]
3159 */
3160function DOMModule(parentNode, template, variables) {
3161
3162  let parentNodeOption = Object.assign({
3163    parentNode: null,
3164    index: null
3165  }, parentNode);
3166
3167  this.template = template;
3168  this.parentNode = parentNodeOption.parentNode;
3169  this.nodeIndex = parentNodeOption.index;
3170  this.variables = variables;
3171  this.DOMElement = null;
3172  this.elements = [];
3173
3174  this.getTemplateVariables();
3175  this.render();
3176}
3177
3178DOMModule.prototype.getTemplateVariables = function () {
3179  this._variableRender = getVariableInJSONTemplate(this.template);
3180};
3181
3182const regexVariable = /\{\{(.*?)\}\}/gm;
3183
3184function getVariableInJSONTemplate(json) {
3185  var JSONVariable = {};
3186
3187  for (let dataKey in json) {
3188    if (json.hasOwnProperty(dataKey)) {
3189      let jsonData = json[dataKey];
3190      switch (typeof jsonData) {
3191        case 'object':
3192          JSONVariable[dataKey] = getVariableInJSONTemplate(jsonData);
3193          break;
3194        case 'function':
3195          JSONVariable[dataKey] = jsonData;
3196          break;
3197        case 'string':
3198          let m;
3199          while ((m = regexVariable.exec(jsonData)) !== null) {
3200            // This is necessary to avoid infinite loops with zero-width matches
3201            if (m.index === regexVariable.lastIndex) {
3202              regexVariable.lastIndex++;
3203            }
3204
3205            if (!JSONVariable.hasOwnProperty(dataKey)) {
3206              JSONVariable[dataKey] = [];
3207            }
3208
3209            JSONVariable[dataKey].push(m[1]);
3210          }
3211
3212          break;
3213        default:
3214          break;
3215      }
3216    }
3217  }
3218
3219  return JSONVariable;
3220}
3221
3222
3223function getAssignKeyTemplate(json, setKey = true) {
3224  var template = {};
3225
3226  for (let dataKey in json) {
3227    if (json.hasOwnProperty(dataKey)) {
3228      let jsonData = json[dataKey];
3229      switch (typeof jsonData) {
3230        case 'object':
3231          if (setKey) {
3232            for (let elementType in jsonData) {
3233              let element = jsonData[elementType];
3234              const newKey = element.hasOwnProperty('key') ? element.key : `${elementType}-${dataKey}`;
3235              template[newKey] = {};
3236              template[newKey][elementType] = element;
3237              template[newKey] = getAssignKeyTemplate(template[newKey], false);
3238            }
3239          } else {
3240            switch (dataKey) {
3241              case 'class':
3242                template[dataKey] = jsonData;
3243                break;
3244              default:
3245                template[dataKey] = getAssignKeyTemplate(jsonData, dataKey === 'children');
3246                break;
3247            }
3248
3249          }
3250
3251          break;
3252        default:
3253          template[dataKey] = jsonData;
3254          break;
3255      }
3256    }
3257  }
3258
3259  return template;
3260}
3261
3262function assignVariableTemplate(context) {
3263  return recursiveAssignVariables(context.template, context._variableRender, context, context.DOMElement, null);
3264}
3265
3266
3267function recursiveAssignVariables(templateCurrent, templateRenderCurrent, context, DOMElementCurrent, elementParent = null) {
3268
3269  let newTemplateArray = {};
3270  let DOMElement = DOMElementCurrent === null ? null : (0,_Helper_Object_js__WEBPACK_IMPORTED_MODULE_1__.cloneObject)(DOMElementCurrent);
3271  let template = (0,_Helper_Object_js__WEBPACK_IMPORTED_MODULE_1__.cloneObject)(templateCurrent);
3272  let templateRender = (0,_Helper_Object_js__WEBPACK_IMPORTED_MODULE_1__.cloneObject)(templateRenderCurrent);
3273
3274  // On boucle sur la template JSON
3275  for (let elementIndex in templateRender) {
3276    if (templateRender.hasOwnProperty(elementIndex) && template.hasOwnProperty(elementIndex)) {
3277      // let newTemplate = JSON.parse(JSON.stringify(template[elementIndex]));
3278
3279      let newTemplate = (0,_Helper_Object_js__WEBPACK_IMPORTED_MODULE_1__.cloneObject)(template[elementIndex]);
3280      newTemplateArray[elementIndex] = newTemplate;
3281
3282      // Dans le cas d'un composant, on transmet le parent, et les propriétés
3283
3284      if (typeof newTemplate === "function") {
3285        let element = null;
3286        if (elementParent === null) {
3287          if (DOMElement !== null) {
3288            element = DOMElement.DOM[elementIndex];
3289          } else {
3290            element = null;
3291          }
3292        } else {
3293          element = elementParent[elementIndex];
3294        }
3295        setVariableOnComponent(
3296          element,
3297          context
3298        )
3299      }
3300
3301      // On boucle sur les élements DOM
3302      for (let elementName in templateRender[elementIndex]) {
3303        if (templateRender[elementIndex].hasOwnProperty(elementName)) {
3304          // On cherche l'element du DOM existant dans la page
3305          // Dans le cas contraire on met null sur element
3306          let element = null;
3307          if (elementParent === null) {
3308            if (DOMElement !== null) {
3309              element = DOMElement.DOM[elementIndex][elementName];
3310            } else {
3311              element = null;
3312            }
3313          } else {
3314            switch (true) {
3315              case elementParent[elementIndex] === undefined:
3316                // Désynchronisation template / mapping DOM : on n'écrase pas le DOM,
3317                // setVariable retombera en mode string. À investiguer si ce warn apparaît.
3318                console.warn('DOMModule: élément "' + elementIndex + '" absent du mapping DOM', elementParent);
3319                element = null;
3320                break;
3321              case elementName === "Component":
3322                element = elementParent[elementIndex];
3323                break;
3324              default:
3325                element = elementParent[elementIndex][elementName];
3326                break;
3327            }
3328          }
3329
3330
3331          let JSONElement = templateRender[elementIndex][elementName];
3332          let JSONElementTemplate = newTemplateArray[elementIndex][elementName];
3333
3334          // On boucle sur les attributs de l'élément du DOM
3335          for (let attributeRender in JSONElement) {
3336            if (JSONElement.hasOwnProperty(attributeRender)) {
3337              let variableNames = JSONElement[attributeRender];
3338              let attributeTemplate = JSONElementTemplate[attributeRender];
3339              switch (attributeRender) {
3340                // On boucle sur les enfants pour créer aussi les variables
3341                case 'children':
3342                  newTemplateArray[elementIndex][elementName][attributeRender] = recursiveAssignVariables(
3343                    attributeTemplate,
3344                    variableNames,
3345                    context,
3346                    !!element && element.hasOwnProperty('DOM') ? element : null,
3347                    !element ? null : element.children,
3348                  );
3349                  break;
3350                default:
3351                  newTemplateArray[elementIndex][elementName][attributeRender] = setVariable(
3352                    element && element.hasOwnProperty('DOM') ? element.DOM : element,
3353                    attributeRender,
3354                    attributeTemplate,
3355                    variableNames,
3356                    context);
3357                  break;
3358              }
3359            }
3360          }
3361        }
3362      }
3363    }
3364  }
3365
3366  return newTemplateArray;
3367}
3368
3369const SET_VARIABLE_STRING = 1;
3370const SET_VARIABLE_DOM = 2;
3371
3372/**
3373 * Transmettre les propriétés au Composent enfant
3374 * @param _component
3375 * @param _context
3376 */
3377function setVariableOnComponent(_component, _context) {
3378  // passe maintenant par autre part
3379
3380}
3381
3382/**
3383 * Changement proprement les variables
3384 * Si le DOM existe, seulement changer la valeur nécessaire pour éviter de reconstruire le DOM
3385 * @param element
3386 * @param attributeName
3387 * @param attributeValue
3388 * @param variablesName
3389 * @param context
3390 * @returns {*}
3391 */
3392function setVariable(element, attributeName, attributeValue, variablesName, context) {
3393  let type = element === null ? SET_VARIABLE_STRING : SET_VARIABLE_DOM;
3394  let value = attributeValue;
3395
3396  if (!Array.isArray(variablesName)) {
3397    if(typeof attributeValue === "function" && attributeName === "function") {
3398      setVariableOnComponent(
3399        attributeValue,
3400        element
3401      )
3402    }
3403    return attributeValue;
3404  };
3405
3406  variablesName.forEach(function (nameVariable) {
3407    if (context.variables.hasOwnProperty(nameVariable)) {
3408      let variableValue = '';
3409      // On vérifie si la valeur est une function
3410      // Si oui, on l'execute
3411      switch (typeof context.variables[nameVariable]) {
3412        case 'function':
3413          variableValue = context.variables[nameVariable]();
3414          break;
3415        default:
3416          variableValue = context.variables[nameVariable];
3417          break;
3418      }
3419
3420      // Sécurité pour les valeurs null, car le remplace parse le null en string
3421      variableValue = variableValue === null ? '' : variableValue;
3422
3423      // split/join : remplace TOUTES les occurrences et n'interprète PAS les motifs
3424      // spéciaux de String.replace ($&, $1, ...) qui pourraient être présents dans la valeur.
3425      value = value.split('{{' + nameVariable + '}}').join(String(variableValue));
3426    }
3427  });
3428  if (type === SET_VARIABLE_DOM) {
3429    switch (attributeName) {
3430      case 'textContent':
3431        element.textContent = (0,_Helper_String_js__WEBPACK_IMPORTED_MODULE_2__.getContentVariable)(value);
3432        break;
3433      case 'value':
3434        element.value = (0,_Helper_String_js__WEBPACK_IMPORTED_MODULE_2__.getContentVariable)(value);
3435        break;
3436      case 'function':
3437        break;
3438      default:
3439        // Note : `value`/`checked` ont leurs cas dédiés plus haut. L'ancienne condition
3440        // `typeof element.hasAttribute(...) === 'string'` était toujours fausse (branche morte).
3441        element.setAttribute(attributeName, value);
3442        break;
3443    }
3444  }
3445
3446  return value;
3447}
3448
3449
3450function getFirstLevelDOMElements(render) {
3451  if (!render || !render.DOMElement || !render.DOMElement.DOM) {
3452    return [];
3453  }
3454  const firstLevelKeys = Object.keys(render.DOMElement.DOM);
3455
3456  return firstLevelKeys.map(key => {
3457    const element = render.DOMElement.DOM[key];
3458    if (!element || typeof element !== 'object') {
3459      return null;
3460    }
3461    // Composant de premier niveau : on expose son premier nœud DOM si disponible.
3462    if (element instanceof _Component_js__WEBPACK_IMPORTED_MODULE_4__["default"]) {
3463      const els = element.DOMModule && element.DOMModule.elements;
3464      return els && els.length ? els[0] : null;
3465    }
3466    const tagName = Object.keys(element)[0];
3467    const tagNode = tagName ? element[tagName] : null;
3468    return tagNode && tagNode.DOM ? tagNode.DOM : null;
3469  }).filter(Boolean);
3470}
3471
3472
3473/**
3474 * Rendu de la template
3475 * @param context
3476 * @param templateCompare {'compare': Difference[], template: {}}
3477 */
3478DOMModule.prototype.render = function (context = null, templateCompare = null) {
3479  context = context === null ? this : context;
3480  if (templateCompare !== null) {
3481    if (templateCompare.hasOwnProperty('compare') && templateCompare.hasOwnProperty('template')) {
3482      context = updateTemplate(context, templateCompare.compare, templateCompare.template);
3483      this.getTemplateVariables(); // Mise à jour des données sur les variables
3484    }
3485  }
3486
3487  let templateWithVariables = assignVariableTemplate(context);
3488  if (context.DOMElement === null) {
3489    context.DOMElement = new _DOM_js__WEBPACK_IMPORTED_MODULE_0__["default"](templateWithVariables, context.parentNode, null, context.nodeIndex);
3490  }
3491
3492  // Passe de réconciliation keyée : un pur réordonnancement d'une liste keyée n'émet
3493  // aucune Difference (js-struct-compare est insensible à l'ordre des clés). Cette passe
3494  // additive réaligne donc l'ordre du DOM sur l'ordre VOULU du template, uniquement via
3495  // insertBefore sur des nœuds existants (préserve l'état natif), de façon idempotente.
3496  // L'ordre voulu vient du template fourni au render (templateCompare.template) car, faute
3497  // de Difference, context.template n'est PAS mis à jour lors d'un réordre.
3498  if (context.DOMElement && context.DOMElement.DOM) {
3499    const desiredTemplate = (templateCompare && templateCompare.template)
3500      ? templateCompare.template
3501      : context.template;
3502    reconcileKeyedOrder(desiredTemplate, context.DOMElement.DOM);
3503  }
3504
3505  // Toujours rafraîchir la liste des nœuds racine : auparavant figée au premier rendu,
3506  // elle devenait périmée après chaque mise à jour (cause de crashs dans afterRender/afterMount).
3507  context.elements = getFirstLevelDOMElements(context);
3508};
3509
3510/**
3511 * Réconciliation keyée : réordonne le DOM pour coller à l'ordre des clés du template.
3512 * Parcourt récursivement les groupes d'enfants keyés et n'émet que des insertBefore sur
3513 * des nœuds existants. Ne crée ni ne supprime rien (le diff s'en charge déjà). Idempotente.
3514 * @param templateGroup objet keyé { cle: { tag: {...children} } | { Component: {...} } }
3515 * @param domGroup map DOM keyée correspondante (context.DOMElement.DOM)
3516 */
3517function reconcileKeyedOrder(templateGroup, domGroup) {
3518  if (!templateGroup || !domGroup || typeof templateGroup !== 'object') {
3519    return;
3520  }
3521  // 1. Réordonner les frères de CE groupe selon l'ordre du template
3522  reorderKeyedGroup(templateGroup, domGroup);
3523  // 2. Descendre récursivement dans les sous-groupes 'children'
3524  for (const key in templateGroup) {
3525    if (!templateGroup.hasOwnProperty(key)) continue;
3526    const childTemplate = getTemplateChildren(templateGroup[key]);
3527    const childDom = getDomChildren(domGroup[key]);
3528    if (childTemplate && childDom) {
3529      reconcileKeyedOrder(childTemplate, childDom);
3530    }
3531  }
3532}
3533
3534/** Récupère le sous-objet keyé `children` d'une entrée de template (forme élément). */
3535function getTemplateChildren(templateEntry) {
3536  if (!templateEntry || typeof templateEntry !== 'object') return null;
3537  for (const tag in templateEntry) {
3538    if (!templateEntry.hasOwnProperty(tag)) continue;
3539    const node = templateEntry[tag];
3540    if (node && typeof node === 'object' && node.children && typeof node.children === 'object') {
3541      return node.children;
3542    }
3543  }
3544  return null;
3545}
3546
3547/** Récupère la sous-map DOM `children` d'une entrée de la map DOM (forme élément). */
3548function getDomChildren(domEntry) {
3549  if (!domEntry || typeof domEntry !== 'object' || domEntry instanceof _Component_js__WEBPACK_IMPORTED_MODULE_4__["default"]) {
3550    return null;
3551  }
3552  const tag = Object.keys(domEntry)[0];
3553  const node = tag ? domEntry[tag] : null;
3554  return node && node.children && typeof node.children === 'object' ? node.children : null;
3555}
3556
3557/**
3558 * Résout une entrée de la map DOM en son/ses nœud(s) DOM réel(s).
3559 * Gère les 3 formes : Component (multi-racines), élément { tag: { DOM } }, et le
3560 * wrapper CreateElementDOM (créé lors d'un ajout via le diff).
3561 * @returns {Element[]|null}
3562 */
3563function resolveKeyNodes(domEntry) {
3564  if (domEntry == null || typeof domEntry !== 'object') return null;
3565
3566  if (domEntry instanceof _Component_js__WEBPACK_IMPORTED_MODULE_4__["default"]) {
3567    const els = domEntry.DOMModule && domEntry.DOMModule.elements;
3568    return els && els.length ? els.filter(Boolean) : null;
3569  }
3570
3571  if (domEntry instanceof _DOM_js__WEBPACK_IMPORTED_MODULE_0__["default"]) {
3572    let nodes = [];
3573    for (const k in domEntry.DOM) {
3574      const sub = resolveKeyNodes(domEntry.DOM[k]);
3575      if (sub) nodes = nodes.concat(sub);
3576    }
3577    return nodes.length ? nodes : null;
3578  }
3579
3580  const tag = Object.keys(domEntry)[0];
3581  const node = tag ? domEntry[tag] : null;
3582  return node && node.DOM ? [node.DOM] : null;
3583}
3584
3585/**
3586 * Réordonne les nœuds d'un groupe keyé pour coller à l'ordre des clés du template.
3587 * N'émet que des insertBefore, et MINIMISE le nombre de déplacements via la plus longue
3588 * sous-suite croissante (LIS) : les nœuds déjà dans le bon ordre relatif ne bougent pas.
3589 * Idempotent (DOM déjà ordonné ⇒ 0 déplacement).
3590 */
3591function reorderKeyedGroup(templateGroup, domGroup) {
3592  // L'ordre voulu est l'ordre d'énumération des clés du template (= ordre d'insertion).
3593  // LIMITATION : pour des clés ENTIÈRES ("0","1",…) JS énumère en ordre numérique croissant,
3594  // pas en ordre d'insertion → l'ordre voulu serait faux. Utiliser des clés `key` explicites
3595  // NON numériques (ex. "Item"+uid), comme le fait l'usage réel. Voir RESEARCH-keyed-reconciliation.md.
3596  const desired = [];
3597  const blocks = {};
3598  for (const key in templateGroup) {
3599    if (!templateGroup.hasOwnProperty(key)) continue;
3600    if (domGroup[key] == null) continue;
3601    const nodes = resolveKeyNodes(domGroup[key]);
3602    if (nodes && nodes.length) {
3603      desired.push(key);
3604      blocks[key] = nodes;
3605    }
3606  }
3607  if (desired.length < 2) return;
3608
3609  const parent = blocks[desired[0]][0].parentNode;
3610  if (!parent) return;
3611
3612  // Ne garder que les blocs dont le premier nœud est bien un enfant direct du parent commun.
3613  const keys = desired.filter(k => blocks[k][0].parentNode === parent);
3614  if (keys.length < 2) return;
3615
3616  // Ordre DOM courant : position de chaque clé (par son premier nœud) parmi les enfants du parent.
3617  const posByKey = new Map();
3618  const firstNodeToKey = new Map();
3619  for (const k of keys) firstNodeToKey.set(blocks[k][0], k);
3620  let idx = 0;
3621  for (let n = parent.firstChild; n; n = n.nextSibling) {
3622    const k = firstNodeToKey.get(n);
3623    if (k !== undefined) posByKey.set(k, idx++);
3624  }
3625
3626  // seq[i] = position DOM courante de la i-ème clé VOULUE (permutation de 0..n-1).
3627  const seq = keys.map(k => posByKey.get(k));
3628
3629  // LIS sur seq : indices (dans `keys`) des blocs déjà en ordre relatif → on ne les déplace PAS.
3630  const keepIdx = longestIncreasingSubsequenceIndices(seq);
3631  let j = keepIdx.length - 1;
3632
3633  // Parcours arrière : l'ancre est le premier nœud du bloc suivant (déjà placé).
3634  for (let i = keys.length - 1; i >= 0; i--) {
3635    const anchor = (i + 1 < keys.length) ? blocks[keys[i + 1]][0] : null;
3636    if (j >= 0 && i === keepIdx[j]) {
3637      j--; // dans la LIS : reste en place
3638      continue;
3639    }
3640    const block = blocks[keys[i]];
3641    // Itération AVANT : avec une ancre fixe, insérer dans l'ordre préserve l'ordre interne
3642    // du bloc (cas des composants multi-racines).
3643    for (let b = 0; b < block.length; b++) {
3644      const node = block[b];
3645      if (node.parentNode !== parent) continue;
3646      parent.insertBefore(node, anchor);
3647    }
3648  }
3649}
3650
3651/**
3652 * Indices de la plus longue sous-suite strictement croissante de `arr` (O(n log n)).
3653 * `arr` est une permutation d'entiers distincts. Renvoie les indices (dans `arr`), croissants.
3654 */
3655function longestIncreasingSubsequenceIndices(arr) {
3656  const n = arr.length;
3657  const predecessor = new Array(n).fill(-1);
3658  const tails = []; // tails[k] = index dans arr du plus petit "tail" d'une sous-suite de longueur k+1
3659  for (let i = 0; i < n; i++) {
3660    let lo = 0;
3661    let hi = tails.length;
3662    while (lo < hi) {
3663      const mid = (lo + hi) >> 1;
3664      if (arr[tails[mid]] < arr[i]) {
3665        lo = mid + 1;
3666      } else {
3667        hi = mid;
3668      }
3669    }
3670    if (lo > 0) predecessor[i] = tails[lo - 1];
3671    tails[lo] = i;
3672  }
3673  const result = [];
3674  let k = tails.length ? tails[tails.length - 1] : -1;
3675  while (k >= 0) {
3676    result.push(k);
3677    k = predecessor[k];
3678  }
3679  result.reverse();
3680  return result;
3681}
3682
3683
3684function filterDeleted(value) {
3685  return value.get_type() === js_struct_compare__WEBPACK_IMPORTED_MODULE_3__.Difference.TYPE_DELETED;
3686}
3687
3688function filterOther(value) {
3689  return value.get_type() !== js_struct_compare__WEBPACK_IMPORTED_MODULE_3__.Difference.TYPE_DELETED;
3690}
3691
3692/**
3693 *
3694 * @param context
3695 * @param differenceList Difference[]
3696 * @param template object
3697 */
3698function updateTemplate(context, differenceList, template) {
3699
3700  let deleted = differenceList.filter(filterDeleted);
3701  let others = differenceList.filter(filterOther);
3702
3703  let list = [...deleted, ...others];
3704
3705  for (let diff in list) {
3706    if (list.hasOwnProperty(diff) && list[diff] instanceof js_struct_compare__WEBPACK_IMPORTED_MODULE_3__.Difference) {
3707      context = editTemplate(context, list[diff], template);
3708    }
3709  }
3710
3711  return context;
3712}
3713
3714/**
3715 *
3716 * @param context
3717 * @param diff
3718 * @param template
3719 */
3720function editTemplate(context, diff, template) {
3721  return updateValue(context, diff.get_path(), diff.get_right_value(), diff.get_left_value(), diff.get_type(), template);
3722}
3723
3724const TYPE_NODELIST = 1;
3725const TYPE_ELEMENT = 2;
3726const TYPE_ATTRIBUTE = 3;
3727const TYPE_ATTRIBUTE_LIST = 4;
3728const TYPE_COMPONENT = 5;
3729
3730/**
3731 *
3732 * @param type
3733 * @param key
3734 * @returns {number}
3735 */
3736function incrementType(type, key) {
3737  switch (type) {
3738    case TYPE_NODELIST:
3739      if (key === 'Component') {
3740        return TYPE_COMPONENT;
3741      } else {
3742        return TYPE_ELEMENT
3743      }
3744    case TYPE_ELEMENT:
3745      if (key === 'Component') {
3746        return TYPE_COMPONENT;
3747      } else {
3748        return TYPE_ATTRIBUTE
3749      }
3750    case TYPE_ATTRIBUTE:
3751      if (key === 'children') {
3752        return TYPE_NODELIST;
3753      }
3754
3755      if (key === 'class') {
3756        return TYPE_ATTRIBUTE_LIST;
3757      }
3758
3759      return TYPE_ATTRIBUTE;
3760
3761    case TYPE_ATTRIBUTE_LIST:
3762      return TYPE_ATTRIBUTE_LIST;
3763    case TYPE_COMPONENT:
3764      return TYPE_COMPONENT;
3765  }
3766  return TYPE_NODELIST;
3767}
3768
3769function deleteChildElement(name, element) {
3770
3771  switch (true) {
3772    // Composant
3773    case element instanceof _Component_js__WEBPACK_IMPORTED_MODULE_4__["default"]:
3774      element.destroy();
3775      break;
3776    // Create DOM Element
3777    case element instanceof _DOM_js__WEBPACK_IMPORTED_MODULE_0__["default"]:
3778      if (element.hasOwnProperty('DOM')) {
3779        for (const indexChild in element.DOM) {
3780          const child = element.DOM[indexChild];
3781          if (child instanceof _Component_js__WEBPACK_IMPORTED_MODULE_4__["default"]) {
3782            child.destroy();
3783          } else {
3784            for (let elementName in child) {
3785              if (child.hasOwnProperty(elementName) && child[elementName].hasOwnProperty('DOM')) {
3786                child[elementName].DOM.remove();
3787              }
3788            }
3789          }
3790        }
3791      }
3792      break;
3793
3794    // DOM
3795    case !element.hasOwnProperty('DOM'):
3796      for (let elementName in element) {
3797        if (element.hasOwnProperty(elementName)) {
3798          if (element[elementName].hasOwnProperty('DOM') && element[elementName].DOM instanceof Element) {
3799            element[elementName].DOM.remove();
3800          }
3801        }
3802      }
3803      break;
3804    // String
3805    case typeof name === "string":
3806      if (element.DOM.hasOwnProperty(name)) {
3807        deleteChildElement(name, element.DOM[name]);
3808      } else {
3809        element.DOM.remove();
3810      }
3811
3812
3813      break;
3814    default:
3815      element['children'][name].DOM.remove();
3816      break;
3817  }
3818
3819}
3820
3821/**
3822 * Normalise une valeur de classe (string "a b", tableau ["a","b"], undefined/null)
3823 * en une liste de jetons exploitable par classList. Évite `undefined.split`/`array.split`.
3824 * @param v
3825 * @returns {string[]}
3826 */
3827function toClassTokens(v) {
3828  if (Array.isArray(v)) {
3829    return v.filter(Boolean);
3830  }
3831  if (typeof v === 'string') {
3832    return v.split(' ').filter(Boolean);
3833  }
3834  return [];
3835}
3836
3837function updateValueInDOM(oldValue, value, typeDiff, name, typeIndex, element, parentElement, lastPathCurrentRight) {
3838  let elementDOM = !!element && element.hasOwnProperty('DOM') ? element.DOM : parentElement;
3839
3840  let thisElement;
3841  switch (true) {
3842    case !!element && element.hasOwnProperty(name):
3843      thisElement = element[name];
3844      break;
3845    case !!element && elementDOM.hasOwnProperty(name):
3846      thisElement = elementDOM[name];
3847      break;
3848    default:
3849      thisElement = element;
3850      break;
3851  }
3852
3853
3854  const REMOVE_OLD = typeDiff === js_struct_compare__WEBPACK_IMPORTED_MODULE_3__.Difference.TYPE_DELETED || typeDiff === js_struct_compare__WEBPACK_IMPORTED_MODULE_3__.Difference.TYPE_CHANGED;
3855  const ADD_NEW = typeDiff === js_struct_compare__WEBPACK_IMPORTED_MODULE_3__.Difference.TYPE_ADDED || typeDiff === js_struct_compare__WEBPACK_IMPORTED_MODULE_3__.Difference.TYPE_CHANGED;
3856
3857  switch (typeIndex) {
3858    case TYPE_NODELIST:
3859      if (REMOVE_OLD) {
3860
3861        for (const indexChild in element[name]) {
3862          const child = element[name][indexChild];
3863          // Suppression Ancienne éléments
3864          if (child instanceof _DOM_js__WEBPACK_IMPORTED_MODULE_0__["default"]) {
3865            child.destroy();
3866          } else if (child.hasOwnProperty('DOM')) {
3867            child.DOM.remove();
3868          } else {
3869            // Format map {tag: {DOM, children}} (sémantique du render initial)
3870            deleteChildElement(indexChild, child);
3871          }
3872        }
3873        element[name] = [];
3874
3875      }
3876
3877      // Création du nouvelle élément
3878      // On stocke la map keyée (.DOM) pour rester cohérent avec le render initial
3879      // (cf. CreateElementDOM : thisDOM[typeElementKey]['children'] = children.DOM)
3880      if (ADD_NEW) {
3881        element[name] = new _DOM_js__WEBPACK_IMPORTED_MODULE_0__["default"](value, elementDOM).DOM;
3882      }
3883
3884      break;
3885
3886    case TYPE_ELEMENT:
3887      // Suppression de l'ancien élément
3888
3889      if (REMOVE_OLD) {
3890        // Suppression Ancienne éléments
3891        deleteChildElement(name, thisElement);
3892        delete element[name];
3893      }
3894
3895      // Création du nouvelle élément
3896      if (ADD_NEW) {
3897        let DOMJSON = {};
3898        DOMJSON[name] = value;
3899        const newElement = new _DOM_js__WEBPACK_IMPORTED_MODULE_0__["default"](DOMJSON, elementDOM);
3900        element[name] = newElement.DOM[name];
3901      }
3902
3903      break;
3904    case TYPE_COMPONENT:
3905
3906      if(name === 'states') {
3907        if(element.hasOwnProperty('DOM')) {
3908          elementDOM.setProps(value);
3909        } else {
3910          element.setProps(value);
3911        }
3912
3913      } else {
3914        if (REMOVE_OLD) {
3915          deleteChildElement(name, thisElement);
3916          delete element[name];
3917        }
3918        // Création du nouvelle élément
3919        if (ADD_NEW) {
3920          let component = null;
3921
3922          if (lastPathCurrentRight.hasOwnProperty(name)) {
3923            component = lastPathCurrentRight[name];
3924          }
3925          let DOMJSON = {};
3926          DOMJSON[name] = component;
3927          element[name] = new _DOM_js__WEBPACK_IMPORTED_MODULE_0__["default"](DOMJSON, elementDOM, null, name);
3928        }
3929      }
3930
3931
3932      break;
3933    case TYPE_ATTRIBUTE:
3934      switch (name) {
3935        case 'children':
3936          break;
3937        default:
3938          switch (name) {
3939            case 'class': {
3940              const removeTokens = toClassTokens(oldValue);
3941              const addTokens = toClassTokens(value);
3942              if (REMOVE_OLD && removeTokens.length) {
3943                elementDOM.classList.remove(...removeTokens);
3944              }
3945              if (ADD_NEW && addTokens.length) {
3946                elementDOM.classList.add(...addTokens);
3947              }
3948              break;
3949            }
3950            case 'textContent':
3951              if (REMOVE_OLD) {
3952                elementDOM.textContent = '';
3953              }
3954              if (ADD_NEW) {
3955                elementDOM.textContent = value;
3956              }
3957              break;
3958            case 'innerHTML':
3959              if (REMOVE_OLD) {
3960                elementDOM.innerHTML = '';
3961              }
3962              if (ADD_NEW) {
3963                elementDOM.innerHTML = value;
3964              }
3965              break;
3966            default:
3967              if (REMOVE_OLD) {
3968                elementDOM.removeAttribute(name);
3969              }
3970              if (ADD_NEW) {
3971                elementDOM.setAttribute(name, value);
3972              }
3973              break;
3974          }
3975          break;
3976      }
3977      break;
3978    case TYPE_ATTRIBUTE_LIST:
3979      switch (name) {
3980        case 'class': {
3981          const removeTokens = toClassTokens(oldValue);
3982          const addTokens = toClassTokens(value);
3983          if (REMOVE_OLD && removeTokens.length) {
3984            elementDOM.classList.remove(...removeTokens);
3985          }
3986          if (ADD_NEW && addTokens.length) {
3987            elementDOM.classList.add(...addTokens);
3988          }
3989          break;
3990        }
3991        default:
3992          break;
3993      }
3994      break;
3995  }
3996
3997  return element;
3998}
3999
4000
4001function recursiveUpdateValuePath(contextTemplate, template, currentDOM, paths, right_value, left_value, typeIndex, typeDiff, parentElement = null, lastKey = null) {
4002
4003  let last = paths.length === 1;
4004  const currentPath = paths.slice();
4005  const keypath = currentPath.shift();
4006
4007  switch (true) {
4008    case keypath === 'class':
4009    case typeIndex === TYPE_COMPONENT && contextTemplate.hasOwnProperty('states'):
4010      last = true;
4011      break;
4012  }
4013  let DOM = (0,_Helper_Object_js__WEBPACK_IMPORTED_MODULE_1__.cloneObject)(currentDOM);
4014
4015  let currentContextTemplate = (0,_Helper_Object_js__WEBPACK_IMPORTED_MODULE_1__.cloneObject)(contextTemplate);
4016  let currentTemplate = (0,_Helper_Object_js__WEBPACK_IMPORTED_MODULE_1__.cloneObject)(template);
4017  const currentParentElement = DOM.hasOwnProperty('DOM') ? DOM.DOM : parentElement;
4018
4019
4020  const keyTypeElement = currentTemplate[keypath] !== "undefined" && typeof currentTemplate[keypath] === "object" && currentTemplate[keypath].hasOwnProperty('Component') ? 'Component' : keypath;
4021  typeIndex = incrementType(typeIndex, keyTypeElement);
4022
4023
4024  // L'élement n'existe pas encore dans la template
4025  if (currentContextTemplate[keypath] === undefined && currentTemplate[keypath] === undefined) {
4026    if (typeDiff === js_struct_compare__WEBPACK_IMPORTED_MODULE_3__.Difference.TYPE_DELETED) {
4027      return {
4028        DOM,
4029        'contextTemplate': currentContextTemplate,
4030        'template': currentTemplate
4031      };
4032    } else {
4033      right_value = keypath === 'children' ? getAssignKeyTemplate([right_value], true) : right_value;
4034      DOM = updateValueInDOM(left_value, right_value, typeDiff, keypath, typeIndex, DOM, parentElement, currentTemplate, lastKey);
4035      currentTemplate[keypath] = right_value;
4036    }
4037  } else {
4038
4039
4040    if (last) {
4041
4042      switch (true) {
4043        case keypath === 'states':
4044          DOM = updateValueInDOM(currentContextTemplate[keypath], currentTemplate[keypath], typeDiff, keypath, typeIndex, DOM, parentElement, currentTemplate, lastKey);
4045          currentContextTemplate[keypath] = currentTemplate[keypath];
4046          break;
4047        case typeDiff === js_struct_compare__WEBPACK_IMPORTED_MODULE_3__.Difference.TYPE_DELETED:
4048          DOM = updateValueInDOM(left_value, right_value, typeDiff, keypath, typeIndex, DOM, parentElement, currentTemplate, lastKey);
4049          switch (keypath) {
4050            case 'class':
4051              const keyclass = currentPath.shift();
4052              if (currentContextTemplate.hasOwnProperty(keypath)) {
4053                if (typeof currentContextTemplate[keypath] === 'string') {
4054                  currentContextTemplate[keypath] = currentContextTemplate[keypath].replace(left_value, '');
4055                }
4056                if (Array.isArray(currentContextTemplate[keypath])) {
4057                  currentContextTemplate[keypath].hasOwnProperty(keyclass) ? delete currentContextTemplate[keypath][keyclass] : '';
4058                }
4059              }
4060
4061              break;
4062            default:
4063              delete currentContextTemplate[keypath];
4064              break;
4065          }
4066          break;
4067        default:
4068          DOM = updateValueInDOM(left_value, right_value, typeDiff, keypath, typeIndex, DOM, parentElement, currentTemplate, lastKey);
4069          currentContextTemplate[keypath] = right_value;
4070          break;
4071      }
4072
4073
4074    } else {
4075
4076      switch (true) {
4077        case DOM.hasOwnProperty(keypath):
4078          currentDOM = DOM[keypath];
4079          break;
4080        case keypath === "Component" && currentDOM.hasOwnProperty('DOM'):
4081          //currentDOM = currentParentElement;
4082          for(const componentKey in currentDOM.DOM) {
4083            currentDOM = currentDOM.DOM[componentKey];
4084          }
4085
4086          break;
4087      }
4088
4089      const dataChild = recursiveUpdateValuePath(currentContextTemplate[keypath], currentTemplate[keypath], currentDOM, currentPath, right_value, left_value, typeIndex, typeDiff, currentParentElement, keypath);
4090      DOM[keypath] = dataChild.DOM;
4091      currentContextTemplate[keypath] = dataChild.contextTemplate;
4092      currentTemplate[keypath] = dataChild.template;
4093
4094    }
4095
4096  }
4097
4098  return {
4099    DOM,
4100    'contextTemplate': currentContextTemplate,
4101    'template': currentTemplate
4102  }
4103
4104}
4105
4106function updateValue(context, paths, right_value, left_value, typeDiff, template) {
4107
4108  const data = recursiveUpdateValuePath(context.template, template, context.DOMElement.DOM, paths, right_value, left_value, TYPE_NODELIST, typeDiff, context.parentNode);
4109
4110  context.template = data.contextTemplate;
4111  context.DOMElement.DOM = data.DOM;
4112
4113  return context;
4114}
4115
4116/**
4117 *
4118 * @param DOM
4119 */
4120function deleteRecursiveDOM(DOM) {
4121  for (const index in DOM) {
4122    const element = DOM[index];
4123    if (element === null || typeof element !== 'object') {
4124      continue;
4125    }
4126
4127    // Composant enfant : on délègue à son propre cycle de destruction
4128    // (qui retire ses écouteurs et détruit ses propres enfants).
4129    if (element instanceof _Component_js__WEBPACK_IMPORTED_MODULE_4__["default"]) {
4130      element.destroy();
4131      continue;
4132    }
4133
4134    for (let name in element) {
4135      const node = element[name];
4136      if (node === null || typeof node !== 'object') {
4137        continue;
4138      }
4139      if (node instanceof _Component_js__WEBPACK_IMPORTED_MODULE_4__["default"]) {
4140        node.destroy();
4141        continue;
4142      }
4143      // Descente récursive pour détruire d'éventuels composants imbriqués
4144      // avant de retirer le nœud parent.
4145      if (node.children) {
4146        deleteRecursiveDOM(node.children);
4147      }
4148      if (node.hasOwnProperty('DOM') && node.DOM && typeof node.DOM.remove === 'function') {
4149        node.DOM.remove();
4150      }
4151    }
4152  }
4153}
4154
4155DOMModule.prototype.deleteDOM = function () {
4156  if (this.DOMElement.DOM !== null) {
4157    this.DOMElement.removeEvent();
4158    deleteRecursiveDOM(this.DOMElement.DOM);
4159  }
4160};
4161
4162/* harmony default export */ __webpack_exports__["default"] = (DOMModule);
4163
4164
4165
4166/***/ }),
4167
vendor: 8,764 bytes, lines 4168-4416
4168/***/ "./node_modules/beekube-dom/DOM.js":
4169/*!*****************************************!*\
4170  !*** ./node_modules/beekube-dom/DOM.js ***!
4171  \*****************************************/
4172/***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
4173
4174/* harmony import */ var _Helper_String_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Helper/String.js */ "./node_modules/beekube-dom/Helper/String.js");
4175
4176
4177/**
4178 * Créer un élement DOM en JSON
4179 * Et créer les évenements si nécessaire
4180 * @param dataJson object
4181 * @param parentElement element
4182 * @constructor
4183 *
4184 * * Voici un exemple de template :
4185 * [{
4186        'p': {
4187            'textContent': 'Remplir le formulaire ci-dessous'
4188        },
4189    }, {
4190        'div': {
4191            'children': [
4192                {
4193                    "label": {
4194                        "textContent": "Nom"
4195                    },
4196                    "input": {
4197                        "type": "text",
4198                        "value": "",
4199                        "change": {
4200                            'listener': this.onChange,
4201                            'useCapture': false
4202                        },
4203                        "keyup": this.onChange
4204                    }
4205                }
4206            ]
4207        }
4208        }]
4209 *
4210 */
4211function CreateElementDOM(dataJson, parentElement, type, indexInsert) {
4212    parentElement = typeof parentElement === "undefined" ? null : parentElement;
4213    type = typeof type === "undefined" ? null : type;
4214    indexInsert = typeof indexInsert === "undefined" ? null : indexInsert;
4215
4216    this.event = [];
4217    this.DOM = {};
4218
4219    let _this = this;
4220
4221    for(const key in dataJson) {
4222        let element = dataJson[key];
4223        let thisDOM = {};
4224
4225        if (typeof element === "function") {
4226            _this.DOM[key] = new element(parentElement, indexInsert);
4227            return true;
4228        }
4229
4230        for (let typeElementKey in element) {
4231            if (element.hasOwnProperty(typeElementKey)) {
4232                let thisType = 'html';
4233                let elemJSON = element[typeElementKey];
4234
4235                const typeElement = !elemJSON.hasOwnProperty('typeElement') ? typeElementKey : elemJSON.typeElement;
4236
4237                if (typeElement === "Component") {
4238                    if (elemJSON.hasOwnProperty('function')) {
4239                        if(elemJSON.hasOwnProperty('states')) {
4240                            _this.DOM[key] = new elemJSON.function(elemJSON.states, parentElement, indexInsert);
4241                        } else {
4242                            _this.DOM[key] = new elemJSON.function(parentElement, indexInsert);
4243                        }
4244
4245                    }
4246                    continue;
4247                }
4248
4249                if (type === 'svg') {
4250                    thisType = type
4251                } else {
4252                    if (typeElement === 'svg') {
4253                        thisType = typeElement;
4254                    } else {
4255                        thisType = 'html';
4256                    }
4257                }
4258                let elem;
4259                if (thisType === 'svg') {
4260                    elem = document.createElementNS("http://www.w3.org/2000/svg", typeElement);
4261                } else {
4262                    elem = document.createElement(typeElement);
4263                }
4264
4265
4266                thisDOM[typeElementKey] = {
4267                    'DOM': elem
4268                };
4269
4270
4271                for (let attribute in elemJSON) {
4272                    if (elemJSON.hasOwnProperty(attribute)) {
4273                        switch (attribute) {
4274                            case 'children':
4275                                let children = new CreateElementDOM(elemJSON[attribute], elem, thisType);
4276                                // concat() retourne un NOUVEAU tableau : il faut réassigner,
4277                                // sinon les écouteurs des enfants ne sont jamais collectés (fuite).
4278                                _this.event = _this.event.concat(children.event);
4279                                thisDOM[typeElementKey]['children'] = children.DOM;
4280                                break;
4281                            case 'textContent':
4282                                elem.textContent = (0,_Helper_String_js__WEBPACK_IMPORTED_MODULE_0__.getContentVariable)(elemJSON[attribute]);
4283                                break;
4284                            case 'innerHTML':
4285                                elem.innerHTML = elemJSON[attribute];
4286                                break;
4287                            case 'class':
4288                                let classes = [];
4289                                if (typeof elemJSON[attribute] === "object") {
4290                                    classes = elemJSON[attribute]
4291                                } else {
4292                                    classes = elemJSON[attribute].split(' ');
4293                                }
4294
4295                                for (let thisClass in classes) {
4296                                    if (classes[thisClass]) {
4297                                        elem.classList.add(classes[thisClass]);
4298                                    }
4299                                }
4300
4301                                break;
4302                            default:
4303                                // Réassignation indispensable (concat ne mute pas) pour
4304                                // pouvoir retirer ces écouteurs via removeEvent().
4305                                _this.event = _this.event.concat(
4306                                  setAttribute(elem, attribute, elemJSON[attribute])
4307                                );
4308                                break;
4309                        }
4310                    }
4311                }
4312
4313                if (parentElement) {
4314                    if (indexInsert === null || !parentElement.children.hasOwnProperty(indexInsert)) {
4315                        parentElement.appendChild(elem);
4316                    } else {
4317                        parentElement.insertBefore(elem, parentElement.children[indexInsert]);
4318                    }
4319                }
4320
4321                _this.DOM[key] = thisDOM;
4322            }
4323        }
4324    }
4325}
4326
4327CreateElementDOM.prototype.removeEvent = function () {
4328    this.event.forEach(function (event) {
4329        let element = event.element;
4330        if (element.removeEventListener) {
4331            element.removeEventListener(event.type, event.listener, event.options);
4332        }
4333    });
4334};
4335
4336const regexAttributeNamespace = /([^:]*):([^:]*)/;
4337
4338const namespaceLink = {
4339    'xlink' : "http://www.w3.org/1999/xlink"
4340}
4341function nameSpaceXmlLink(namespace) {
4342    if(namespaceLink.hasOwnProperty(namespace)) {
4343        return namespaceLink[namespace];
4344    } else {
4345        return namespace;
4346    }
4347}
4348/**
4349 * SetAttribute element and return event
4350 * @param element
4351 * @param attributeName
4352 * @param attributeValue
4353 * @returns {Array}
4354 */
4355function setAttribute(element, attributeName, attributeValue) {
4356
4357    let event = [];
4358
4359    switch (typeof attributeValue) {
4360
4361        case 'string':
4362        case 'number':
4363            let withNamespace = regexAttributeNamespace.exec(attributeName);
4364            if(withNamespace) {
4365                element.setAttributeNS(nameSpaceXmlLink(withNamespace[1]),  withNamespace[2], attributeValue);
4366            } else {
4367                element.setAttribute(attributeName, attributeValue);
4368            }
4369
4370            break;
4371
4372        case 'function':
4373            element.addEventListener(attributeName, attributeValue, false);
4374            // On enregistre aussi les écouteurs passés sous forme de fonction,
4375            // sinon removeEvent() ne peut pas les retirer (fuite mémoire).
4376            event.push({
4377                'element': element,
4378                'type': attributeName,
4379                'listener': attributeValue,
4380                'options': false
4381            });
4382            break;
4383
4384        case 'object':
4385            let listener = attributeValue.hasOwnProperty('listener') ? attributeValue.listener : function () {
4386            };
4387            let useCapture = attributeValue.hasOwnProperty('useCapture') ? attributeValue.useCapture : null;
4388            let options = false;
4389
4390            if (useCapture === null) {
4391                options = attributeValue.hasOwnProperty('options') ? attributeValue.options : false;
4392            }
4393
4394            element.addEventListener(attributeName, listener, options);
4395
4396            event.push({
4397                'element': element,
4398                'type': attributeName,
4399                'listener': listener,
4400                'options': options
4401            });
4402
4403            break;
4404
4405        default:
4406            break;
4407    }
4408
4409    return event;
4410}
4411
4412/* harmony default export */ __webpack_exports__["default"] = (CreateElementDOM);
4413
4414
4415/***/ }),
4416
vendor: 6,216 bytes, lines 4417-4630
4417/***/ "./node_modules/beekube-dom/Helper/Event.js":
4418/*!**************************************************!*\
4419  !*** ./node_modules/beekube-dom/Helper/Event.js ***!
4420  \**************************************************/
4421/***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
4422
4423/* harmony export */ __webpack_require__.d(__webpack_exports__, {
4424/* harmony export */   EventOn: function() { return /* binding */ EventOn; },
4425/* harmony export */   defaultEventOptions: function() { return /* binding */ defaultEventOptions; }
4426/* harmony export */ });
4427/* unused harmony exports EventOff, EventFire, eventIsOnSelector */
4428/* harmony import */ var _Object_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Object.js */ "./node_modules/beekube-dom/Helper/Object.js");
4429// Gestionnaire d'evenement
4430
4431
4432const EVENT_ON = 1;
4433const EVENT_OFF = 0;
4434
4435
4436
4437function dispatchTypeEvent(status, eventObject) {
4438    if (!eventObject.element || typeof eventObject.element.addEventListener !== 'function') {
4439        return;
4440    }
4441    switch (status) {
4442        case EVENT_ON:
4443            eventObject.element.addEventListener(eventObject.type, eventObject.listener, eventObject.options);
4444            break;
4445        case EVENT_OFF:
4446            eventObject.element.removeEventListener(eventObject.type, eventObject.listener, eventObject.options);
4447            break;
4448    }
4449}
4450
4451/**
4452 * @param status
4453 * @param eventObject object
4454 * @returns {*}
4455 *
4456 *
4457 */
4458function configureEvent(status, eventObject) {
4459
4460    eventObject = Object.assign({}, defaultEventOptions, eventObject);
4461
4462    if (eventObject.element === null) {
4463        return false;
4464    }
4465
4466    switch(true) {
4467
4468        case eventObject.element instanceof eventObject.context.NodeList:
4469        case eventObject.element instanceof Array:
4470
4471            let elements = Array.from(eventObject.element);
4472            elements.forEach(function (element) {
4473                let eventObjectClone = {
4474                    'element': element,
4475                    'type': eventObject.type,
4476                    'listener': eventObject.listener,
4477                    'options': eventObject.options,
4478                };
4479
4480                dispatchTypeEvent(status, eventObjectClone);
4481            });
4482
4483            break;
4484        case eventObject.element instanceof eventObject.context.Element:
4485            dispatchTypeEvent(status, eventObject);
4486            break;
4487        default:
4488            dispatchTypeEvent(status, eventObject);
4489            break;
4490    }
4491
4492
4493
4494    return true;
4495}
4496
4497
4498const matchEventType = {
4499    'FocusEvent': ['focus', 'blur', 'focusin', 'focusout'],
4500    'MouseEvent': ['click', 'dblclick', 'mouseup', 'mousedown'],
4501    'TouchEvent': ['touchstart', 'touchend', 'touchmove', 'touchcancel'],
4502    'KeyboardEvent': ['keydown', 'keypress', 'keyup'],
4503};
4504
4505const matchEventObject = {
4506    'FocusEvent': typeof FocusEvent === "undefined" ? Event : FocusEvent,
4507    'MouseEvent':  typeof MouseEvent === "undefined" ? Event : MouseEvent,
4508    'TouchEvent':  typeof TouchEvent === "undefined" ? Event : TouchEvent,
4509    'KeyboardEvent': typeof KeyboardEvent === "undefined" ? Event : KeyboardEvent,
4510}
4511
4512function getEventObject(eventName) {
4513    for( let event in matchEventType ) {
4514
4515        if(matchEventType[event].indexOf(eventName) !== -1) {
4516            return matchEventObject[event];
4517        }
4518    }
4519    return Event;
4520}
4521
4522
4523/**
4524 * @param obj
4525 * @param evts
4526 * @param data
4527 * @param options
4528 * @returns {boolean}
4529 */
4530function fireEventElement(obj, evts, data = false, options = {"bubbles":true, "cancelable":true}) {
4531    var t, evt;
4532
4533    if (obj === null || typeof obj === "undefined") {
4534        return false;
4535    }
4536    // on verifie si il y a plusieurs élements
4537    evts = (evts || "").match(/\S+/g) || [""];
4538    // on les comptes
4539    t = evts.length;
4540    // On créé chaque évenement un par un
4541    while (t--) {
4542        evt = evts[t];
4543        if (typeof Event === 'function' || !document.fireEvent) {
4544            var eventClass = getEventObject(evt, options);
4545            var event = new eventClass(evt, options);
4546
4547            if(data) {
4548                Object.assign(event, data);
4549            }
4550
4551            obj.dispatchEvent(event);
4552        } else {
4553            obj.fireEvent('on' + evt);
4554        }
4555    }
4556}
4557
4558/**
4559 * @param objs
4560 * @param evts
4561 * @param data
4562 * @param options
4563 * @returns {boolean}
4564 */
4565function fireEvent(objs, evts, data = false, options = {"bubbles":true, "cancelable":true}) {
4566
4567
4568    if (objs === null || typeof objs === "undefined") {
4569        return false;
4570    }
4571
4572    objs = objs instanceof NodeList || (0,_Object_js__WEBPACK_IMPORTED_MODULE_0__.isNodeList)(objs) || Array.isArray(objs) ? Array.from(objs) : [objs];
4573    objs.forEach(obj => {
4574        fireEventElement(obj, evts, data, options);
4575    });
4576
4577    return true;
4578}
4579
4580//Returns true if it is a DOM element
4581function isElement(o) {
4582    // `o != null` est indispensable : `typeof null === "object"`, donc sans cette garde
4583    // l'accès à `o.nodeType` lèverait une TypeError sur une cible nulle.
4584    return (
4585        o != null && typeof o === "object" && o.nodeType === 1 && typeof o.nodeName === "string"
4586    );
4587}
4588
4589function eventIsOnSelector(event, selector) {
4590    if (!isElement(event.target)) {
4591        return false;
4592    }
4593    var DOM = event.target.matches(selector) ? event.target : event.target.closest(selector);
4594    if (DOM === null) {
4595        return false;
4596    }
4597
4598    return DOM;
4599}
4600
4601
4602
4603const EventOn = configureEvent.bind(null, EVENT_ON);
4604const EventOff = configureEvent.bind(null, EVENT_OFF);
4605const EventFire = fireEvent;
4606
4607const defaultEventOptions = {
4608    'element': null,
4609    'type': 'click',
4610    'listener': function () {},
4611    'options': false,
4612    // Garde : éviter une ReferenceError au chargement du module en environnement sans `window`
4613    // (Node/SSR). Les fonctions d'événements ne sont de toute façon utiles que côté navigateur.
4614    'context': typeof window !== 'undefined' ? window : undefined
4615};
4616
4617const HelperEvent = {
4618    on: EventOn,
4619    off: EventOff,
4620    fire: EventFire,
4621    eventIsOnSelector: eventIsOnSelector,
4622    defaultEventOptions: defaultEventOptions
4623};
4624
4625
4626/* unused harmony default export */ var __WEBPACK_DEFAULT_EXPORT__ = (HelperEvent);
4627
4628
4629/***/ }),
4630
vendor: 2,555 bytes, lines 4631-4701
4631/***/ "./node_modules/beekube-dom/Helper/Object.js":
4632/*!***************************************************!*\
4633  !*** ./node_modules/beekube-dom/Helper/Object.js ***!
4634  \***************************************************/
4635/***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
4636
4637/* harmony export */ __webpack_require__.d(__webpack_exports__, {
4638/* harmony export */   cloneObject: function() { return /* binding */ cloneObject; },
4639/* harmony export */   isNodeList: function() { return /* binding */ isNodeList; }
4640/* harmony export */ });
4641/* unused harmony export isObject */
4642/* harmony import */ var _BaseApp_Component_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../BaseApp/Component.js */ "./node_modules/beekube-dom/BaseApp/Component.js");
4643
4644
4645function isObject(obj) {
4646    let type = typeof obj;
4647    return type === 'object' && !!obj;
4648}
4649
4650// Détecte un élément DOM sans référencer un global `window` non garanti (SSR / tests Node).
4651function isDomElement(o) {
4652    if (o === null || typeof o !== 'object') return false;
4653    if (typeof Element !== 'undefined' && o instanceof Element) return true;
4654    const doc = o.ownerDocument;
4655    if (doc && doc.defaultView && o instanceof doc.defaultView.Element) return true;
4656    return false;
4657}
4658
4659function cloneObject(src) {
4660    // Fonctions : retournées telles quelles
4661    if (typeof src === "function") return src;
4662
4663    // null / primitives : rien à cloner.
4664    // Garde indispensable : sans elle, `null.ownerDocument` lève TypeError, ce qui
4665    // fait planter tout cycle de diff de liste (chemins ADDED/DELETED asymétriques).
4666    if (src === null || typeof src !== "object") return src;
4667
4668    // Éléments DOM et composants : on conserve la référence (pas de clone profond)
4669    if (isDomElement(src)) return src;
4670    if (src instanceof _BaseApp_Component_js__WEBPACK_IMPORTED_MODULE_0__["default"]) return src;
4671
4672    let target = Array.isArray(src) ? [] : {};
4673
4674    for (let prop in src) {
4675        if (src.hasOwnProperty(prop)) {
4676            // if the value is a nested object, recursively copy all it's properties
4677            if (isObject(src[prop])) {
4678                target[prop] = cloneObject(src[prop]);
4679            } else {
4680                target[prop] = src[prop];
4681            }
4682        }
4683    }
4684
4685    return target;
4686}
4687
4688function isNodeList(el) {
4689    return el != null
4690      && typeof el.length == 'number'
4691      && typeof el.item == 'function'
4692      && typeof el.nextNode == 'function'
4693      && typeof el.reset == 'function';
4694}
4695
4696
4697
4698
4699
4700/***/ }),
4701
vendor: 790 bytes, lines 4702-4728
4702/***/ "./node_modules/beekube-dom/Helper/String.js":
4703/*!***************************************************!*\
4704  !*** ./node_modules/beekube-dom/Helper/String.js ***!
4705  \***************************************************/
4706/***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
4707
4708/* harmony export */ __webpack_require__.d(__webpack_exports__, {
4709/* harmony export */   getContentVariable: function() { return /* binding */ getContentVariable; }
4710/* harmony export */ });
4711
4712function getContentVariable(element) {
4713    let content = '';
4714    switch (typeof element) {
4715        case 'function':
4716            content = element();
4717            break;
4718        default :
4719            content = element;
4720            break;
4721    }
4722    return content;
4723}
4724
4725
4726
4727/***/ }),
4728
vendor: 4,606 bytes, lines 4729-4861
4729/***/ "./node_modules/js-struct-compare/src/Comparator.mjs":
4730/*!***********************************************************!*\
4731  !*** ./node_modules/js-struct-compare/src/Comparator.mjs ***!
4732  \***********************************************************/
4733/***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
4734
4735/* harmony export */ __webpack_require__.d(__webpack_exports__, {
4736/* harmony export */   "default": function() { return /* binding */ Comparator; }
4737/* harmony export */ });
4738/* harmony import */ var _Difference_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Difference.mjs */ "./node_modules/js-struct-compare/src/Difference.mjs");
4739/* harmony import */ var _utils_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils.mjs */ "./node_modules/js-struct-compare/src/utils.mjs");
4740
4741
4742
4743/**
4744 * Compares two (JSON-serializable) structures and returns their differences.
4745 * @constructor
4746 */
4747function Comparator() {
4748}
4749
4750/**
4751 * Compares two structures and returns an array of their differences.
4752 *
4753 * @param {*} left
4754 * @param {*} right
4755 * @return {Difference[]}
4756 */
4757Comparator.prototype.compare = function (left, right) {
4758	return this.compare_values(left, right, []);
4759};
4760
4761/**
4762 * Compares two values at the same path.
4763 *
4764 * @param {*} left
4765 * @param {*} right
4766 * @param {Array} path
4767 * @return {Difference[]}
4768 * @private
4769 */
4770Comparator.prototype.compare_values = function (left, right, path) {
4771	let left_is_array, right_is_array, left_is_object, right_is_object;
4772
4773	left_is_array = Array.isArray(left);
4774	right_is_array = Array.isArray(right);
4775	left_is_object = left_is_array === false && (0,_utils_mjs__WEBPACK_IMPORTED_MODULE_1__.is_object)(left);
4776	right_is_object = right_is_array === false && (0,_utils_mjs__WEBPACK_IMPORTED_MODULE_1__.is_object)(right);
4777
4778	if (left_is_array && right_is_array) {
4779		return this.compare_arrays(left, right, path);
4780	} else if (left_is_object && right_is_object) {
4781		return this.compare_objects(left, right, path);
4782	}
4783
4784	if (left !== right) {
4785		return [ new _Difference_mjs__WEBPACK_IMPORTED_MODULE_0__["default"](path, _Difference_mjs__WEBPACK_IMPORTED_MODULE_0__["default"].TYPE_CHANGED, left, right) ];
4786	} else {
4787		return [];
4788	}
4789};
4790
4791/**
4792 * Compares the elements in two objects at the same path.
4793 *
4794 * @param {Object} left
4795 * @param {Object} right
4796 * @param {Array} path
4797 * @return {Difference[]}
4798 * @private
4799 */
4800Comparator.prototype.compare_objects = function (left, right, path) {
4801	let self = this, differences = [];
4802
4803	for (let left_key in left) {
4804		if (left.hasOwnProperty(left_key)) {
4805			const element_path = path.concat(left_key);
4806			const left_value = left[left_key];
4807			if (typeof right[left_key] === "undefined") {
4808				differences.push(new _Difference_mjs__WEBPACK_IMPORTED_MODULE_0__["default"](element_path, _Difference_mjs__WEBPACK_IMPORTED_MODULE_0__["default"].TYPE_DELETED, left_value, undefined));
4809			} else {
4810				differences = differences.concat(self.compare_values(left_value, right[left_key], element_path));
4811			}
4812		}
4813	}
4814
4815	for (let right_key in right) {
4816		if (right.hasOwnProperty(right_key)) {
4817			const element_path = path.concat(right_key);
4818			const right_value = right[right_key];
4819			if (typeof left[right_key] === "undefined") {
4820				differences.push(new _Difference_mjs__WEBPACK_IMPORTED_MODULE_0__["default"](element_path, _Difference_mjs__WEBPACK_IMPORTED_MODULE_0__["default"].TYPE_ADDED, undefined, right_value));
4821			}
4822		}
4823	}
4824
4825	return differences;
4826};
4827
4828/**
4829 * Compares the elements in two arrays at the same path.
4830 *
4831 * @param {Array} left
4832 * @param {Array} right
4833 * @param {Array} path
4834 * @return {Difference[]}
4835 * @private
4836 */
4837Comparator.prototype.compare_arrays = function (left, right, path) {
4838	let self = this, differences = [];
4839
4840	left.forEach(function (left_value, left_index) {
4841		const element_path = path.concat(left_index);
4842		if (typeof right[left_index] === "undefined") {
4843			differences.push(new _Difference_mjs__WEBPACK_IMPORTED_MODULE_0__["default"](element_path, _Difference_mjs__WEBPACK_IMPORTED_MODULE_0__["default"].TYPE_DELETED, left_value, undefined));
4844		} else {
4845			differences = differences.concat(self.compare_values(left_value, right[left_index], element_path));
4846		}
4847	});
4848
4849	right.forEach(function (right_value, right_index) {
4850		const element_path = path.concat(right_index);
4851		if (typeof left[right_index] === "undefined") {
4852			differences.push(new _Difference_mjs__WEBPACK_IMPORTED_MODULE_0__["default"](element_path, _Difference_mjs__WEBPACK_IMPORTED_MODULE_0__["default"].TYPE_ADDED, undefined, right_value));
4853		}
4854	});
4855
4856	return differences;
4857};
4858
4859
4860/***/ }),
4861
vendor: 2,151 bytes, lines 4862-4948
4862/***/ "./node_modules/js-struct-compare/src/Difference.mjs":
4863/*!***********************************************************!*\
4864  !*** ./node_modules/js-struct-compare/src/Difference.mjs ***!
4865  \***********************************************************/
4866/***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
4867
4868/* harmony export */ __webpack_require__.d(__webpack_exports__, {
4869/* harmony export */   "default": function() { return /* binding */ Difference; }
4870/* harmony export */ });
4871/**
4872 * @param {Array} path
4873 * @param {String} type
4874 * @param {*} left_value
4875 * @param {*} right_value
4876 * @constructor
4877 */
4878function Difference(path, type, left_value, right_value) {
4879	/** @private */
4880	this.path = path;
4881	/** @private */
4882	this.type = type;
4883	/** @private */
4884	this.left_value = left_value;
4885	/** @private */
4886	this.right_value = right_value;
4887}
4888
4889/**
4890 * Indicates that the element was added in the transition from 'left' to 'right' structure
4891 * @const {String}
4892 */
4893Difference.TYPE_ADDED = "added";
4894
4895/**
4896 * Indicates that the element was deleted in the transition from 'left' to 'right' structure
4897 * @const {String}
4898 */
4899Difference.TYPE_DELETED = "deleted";
4900
4901/**
4902 * Indicates that the element was changed in the transition from 'left' to 'right' structure
4903 * @const {String}
4904 */
4905Difference.TYPE_CHANGED = "changed";
4906
4907/**
4908 * Returns the path to the element where the difference is located.
4909 *
4910 * @return {Array}
4911 */
4912Difference.prototype.get_path = function () {
4913	return this.path;
4914};
4915
4916/**
4917 * Returns the type of difference. Should be one of the Difference.TYPE_*
4918 * constants.
4919 *
4920 * @return {String}
4921 */
4922Difference.prototype.get_type = function () {
4923	return this.type;
4924};
4925
4926/**
4927 * Returns the value of the element in the 'left' structure, or undefined if the
4928 * element is missing there.
4929 *
4930 * @return {*}
4931 */
4932Difference.prototype.get_left_value = function () {
4933	return this.left_value;
4934};
4935
4936/**
4937 * Returns the value of the element in the 'left' structure, or undefined if the
4938 * element is missing there.
4939 *
4940 * @return {*}
4941 */
4942Difference.prototype.get_right_value = function () {
4943	return this.right_value;
4944};
4945
4946
4947/***/ }),
4948
vendor: 1,003 bytes, lines 4949-4976
4949/***/ "./node_modules/js-struct-compare/src/compare.mjs":
4950/*!********************************************************!*\
4951  !*** ./node_modules/js-struct-compare/src/compare.mjs ***!
4952  \********************************************************/
4953/***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
4954
4955/* harmony export */ __webpack_require__.d(__webpack_exports__, {
4956/* harmony export */   "default": function() { return /* binding */ compare; }
4957/* harmony export */ });
4958/* harmony import */ var _Comparator_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Comparator.mjs */ "./node_modules/js-struct-compare/src/Comparator.mjs");
4959
4960
4961const comparator = new _Comparator_mjs__WEBPACK_IMPORTED_MODULE_0__["default"]();
4962
4963/**
4964 * Compares two structures and returns an array of their differences.
4965 *
4966 * @param {*} left
4967 * @param {*} right
4968 * @return {Difference[]}
4969 */
4970function compare(left, right) {
4971	return comparator.compare(left, right);
4972};
4973
4974
4975/***/ }),
4976
vendor: 1,212 bytes, lines 4977-4996
4977/***/ "./node_modules/js-struct-compare/src/index.mjs":
4978/*!******************************************************!*\
4979  !*** ./node_modules/js-struct-compare/src/index.mjs ***!
4980  \******************************************************/
4981/***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
4982
4983/* harmony export */ __webpack_require__.d(__webpack_exports__, {
4984/* harmony export */   Difference: function() { return /* reexport safe */ _Difference_mjs__WEBPACK_IMPORTED_MODULE_0__["default"]; },
4985/* harmony export */   "default": function() { return /* reexport safe */ _compare_mjs__WEBPACK_IMPORTED_MODULE_2__["default"]; }
4986/* harmony export */ });
4987/* harmony import */ var _Difference_mjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Difference.mjs */ "./node_modules/js-struct-compare/src/Difference.mjs");
4988/* harmony import */ var _Comparator_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Comparator.mjs */ "./node_modules/js-struct-compare/src/Comparator.mjs");
4989/* harmony import */ var _compare_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./compare.mjs */ "./node_modules/js-struct-compare/src/compare.mjs");
4990
4991
4992
4993
4994
4995/***/ }),
4996
vendor: 575 bytes, lines 4997-5012
4997/***/ "./node_modules/js-struct-compare/src/utils.mjs":
4998/*!******************************************************!*\
4999  !*** ./node_modules/js-struct-compare/src/utils.mjs ***!
5000  \******************************************************/
5001/***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
5002
5003/* harmony export */ __webpack_require__.d(__webpack_exports__, {
5004/* harmony export */   is_object: function() { return /* binding */ is_object; }
5005/* harmony export */ });
5006function is_object(obj) {
5007	return obj === Object(obj);
5008}
5009
5010
5011/***/ }),
5012
vendor: 23,853 bytes, lines 5013-5785
5013/***/ "./node_modules/mustache/mustache.mjs":
5014/*!********************************************!*\
5015  !*** ./node_modules/mustache/mustache.mjs ***!
5016  \********************************************/
5017/***/ (function(__unused_webpack___webpack_module__, __webpack_exports__) {
5018
5019/*!
5020 * mustache.js - Logic-less {{mustache}} templates with JavaScript
5021 * http://github.com/janl/mustache.js
5022 */
5023
5024var objectToString = Object.prototype.toString;
5025var isArray = Array.isArray || function isArrayPolyfill (object) {
5026  return objectToString.call(object) === '[object Array]';
5027};
5028
5029function isFunction (object) {
5030  return typeof object === 'function';
5031}
5032
5033/**
5034 * More correct typeof string handling array
5035 * which normally returns typeof 'object'
5036 */
5037function typeStr (obj) {
5038  return isArray(obj) ? 'array' : typeof obj;
5039}
5040
5041function escapeRegExp (string) {
5042  return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
5043}
5044
5045/**
5046 * Null safe way of checking whether or not an object,
5047 * including its prototype, has a given property
5048 */
5049function hasProperty (obj, propName) {
5050  return obj != null && typeof obj === 'object' && (propName in obj);
5051}
5052
5053/**
5054 * Safe way of detecting whether or not the given thing is a primitive and
5055 * whether it has the given property
5056 */
5057function primitiveHasOwnProperty (primitive, propName) {
5058  return (
5059    primitive != null
5060    && typeof primitive !== 'object'
5061    && primitive.hasOwnProperty
5062    && primitive.hasOwnProperty(propName)
5063  );
5064}
5065
5066// Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
5067// See https://github.com/janl/mustache.js/issues/189
5068var regExpTest = RegExp.prototype.test;
5069function testRegExp (re, string) {
5070  return regExpTest.call(re, string);
5071}
5072
5073var nonSpaceRe = /\S/;
5074function isWhitespace (string) {
5075  return !testRegExp(nonSpaceRe, string);
5076}
5077
5078var entityMap = {
5079  '&': '&amp;',
5080  '<': '&lt;',
5081  '>': '&gt;',
5082  '"': '&quot;',
5083  "'": '&#39;',
5084  '/': '&#x2F;',
5085  '`': '&#x60;',
5086  '=': '&#x3D;'
5087};
5088
5089function escapeHtml (string) {
5090  return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap (s) {
5091    return entityMap[s];
5092  });
5093}
5094
5095var whiteRe = /\s*/;
5096var spaceRe = /\s+/;
5097var equalsRe = /\s*=/;
5098var curlyRe = /\s*\}/;
5099var tagRe = /#|\^|\/|>|\{|&|=|!/;
5100
5101/**
5102 * Breaks up the given `template` string into a tree of tokens. If the `tags`
5103 * argument is given here it must be an array with two string values: the
5104 * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of
5105 * course, the default is to use mustaches (i.e. mustache.tags).
5106 *
5107 * A token is an array with at least 4 elements. The first element is the
5108 * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag
5109 * did not contain a symbol (i.e. {{myValue}}) this element is "name". For
5110 * all text that appears outside a symbol this element is "text".
5111 *
5112 * The second element of a token is its "value". For mustache tags this is
5113 * whatever else was inside the tag besides the opening symbol. For text tokens
5114 * this is the text itself.
5115 *
5116 * The third and fourth elements of the token are the start and end indices,
5117 * respectively, of the token in the original template.
5118 *
5119 * Tokens that are the root node of a subtree contain two more elements: 1) an
5120 * array of tokens in the subtree and 2) the index in the original template at
5121 * which the closing tag for that section begins.
5122 *
5123 * Tokens for partials also contain two more elements: 1) a string value of
5124 * indendation prior to that tag and 2) the index of that tag on that line -
5125 * eg a value of 2 indicates the partial is the third tag on this line.
5126 */
5127function parseTemplate (template, tags) {
5128  if (!template)
5129    return [];
5130  var lineHasNonSpace = false;
5131  var sections = [];     // Stack to hold section tokens
5132  var tokens = [];       // Buffer to hold the tokens
5133  var spaces = [];       // Indices of whitespace tokens on the current line
5134  var hasTag = false;    // Is there a {{tag}} on the current line?
5135  var nonSpace = false;  // Is there a non-space char on the current line?
5136  var indentation = '';  // Tracks indentation for tags that use it
5137  var tagIndex = 0;      // Stores a count of number of tags encountered on a line
5138
5139  // Strips all whitespace tokens array for the current line
5140  // if there was a {{#tag}} on it and otherwise only space.
5141  function stripSpace () {
5142    if (hasTag && !nonSpace) {
5143      while (spaces.length)
5144        delete tokens[spaces.pop()];
5145    } else {
5146      spaces = [];
5147    }
5148
5149    hasTag = false;
5150    nonSpace = false;
5151  }
5152
5153  var openingTagRe, closingTagRe, closingCurlyRe;
5154  function compileTags (tagsToCompile) {
5155    if (typeof tagsToCompile === 'string')
5156      tagsToCompile = tagsToCompile.split(spaceRe, 2);
5157
5158    if (!isArray(tagsToCompile) || tagsToCompile.length !== 2)
5159      throw new Error('Invalid tags: ' + tagsToCompile);
5160
5161    openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + '\\s*');
5162    closingTagRe = new RegExp('\\s*' + escapeRegExp(tagsToCompile[1]));
5163    closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tagsToCompile[1]));
5164  }
5165
5166  compileTags(tags || mustache.tags);
5167
5168  var scanner = new Scanner(template);
5169
5170  var start, type, value, chr, token, openSection;
5171  while (!scanner.eos()) {
5172    start = scanner.pos;
5173
5174    // Match any text between tags.
5175    value = scanner.scanUntil(openingTagRe);
5176
5177    if (value) {
5178      for (var i = 0, valueLength = value.length; i < valueLength; ++i) {
5179        chr = value.charAt(i);
5180
5181        if (isWhitespace(chr)) {
5182          spaces.push(tokens.length);
5183          indentation += chr;
5184        } else {
5185          nonSpace = true;
5186          lineHasNonSpace = true;
5187          indentation += ' ';
5188        }
5189
5190        tokens.push([ 'text', chr, start, start + 1 ]);
5191        start += 1;
5192
5193        // Check for whitespace on the current line.
5194        if (chr === '\n') {
5195          stripSpace();
5196          indentation = '';
5197          tagIndex = 0;
5198          lineHasNonSpace = false;
5199        }
5200      }
5201    }
5202
5203    // Match the opening tag.
5204    if (!scanner.scan(openingTagRe))
5205      break;
5206
5207    hasTag = true;
5208
5209    // Get the tag type.
5210    type = scanner.scan(tagRe) || 'name';
5211    scanner.scan(whiteRe);
5212
5213    // Get the tag value.
5214    if (type === '=') {
5215      value = scanner.scanUntil(equalsRe);
5216      scanner.scan(equalsRe);
5217      scanner.scanUntil(closingTagRe);
5218    } else if (type === '{') {
5219      value = scanner.scanUntil(closingCurlyRe);
5220      scanner.scan(curlyRe);
5221      scanner.scanUntil(closingTagRe);
5222      type = '&';
5223    } else {
5224      value = scanner.scanUntil(closingTagRe);
5225    }
5226
5227    // Match the closing tag.
5228    if (!scanner.scan(closingTagRe))
5229      throw new Error('Unclosed tag at ' + scanner.pos);
5230
5231    if (type == '>') {
5232      token = [ type, value, start, scanner.pos, indentation, tagIndex, lineHasNonSpace ];
5233    } else {
5234      token = [ type, value, start, scanner.pos ];
5235    }
5236    tagIndex++;
5237    tokens.push(token);
5238
5239    if (type === '#' || type === '^') {
5240      sections.push(token);
5241    } else if (type === '/') {
5242      // Check section nesting.
5243      openSection = sections.pop();
5244
5245      if (!openSection)
5246        throw new Error('Unopened section "' + value + '" at ' + start);
5247
5248      if (openSection[1] !== value)
5249        throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
5250    } else if (type === 'name' || type === '{' || type === '&') {
5251      nonSpace = true;
5252    } else if (type === '=') {
5253      // Set the tags for the next time around.
5254      compileTags(value);
5255    }
5256  }
5257
5258  stripSpace();
5259
5260  // Make sure there are no open sections when we're done.
5261  openSection = sections.pop();
5262
5263  if (openSection)
5264    throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
5265
5266  return nestTokens(squashTokens(tokens));
5267}
5268
5269/**
5270 * Combines the values of consecutive text tokens in the given `tokens` array
5271 * to a single token.
5272 */
5273function squashTokens (tokens) {
5274  var squashedTokens = [];
5275
5276  var token, lastToken;
5277  for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
5278    token = tokens[i];
5279
5280    if (token) {
5281      if (token[0] === 'text' && lastToken && lastToken[0] === 'text') {
5282        lastToken[1] += token[1];
5283        lastToken[3] = token[3];
5284      } else {
5285        squashedTokens.push(token);
5286        lastToken = token;
5287      }
5288    }
5289  }
5290
5291  return squashedTokens;
5292}
5293
5294/**
5295 * Forms the given array of `tokens` into a nested tree structure where
5296 * tokens that represent a section have two additional items: 1) an array of
5297 * all tokens that appear in that section and 2) the index in the original
5298 * template that represents the end of that section.
5299 */
5300function nestTokens (tokens) {
5301  var nestedTokens = [];
5302  var collector = nestedTokens;
5303  var sections = [];
5304
5305  var token, section;
5306  for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
5307    token = tokens[i];
5308
5309    switch (token[0]) {
5310      case '#':
5311      case '^':
5312        collector.push(token);
5313        sections.push(token);
5314        collector = token[4] = [];
5315        break;
5316      case '/':
5317        section = sections.pop();
5318        section[5] = token[2];
5319        collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
5320        break;
5321      default:
5322        collector.push(token);
5323    }
5324  }
5325
5326  return nestedTokens;
5327}
5328
5329/**
5330 * A simple string scanner that is used by the template parser to find
5331 * tokens in template strings.
5332 */
5333function Scanner (string) {
5334  this.string = string;
5335  this.tail = string;
5336  this.pos = 0;
5337}
5338
5339/**
5340 * Returns `true` if the tail is empty (end of string).
5341 */
5342Scanner.prototype.eos = function eos () {
5343  return this.tail === '';
5344};
5345
5346/**
5347 * Tries to match the given regular expression at the current position.
5348 * Returns the matched text if it can match, the empty string otherwise.
5349 */
5350Scanner.prototype.scan = function scan (re) {
5351  var match = this.tail.match(re);
5352
5353  if (!match || match.index !== 0)
5354    return '';
5355
5356  var string = match[0];
5357
5358  this.tail = this.tail.substring(string.length);
5359  this.pos += string.length;
5360
5361  return string;
5362};
5363
5364/**
5365 * Skips all text until the given regular expression can be matched. Returns
5366 * the skipped string, which is the entire tail if no match can be made.
5367 */
5368Scanner.prototype.scanUntil = function scanUntil (re) {
5369  var index = this.tail.search(re), match;
5370
5371  switch (index) {
5372    case -1:
5373      match = this.tail;
5374      this.tail = '';
5375      break;
5376    case 0:
5377      match = '';
5378      break;
5379    default:
5380      match = this.tail.substring(0, index);
5381      this.tail = this.tail.substring(index);
5382  }
5383
5384  this.pos += match.length;
5385
5386  return match;
5387};
5388
5389/**
5390 * Represents a rendering context by wrapping a view object and
5391 * maintaining a reference to the parent context.
5392 */
5393function Context (view, parentContext) {
5394  this.view = view;
5395  this.cache = { '.': this.view };
5396  this.parent = parentContext;
5397}
5398
5399/**
5400 * Creates a new context using the given view with this context
5401 * as the parent.
5402 */
5403Context.prototype.push = function push (view) {
5404  return new Context(view, this);
5405};
5406
5407/**
5408 * Returns the value of the given name in this context, traversing
5409 * up the context hierarchy if the value is absent in this context's view.
5410 */
5411Context.prototype.lookup = function lookup (name) {
5412  var cache = this.cache;
5413
5414  var value;
5415  if (cache.hasOwnProperty(name)) {
5416    value = cache[name];
5417  } else {
5418    var context = this, intermediateValue, names, index, lookupHit = false;
5419
5420    while (context) {
5421      if (name.indexOf('.') > 0) {
5422        intermediateValue = context.view;
5423        names = name.split('.');
5424        index = 0;
5425
5426        /**
5427         * Using the dot notion path in `name`, we descend through the
5428         * nested objects.
5429         *
5430         * To be certain that the lookup has been successful, we have to
5431         * check if the last object in the path actually has the property
5432         * we are looking for. We store the result in `lookupHit`.
5433         *
5434         * This is specially necessary for when the value has been set to
5435         * `undefined` and we want to avoid looking up parent contexts.
5436         *
5437         * In the case where dot notation is used, we consider the lookup
5438         * to be successful even if the last "object" in the path is
5439         * not actually an object but a primitive (e.g., a string, or an
5440         * integer), because it is sometimes useful to access a property
5441         * of an autoboxed primitive, such as the length of a string.
5442         **/
5443        while (intermediateValue != null && index < names.length) {
5444          if (index === names.length - 1)
5445            lookupHit = (
5446              hasProperty(intermediateValue, names[index])
5447              || primitiveHasOwnProperty(intermediateValue, names[index])
5448            );
5449
5450          intermediateValue = intermediateValue[names[index++]];
5451        }
5452      } else {
5453        intermediateValue = context.view[name];
5454
5455        /**
5456         * Only checking against `hasProperty`, which always returns `false` if
5457         * `context.view` is not an object. Deliberately omitting the check
5458         * against `primitiveHasOwnProperty` if dot notation is not used.
5459         *
5460         * Consider this example:
5461         * ```
5462         * Mustache.render("The length of a football field is {{#length}}{{length}}{{/length}}.", {length: "100 yards"})
5463         * ```
5464         *
5465         * If we were to check also against `primitiveHasOwnProperty`, as we do
5466         * in the dot notation case, then render call would return:
5467         *
5468         * "The length of a football field is 9."
5469         *
5470         * rather than the expected:
5471         *
5472         * "The length of a football field is 100 yards."
5473         **/
5474        lookupHit = hasProperty(context.view, name);
5475      }
5476
5477      if (lookupHit) {
5478        value = intermediateValue;
5479        break;
5480      }
5481
5482      context = context.parent;
5483    }
5484
5485    cache[name] = value;
5486  }
5487
5488  if (isFunction(value))
5489    value = value.call(this.view);
5490
5491  return value;
5492};
5493
5494/**
5495 * A Writer knows how to take a stream of tokens and render them to a
5496 * string, given a context. It also maintains a cache of templates to
5497 * avoid the need to parse the same template twice.
5498 */
5499function Writer () {
5500  this.templateCache = {
5501    _cache: {},
5502    set: function set (key, value) {
5503      this._cache[key] = value;
5504    },
5505    get: function get (key) {
5506      return this._cache[key];
5507    },
5508    clear: function clear () {
5509      this._cache = {};
5510    }
5511  };
5512}
5513
5514/**
5515 * Clears all cached templates in this writer.
5516 */
5517Writer.prototype.clearCache = function clearCache () {
5518  if (typeof this.templateCache !== 'undefined') {
5519    this.templateCache.clear();
5520  }
5521};
5522
5523/**
5524 * Parses and caches the given `template` according to the given `tags` or
5525 * `mustache.tags` if `tags` is omitted,  and returns the array of tokens
5526 * that is generated from the parse.
5527 */
5528Writer.prototype.parse = function parse (template, tags) {
5529  var cache = this.templateCache;
5530  var cacheKey = template + ':' + (tags || mustache.tags).join(':');
5531  var isCacheEnabled = typeof cache !== 'undefined';
5532  var tokens = isCacheEnabled ? cache.get(cacheKey) : undefined;
5533
5534  if (tokens == undefined) {
5535    tokens = parseTemplate(template, tags);
5536    isCacheEnabled && cache.set(cacheKey, tokens);
5537  }
5538  return tokens;
5539};
5540
5541/**
5542 * High-level method that is used to render the given `template` with
5543 * the given `view`.
5544 *
5545 * The optional `partials` argument may be an object that contains the
5546 * names and templates of partials that are used in the template. It may
5547 * also be a function that is used to load partial templates on the fly
5548 * that takes a single argument: the name of the partial.
5549 *
5550 * If the optional `config` argument is given here, then it should be an
5551 * object with a `tags` attribute or an `escape` attribute or both.
5552 * If an array is passed, then it will be interpreted the same way as
5553 * a `tags` attribute on a `config` object.
5554 *
5555 * The `tags` attribute of a `config` object must be an array with two
5556 * string values: the opening and closing tags used in the template (e.g.
5557 * [ "<%", "%>" ]). The default is to mustache.tags.
5558 *
5559 * The `escape` attribute of a `config` object must be a function which
5560 * accepts a string as input and outputs a safely escaped string.
5561 * If an `escape` function is not provided, then an HTML-safe string
5562 * escaping function is used as the default.
5563 */
5564Writer.prototype.render = function render (template, view, partials, config) {
5565  var tags = this.getConfigTags(config);
5566  var tokens = this.parse(template, tags);
5567  var context = (view instanceof Context) ? view : new Context(view, undefined);
5568  return this.renderTokens(tokens, context, partials, template, config);
5569};
5570
5571/**
5572 * Low-level method that renders the given array of `tokens` using
5573 * the given `context` and `partials`.
5574 *
5575 * Note: The `originalTemplate` is only ever used to extract the portion
5576 * of the original template that was contained in a higher-order section.
5577 * If the template doesn't use higher-order sections, this argument may
5578 * be omitted.
5579 */
5580Writer.prototype.renderTokens = function renderTokens (tokens, context, partials, originalTemplate, config) {
5581  var buffer = '';
5582
5583  var token, symbol, value;
5584  for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
5585    value = undefined;
5586    token = tokens[i];
5587    symbol = token[0];
5588
5589    if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate, config);
5590    else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate, config);
5591    else if (symbol === '>') value = this.renderPartial(token, context, partials, config);
5592    else if (symbol === '&') value = this.unescapedValue(token, context);
5593    else if (symbol === 'name') value = this.escapedValue(token, context, config);
5594    else if (symbol === 'text') value = this.rawValue(token);
5595
5596    if (value !== undefined)
5597      buffer += value;
5598  }
5599
5600  return buffer;
5601};
5602
5603Writer.prototype.renderSection = function renderSection (token, context, partials, originalTemplate, config) {
5604  var self = this;
5605  var buffer = '';
5606  var value = context.lookup(token[1]);
5607
5608  // This function is used to render an arbitrary template
5609  // in the current context by higher-order sections.
5610  function subRender (template) {
5611    return self.render(template, context, partials, config);
5612  }
5613
5614  if (!value) return;
5615
5616  if (isArray(value)) {
5617    for (var j = 0, valueLength = value.length; j < valueLength; ++j) {
5618      buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate, config);
5619    }
5620  } else if (typeof value === 'object' || typeof value === 'string' || typeof value === 'number') {
5621    buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate, config);
5622  } else if (isFunction(value)) {
5623    if (typeof originalTemplate !== 'string')
5624      throw new Error('Cannot use higher-order sections without the original template');
5625
5626    // Extract the portion of the original template that the section contains.
5627    value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
5628
5629    if (value != null)
5630      buffer += value;
5631  } else {
5632    buffer += this.renderTokens(token[4], context, partials, originalTemplate, config);
5633  }
5634  return buffer;
5635};
5636
5637Writer.prototype.renderInverted = function renderInverted (token, context, partials, originalTemplate, config) {
5638  var value = context.lookup(token[1]);
5639
5640  // Use JavaScript's definition of falsy. Include empty arrays.
5641  // See https://github.com/janl/mustache.js/issues/186
5642  if (!value || (isArray(value) && value.length === 0))
5643    return this.renderTokens(token[4], context, partials, originalTemplate, config);
5644};
5645
5646Writer.prototype.indentPartial = function indentPartial (partial, indentation, lineHasNonSpace) {
5647  var filteredIndentation = indentation.replace(/[^ \t]/g, '');
5648  var partialByNl = partial.split('\n');
5649  for (var i = 0; i < partialByNl.length; i++) {
5650    if (partialByNl[i].length && (i > 0 || !lineHasNonSpace)) {
5651      partialByNl[i] = filteredIndentation + partialByNl[i];
5652    }
5653  }
5654  return partialByNl.join('\n');
5655};
5656
5657Writer.prototype.renderPartial = function renderPartial (token, context, partials, config) {
5658  if (!partials) return;
5659  var tags = this.getConfigTags(config);
5660
5661  var value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
5662  if (value != null) {
5663    var lineHasNonSpace = token[6];
5664    var tagIndex = token[5];
5665    var indentation = token[4];
5666    var indentedValue = value;
5667    if (tagIndex == 0 && indentation) {
5668      indentedValue = this.indentPartial(value, indentation, lineHasNonSpace);
5669    }
5670    var tokens = this.parse(indentedValue, tags);
5671    return this.renderTokens(tokens, context, partials, indentedValue, config);
5672  }
5673};
5674
5675Writer.prototype.unescapedValue = function unescapedValue (token, context) {
5676  var value = context.lookup(token[1]);
5677  if (value != null)
5678    return value;
5679};
5680
5681Writer.prototype.escapedValue = function escapedValue (token, context, config) {
5682  var escape = this.getConfigEscape(config) || mustache.escape;
5683  var value = context.lookup(token[1]);
5684  if (value != null)
5685    return (typeof value === 'number' && escape === mustache.escape) ? String(value) : escape(value);
5686};
5687
5688Writer.prototype.rawValue = function rawValue (token) {
5689  return token[1];
5690};
5691
5692Writer.prototype.getConfigTags = function getConfigTags (config) {
5693  if (isArray(config)) {
5694    return config;
5695  }
5696  else if (config && typeof config === 'object') {
5697    return config.tags;
5698  }
5699  else {
5700    return undefined;
5701  }
5702};
5703
5704Writer.prototype.getConfigEscape = function getConfigEscape (config) {
5705  if (config && typeof config === 'object' && !isArray(config)) {
5706    return config.escape;
5707  }
5708  else {
5709    return undefined;
5710  }
5711};
5712
5713var mustache = {
5714  name: 'mustache.js',
5715  version: '4.2.0',
5716  tags: [ '{{', '}}' ],
5717  clearCache: undefined,
5718  escape: undefined,
5719  parse: undefined,
5720  render: undefined,
5721  Scanner: undefined,
5722  Context: undefined,
5723  Writer: undefined,
5724  /**
5725   * Allows a user to override the default caching strategy, by providing an
5726   * object with set, get and clear methods. This can also be used to disable
5727   * the cache by setting it to the literal `undefined`.
5728   */
5729  set templateCache (cache) {
5730    defaultWriter.templateCache = cache;
5731  },
5732  /**
5733   * Gets the default or overridden caching object from the default writer.
5734   */
5735  get templateCache () {
5736    return defaultWriter.templateCache;
5737  }
5738};
5739
5740// All high-level mustache.* functions use this writer.
5741var defaultWriter = new Writer();
5742
5743/**
5744 * Clears all cached templates in the default writer.
5745 */
5746mustache.clearCache = function clearCache () {
5747  return defaultWriter.clearCache();
5748};
5749
5750/**
5751 * Parses and caches the given template in the default writer and returns the
5752 * array of tokens it contains. Doing this ahead of time avoids the need to
5753 * parse templates on the fly as they are rendered.
5754 */
5755mustache.parse = function parse (template, tags) {
5756  return defaultWriter.parse(template, tags);
5757};
5758
5759/**
5760 * Renders the `template` with the given `view`, `partials`, and `config`
5761 * using the default writer.
5762 */
5763mustache.render = function render (template, view, partials, config) {
5764  if (typeof template !== 'string') {
5765    throw new TypeError('Invalid template! Template should be a "string" ' +
5766                        'but "' + typeStr(template) + '" was given as the first ' +
5767                        'argument for mustache#render(template, view, partials)');
5768  }
5769
5770  return defaultWriter.render(template, view, partials, config);
5771};
5772
5773// Export the escaping function so that the user may override it.
5774// See https://github.com/janl/mustache.js/issues/244
5775mustache.escape = escapeHtml;
5776
5777// Export these mainly for testing, but also for advanced usage.
5778mustache.Scanner = Scanner;
5779mustache.Context = Context;
5780mustache.Writer = Writer;
5781
5782/* harmony default export */ __webpack_exports__["default"] = (mustache);
5783
5784
5785/***/ })
5785
5786
5787/******/ 	});
5788/************************************************************************/
5789/******/ 	// The module cache
5790/******/ 	var __webpack_module_cache__ = {};
5791/******/ 	
5792/******/ 	// The require function
5793/******/ 	function __webpack_require__(moduleId) {
5794/******/ 		// Check if module is in cache
5795/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
5796/******/ 		if (cachedModule !== undefined) {
5797/******/ 			return cachedModule.exports;
5798/******/ 		}
5799/******/ 		// Create a new module (and put it into the cache)
5800/******/ 		var module = __webpack_module_cache__[moduleId] = {
5801/******/ 			// no module.id needed
5802/******/ 			// no module.loaded needed
5803/******/ 			exports: {}
5804/******/ 		};
5805/******/ 	
5806/******/ 		// Execute the module function
5807/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
5808/******/ 	
5809/******/ 		// Return the exports of the module
5810/******/ 		return module.exports;
5811/******/ 	}
5812/******/ 	
5813/************************************************************************/
5814/******/ 	/* webpack/runtime/define property getters */
5815/******/ 	!function() {
5816/******/ 		// define getter functions for harmony exports
5817/******/ 		__webpack_require__.d = function(exports, definition) {
5818/******/ 			for(var key in definition) {
5819/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
5820/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
5821/******/ 				}
5822/******/ 			}
5823/******/ 		};
5824/******/ 	}();
5825/******/ 	
5826/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
5827/******/ 	!function() {
5828/******/ 		__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
5829/******/ 	}();
5830/******/ 	
5831/************************************************************************/
5832var __webpack_exports__ = {};
5833// This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk.
5834!function() {
5835/*!*************************************!*\
5836  !*** ./js/design/paniercommande.js ***!
5837  \*************************************/
5838/* harmony import */ var _components_SwiperEditorConfig__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/SwiperEditorConfig */ "./js/components/SwiperEditorConfig.js");
5839/* harmony import */ var beekube_dom_Helper_Event__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! beekube-dom/Helper/Event */ "./node_modules/beekube-dom/Helper/Event.js");
5840/* harmony import */ var mustache__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! mustache */ "./node_modules/mustache/mustache.mjs");
5841
5842
5843
5844$(document).ready(function () {
5845  var sticky = null,
5846    stickyStep2 = null;
5847  setTimeout(function () {
5848    sticky = new Sticky('.block-info-payment__sticky');
5849    stickyStep2 = new Sticky('.block-info-commande__sticky');
5850  });
5851  var $formOrder = $('[name="form-order"]');
5852  if ($formOrder.length) {
5853    var dateBrowserInfo = new Date();
5854    $formOrder.append($('<input />', {
5855      'type': 'hidden',
5856      'name': 'browser_info[color_depth]',
5857      'value': screen.colorDepth
5858    })).append($('<input />', {
5859      'type': 'hidden',
5860      'name': 'browser_info[screen_height]',
5861      'value': screen.height
5862    })).append($('<input />', {
5863      'type': 'hidden',
5864      'name': 'browser_info[screen_width]',
5865      'value': screen.width
5866    })).append($('<input />', {
5867      'type': 'hidden',
5868      'name': 'browser_info[timezone_offset_minutes_utc]',
5869      'value': dateBrowserInfo.getTimezoneOffset()
5870    }));
5871  }
5872  var cart_step_1 = $('.cart-step-1'),
5873    cart_step_2 = $('.cart-step-2'),
5874    cart_step_3 = $('.cart-step-3'),
5875    haveUniqShipping = false,
5876    $body = $('body'),
5877    options_price = 0.00,
5878    options_price_currency = 0.00,
5879    vitesse_scroll = 400,
5880    hasTrackedBeginCheckout = false;
5881  var sidebar = new sideMenu('.steps-panier', {
5882    sidebar: '.stepper-tabs',
5883    onClick: function (event, link) {
5884      $(link).closest('ul').children('li').removeClass('active').removeClass('step-done').find('a').removeClass('step-done');
5885      $(link).closest('li').addClass('active').prevAll().addClass('step-done').find('a').addClass('step-done');
5886      if (stickyStep2 !== null) {
5887        stickyStep2.destroy();
5888      }
5889      if (sticky !== null) {
5890        sticky.destroy();
5891      }
5892      stickyStep2 = new Sticky('.block-info-commande__sticky');
5893      sticky = new Sticky('.block-info-payment__sticky');
5894      if (typeof $($(link).attr('href')).offset() !== "undefined") {
5895        $('html,body').animate({
5896          scrollTop: $($(link).attr('href')).offset().top
5897        }, vitesse_scroll);
5898      }
5899    }
5900  });
5901  setTimeout(function () {
5902    loadCarriers();
5903  }, 1);
5904  setTimeout(function () {
5905    if (typeof currencyIsoCode !== "undefined" && typeof amountProductDefaultCurrency !== "undefined") {
5906      refreshPaymentMode({
5907        'currencyIsoCode': currencyIsoCode,
5908        'amountProductDefaultCurrency': amountProductDefaultCurrency
5909      });
5910    }
5911  }, 1);
5912  let swiper = null;
5913  let giftDiscountHeightAlign = null;
5914  let giftDiscountResizeBound = false;
5915
5916  // Position à réappliquer à la prochaine création du slider, relevée avant que le
5917  // rechargement Ajax ne remplace le HTML du bloc.
5918  let pendingGiftDiscountIndex = 0;
5919
5920  // Dernier rendu serveur appliqué au bloc cadeaux. Un ajout de cadeau déclenche deux
5921  // rechargements du panier (celui du bouton, puis celui de loadCarriers), qui renvoient
5922  // le même HTML : sans cette comparaison, le slider est détruit et recréé une seconde
5923  // fois près d'une seconde après le clic, ce qui se voit à l'écran.
5924  let lastGiftDiscountHtml = null;
5925
5926  // Valeurs du dernier rendu du slider, pour ne le recréer que si la config change.
5927  // Volontairement hors de loadGiftDiscountSwiper() : cette fonction est rappelée à
5928  // chaque rechargement Ajax du bloc cadeaux, et des valeurs locales seraient
5929  // réinitialisées à null à chaque fois (donc destroy + new Swiper systématiques).
5930  let prevGiftDiscountParams = {
5931    slidesPerView: null,
5932    spaceBetween: null,
5933    autoplayRaw: null
5934  };
5935  function resetGiftDiscountParams() {
5936    prevGiftDiscountParams = {
5937      slidesPerView: null,
5938      spaceBetween: null,
5939      autoplayRaw: null
5940    };
5941  }
5942
5943  /**
5944   * Détruit l'instance Swiper des cadeaux et retourne la position courante.
5945   * À appeler AVANT de remplacer le HTML du bloc : après remplacement, l'instance
5946   * pointe sur un DOM détaché et ne peut plus être nettoyée.
5947   * @returns {number} index réel (hors slides clonées) au moment de la destruction
5948   */
5949  function destroyGiftDiscountSwiper() {
5950    let realIndex = 0;
5951    if (swiper) {
5952      realIndex = swiper.realIndex || 0;
5953      swiper.destroy(true, true);
5954      swiper = null;
5955      resetGiftDiscountParams();
5956    }
5957    return realIndex;
5958  }
5959  function giftDiscountParamsChanged(newParams) {
5960    return newParams.slidesPerView !== prevGiftDiscountParams.slidesPerView || newParams.spaceBetween !== prevGiftDiscountParams.spaceBetween || newParams.autoplayRaw !== prevGiftDiscountParams.autoplayRaw;
5961  }
5962  function createOrUpdateGiftDiscountSwiper() {
5963    let giftDiscountAdvanced = document.querySelector('.gift-discount__item__products');
5964    if (giftDiscountAdvanced === null || document.querySelector('.gift-discount__swiper') === null) {
5965      return;
5966    }
5967    let params = (0,_components_SwiperEditorConfig__WEBPACK_IMPORTED_MODULE_0__.getSliderParams)(giftDiscountAdvanced);
5968
5969    // Vérifier si les paramètres ont changé avant de mettre à jour
5970    if (swiper && !giftDiscountParamsChanged(params)) {
5971      return;
5972    }
5973
5974    // Mémoriser les nouvelles valeurs
5975    prevGiftDiscountParams.slidesPerView = params.slidesPerView;
5976    prevGiftDiscountParams.spaceBetween = params.spaceBetween;
5977    prevGiftDiscountParams.autoplayRaw = params.autoplayRaw;
5978
5979    // Position conservée : celle de l'instance vivante (redimensionnement), sinon
5980    // celle relevée avant le remplacement du HTML. Elle est passée à la création via
5981    // initialSlide : un slideTo posé après l'init produit un déplacement visible.
5982    const realSlideCount = giftDiscountAdvanced.querySelectorAll('.gift-discount__swiper .swiper-slide:not(.swiper-slide-duplicate)').length;
5983    const wantedIndex = swiper ? swiper.realIndex || 0 : pendingGiftDiscountIndex;
5984    let swiperProductSliderConfiguration = {
5985      initialSlide: realSlideCount > 0 ? Math.min(Math.max(wantedIndex, 0), realSlideCount - 1) : 0,
5986      slidesPerView: params.slidesPerView,
5987      spaceBetween: params.spaceBetween,
5988      wrapperClass: 'gift-discount__swiper-wrapper',
5989      loop: true,
5990      preloadImages: false,
5991      lazy: true,
5992      // Le module A11y de Swiper deplace le slider des qu'un element recoit le
5993      // focus dans une slide differente de la slide active : cliquer sur le bouton
5994      // d'un cadeau visible mais non actif provoquait un slideTo parasite. Avec
5995      // watchSlidesProgress, Swiper connait visibleSlides et n'agit plus que si la
5996      // slide focalisee est reellement hors champ.
5997      watchSlidesProgress: true
5998    };
5999    if (giftDiscountAdvanced.querySelector('.swiper-pagination') !== null) {
6000      swiperProductSliderConfiguration['pagination'] = {
6001        el: '.swiper-pagination',
6002        type: 'bullets',
6003        clickable: true
6004      };
6005    }
6006    if (giftDiscountAdvanced.querySelector('.swiper-button-next') && giftDiscountAdvanced.querySelector('.swiper-button-prev')) {
6007      swiperProductSliderConfiguration['navigation'] = {
6008        nextEl: '.swiper-button-next',
6009        prevEl: '.swiper-button-prev'
6010      };
6011    }
6012
6013    // Si un Swiper existe déjà, le détruire avant d'en créer un nouveau
6014    if (swiper) {
6015      swiper.destroy(true, true);
6016      swiper = null;
6017    }
6018
6019    // Créer une nouvelle instance avec les paramètres mis à jour
6020    swiper = new Swiper('.gift-discount__swiper', swiperProductSliderConfiguration);
6021  }
6022
6023  // Écouter les changements de taille de fenêtre avec debounce
6024  const updateGiftDiscountSwiperOnResize = CmonSite.debounce(function () {
6025    createOrUpdateGiftDiscountSwiper();
6026  }, 250);
6027
6028  /**
6029   * (Ré)initialise le bloc cadeaux : slider, alignement des hauteurs, écouteurs.
6030   * @param {number} [restoreIndex] position à restaurer, retournée par destroyGiftDiscountSwiper()
6031   */
6032  function loadGiftDiscountSwiper(restoreIndex) {
6033    const giftDiscountAdvanced = document.querySelector('.gift-discount__item__products');
6034    const giftDiscountAdvancedSwiper = document.querySelector('.gift-discount__swiper');
6035    if (giftDiscountAdvanced === null || giftDiscountAdvancedSwiper === null) {
6036      // Le nouveau rendu n'a plus de slider (moins de cadeaux qu'avant) :
6037      // ne pas garder une instance qui pointe sur un DOM disparu.
6038      destroyGiftDiscountSwiper();
6039      if (giftDiscountAdvanced !== null && giftDiscountHeightAlign !== null) {
6040        document.body.dispatchEvent(new Event('heightAlign.refresh'));
6041      }
6042      return;
6043    }
6044    pendingGiftDiscountIndex = typeof restoreIndex === 'number' && restoreIndex > 0 ? restoreIndex : 0;
6045    createOrUpdateGiftDiscountSwiper();
6046    pendingGiftDiscountIndex = 0;
6047
6048    // Écouteur global : posé une seule fois, sinon un simple redimensionnement
6049    // déclencherait autant de réinitialisations que de rechargements du bloc.
6050    if (!giftDiscountResizeBound) {
6051      window.addEventListener('resize', updateGiftDiscountSwiperOnResize);
6052      giftDiscountResizeBound = true;
6053    }
6054
6055    // Porté par l'élément lui-même, remplacé à chaque rechargement : pas d'accumulation.
6056    (0,beekube_dom_Helper_Event__WEBPACK_IMPORTED_MODULE_1__.EventOn)(Object.assign({}, beekube_dom_Helper_Event__WEBPACK_IMPORTED_MODULE_1__.defaultEventOptions, {
6057      'element': giftDiscountAdvanced,
6058      'type': 'changeCSS',
6059      'listener': updateGiftDiscountSwiperOnResize
6060    }));
6061
6062    // heightAlign relit ses éléments à chaque rafraîchissement : une instance suffit
6063    // pour toute la page, même après remplacement du HTML.
6064    if (giftDiscountHeightAlign === null) {
6065      giftDiscountHeightAlign = new heightAlign('.gift-discount__item__product', {
6066        "elementChild": [".gift-discount__item__product__title", ".gift-discount__item__product__button"],
6067        "nombreBlocsLigne": 1000
6068      });
6069    } else {
6070      document.body.dispatchEvent(new Event('heightAlign.refresh'));
6071    }
6072  }
6073  loadGiftDiscountSwiper();
6074  $('[name="form-order"]').validationEngine();
6075  if ($('.step-finish').is('.active')) {
6076    $('.step-finish').siblings('span').addClass('active');
6077  }
6078  $body.on('touchstart click', 'a.step-finish', function () {
6079    loadCarriers();
6080  }).on('click', '[name="product_gift_discount_add"]', function () {
6081    var $self = $(this),
6082      product = $self.val(),
6083      id_discount = $self.attr('data-id'),
6084      $discountItem = $self.closest('.gift-discount__item');
6085    $discountItem.waitMe();
6086    $.ajax({
6087      type: "POST",
6088      url: "/ajax/minisite/panier/add_discount_advanced_gift.php",
6089      data: {
6090        'id_discount': id_discount,
6091        'product': product
6092      },
6093      dataType: 'json',
6094      success: function (response) {
6095        if (response.hasOwnProperty('reload')) {
6096          location.reload();
6097        }
6098        $discountItem.waitMe('hide');
6099        flag = false;
6100        setTimeout(function () {
6101          if (response.reload_cart) {
6102            reloadResumeAndPaymentCart(response.resume_cart, response.payment_cart, response.gift_discount_advanced);
6103          }
6104          reloadBlockReductionCode();
6105          loadCarriers();
6106        }, 0);
6107      }
6108    });
6109  }).on('click', '.show-modal-information-oney', function () {
6110    var $self = $(this),
6111      $modalInformationOney = $('#modal-information-oney'),
6112      country = $('[name=pays]').val(),
6113      modalType = $self.attr('data-type');
6114    if ($modalInformationOney.length === 0) {
6115      /* Créer la modal */
6116      $modalInformationOney = $('<div />', {
6117        'class': 'modal fade modal-information-oney',
6118        'id': 'modal-information-oney',
6119        'tabindex': '-1',
6120        'role': 'dialog'
6121      }).append($('<div />', {
6122        'class': 'modal-dialog modal-lg',
6123        'role': 'document'
6124      }).append($('<div />', {
6125        'class': 'modal-content'
6126      }).append($('<div />', {
6127        'class': 'modal-header'
6128      }).append($('<button />', {
6129        'type': 'button',
6130        'class': 'close',
6131        'data-dismiss': 'modal',
6132        'aria-label': 'Close'
6133      }).append($('<span />', {
6134        'aria-hidden': 'true',
6135        'html': '&times;'
6136      }))).append($('<span />', {
6137        'class': 'modal-information-oney__title',
6138        'html': _lang.get('Simulation pour un paiement via Oney')
6139      }))).append($('<div />', {
6140        'class': 'modal-body'
6141      }))));
6142      $('#main-conteneur').append($modalInformationOney);
6143    }
6144    if (modalType === undefined) {
6145      modalType = null;
6146      $modalInformationOney.find('.modal-dialog').addClass('modal-lg');
6147    } else {
6148      $modalInformationOney.find('.modal-dialog').removeClass('modal-lg');
6149    }
6150    var amountCarrier = -1,
6151      amountCarrierInsurance = 0,
6152      $containerCarriers = $('.content-carriers__item');
6153    if ($containerCarriers.length) {
6154      var amountCarrierTmp = 0,
6155        haveCarrierChecked = false;
6156      $containerCarriers.each(function (index, itemCarrier) {
6157        var $itemCarrier = $(itemCarrier),
6158          $radioCarrierChecked = $itemCarrier.find('.radio_carrier:checked'),
6159          $insuranceItem;
6160        if ($radioCarrierChecked.length) {
6161          haveCarrierChecked = true;
6162          amountCarrierTmp += parseFloat($radioCarrierChecked.attr('data-price'));
6163          $insuranceItem = $('[name=insurance_' + $radioCarrierChecked.attr('data-product-group') + '_' + $radioCarrierChecked.val() + ']:checked');
6164          if ($insuranceItem.length) {
6165            amountCarrierInsurance += parseFloat($insuranceItem.attr('data-price'));
6166          }
6167        }
6168      });
6169      if (haveCarrierChecked) {
6170        amountCarrier = amountCarrierTmp;
6171      }
6172    }
6173    $modalInformationOney.modal();
6174    var $modalBody = $modalInformationOney.find('.modal-body');
6175    $modalBody.waitMe();
6176    $.ajax({
6177      type: "POST",
6178      url: "/ajax/minisite/panier/payplug_oney_simulation.php",
6179      data: {
6180        'country': country,
6181        'modalType': modalType,
6182        'amountCarrier': amountCarrier,
6183        'amountCarrierInsurance': amountCarrierInsurance,
6184        'options_price': options_price
6185      },
6186      dataType: 'json',
6187      success: function (json) {
6188        if (json.hasOwnProperty('reload')) {
6189          location.reload();
6190        }
6191        $modalBody.waitMe('hide');
6192        $modalBody.html(json.html);
6193      }
6194    });
6195  }).on('keyup', '[name="nom_societe"]', function () {
6196    var $self = $(this),
6197      $block = $('.information-society');
6198    if ($self.val() === '') {
6199      $block.hide();
6200    } else {
6201      $block.show();
6202    }
6203  }).on('change', '.block_address .change_address', function () {
6204    var self = $(this),
6205      $block = self.closest('.block_address'),
6206      $container = $('.block-info-commande'),
6207      $item = self.find('option[value="' + self.val() + '"]');
6208    if ($block.hasClass('billing_address')) {
6209      $block.find('[name="nom"]').val($item.attr('data-nom'));
6210      $block.find('[name="prenom"]').val($item.attr('data-prenom'));
6211      $block.find('[name="tel"]').val($item.attr('data-tel'));
6212      $block.find('[name="adresse"]').val($item.attr('data-adresse'));
6213      $block.find('[name="cp"]').val($item.attr('data-code-postal'));
6214      $block.find('[name="ville"]').val($item.attr('data-ville'));
6215      $block.find('[name="pays"]').val($item.attr('data-pays'));
6216      $block.find('[name="commentaires"]').val($item.attr('data-commentaires'));
6217    } else {
6218      $block.find('[name="nom_livraison"]').val($item.attr('data-nom'));
6219      $block.find('[name="prenom_livraison"]').val($item.attr('data-prenom'));
6220      $block.find('[name="societe_livraison"]').val($item.attr('data-societe'));
6221      $block.find('[name="tel_livraison"]').val($item.attr('data-tel'));
6222      $block.find('[name="adresse_livraison"]').val($item.attr('data-adresse'));
6223      $block.find('[name="cp_livraison"]').val($item.attr('data-code-postal'));
6224      $block.find('[name="ville_livraison"]').val($item.attr('data-ville'));
6225      $block.find('[name="pays_livraison"]').val($item.attr('data-pays'));
6226      $block.find('[name="commentaires_livraison"]').val($item.attr('data-commentaires'));
6227    }
6228    loadCarriers();
6229  }).on('change', '.block_address [name="pays"], .block_address [name="pays_livraison"]', function () {
6230    loadCarriers();
6231  });
6232
6233  //Fonction pour afficher / cacher les réduction
6234  $body.on('click', '.block-reduc-deploy', function () {
6235    var self = $(this),
6236      $blockPromo = self.nextAll('ul');
6237    $blockPromo.stop().slideToggle(200);
6238  });
6239  $body.on('touchstart click', 'a.next-step', function () {
6240    var self = $(this),
6241      href = $(self).attr('href');
6242    if ($(self).hasClass('step-1')) {
6243      changeSideBar(href);
6244      if (!hasTrackedBeginCheckout && trackCartStepEvent('begin_checkout')) {
6245        hasTrackedBeginCheckout = true;
6246      }
6247    }
6248    if ($(self).hasClass('step-2')) {
6249      if (validFormAddress()) {
6250        var $addressRgpd = $('#address_rgpd_checkbox');
6251
6252        /* Tester la validation de l'adresse RGPD */
6253        if ($addressRgpd.length && !$addressRgpd.is(':checked')) {
6254          $addressRgpd.validationEngine('validate');
6255          return false;
6256        }
6257        var $blockInvoiceAddress = $('#infoscommande .billing_address'),
6258          $blockDeliveryAddress = $('#infoscommande .delivery_address');
6259        /* Enlever l'espace sur un code postal fr (facture)*/
6260        if ($blockInvoiceAddress.find('[name="pays"]').val() === 'France') {
6261          var $zipCodeInvoice = $blockInvoiceAddress.find('[name="cp"]'),
6262            zipCodeInvoice = $zipCodeInvoice.val();
6263          zipCodeInvoice = zipCodeInvoice.replace(/\s/g, '');
6264          $zipCodeInvoice.val(zipCodeInvoice);
6265        }
6266        /* Enlever l'espace sur un code postal fr (livraison)*/
6267        if ($blockDeliveryAddress.find('[name="pays_livraison"]').val() === 'France') {
6268          var $zipCodeDelivery = $blockDeliveryAddress.find('[name="cp_livraison"]'),
6269            zipCodeDelivery = $zipCodeDelivery.val();
6270          zipCodeDelivery = zipCodeDelivery.replace(/\s/g, '');
6271          $zipCodeDelivery.val(zipCodeDelivery);
6272        }
6273        setTimeout(function () {
6274          saveAddr(function () {
6275            loadCarriers();
6276            changeSideBar(href);
6277          });
6278        }, 1);
6279      }
6280    }
6281    return false;
6282  });
6283  $body.on('change', '[name=address_billing_same_delivery]', function () {
6284    var value = $(this).val();
6285    if (value === '1') {
6286      $('.block_delivery_address').hide();
6287    } else {
6288      $('.block_delivery_address').show();
6289    }
6290  });
6291  $('[name=form-order] input').on('keyup keypress', function (e) {
6292    var code = e.keyCode || e.which,
6293      self = $(this);
6294    if (code == 13) {
6295      switch (true) {
6296        case self.closest('.inscription').length > 0:
6297          $('[name=submit-inscription]').trigger('click');
6298          break;
6299        case self.closest('.connexion').length > 0:
6300          $('[name=submit-connexion]').trigger('click');
6301          break;
6302      }
6303      e.preventDefault();
6304      return false;
6305    }
6306  });
6307  function changePrice(radio, calculatePriceParams) {
6308    var $self = $(radio),
6309      price = $self.attr('data-price'),
6310      price_format = $self.attr('data-price-format'),
6311      value = $self.val(),
6312      $item = $self.closest('.content-carriers__item');
6313    $item.find('.line_carrier label').removeClass('selected').parent().removeClass('selected');
6314    $self.closest('label').addClass('selected').closest('li').addClass('selected').closest('ul').addClass('group-selected');
6315    $self.closest('li').addClass('selected').closest('ul').addClass('group-selected');
6316    //
6317    // if (price === '0') {
6318    //     cart_step_1.find('.content-payment-product-global').hide();
6319    //     cart_step_1.find('.content-payment-carrier-ttc').hide();
6320    //     cart_step_1.find('.content-payment-carrier-ttc').hide();
6321    //     cart_step_1.find('.total-global').html(cart_step_1.find('.total-product-global').html());
6322    //
6323    //
6324    //     cart_step_3.find('.content-payment-product-global').hide();
6325    //     cart_step_3.find('.content-payment-carrier-ttc').hide();
6326    //     cart_step_3.find('.content-payment-carrier-ttc').hide();
6327    //     cart_step_3.find('.total-global').html(cart_step_3.find('.total-product-global').html());
6328    //
6329    //
6330    // } else {
6331    //     cart_step_3.find('.total-carrier-ttc').html(price_format);
6332    //
6333    //     if (haveUniqShipping) {
6334    //         cart_step_1.find('.total-carrier-ttc').html(price_format);
6335    //     }
6336    //
6337    //
6338    //     var total_product_global = cart_step_3.find('.total-product-global').html();
6339    //
6340    //     float_price_carrier = parseFloat(price.replace(",", "."));
6341    //     float_total_product_global = parseFloat(total_product_global.replace(",", "."));
6342    //
6343    //     global_price = float_price_carrier + float_total_product_global;
6344    //
6345    //     global_price = Math.round(global_price * 100) / 100;
6346    //
6347    //     cart_step_3.find('.total-global').html(global_price.toFixed(2));
6348    //     cart_step_3.find('.content-payment-product-global').show();
6349    //     cart_step_3.find('.content-payment-carrier-ttc').show();
6350    //
6351    //     if (haveUniqShipping) {
6352    //         cart_step_1.find('.total-global').html(global_price.toFixed(2));
6353    //         cart_step_1.find('.content-payment-product-global').show();
6354    //         cart_step_1.find('.content-payment-carrier-ttc').show();
6355    //     }
6356    // }
6357
6358    $('[name="relay_id_' + $self.attr('data-product-group') + '"]').remove();
6359    $item.find('.change_relay').parent().remove();
6360    $item.find('.change_colissimo_relay').parent().remove();
6361    $item.find('.change_chronopost_relay').parent().remove();
6362    $item.find('.change_mondialrelay_relay').parent().remove();
6363    $item.find('.change_disponibility').parent().remove();
6364    $item.find('.information-relay').hide().html();
6365    if (typeof calculatePriceParams === 'undefined') {
6366      calculatePriceParams = {};
6367    }
6368    calculatePrice(calculatePriceParams);
6369    loadFancyboxRelay($self);
6370  }
6371  $body.on('change', '.radio_carrier', function (event, params) {
6372    var $self = $(this),
6373      name = $self.attr('name'),
6374      $item = $self.closest('.content-carriers__item'),
6375      productGroup = $self.attr('data-product-group'),
6376      $insurance = $item.find('[name=insurance_' + productGroup + '_' + $('[name="' + name + '"]:checked').val() + ']');
6377    $item.find('.insurance-block').each(function (index, value) {
6378      $(value).find('.checkbox_insurance').prop('checked', false);
6379    });
6380    $item.find('.insurance-block').hide();
6381    if ($insurance.length > 0) {
6382      $insurance.parents('.insurance-block').show();
6383    }
6384    if (event && event.originalEvent) {
6385      var $lineCarrier = $self.closest('.line_carrier'),
6386        shippingTier = $.trim($lineCarrier.find('.carrier_name span').first().text()) || $self.val();
6387      trackCartStepEvent('add_shipping_info', {
6388        shipping_tier: shippingTier
6389      });
6390    }
6391    if (typeof params === 'undefined') {
6392      params = {};
6393    }
6394    changePrice(this, params.hasOwnProperty('calculatePriceParams') ? params.calculatePriceParams : {});
6395  });
6396  $body.on('click', '.change_relay', function () {
6397    var self;
6398    changePrice($(this).parents('.line_carrier').find('.radio_carrier'));
6399    return false;
6400  });
6401  $body.on('click', '.change_colissimo_relay', function () {
6402    var self;
6403    changePrice($(this).parents('.line_carrier').find('.radio_carrier'));
6404    return false;
6405  });
6406  $body.on('click', '.change_chronopost_relay', function () {
6407    var self;
6408    changePrice($(this).parents('.line_carrier').find('.radio_carrier'));
6409    return false;
6410  });
6411  $body.on('click', '.change_disponibility', function () {
6412    var self;
6413    changePrice($(this).parents('.line_carrier').find('.radio_carrier'));
6414    return false;
6415  });
6416  $body.on('click', '.change_mondialrelay_relay', function () {
6417    var self;
6418    changePrice($(this).parents('.line_carrier').find('.radio_carrier'));
6419    return false;
6420  });
6421  function loadFancyboxRelay($inputCarrier) {
6422    /* Verifier si on a des points relay pour faire selectionner le point au client */
6423    var $carrier = $inputCarrier,
6424      relay = $carrier.attr('data-relay'),
6425      colissimo = $carrier.attr('data-colissimo'),
6426      mondialrelay = $carrier.attr('data-mondialrelay'),
6427      chronopostrelay = $carrier.attr('data-chronopostrelay'),
6428      choiceDisponibility = $carrier.attr('data-choice-disponibility');
6429    var lastname_delivery = $('[name=nom]').val(),
6430      firstname_delivery = $('[name=prenom]').val(),
6431      address_delivery = $('[name=adresse]').val(),
6432      zip_code_delivery = $('[name=cp]').val(),
6433      city_delivery = $('[name=ville]').val(),
6434      country_delivery = $('[name=pays]').val(),
6435      iso_code_country_delivery = $('[name=pays] option[value="' + country_delivery + '"]').attr('data-iso-code');
6436    if ($('[name=address_billing_same_delivery]:checked').val() === '0') {
6437      lastname_delivery = $('[name=nom_livraison]').val();
6438      firstname_delivery = $('[name=prenom_livraison]').val();
6439      address_delivery = $('[name=adresse_livraison]').val();
6440      zip_code_delivery = $('[name=cp_livraison]').val();
6441      city_delivery = $('[name=ville_livraison]').val();
6442      country_delivery = $('[name=pays_livraison]').val(), iso_code_country_delivery = $('[name=pays_livraison] option[value="' + country_delivery + '"]').attr('data-iso-code');
6443    }
6444    switch (true) {
6445      case typeof relay !== typeof undefined && relay !== false:
6446        $.fancybox.open({
6447          href: '/page/choice_relay.php?relay=' + relay + '&address=' + address_delivery + '&zip_code=' + zip_code_delivery + '&city=' + city_delivery + '&country=' + country_delivery + '&t=' + new Date().getTime(),
6448          type: 'iframe',
6449          padding: 5,
6450          beforeClose: function () {
6451            var contentIframe = $("iframe.fancybox-iframe").contents(),
6452              radio_relay = $(contentIframe).find('[name=relay]:checked'),
6453              addressRelay = $(radio_relay).parents('.line_relay').find('.information-relay-address').html();
6454            $('[name=form-order]').append($('<input />').attr({
6455              'name': 'relay_id_' + $inputCarrier.attr('data-product-group'),
6456              'type': 'hidden',
6457              'value': $(radio_relay).val()
6458            }));
6459            $inputCarrier.parents('.line_carrier').find('.information-relay').show().html(addressRelay);
6460            $($('<span />', {
6461              'style': 'display: block;'
6462            }).html($('<a />').attr({
6463              'href': '#',
6464              'class': 'change_relay'
6465            }).html('Changer de relais'))).insertAfter($inputCarrier.parents('.line_carrier').find('.carrier_name > span'));
6466          }
6467        });
6468        break;
6469      case typeof colissimo !== typeof undefined && colissimo === '1':
6470        $.fancybox.open({
6471          href: '/page/choice_relay_colissimo.php?value=' + $carrier.val() + 'address=' + address_delivery + '&zip_code=' + zip_code_delivery + '&city=' + city_delivery + '&country=' + country_delivery + '&t=' + new Date().getTime(),
6472          type: 'iframe',
6473          padding: 5,
6474          beforeClose: function () {
6475            var contentIframe = $("iframe.fancybox-iframe").contents(),
6476              radio_relay = $(contentIframe).find('[name=relay]:checked'),
6477              addressRelay = $(radio_relay).closest('.block-colissimo__list__item__label').find('.block-colissimo__list__item__label__address').html();
6478            $('[name=form-order] [name="colissimo_id_' + $inputCarrier.attr('data-product-group') + '"]').remove();
6479            $('[name=form-order]').append($('<input />').attr({
6480              'name': 'colissimo_id_' + $inputCarrier.attr('data-product-group'),
6481              'type': 'hidden',
6482              'value': $(radio_relay).val()
6483            }));
6484            $inputCarrier.closest('.line_carrier').find('.information-relay').show().html(addressRelay);
6485            if ($inputCarrier.parents('.line_carrier').find('.change_colissimo_relay').length) {
6486              $inputCarrier.parents('.line_carrier').find('.change_colissimo_relay').parent().remove();
6487            }
6488            $($('<span />', {
6489              'style': 'display: block;'
6490            }).html($('<a />').attr({
6491              'href': '#',
6492              'class': 'change_colissimo_relay'
6493            }).html('Changer de relais'))).insertAfter($inputCarrier.parents('.line_carrier').find('.carrier_name > span'));
6494          }
6495        });
6496        break;
6497      case typeof chronopostrelay !== typeof undefined && chronopostrelay === '1':
6498        $.fancybox.open({
6499          href: '/page/choice_relay_chronopost.php?value=' + $carrier.val() + 'address=' + address_delivery + '&zip_code=' + zip_code_delivery + '&city=' + city_delivery + '&country=' + country_delivery + '&t=' + new Date().getTime(),
6500          type: 'iframe',
6501          padding: 5,
6502          beforeClose: function () {
6503            var contentIframe = $("iframe.fancybox-iframe").contents(),
6504              radio_relay = $(contentIframe).find('[name=relay]:checked'),
6505              addressRelay = $(radio_relay).closest('.block-chronopost__list__item__label').find('.block-chronopost__list__item__label__address').html();
6506            $('[name=form-order] [name="chronopost_id_' + $inputCarrier.attr('data-product-group') + '"]').remove();
6507            $('[name=form-order]').append($('<input />').attr({
6508              'name': 'chronopost_id_' + $inputCarrier.attr('data-product-group'),
6509              'type': 'hidden',
6510              'value': $(radio_relay).val()
6511            }));
6512            $inputCarrier.closest('.line_carrier').find('.information-relay').show().html(addressRelay);
6513            if ($inputCarrier.parents('.line_carrier').find('.change_chronopost_relay').length) {
6514              $inputCarrier.parents('.line_carrier').find('.change_chronopost_relay').parent().remove();
6515            }
6516            $($('<span />', {
6517              'style': 'display: block;'
6518            }).html($('<a />').attr({
6519              'href': '#',
6520              'class': 'change_chronopost_relay'
6521            }).html('Changer de relais'))).insertAfter($inputCarrier.parents('.line_carrier').find('.carrier_name > span'));
6522          }
6523        });
6524        break;
6525      case typeof mondialrelay !== typeof undefined && mondialrelay === '1':
6526        $.fancybox.open({
6527          href: '/page/choice_relay_mondialrelay.php?value=' + $carrier.val() + '&address=' + address_delivery + '&zip_code=' + zip_code_delivery + '&city=' + city_delivery + '&country=' + country_delivery + '&t=' + new Date().getTime(),
6528          type: 'iframe',
6529          padding: 5,
6530          beforeClose: function () {
6531            var contentIframe = $("iframe.fancybox-iframe").contents(),
6532              radio_relay = $(contentIframe).find('[name=relay]:checked'),
6533              addressRelay = $(radio_relay).closest('.block-mondialrelay__list__item__label').find('.block-mondialrelay__list__item__label__address').html();
6534            $('[name=form-order] [name="mondialrelay_id_' + $inputCarrier.attr('data-product-group') + '"]').remove();
6535            $('[name=form-order]').append($('<input />').attr({
6536              'name': 'mondialrelay_id_' + $inputCarrier.attr('data-product-group'),
6537              'type': 'hidden',
6538              'value': $(radio_relay).val()
6539            }));
6540            $inputCarrier.closest('.line_carrier').find('.information-relay').show().html(addressRelay);
6541            if ($inputCarrier.parents('.line_carrier').find('.change_mondialrelay_relay').length) {
6542              $inputCarrier.parents('.line_carrier').find('.change_mondialrelay_relay').parent().remove();
6543            }
6544            $($('<span />', {
6545              'style': 'display: block;'
6546            }).html($('<a />').attr({
6547              'href': '#',
6548              'class': 'change_mondialrelay_relay'
6549            }).html('Changer de relais'))).insertAfter($inputCarrier.parents('.line_carrier').find('.carrier_name > span'));
6550          }
6551        });
6552        break;
6553      case typeof choiceDisponibility !== typeof undefined && choiceDisponibility === '1':
6554        $.fancybox.open({
6555          href: '/page/choice_disponibility.php?value=' + $carrier.val() + '&t=' + new Date().getTime(),
6556          type: 'iframe',
6557          padding: 5,
6558          beforeClose: function () {
6559            var contentIframe = $("iframe.fancybox-iframe").contents(),
6560              $radio_disponibility = $(contentIframe).find('[name=disponibility]:checked'),
6561              information_disponibility = $radio_disponibility.attr('data-label-hour');
6562            $('[name=form-order] [name="disponibility_' + $inputCarrier.attr('data-product-group') + '"]').remove();
6563            $('[name=form-order]').append($('<input />').attr({
6564              'name': 'disponibility_' + $inputCarrier.attr('data-product-group'),
6565              'type': 'hidden',
6566              'value': $radio_disponibility.val()
6567            }));
6568            $inputCarrier.closest('.line_carrier').find('.information-relay').show().html(information_disponibility);
6569            if ($inputCarrier.parents('.line_carrier').find('.change_disponibility').length) {
6570              $inputCarrier.parents('.line_carrier').find('.change_disponibility').parent().remove();
6571            }
6572            $($('<span />', {
6573              'style': 'display: block;'
6574            }).html($('<a />').attr({
6575              'href': '#',
6576              'class': 'change_disponibility'
6577            }).html('Changer de créneau'))).insertAfter($inputCarrier.parents('.line_carrier').find('.carrier_name > span'));
6578          }
6579        });
6580        break;
6581    }
6582  }
6583  let loadCarriers = debounce(function () {
6584    if ($('#finish').length == 0) {
6585      return false;
6586    }
6587    cart_step_3.find('.content-payment-carrier-ttc').hide();
6588    cart_step_3.find('.content-payment-carrier-ttc .total-carrier-ttc').html('');
6589    cart_step_3.find('.content-payment-carrier-ttc .total-carrier-insurance').html('');
6590    var society_delivery = $('[name=nom_societe]').val(),
6591      lastname_delivery = $('[name=nom]').val(),
6592      firstname_delivery = $('[name=prenom]').val(),
6593      address_delivery = $('[name=adresse]').val(),
6594      zip_code_delivery = $('[name=cp]').val(),
6595      city_delivery = $('[name=ville]').val(),
6596      country_delivery = $('[name=pays]').val(),
6597      iso_code_country_delivery = $('[name=pays] option[value="' + country_delivery + '"]').attr('data-iso-code');
6598    if ($('[name=address_billing_same_delivery]:checked').val() == 0) {
6599      lastname_delivery = $('[name=nom_livraison]').val();
6600      society_delivery = $('[societe_livraison]').val();
6601      firstname_delivery = $('[name=prenom_livraison]').val();
6602      address_delivery = $('[name=adresse_livraison]').val();
6603      zip_code_delivery = $('[name=cp_livraison]').val();
6604      city_delivery = $('[name=ville_livraison]').val();
6605      country_delivery = $('[name=pays_livraison]').val(), iso_code_country_delivery = $('[name=pays_livraison] option[value="' + country_delivery + '"]').attr('data-iso-code');
6606    }
6607    var content_loader = $('<div />', {
6608      'class': 'bloc-total-loader',
6609      'html': $('<i />', {
6610        'class': 'fa fa-spinner fa-spin'
6611      })
6612    });
6613    $('.content-carriers').html(content_loader).removeClass('content-carriers-none');
6614    $.ajax({
6615      type: "POST",
6616      url: "/ajax/minisite/panier/get_carrier.php",
6617      data: {
6618        'society_delivery': society_delivery,
6619        'lastname_delivery': lastname_delivery,
6620        'firstname_delivery': firstname_delivery,
6621        'address_delivery': address_delivery,
6622        'zip_code_delivery': zip_code_delivery,
6623        'city_delivery': city_delivery,
6624        'country_delivery': country_delivery,
6625        'iso_code_country_delivery': iso_code_country_delivery
6626      },
6627      dataType: 'json',
6628      success: function (json) {
6629        if (json.hasOwnProperty('reload')) {
6630          location.reload();
6631        }
6632        if (json.hasOwnProperty('carriers') && json.carriers.length > 0) {
6633          var tplCarriers = '',
6634            priceCarrier,
6635            aInformationCarrierProducts = [],
6636            canAutoSelected = json.hasOwnProperty('haveUniqShipping') && json.haveUniqShipping;
6637          haveUniqShipping = json.hasOwnProperty('haveUniqShipping') && json.haveUniqShipping;
6638          var isChecked = false;
6639          $('.content-carriers').html('');
6640          var iterator = 0;
6641          $.each(json.carriers, function (indexCarrierGroup, item) {
6642            tplCarriers += '<div class="content-carriers__item">';
6643            iterator++;
6644            if (json.carriers.length > 1) {
6645              aInformationCarrierProducts = [];
6646              if (json.hasOwnProperty('products') && json.products[indexCarrierGroup]) {
6647                $.each(json.products[indexCarrierGroup], function (productKey, productLabel) {
6648                  aInformationCarrierProducts.push(productLabel);
6649                });
6650              }
6651              tplCarriers += '<div class="content-carriers__label"><i class="fa fa-truck"></i> ' + _lang.get('Livraison') + ' ' + iterator + ' :</div>';
6652              if (aInformationCarrierProducts.length) {
6653                tplCarriers += '<div class="content-carriers__products">' + aInformationCarrierProducts.join(', ') + '</div>';
6654              }
6655            }
6656            tplCarriers += '<ul>';
6657            $.each(item, function (index, value) {
6658              var data_attr = '',
6659                optionsInput = '';
6660              if (Object.keys(value._dateAttr).length > 0) {
6661                $.each(value._dateAttr, function (index, value) {
6662                  data_attr += ' data-' + index + '="' + value + '"';
6663                });
6664              }
6665              if (Object.keys(value._dataOptions).length > 0) {
6666                $.each(value._dataOptions, function (index, value) {
6667                  optionsInput += ' ' + index + '="' + value + '"';
6668                });
6669              }
6670              if (value._isCmonSiteRelay) {
6671                data_attr += ' data-cmonsite-relay="1"';
6672              } else {
6673                data_attr += ' data-cmonsite-relay="0"';
6674              }
6675              var logoTransporteur,
6676                insuranceBlock = '';
6677              if (value._logo) {
6678                logoTransporteur = '<div class="logo-carrier" style="background-image: url(' + value._logo + ');"></div>';
6679              } else {
6680                logoTransporteur = '<div class="logo-carrier-none"><i class="fa fa-truck"></i></div>';
6681              }
6682              if (value._hasInsurance) {
6683                insuranceBlock += '' + '<div class="insurance-block col s12" style="margin: 0;display:none;">' + '<div class="insurance-block__label row">' + '<div class="col s2">&nbsp;' + '</div>' + '<div class="col s7">' + '<input class="checkbox_insurance" value="1" style="margin-top: 2px;display: inline-block" type="checkbox" name="insurance_' + indexCarrierGroup + '_' + value._id + '" data-price="' + value._priceInsurance + '" data-price-format="' + value._priceInsuranceFormat + '" />' + lang_assurer_mon_colis + (value._detailInsurance !== '' ? ' ( ' + value._detailInsurance + ' )' : '') + ' ' + '</div>' + '<div class="col s3" style="text-align: right""><span style="padding-right: 11px;"> + ' + value._priceInsuranceFormat + ' </span></div>' + '</label>' + '</div>';
6684              }
6685              priceCarrier = value._priceFormat;
6686
6687              /* Reduction "frais de port" d'un code Pro : annoncer l'avantage sur la ligne,
6688                 avant meme que le transporteur soit selectionne. Renseigne par
6689                 ajax/minisite/panier/get_carrier.php, uniquement sur un envoi unique. */
6690              var priceCarrierBlock,
6691                discountCarrierMessage = '';
6692              if (value._priceAfterDiscountFormat) {
6693                priceCarrierBlock = '<span class="carrier_price__before" style="text-decoration: line-through;">' + priceCarrier.toString().replace('.00', '') + '</span>' + '<span class="carrier_price__after">' + value._priceAfterDiscountFormat.toString().replace('.00', '') + '</span>';
6694                /* Pas de rangee grid vide quand le prix remise se suffit a lui-meme */
6695                if (value._discountShippingLabel) {
6696                  discountCarrierMessage = '<div class="col s12 carrier-discount-message">' + value._discountShippingLabel + '</div>';
6697                }
6698              } else {
6699                priceCarrierBlock = '<span>' + (value._price == null ? '' : priceCarrier.toString().replace('.00', '')) + '</span>';
6700              }
6701              tplCarriers += '<li class="line_carrier">' + '<label>' + '<div class="col xs3 s2"><input class="radio_carrier" data-product-group="' + indexCarrierGroup + '" ' + (isChecked ? 'checked' : '') + ' ' + optionsInput + ' ' + data_attr + ' type="radio" data-price="' + value._price + '"  data-price-format="' + value._priceFormat + '" name="carrier[' + indexCarrierGroup + ']" value="' + value._id + '" />' + logoTransporteur + '</div>' + '<div class="col xs9 s7 carrier_name"><span>' + value._name + '</span>' + '</div>' + '<div class="col s3 carrier_price">' + priceCarrierBlock + '</div>' + insuranceBlock + '<div class="col s12 transporteur-message">' + value._message + '</div>' + '<div class="col s12 information-relay" style="display:none;"></div>' + '</label>' + '</li>';
6702            });
6703            tplCarriers += '</ul>';
6704            tplCarriers += '</div>';
6705            $('.content-carriers').append(tplCarriers);
6706            tplCarriers = '';
6707          });
6708          if (haveUniqShipping) {
6709            var $radioCarrierUniq = $('.content-carriers').find('.radio_carrier');
6710            if ($radioCarrierUniq.length === 1) {
6711              var $container = $('.block-info-commande'),
6712                $optionCountry = $container.find('[name="pays"] option[value="' + $container.find('[name="pays"]').val() + '"]');
6713              if ($('[name="address_billing_same_delivery"]:checked').val() === '0') {
6714                $optionCountry = $container.find('[name="pays_livraison"] option[value="' + $container.find('[name="pays_livraison"]').val() + '"]');
6715              }
6716              $radioCarrierUniq.prop('checked', true).trigger('change', [{
6717                'calculatePriceParams': {
6718                  'countryIsoTax': $optionCountry.attr('data-iso-code')
6719                }
6720              }]);
6721              isChecked = true;
6722            }
6723          }
6724        } else {
6725          $('.content-carriers').html($('<p />').html(MessageNoTransporteur)).addClass('content-carriers-none');
6726          //$('.block-payment-mode').hide();
6727          //$('#finish [type="submit"]').prop('disabled', true);
6728        }
6729        if (!isChecked) {
6730          var $containerInfoCommande = $('.block-info-commande'),
6731            $optionCountryInfoCommande = $containerInfoCommande.find('[name="pays"] option[value="' + $containerInfoCommande.find('[name="pays"]').val() + '"]');
6732          if ($('[name="address_billing_same_delivery"]:checked').val() === '0') {
6733            $optionCountryInfoCommande = $containerInfoCommande.find('[name="pays_livraison"] option[value="' + $containerInfoCommande.find('[name="pays_livraison"]').val() + '"]');
6734          }
6735          calculatePrice({
6736            'countryIsoTax': $optionCountryInfoCommande.attr('data-iso-code')
6737          });
6738        }
6739      }
6740    });
6741  }, 500);
6742  $(".template_flux_panier .various").on('click', function () {
6743    var $item = $(this);
6744    if ($item.hasClass('fancybox.iframe')) {
6745      var urlApi = null,
6746        url = $item.attr('href');
6747      switch (true) {
6748        case /^\/(?![\/])/.test(url):
6749          urlApi = new URL(url, window.location.origin);
6750          break;
6751        case url.indexOf(window.location.origin) === 0:
6752          urlApi = new URL(url);
6753          break;
6754      }
6755      if (urlApi !== null) {
6756        if (urlApi.search === '') {
6757          urlApi.search = '?isIframe=1';
6758        } else {
6759          urlApi.search = '&isIframe=1';
6760        }
6761        $.fancybox({
6762          'minHeight': '400',
6763          'type': 'iframe',
6764          'href': urlApi.pathname + urlApi.search
6765        });
6766        return false;
6767      }
6768    }
6769    $item.fancybox({
6770      minHeight: '400'
6771    });
6772    return false;
6773  });
6774  $body.on('click', '.line_carrier .insurance-block__label', function (e) {
6775    var $self = $(this),
6776      $checkbox = $self.find('.checkbox_insurance');
6777    if ($(e.target).hasClass('checkbox_insurance')) {
6778      calculatePrice();
6779      return true;
6780    }
6781    if ($checkbox.is(':checked')) {
6782      $checkbox.prop('checked', false);
6783    } else {
6784      $checkbox.prop('checked', true);
6785    }
6786    calculatePrice();
6787  });
6788  const optionOrderSubmit = {
6789    'PayPalCardFields': null
6790  };
6791  async function formOrderSubmit(...parameters) {
6792    const e = parameters.pop();
6793    const optionParameter = parameters.pop();
6794    const option = Object.assign({}, optionOrderSubmit, optionParameter);
6795    var $form = $('[name=form-order]'),
6796      resultValidFormOrder = validFormOrder();
6797    if ($('.block-payment-mode').hasClass('hide')) {
6798      return resultValidFormOrder;
6799    }
6800    switch (true) {
6801      case window.paypal && window.paypal.Buttons && typeof PayPalUseInContext !== 'undefined' && PayPalUseInContext && $('[name=moyenspaiements]:checked').val() === 'paypal_api':
6802        if (!resultValidFormOrder) {
6803          e.preventDefault();
6804        }
6805        return resultValidFormOrder;
6806        // removed by dead control flow
6807{}
6808      case window.paypal && window.paypal.HostedFields && option.PayPalCardFields !== null && $('[name=moyenspaiements]:checked').val() === 'paypal_cb':
6809        var state = option.PayPalCardFields.getState();
6810        var formValid = Object.keys(state.fields).every(function (key) {
6811          return state.fields[key].isValid;
6812        });
6813        if (resultValidFormOrder && formValid) {
6814          $('.flux-panier-container').waitMe();
6815          if ($form.find('.block-payment-mode').hasClass('hide')) {
6816            return true;
6817          }
6818          e.preventDefault();
6819          option.PayPalCardFields.submit({
6820            contingencies: ['SCA_ALWAYS']
6821          }).then(function (payload) {
6822            var formData = new FormData();
6823            formData.append('paypal_id_order', paypalHostedFieldsOrderId);
6824            return fetch('/ajax/minisite/payment/paypal/capture.php', {
6825              method: 'post',
6826              body: formData
6827            }).then(function (res) {
6828              return res.json();
6829            }).then(function (response) {
6830              switch (response.status) {
6831                case 'success':
6832                  location.href = response.href;
6833                  break;
6834                default:
6835                  switch (true) {
6836                    case response.hasOwnProperty('paypalIssueError'):
6837                      $('.flux-panier-container').waitMe('hide');
6838                      var $dangerPayPalError = $('<div />', {
6839                          'class': 'alert alert-danger text-center',
6840                          'html': response.error
6841                        }),
6842                        $paiementchoix = $('#paiementchoix');
6843                      $paiementchoix.prepend($dangerPayPalError);
6844                      $("html, body").animate({
6845                        scrollTop: $paiementchoix.offset().top - 180
6846                      }, 500, 'swing');
6847                      setTimeout(function () {
6848                        $dangerPayPalError.slideUp('slow', function () {
6849                          $(this).remove();
6850                        });
6851                      }, 5000);
6852                      break;
6853                    case response.hasOwnProperty('href'):
6854                      location.href = response.href;
6855                      break;
6856                    default:
6857                      $('.flux-panier-container').waitMe('hide');
6858                      var $item = $('<div />', {
6859                        'class': 'item',
6860                        'html': response.error
6861                      });
6862                      $('.payment_item_information__paypal_cb__notification').prepend($item);
6863                      setTimeout(function () {
6864                        $item.slideUp('slow', function () {
6865                          $(this).remove();
6866                        });
6867                      }, 8000);
6868                  }
6869              }
6870            });
6871          }).catch(error => {
6872            $('.flux-panier-container').waitMe('hide');
6873            var $dangerPayPalError = $('<div />', {
6874                'class': 'alert alert-danger text-center',
6875                'html': _lang.get('Nous n\'arrivons pas à finaliser le paiement via ce mode de paiement, nous vous conseillons d\'utiliser un autre mode de mode de paiement.')
6876              }),
6877              $paymentItemPayPalCbNotification = $('.payment_item_information__paypal_cb__notification');
6878            $paymentItemPayPalCbNotification.prepend($dangerPayPalError);
6879            setTimeout(function () {
6880              $paymentItemPayPalCbNotification.slideUp(function () {
6881                $(this).html('');
6882              });
6883            }, 6000);
6884          });
6885        }
6886        e.preventDefault();
6887        return false;
6888        // removed by dead control flow
6889{}
6890      case typeof mollie_compoment !== 'undefined' && mollie_compoment && $('[name=moyenspaiements]:checked').val() === 'mollie_creditcard':
6891        if (resultValidFormOrder) {
6892          $('.flux-panier-container').waitMe();
6893          if ($form.find('.block-payment-mode').hasClass('hide')) {
6894            return true;
6895          }
6896          e.preventDefault();
6897          var $containerNotification = $form.find('.payment_item_information__mollie_creditcard__notification');
6898          $containerNotification.html('');
6899          const {
6900            token,
6901            error
6902          } = await mollie.createToken();
6903          if (error) {
6904            // Something wrong happened while creating the token. Handle this situation gracefully.
6905            $containerNotification.html($('<div />', {
6906              'class': 'alert alert-danger',
6907              'html': error.message
6908            }));
6909            $('.flux-panier-container').waitMe('hide');
6910            return false;
6911          }
6912          $.ajax({
6913            url: "/paniercommande.php",
6914            data: $form.serialize() + '&submit=1&ajax=1',
6915            method: 'POST',
6916            dataType: 'json',
6917            success: function (data) {
6918              switch (data.status) {
6919                case 'reload':
6920                  location.reload();
6921                  break;
6922                case 'success':
6923                  $.ajax({
6924                    url: '/ajax/minisite/payment/mollie/valid.php',
6925                    type: 'POST',
6926                    dataType: 'json',
6927                    data: {
6928                      'reference': data.reference,
6929                      'token_acompte': data.token_acompte,
6930                      'token': token
6931                    },
6932                    success: function (response) {
6933                      switch (response.status) {
6934                        case 'requires_action':
6935                          break;
6936                        case 'success':
6937                          location.href = response.redirect;
6938                          break;
6939                        case 'redirect':
6940                          location.href = response.redirect;
6941                          break;
6942                        case 'error':
6943                          $('.flux-panier-container').waitMe('hide');
6944                          $containerNotification.html($('<div />', {
6945                            'class': 'alert alert-danger',
6946                            'html': response.error
6947                          }));
6948                          break;
6949                      }
6950                    }
6951                  });
6952                  break;
6953                case 'cancel':
6954                  location.href = data.url;
6955                  break;
6956                case 'error':
6957                  location.href = '/paniercommande.php#information';
6958                  break;
6959              }
6960            },
6961            error: function (e) {}
6962          });
6963        }
6964        e.preventDefault();
6965        return false;
6966        // removed by dead control flow
6967{}
6968      default:
6969        if (resultValidFormOrder) {
6970          $('.flux-panier-container').waitMe();
6971        }
6972    }
6973    if (!resultValidFormOrder) {
6974      e.preventDefault();
6975    }
6976    return resultValidFormOrder;
6977  }
6978  $body.on('submit', '[name=form-order]', formOrderSubmit);
6979
6980  // $body.on('submit', '[name=form-order]', function (event) {
6981  //
6982  // });
6983
6984  var $moyenspaiements_checked = $('[name=moyenspaiements]:checked');
6985  if ($moyenspaiements_checked.length) {
6986    $moyenspaiements_checked.trigger('change');
6987  }
6988  if (window.paypal && window.paypal.HostedFields) {
6989    var paypalHostedFieldsOrderId;
6990    paypal.HostedFields.render({
6991      createOrder: function (data, actions) {
6992        var formOrder = new FormData(document.querySelector('[name=form-order]'));
6993        formOrder.append('submit', '1');
6994        formOrder.append('ajax', '1');
6995        return fetch('/paniercommande.php', {
6996          method: "POST",
6997          body: formOrder
6998        }).then(function (res) {
6999          return res.json();
7000        }).then(function (orderData) {
7001          paypalHostedFieldsOrderId = orderData.token;
7002          return orderData.token;
7003        });
7004      },
7005      styles: {
7006        '.valid': {
7007          color: 'green'
7008        },
7009        '.invalid': {
7010          color: 'red'
7011        }
7012      },
7013      fields: {
7014        number: {
7015          selector: "#paypal-card-number",
7016          placeholder: "4111 1111 1111 1111"
7017        },
7018        cvv: {
7019          selector: "#paypal-card-cvc",
7020          placeholder: "123"
7021        },
7022        expirationDate: {
7023          selector: "#paypal-card-expiry",
7024          placeholder: "MM/YY"
7025        }
7026      }
7027    }).then(function (cardFields) {
7028      $body.off('submit', '[name=form-order]', formOrderSubmit);
7029      $body.on('submit', '[name=form-order]', formOrderSubmit.bind(null, {
7030        'PayPalCardFields': cardFields
7031      }));
7032    });
7033  }
7034  if (window.paypal && window.paypal.Buttons && typeof PayPalUseInContext !== 'undefined' && PayPalUseInContext) {
7035    paypal.Buttons({
7036      style: {
7037        layout: 'horizontal',
7038        pill: 'pill',
7039        label: 'pay'
7040      },
7041      onInit: function (data, actions) {
7042        // Disable the buttons
7043        actions.disable();
7044        if (validFormOrder(false)) {
7045          actions.enable();
7046        }
7047
7048        // Listen for changes to the checkbox
7049        document.querySelector('[name="form-order"]').addEventListener('change', function (event) {
7050          if (validFormOrder(false)) {
7051            actions.enable();
7052          } else {
7053            actions.disable();
7054          }
7055        });
7056      },
7057      onClick: function () {
7058        $('[name="form-order"]').trigger('change');
7059        validFormOrder();
7060      },
7061      onCancel: function (data) {
7062        var formData = new FormData();
7063        formData.append('paypal_id_order', data.orderID);
7064        return fetch('/ajax/minisite/payment/paypal/cancel.php', {
7065          method: 'post',
7066          body: formData
7067        }).then(function (res) {
7068          return res.json();
7069        }).then(function (response) {
7070          if (response.hasOwnProperty('href')) {
7071            location.href = response.href;
7072          } else {
7073            $('.flux-panier-container').waitMe('hide');
7074          }
7075        });
7076      },
7077      onError: function (err) {
7078        location.href = '/paiement-site/error/';
7079      },
7080      // Call your server to set up the transaction
7081      createOrder: function (data, actions) {
7082        $('.flux-panier-container').waitMe();
7083        var formOrder = new FormData(document.querySelector('[name=form-order]'));
7084        formOrder.append('submit', '1');
7085        formOrder.append('ajax', '1');
7086        return fetch('/paniercommande.php', {
7087          method: "POST",
7088          body: formOrder
7089        }).then(function (res) {
7090          return res.json();
7091        }).then(function (orderData) {
7092          switch (true) {
7093            case orderData.hasOwnProperty('status') && orderData.status === 'error':
7094              //alert(orderData.data.msg_error);
7095              return null;
7096              // removed by dead control flow
7097{}
7098          }
7099          return orderData.token;
7100        });
7101      },
7102      onApprove: function (data, actions) {
7103        var formData = new FormData();
7104        formData.append('paypal_id_order', data.orderID);
7105        formData.append('payer_id', data.payerID);
7106        return fetch('/ajax/minisite/payment/paypal/capture.php', {
7107          method: 'post',
7108          body: formData
7109        }).then(function (res) {
7110          return res.json();
7111        }).then(function (response) {
7112          if (response.hasOwnProperty('paypalIssueError')) {
7113            $('.flux-panier-container').waitMe('hide');
7114            var $dangerPayPalError = $('<div />', {
7115                'class': 'alert alert-danger text-center',
7116                'html': response.error
7117              }),
7118              $paiementchoix = $('#paiementchoix');
7119            $paiementchoix.prepend($dangerPayPalError);
7120            $("html, body").animate({
7121              scrollTop: $paiementchoix.offset().top - 180
7122            }, 500, 'swing');
7123            setTimeout(function () {
7124              $dangerPayPalError.slideUp('slow', function () {
7125                $(this).remove();
7126              });
7127            }, 5000);
7128          } else {
7129            location.href = response.href;
7130          }
7131        });
7132      }
7133    }).render('#paypal-button-container');
7134  }
7135  $body.on('change', '[name=moyenspaiements]', function (event) {
7136    var $self = $(this),
7137      $parent = $self.closest('.line_payment'),
7138      value = $self.val(),
7139      $btn_PAYPAL = $('#paypal-button-container'),
7140      $order_confirm = $('#confirmBtn');
7141    if (event && event.originalEvent) {
7142      trackCartStepEvent('add_payment_info', {
7143        payment_type: value
7144      });
7145    }
7146    $('#paiementchoix label').removeClass('selected').parent().removeClass('selected');
7147    $self.parent('label').addClass('selected').closest('li').addClass('selected').closest('ul').addClass('group-selected');
7148    $('.line_payment').removeClass('line_payment__checked');
7149    $parent.addClass('line_payment__checked');
7150    switch (value) {
7151      case 'paypal_api':
7152        if (window.paypal && window.paypal.Buttons && typeof PayPalUseInContext !== 'undefined' && PayPalUseInContext) {
7153          $btn_PAYPAL.show();
7154          $order_confirm.hide();
7155        }
7156        break;
7157      case 'mollie_creditcard':
7158        mollieMountComponents();
7159        if (window.paypal && window.paypal.Buttons && typeof PayPalUseInContext !== 'undefined' && PayPalUseInContext) {
7160          $btn_PAYPAL.hide();
7161          $order_confirm.show();
7162        }
7163        break;
7164      default:
7165        if (window.paypal && window.paypal.Buttons && typeof PayPalUseInContext !== 'undefined' && PayPalUseInContext) {
7166          $btn_PAYPAL.hide();
7167          $order_confirm.show();
7168        }
7169    }
7170  });
7171  function validFormOrder(showAlert) {
7172    if (typeof showAlert === 'undefined') {
7173      showAlert = true;
7174    }
7175
7176    /* valider les champs */
7177    var radio_payment_mode = $('[name=moyenspaiements]:checked'),
7178      checkbox_cgv = $('[name=cgv]'),
7179      $containerCarrier = $('.content-carriers__item'),
7180      resultShipping = true;
7181
7182    /* Tester si on utilise la livraison */
7183    if ($useShipping > 0) {
7184      $containerCarrier.each(function (index, itemCarrier) {
7185        var $itemCarrier = $(itemCarrier),
7186          $radioCarriers = $itemCarrier.find('.radio_carrier'),
7187          $radioCarrierChecked = $itemCarrier.find('.radio_carrier:checked');
7188        if ($radioCarriers.length > 0 && $radioCarrierChecked.length === 0) {
7189          resultShipping = false;
7190        }
7191      });
7192    }
7193    if (resultShipping === false) {
7194      if (showAlert) {
7195        $("html, body").animate({
7196          scrollTop: $('.block-info-payment_carriers').offset().top - 100
7197        }, 500, 'swing');
7198        alert('Veuillez sélectionner un moyen de livraison.');
7199      }
7200      return false;
7201    }
7202    if ($('[name=moyenspaiements]').length > 0 && radio_payment_mode.length === 0) {
7203      if (showAlert) {
7204        $("html, body").animate({
7205          scrollTop: $('.block-payment-mode').offset().top - 100
7206        }, 500, 'swing');
7207        alert('Veuillez sélectionner un moyen de paiement.');
7208      }
7209      return false;
7210    }
7211    if (checkbox_cgv.length > 0 && !checkbox_cgv.is(':checked')) {
7212      if (showAlert) {
7213        alert('Veuillez valider les conditions génénerales de vente.');
7214      }
7215      return false;
7216    }
7217    if (!$('[name="form-order"]').validationEngine('validate')) {
7218      if (!showAlert) {
7219        $('[name="form-order"]').validationEngine('hide');
7220      }
7221      return false;
7222    }
7223    let formOrderQuery = document.querySelector('[name="form-order"]');
7224    if (!formOrderQuery.checkValidity()) {
7225      if (showAlert) {
7226        formOrderQuery.reportValidity();
7227      }
7228      return false;
7229    }
7230    if (checkbox_cgv.length === 0 || $(checkbox_cgv).length > 0 && checkbox_cgv.is(':checked')) {
7231      if (typeof fbq === 'function') {
7232        var facebookParameter = {};
7233        fbq('track', 'InitiateCheckout');
7234      }
7235      if (typeof pintrk === 'function') {
7236        //pintrk('track', 'custom', {value: 'initiatecheckout'});
7237      }
7238      return true;
7239    }
7240    return false;
7241  }
7242  function trackCartProductEvent(eventName, product, quantity) {
7243    if (!window.CmonSiteTracking || !product) {
7244      return;
7245    }
7246    var qty = Math.abs(quantity),
7247      price = parseFloat(product.price) || 0,
7248      item = {
7249        item_id: product.id,
7250        item_name: product.title_without_variation,
7251        item_category: product.category,
7252        quantity: qty,
7253        price: price
7254      };
7255
7256    /* Cles optionnelles GA4 : omises plutot que null */
7257    if (product.brand) {
7258      item.item_brand = product.brand;
7259    }
7260    if (product.variation) {
7261      item.item_variant = product.variation;
7262    }
7263    window.CmonSiteTracking.event(eventName, {
7264      currency: product.currency,
7265      value: +(price * qty).toFixed(2),
7266      items: [item]
7267    });
7268  }
7269  function trackCartStepEvent(eventName, extraParams) {
7270    if (!window.CmonSiteTracking || !window.CmonSiteTrackingCart || !window.CmonSiteTrackingCart.items || !window.CmonSiteTrackingCart.items.length) {
7271      return false;
7272    }
7273    window.CmonSiteTracking.event(eventName, $.extend({}, window.CmonSiteTrackingCart, extraParams || {}));
7274    return true;
7275  }
7276  function changeQuantityProduct(idProduct, idProductAttribute, quantity) {
7277    $.ajax({
7278      type: "POST",
7279      url: "/ajax/minisite/panier/add_product_quantity.php",
7280      data: {
7281        'id_product': idProduct,
7282        'id_product_attribute': idProductAttribute,
7283        'quantity': quantity
7284      },
7285      dataType: 'json',
7286      success: function (json) {
7287        if (json.hasOwnProperty('reload')) {
7288          location.reload();
7289        }
7290        reloadResumeAndPaymentCartAjax();
7291        reloadBlockReductionCode();
7292        calculatePrice();
7293      }
7294    });
7295  }
7296  function changeQuantityProductByKey(key, quantity) {
7297    $('.resume-cart-products.table').waitMe();
7298    $.ajax({
7299      type: "POST",
7300      url: "/ajax/minisite/panier/add_product_quantity.php",
7301      data: {
7302        'key': key,
7303        'quantity': quantity
7304      },
7305      dataType: 'json',
7306      success: function (json) {
7307        if (json.hasOwnProperty('reload')) {
7308          location.reload();
7309        }
7310        setTimeout(function () {
7311          $('.resume-cart-products.table').waitMe('hide');
7312        }, 500);
7313        if (json.hasOwnProperty('product') && json.product !== null) {
7314          trackCartProductEvent(quantity < 0 ? 'remove_from_cart' : 'add_to_cart', json.product, quantity);
7315        }
7316        reloadResumeAndPaymentCartAjax();
7317        reloadBlockReductionCode();
7318        loadCarriers();
7319        $('#panier').trigger('reload');
7320      }
7321    });
7322  }
7323  function changeQuantityProductBookingByKey(key, quantity) {
7324    $('.resume-cart-products.table').waitMe();
7325    $.ajax({
7326      type: "POST",
7327      url: "/ajax/minisite/panier/add_booking_quantity.php",
7328      data: {
7329        'key': key,
7330        'quantity': quantity
7331      },
7332      dataType: 'json',
7333      success: function (response) {
7334        setTimeout(function () {
7335          $('.resume-cart-products.table').waitMe('hide');
7336        }, 500);
7337        switch (true) {
7338          case response.hasOwnProperty('status') && response.status === 'reload':
7339            location.reload();
7340            break;
7341          case response.hasOwnProperty('status') && response.status === 'error':
7342            break;
7343          case response.hasOwnProperty('status') && response.status === 'success':
7344            reloadResumeAndPaymentCartAjax();
7345            reloadBlockReductionCode();
7346            calculatePrice();
7347            $('#panier').trigger('reload');
7348            break;
7349        }
7350      }
7351    });
7352  }
7353  function deleteProduct(idProduct, idProductAttribute) {
7354    $.ajax({
7355      type: "POST",
7356      url: "/ajax/minisite/panier/remove_product.php",
7357      data: {
7358        'id_product': idProduct,
7359        'id_product_attribute': idProductAttribute
7360      },
7361      dataType: 'json',
7362      success: function (json) {
7363        if (json.hasOwnProperty('reload')) {
7364          location.reload();
7365        }
7366        $('.content-payment-product-ht .total-product-ht').html(json.total_product_ht);
7367        $('.content-payment-tva .total-product-tva').html(json.tva);
7368        $('.content-payment-product-global .total-product-global').html(json.total_product_ttc);
7369        $('.content-payment-global .total-global').html(json.total_global);
7370        $useShipping = json.useShipping;
7371        if ($useShipping == 0) {
7372          $('.use_shipping').hide();
7373        }
7374        reloadBlockReductionCode();
7375        reloadResumeAndPaymentCartAjax();
7376        calculatePrice();
7377      }
7378    });
7379  }
7380  function deleteProductByKey(key) {
7381    $('.resume-cart-products.table').waitMe();
7382    $.ajax({
7383      type: "POST",
7384      url: "/ajax/minisite/panier/remove_product.php",
7385      data: {
7386        'key': key
7387      },
7388      dataType: 'json',
7389      success: function (json) {
7390        if (json.hasOwnProperty('reload')) {
7391          location.reload();
7392        }
7393        if (json.hasOwnProperty('productData') && json.productData !== null) {
7394          trackCartProductEvent('remove_from_cart', json.productData, json.productData.quantity);
7395        }
7396        $('.content-payment-product-ht .total-product-ht').html(json.total_product_ht);
7397        $('.content-payment-tva .total-product-tva').html(json.tva);
7398        $('.content-payment-product-global .total-product-global').html(json.total_product_ttc);
7399        $('.content-payment-global .total-global').html(json.total_global);
7400        $useShipping = json.useShipping;
7401        if ($useShipping == 0) {
7402          $('.use_shipping').hide();
7403        }
7404        setTimeout(function () {
7405          $('.resume-cart-products.table').waitMe('hide');
7406        }, 500);
7407        reloadBlockReductionCode();
7408        reloadResumeAndPaymentCartAjax();
7409        loadCarriers();
7410        calculatePrice();
7411        $('#panier').trigger('reload');
7412      }
7413    });
7414  }
7415  var can_calculate_price = true;
7416  function calculatePrice(params) {
7417    if (!can_calculate_price) {
7418      return;
7419    }
7420    can_calculate_price = false;
7421    var haveInformationToCarrierPrice = false,
7422      amountCarrier = -1,
7423      amountCarrierInsurance = 0;
7424    $('.bloc-total-loader').show();
7425    $('.bloc-total').hide();
7426    if (typeof params === 'undefined') {
7427      params = {};
7428    }
7429    var $containerCarriers = $('.content-carriers__item');
7430    if ($containerCarriers.length) {
7431      var amountCarrierTmp = 0,
7432        haveCarrierChecked = false,
7433        carriers = [];
7434      $containerCarriers.each(function (index, itemCarrier) {
7435        var $itemCarrier = $(itemCarrier),
7436          $radioCarrierChecked = $itemCarrier.find('.radio_carrier:checked'),
7437          $insuranceItem;
7438        if ($radioCarrierChecked.length) {
7439          haveCarrierChecked = true;
7440          amountCarrierTmp += parseFloat($radioCarrierChecked.attr('data-price'));
7441          $insuranceItem = $('[name=insurance_' + $radioCarrierChecked.attr('data-product-group') + '_' + $radioCarrierChecked.val() + ']:checked');
7442          carriers.push({
7443            'carrier': $radioCarrierChecked.val(),
7444            'amount': parseFloat($radioCarrierChecked.attr('data-price'))
7445          });
7446          if ($insuranceItem.length) {
7447            amountCarrierInsurance += parseFloat($insuranceItem.attr('data-price'));
7448          }
7449        }
7450      });
7451      if (haveCarrierChecked) {
7452        amountCarrier = amountCarrierTmp;
7453      } else {
7454        /* Tester si nous avons seulement un groupe de transporteur */
7455        if ($containerCarriers.length === 1) {
7456          $containerCarriers.each(function (index, itemCarrier) {
7457            var $itemCarrier = $(itemCarrier),
7458              $radioCarrier = $itemCarrier.find('.radio_carrier');
7459            if ($radioCarrier.length === 1) {
7460              if (priceShippingEstimatedWithClickAndCollect || !priceShippingEstimatedWithClickAndCollect && $radioCarrier.attr('data-cmonsite-relay') === '0') {
7461                haveUniqShipping = true;
7462              } else {
7463                $radioCarrier = null;
7464              }
7465            } else {
7466              if (showShippingEstimatedWithSeveralCarrier) {
7467                if (priceShippingEstimatedWithClickAndCollect) {
7468                  $radioCarrier = $itemCarrier.find('.radio_carrier').first();
7469                } else {
7470                  $radioCarrier = $itemCarrier.find('.radio_carrier[data-cmonsite-relay="0"]').first();
7471                }
7472                if ($radioCarrier.length) {
7473                  haveInformationToCarrierPrice = true;
7474                }
7475              } else {
7476                $radioCarrier = null;
7477              }
7478            }
7479            if ($radioCarrier !== null && $radioCarrier.length) {
7480              /* Faire comme si le client avais sélectionné ce transporteur */
7481              amountCarrier = parseFloat($radioCarrier.attr('data-price'));
7482              carriers.push({
7483                'carrier': $radioCarrier.val(),
7484                'amount': parseFloat($radioCarrier.attr('data-price'))
7485              });
7486            }
7487          });
7488        }
7489      }
7490    }
7491    $.ajax({
7492      type: "POST",
7493      url: "/ajax/minisite/panier/calculate_price.php",
7494      data: {
7495        'carriers': carriers,
7496        'amountCarrier': amountCarrier,
7497        'amountCarrierInsurance': amountCarrierInsurance,
7498        'options_price': options_price,
7499        'options_price_currency': options_price_currency,
7500        'force_country_tax': params.hasOwnProperty('countryIsoTax') ? params.countryIsoTax : null
7501      },
7502      dataType: 'json',
7503      success: function (json) {
7504        can_calculate_price = true;
7505        if (json.hasOwnProperty('reload')) {
7506          location.reload();
7507        }
7508        if (json.haveMinOrderAmount) {
7509          cart_step_1.find('.block-min-order-amount').html(json.minOrderAmountText);
7510          cart_step_1.find('.block-min-order-amount').show();
7511          cart_step_1.find('.block-order-btn').hide();
7512          $('.side-tabs.etapes').hide();
7513        } else {
7514          cart_step_1.find('.block-min-order-amount').html('');
7515          cart_step_1.find('.block-min-order-amount').hide();
7516          cart_step_1.find('.block-order-btn').show();
7517          $('.side-tabs.etapes').show();
7518        }
7519        cart_step_1.find('.content-payment-reduction').hide();
7520        cart_step_1.find('.content-payment-carrier-ttc').hide();
7521        cart_step_1.find('.content-payment-product-global').hide();
7522        cart_step_2.find('.content-payment-reduction').hide();
7523        cart_step_2.find('.content-payment-carrier-ttc').hide();
7524        cart_step_2.find('.content-payment-product-global').hide();
7525        $('.content-payment-reduction-carrier').hide();
7526        if (json.have_discount_code) {
7527          cart_step_3.find('.content-payment-reduction').show();
7528          cart_step_3.find('.content-payment-product-global').show();
7529          if (haveUniqShipping) {
7530            cart_step_1.find('.content-payment-reduction').show();
7531            cart_step_1.find('.content-payment-product-global').show();
7532            cart_step_2.find('.content-payment-reduction').show();
7533            cart_step_2.find('.content-payment-product-global').show();
7534          }
7535          if (amountCarrier === -1 && json.discount_code_type === 'fdp') {
7536            cart_step_3.find('.content-payment-reduction .total-reduction').html('Vous devez sélectionner un transporteur.');
7537            if (haveUniqShipping) {
7538              cart_step_1.find('.content-payment-reduction .total-reduction').html('Vous devez sélectionner un transporteur.');
7539              cart_step_2.find('.content-payment-reduction .total-reduction').html('Vous devez sélectionner un transporteur.');
7540            }
7541          } else {
7542            if (json.have_discount_code_without_shipping || amountC
7542arrier >= 0) {
7543              cart_step_1.find('.content-payment-reduction').show();
7544              cart_step_1.find('.content-payment-product-global').show();
7545              cart_step_1.find('.content-payment-reduction .total-reduction').html(json.reduction_whitout_shipping);
7546              cart_step_2.find('.content-payment-reduction').show();
7547              cart_step_2.find('.content-payment-product-global').show();
7548              cart_step_2.find('.content-payment-reduction .total-reduction').html(json.reduction_whitout_shipping);
7549            }
7550            if (json.discount_code_type === 'fdp') {
7551              cart_step_1.find('.content-payment-reduction').show();
7552              cart_step_1.find('.content-payment-reduction .total-reduction').html('Vous devez sélectionner un transporteur.');
7553              cart_step_2.find('.content-payment-reduction').show();
7554              cart_step_2.find('.content-payment-reduction .total-reduction').html('Vous devez sélectionner un transporteur.');
7555            }
7556
7557            /* PRD 32 R6 : la ligne "Réduction" ne porte plus la réduction sur le port */
7558            cart_step_3.find('.content-payment-reduction .total-reduction').html(json.reduction_whitout_shipping);
7559            if (!json.have_discount_code_without_shipping) {
7560              cart_step_3.find('.content-payment-reduction').hide();
7561            }
7562            if (haveUniqShipping || haveInformationToCarrierPrice) {
7563              cart_step_1.find('.content-payment-reduction .total-reduction').html(json.reduction_whitout_shipping);
7564              cart_step_2.find('.content-payment-reduction .total-reduction').html(json.reduction_whitout_shipping);
7565              if (!json.have_discount_code_without_shipping) {
7566                cart_step_1.find('.content-payment-reduction').hide();
7567                cart_step_2.find('.content-payment-reduction').hide();
7568              }
7569            }
7570
7571            /* PRD 32 R6 : ligne dédiée "Réduction frais de port", même condition que la ligne port */
7572            if (json.have_discount_code_carrier && amountCarrier >= 0) {
7573              cart_step_3.find('.content-payment-reduction-carrier').show();
7574              cart_step_3.find('.content-payment-reduction-carrier .total-reduction-carrier').html(json.reduction_carrier);
7575              if (haveUniqShipping || haveInformationToCarrierPrice) {
7576                cart_step_1.find('.content-payment-reduction-carrier').show();
7577                cart_step_1.find('.content-payment-reduction-carrier .total-reduction-carrier').html(json.reduction_carrier);
7578                cart_step_2.find('.content-payment-reduction-carrier').show();
7579                cart_step_2.find('.content-payment-reduction-carrier .total-reduction-carrier').html(json.reduction_carrier);
7580              }
7581            }
7582          }
7583        } else {
7584          $('.content-payment-reduction').hide();
7585          $('.content-payment-reduction-carrier').hide();
7586          $("#code_reduc").removeAttr("disabled");
7587          $('#submit_reduc_code').show();
7588          $('#submit_remove_reduc_code').hide();
7589        }
7590        if (amountCarrier >= 0) {
7591          cart_step_1.find('.content-payment-carrier-ttc').show();
7592          cart_step_2.find('.content-payment-carrier-ttc').show();
7593          cart_step_3.find('.content-payment-carrier-ttc').show();
7594
7595          /* Port entierement offert : une seule ligne "Frais de port" avec le montant
7596             barre, au lieu d'une ligne port et d'une ligne reduction qui s'annulent.
7597             Une reduction partielle garde les deux lignes. */
7598          var amountCarrierHtml = json.amountCarrier;
7599          if (json.carrier_fully_discounted) {
7600            amountCarrierHtml = '<span class="total-carrier-ttc__before" style="text-decoration: line-through;">' + json.amountCarrier + '</span>' + '<span class="total-carrier-ttc__after">' + json.amountCarrierAfterDiscount + '</span>';
7601            $('.content-payment-reduction-carrier').hide();
7602          }
7603          cart_step_1.find('.total-carrier-ttc').html(amountCarrierHtml);
7604          cart_step_2.find('.total-carrier-ttc').html(amountCarrierHtml);
7605          cart_step_3.find('.total-carrier-ttc').html(amountCarrierHtml);
7606        } else {
7607          cart_step_1.find('.content-payment-carrier-ttc').hide();
7608          cart_step_2.find('.content-payment-carrier-ttc').hide();
7609          cart_step_3.find('.content-payment-carrier-ttc').hide();
7610        }
7611
7612        /* Etape 1 */
7613        cart_step_1.find('.content-payment-product-ht .total-product-ht').html(json.total_product_ht);
7614        cart_step_1.find('.content-payment-tva .total-product-tva').html(json.tva);
7615        cart_step_1.find('.content-payment-product-global .total-product-global').html(json.total_product_ttc);
7616        cart_step_1.find('.content-payment-global .total-global').html(json.total_global_without_shipping);
7617        if (cart_step_1.find('.content-payment-advance-payment').length) {
7618          cart_step_1.find('.content-payment-advance-payment .total-advance-payment').html(json.total_advance_payment);
7619        }
7620        if (haveUniqShipping || haveInformationToCarrierPrice) {
7621          cart_step_1.find('.content-payment-global .total-global').html(json.total_global);
7622        }
7623        cart_step_1.find('.content-payment-carrier-ttc .total-carrier-insurance').html('');
7624
7625        /* Etape 2 */
7626        cart_step_2.find('.content-payment-product-ht .total-product-ht').html(json.total_product_ht);
7627        cart_step_2.find('.content-payment-tva .total-product-tva').html(json.tva);
7628        cart_step_2.find('.content-payment-product-global .total-product-global').html(json.total_product_ttc);
7629        cart_step_2.find('.content-payment-global .total-global').html(json.total_global_without_shipping);
7630        if (cart_step_2.find('.content-payment-advance-payment').length) {
7631          cart_step_2.find('.content-payment-advance-payment .total-advance-payment').html(json.total_advance_payment);
7632        }
7633        if (haveUniqShipping || haveInformationToCarrierPrice) {
7634          cart_step_2.find('.content-payment-global .total-global').html(json.total_global);
7635        }
7636        cart_step_2.find('.content-payment-carrier-ttc .total-carrier-insurance').html('');
7637
7638        /* Etape 3 */
7639        cart_step_3.find('.content-payment-product-ht .total-product-ht').html(json.total_product_ht);
7640        cart_step_3.find('.content-payment-tva .total-product-tva').html(json.tva);
7641        cart_step_3.find('.content-payment-product-global .total-product-global').html(json.total_product_ttc);
7642        cart_step_3.find('.content-payment-global .total-global').html(json.total_global);
7643        if (cart_step_1.find('.content-payment-advance-payment').length) {
7644          cart_step_3.find('.content-payment-advance-payment .total-advance-payment').html(json.total_advance_payment);
7645        }
7646        cart_step_3.find('.content-payment-carrier-ttc .total-carrier-insurance').html('');
7647        if (amountCarrierInsurance > 0) {
7648          cart_step_3.find('.content-payment-carrier-ttc .total-carrier-insurance').html(' + ' + json.amountC
7648arrierInsurance);
7649        }
7650        var $itemPaymentMode = cart_step_3.find('.block-payment-mode');
7651        if (!json.show_payment_mode) {
7652          $itemPaymentMode.addClass('hide');
7653          var $firstPaymentMode = $itemPaymentMode.find('[name="moyenspaiements"]').filter(function () {
7654            var $self = $(this);
7655            switch ($self.val()) {
7656              case 'alma2':
7657              case 'alma3':
7658              case 'alma4':
7659              case 'payplugOneyX3':
7660              case 'payplugOneyX4':
7661                return false;
7662                // removed by dead control flow
7663{}
7664              default:
7665                return true;
7666            }
7667          }).first();
7668          if ($firstPaymentMode.length) {
7669            $firstPaymentMode.prop('checked', true);
7670            $firstPaymentMode.trigger('change');
7671          }
7672        } else {
7673          $itemPaymentMode.removeClass('hide');
7674        }
7675        $('.bloc-total-loader').hide();
7676        $('.bloc-total').show();
7677        if (stickyStep2 !== null) {
7678          stickyStep2.destroy();
7679        }
7680        if (sticky !== null) {
7681          sticky.destroy();
7682        }
7683        stickyStep2 = new Sticky('.block-info-commande__sticky');
7684        sticky = new Sticky('.block-info-payment__sticky');
7685        var optionsPaymentMode = {
7686          'currencyIsoCode': json.current_currency_iso_code,
7687          'amountProductDefaultCurrency': json.total_ttc_product_on_default_currency
7688        };
7689        refreshPaymentMode(optionsPaymentMode);
7690        if (json.hasOwnProperty('resume_cart') && json.hasOwnProperty('payment_cart') && json.hasOwnProperty('gift_discount_advanced')) {
7691          reloadResumeAndPaymentCart(json.resume_cart, json.payment_cart, json.gift_discount_advanced);
7692        }
7693
7694        /* */
7695        if (window.paypal && window.paypal.Messages) {
7696          if (cart_step_1.find('.pp-pay-later-message').length === 0) {
7697            $('<div />', {
7698              'class': 'pp-pay-later-message'
7699            }).insertAfter(cart_step_1.find('.container-order-btn'));
7700          }
7701          if (cart_step_3.find('.pp-pay-later-message-payment').length === 0) {
7702            $('<div />', {
7703              'class': 'pp-pay-later-message-payment'
7704            }).insertAfter(cart_step_3.find('.container-order-btn'));
7705          }
7706          window.paypal.Messages({
7707            amount: json.total_ttc_product_on_current_currency,
7708            placement: 'cart',
7709            style: {
7710              layout: "text",
7711              text: {
7712                align: 'center',
7713                color: ppStyleTextColor,
7714                size: 14
7715              }
7716            }
7717          }).render(".pp-pay-later-message");
7718          window.paypal.Messages({
7719            amount: json.total_ttc_product_on_current_currency,
7720            placement: 'payment',
7721            style: {
7722              layout: "text",
7723              text: {
7724                align: 'center',
7725                color: ppStyleTextColor,
7726                size: 14
7727              }
7728            }
7729          }).render(".pp-pay-later-message-payment");
7730        }
7731        if (typeof mountAlmaPayMessage === "function") {
7732          mountAlmaPayMessage(Math.round(json.total_ttc_product_on_current_currency * 100));
7733        }
7734        const freeShippingProgress = document.querySelectorAll('.free-shipping-progress');
7735        freeShippingProgress.forEach(element => {
7736          element.innerHTML = '';
7737        });
7738        if (json.hasOwnProperty('free_shipping_progress_added')) {
7739          if (json.free_shipping_progress_added.status) {
7740            const view = {
7741              title: json.free_shipping_progress_added.title,
7742              percentage: json.free_shipping_progress_added.data.percentage,
7743              reached: json.free_shipping_progress_added.data.reached,
7744              message: json.free_shipping_progress_added.message,
7745              success_message: json.free_shipping_progress_added.success_message
7746            };
7747            freeShippingProgress.forEach(element => {
7748              element.insertAdjacentHTML('beforeend', mustache__WEBPACK_IMPORTED_MODULE_2__["default"].render(json.free_shipping_progress_added.template, view));
7749            });
7750          } else {}
7751        }
7752        if (json.hasOwnProperty('free_shipping_progress')) {
7753          if (json.free_shipping_progress.status) {
7754            const view = {
7755              title: json.free_shipping_progress.title,
7756              percentage: json.free_shipping_progress.data.percentage,
7757              reached: json.free_shipping_progress.data.reached,
7758              message: json.free_shipping_progress.message,
7759              success_message: json.free_shipping_progress.success_message
7760            };
7761            freeShippingProgress.forEach(element => {
7762              element.insertAdjacentHTML('beforeend', mustache__WEBPACK_IMPORTED_MODULE_2__["default"].render(json.free_shipping_progress.template, view));
7763            });
7764          } else {}
7765        }
7766      }
7767    });
7768  }
7769
7770  /**
7771   * Rafraichir les modes de paiement
7772   * @param options
7773   * @return {boolean}
7774   */
7775  function refreshPaymentMode(options) {
7776    if (typeof options === 'undefined') {
7777      return false;
7778    }
7779    if (!options.hasOwnProperty('currencyIsoCode')) {
7780      return false;
7781    }
7782    if (!options.hasOwnProperty('amountProductDefaultCurrency')) {
7783      return false;
7784    }
7785    var countryBilling = $('[name=pays]').val(),
7786      isoCodeCountryBilling = $('[name=pays] option[value="' + countryBilling + '"]').attr('data-iso-code'),
7787      countryDelivery = countryBilling,
7788      isoCodeCountryDelivery = isoCodeCountryBilling;
7789    if ($('[name=address_billing_same_delivery]:checked').val() == 0) {
7790      countryDelivery = $('[name=pays_livraison]').val();
7791      isoCodeCountryDelivery = $('[name=pays_livraison] option[value="' + countryDelivery + '"]').attr('data-iso-code');
7792    }
7793    var $paymentModeCheckbox = $('[name="moyenspaiements"]');
7794    if ($paymentModeCheckbox.length) {
7795      $paymentModeCheckbox.each(function (index, checkbox) {
7796        var $checkbox = $(checkbox),
7797          $itemCheckbox = $checkbox.closest('li'),
7798          minAmount = $checkbox.attr('data-min-amount'),
7799          maxAmount = $checkbox.attr('data-max-amount'),
7800          countryAvailable = null;
7801        if (typeof $checkbox.attr('data-country-available') !== 'undefined') {
7802          countryAvailable = JSON.parse($checkbox.attr('data-country-available'));
7803        }
7804        switch ($checkbox.val()) {
7805          case 'alma2':
7806          case 'alma3':
7807          case 'alma4':
7808            if (options.currencyIsoCode === 'EUR') {
7809              if (typeof minAmount !== 'undefined' && typeof maxAmount !== "undefined") {
7810                if (minAmount <= options.amountProductDefaultCurrency && options.amountProductDefaultCurrency <= maxAmount) {
7811                  $itemCheckbox.removeClass('hide');
7812                } else {
7813                  $itemCheckbox.addClass('hide');
7814                }
7815              }
7816            } else {
7817              $itemCheckbox.addClass('hide');
7818            }
7819            break;
7820          case 'stripe-afterpay':
7821            if (countryAvailable !== null && countryAvailable.includes(isoCodeCountryBilling)) {
7822              if (typeof minAmount !== 'undefined' && typeof maxAmount !== "undefined") {
7823                if (minAmount <= options.amountProductDefaultCurrency && options.amountProductDefaultCurrency <= maxAmount) {
7824                  $itemCheckbox.removeClass('hide');
7825                } else {
7826                  $itemCheckbox.addClass('hide');
7827                }
7828              }
7829            } else {
7830              $itemCheckbox.addClass('hide');
7831            }
7832            break;
7833          default:
7834            if (typeof minAmount !== 'undefined' && typeof maxAmount !== "undefined") {
7835              if (minAmount <= options.amountProductDefaultCurrency && options.amountProductDefaultCurrency <= maxAmount) {
7836                $itemCheckbox.removeClass('hide');
7837              } else {
7838                $itemCheckbox.addClass('hide');
7839              }
7840            }
7841        }
7842      });
7843    }
7844  }
7845  $body.on('click', '#resume .up-quantity-booking-service,#resume .down-quantity-booking-service', function () {
7846    var $self = $(this),
7847      sign = $self.attr('data-sign'),
7848      key = $self.attr('data-key');
7849    $('.resume-cart-products.table').waitMe();
7850    $.ajax({
7851      type: 'POST',
7852      url: '/ajax/minisite/panier/add_booking_quantity.php',
7853      dataType: 'json',
7854      data: {
7855        key: key,
7856        sign: sign,
7857        quantity: '1'
7858      },
7859      success: function (response) {
7860        setTimeout(function () {
7861          $('.resume-cart-products.table').waitMe('hide');
7862        }, 500);
7863        switch (true) {
7864          case response.hasOwnProperty('status') && response.status === 'reload':
7865            location.reload();
7866            break;
7867          case response.hasOwnProperty('status') && response.status === 'error':
7868            break;
7869          case response.hasOwnProperty('status') && response.status === 'success':
7870            reloadResumeAndPaymentCartAjax();
7871            reloadBlockReductionCode();
7872            calculatePrice();
7873            $('#panier').trigger('reload');
7874            break;
7875        }
7876      }
7877    });
7878  });
7879  function debounce(func, wait, immediate) {
7880    var timeout;
7881    return function () {
7882      var context = this,
7883        args = arguments;
7884      var later = function () {
7885        timeout = null;
7886        if (!immediate) func.apply(context, args);
7887      };
7888      var callNow = immediate && !timeout;
7889      clearTimeout(timeout);
7890      timeout = setTimeout(later, wait);
7891      if (callNow) func.apply(context, args);
7892    };
7893  }
7894  ;
7895  var $lastInputQuantity = null;
7896  var debounceResumeUpdateQtyCart = debounce(function updateQtyCart(val, el) {
7897    var prefix = "#resume ";
7898    var $el = $(el),
7899      id = $el.attr('name'),
7900      key = $el.attr('data-key'),
7901      productType = $el.attr('data-product-type');
7902    var exp = new RegExp("^[0-9]+$");
7903    var $input = $(prefix + 'input[name=' + id + ']');
7904    $lastInputQuantity = $input;
7905    if (val !== '') {
7906      if (exp.test(val) === true) {
7907        var hidden = $(prefix + 'input[name=' + id + '_hidden]').val(),
7908          input = $input.val();
7909        var QtyToUp = parseInt(input) - parseInt(hidden);
7910        if (QtyToUp !== 0) {
7911          if (productType === 'booking') {
7912            changeQuantityProductBookingByKey(key, QtyToUp);
7913          } else {
7914            changeQuantityProductByKey(key, QtyToUp);
7915          }
7916        }
7917      } else {
7918        $input.val($(prefix + 'input[name=' + id + '_hidden]').val());
7919      }
7920    }
7921  }, 850);
7922  $body.on('reloadResumeAndPaymentCart', function () {
7923    if ($lastInputQuantity !== null) {
7924      var elem = $('#resume [name="' + $lastInputQuantity.attr('name') + '"]')[0],
7925        caretPos = 99;
7926      if (elem) {
7927        if (typeof elem.createTextRange !== 'undefined') {
7928          var range = elem.createTextRange();
7929          range.move('character', caretPos);
7930          range.select();
7931        } else {
7932          if (typeof elem.selectionStart !== 'undefined') elem.selectionStart = caretPos;
7933          elem.focus();
7934        }
7935      }
7936      $lastInputQuantity = null;
7937    }
7938  }).on('keydown paste cut input', '#resume .resume_quantity_input', function () {
7939    var $self = $(this);
7940    debounceResumeUpdateQtyCart($self.val(), $self);
7941  });
7942  $body.on('click', '#resume .up-quantity', function () {
7943    var self = $(this),
7944      key = $(self).attr('data-key');
7945    changeQuantityProductByKey(key, +1);
7946  });
7947  $body.on('click', '#resume .down-quantity', function () {
7948    var self = $(this),
7949      key = $(self).attr('data-key');
7950    if (parseInt($('#resume .label-quantity').text()) < 1) {
7951      deleteProductByKey(key);
7952    } else {
7953      changeQuantityProductByKey(key, -1);
7954    }
7955  });
7956  $body.on('click', '#resume .remove-product', function () {
7957    var self = $(this),
7958      key = $(self).attr('data-key');
7959    deleteProductByKey(key);
7960  });
7961  $body.on('touchstart click', '#resume #submit_remove_reduc_code', function () {
7962    $.ajax({
7963      type: "POST",
7964      url: "/ajax/minisite/panier/remove_discount_code.php",
7965      dataType: 'json',
7966      success: function (json) {
7967        $('#code_reduc').removeAttr('disabled');
7968        $("#code_reduc").val('');
7969        $('#submit_reduc_code').show();
7970        $('#submit_remove_reduc_code').hide();
7971        $("#code_reponse").empty();
7972        $("#code_reponse").removeAttr('style');
7973        calculatePrice();
7974      }
7975    });
7976  });
7977  var flag = false;
7978  $('.template-panier-1').css('display', 'none');
7979  var $payment_mode = $('#paiementchoix [name="moyenspaiements"]');
7980  if ($payment_mode.length === 1) {
7981    $payment_mode.prop('checked', true);
7982    $payment_mode.trigger('change');
7983  }
7984
7985  /* Panier Responsive */
7986  var responsive_livraison_status = false;
7987  $(window).on('load', function () {
7988    function generateResponsiveTable() {
7989      if ($(window).width() < 484) {
7990        if (!responsive_livraison_status) {
7991          var tables = $(document.getElementById('resume')).find('.resume-cart-products');
7992          tables.each(function (t, table) {
7993            table = $(table);
7994            var line = table.find('.resume-cart-item');
7995            var head = table.find('.resume-cart-legend .row');
7996            head.children('.col').each(function (index, elem) {
7997              var text = $(elem).text();
7998              line.each(function (i, tr) {
7999                var td = $(tr).children('.col').eq(index);
8000                if (text !== '') {
8001                  td.html('<span class="panier-entete">
8001' + text + ': </span>' + td.html());
8002                }
8003              });
8004            });
8005          });
8006          responsive_livraison_status = true;
8007        }
8008      } else {
8009        $('span.panier-entete').remove();
8010        responsive_livraison_status = false;
8011      }
8012    }
8013    generateResponsiveTable();
8014    $(document.getElementById('resume')).on('isUpdate', function () {
8015      responsive_livraison_status = false;
8016      generateResponsiveTable();
8017    });
8018    $(window).resize(function () {
8019      generateResponsiveTable();
8020    });
8021  });
8022  function getModalConfirmConvertPoints() {
8023    var $modalConfirmConvertPoints = $('#modal-confirm-convert-points');
8024    if ($modalConfirmConvertPoints.length === 0) {
8025      $modalConfirmConvertPoints = $('<div />', {
8026        'class': 'modal fade',
8027        'id': 'modal-confirm-convert-points',
8028        'tabindex': '-1',
8029        'role': 'dialog'
8030      }).append($('<div />', {
8031        'class': 'modal-dialog',
8032        'role': 'document'
8033      }).append($('<div />', {
8034        'class': 'modal-content'
8035      }).append($('<div />', {
8036        'class': 'modal-header'
8037      }).append($('<button />', {
8038        'type': 'button',
8039        'class': 'close',
8040        'data-dismiss': 'modal',
8041        'aria-label': 'Close',
8042        'html': $('<span />', {
8043          'aria-hidden': 'true',
8044          'html': '&times;'
8045        })
8046      })).append($('<h4 />', {
8047        'class': 'modal-title'
8048      }))).append($('<div />', {
8049        'class': 'modal-body'
8050      }))));
8051      $body.find('#main-conteneur').append($modalConfirmConvertPoints);
8052    }
8053    return $modalConfirmConvertPoints;
8054  }
8055  function getModalGiftProductFidelityPoints() {
8056    var $modalGiftProductFidelityPoints = $('#modal-gift-product-fidelity-points');
8057    if ($modalGiftProductFidelityPoints.length === 0) {
8058      $modalGiftProductFidelityPoints = $('<div />', {
8059        'class': 'modal fade',
8060        'id': 'modal-gift-product-fidelity-points',
8061        'tabindex': '-1',
8062        'role': 'dialog'
8063      }).append($('<div />', {
8064        'class': 'modal-dialog',
8065        'role': 'document'
8066      }).append($('<div />', {
8067        'class': 'modal-content'
8068      }).append($('<form />', {
8069        'name': 'form-gift-product'
8070      }).append($('<div />', {
8071        'class': 'modal-header'
8072      }).append($('<button />', {
8073        'type': 'button',
8074        'class': 'close',
8075        'data-dismiss': 'modal',
8076        'aria-label': 'Close',
8077        'html': $('<span />', {
8078          'aria-hidden': 'true',
8079          'html': '&times;'
8080        })
8081      })).append($('<h4 />', {
8082        'class': 'modal-title',
8083        'html': ''
8084      }))).append($('<div />', {
8085        'class': 'modal-body'
8086      })))));
8087      $body.find('#main-conteneur').append($modalGiftProductFidelityPoints);
8088    }
8089    return $modalGiftProductFidelityPoints;
8090  }
8091  $body.on('click', '.convert-fidelity-points', function () {
8092    var $self = $(this),
8093      $container = $('.block-reduction'),
8094      $modalConfirmConvertPoints = getModalConfirmConvertPoints();
8095    $.ajax({
8096      url: "/ajax/minisite/fidelity/getNbPoints.php",
8097      type: "GET",
8098      dataType: "json",
8099      success: function (response) {
8100        $container.waitMe('hide');
8101        if (response.hasOwnProperty('status')) {
8102          switch (true) {
8103            case response.status === 'reload':
8104              location.reload();
8105              break;
8106            case response.status === 'error':
8107              alert(response.error);
8108              break;
8109            case response.status === 'success':
8110              $modalConfirmConvertPoints.find('.modal-title').html(_lang.get('Convertir vos') + ' ' + response.labelPoint + ' ' + _lang.get('en bon d\'achat'));
8111              var $modalConfirmConvertPointsBody = $modalConfirmConvertPoints.find('.modal-body'),
8112                information = _lang.get('Souhaitez-vous convertir vos {{points}} en bon d\'achat ?');
8113              information = information.replace('{{points}}', response.nbPoints + ' ' + response.labelPoint);
8114              $modalConfirmConvertPointsBody.html('');
8115              $modalConfirmConvertPointsBody.append($('<div />', {
8116                'class': 'modal__convert-points__information'
8117              }).html(information));
8118              $modalConfirmConvertPointsBody.append($('<div />', {
8119                'class': 'modal__convert-points__btn'
8120              }).append($('<button />', {
8121                'type': 'button',
8122                'class': 'button confirm-convert-points',
8123                'html': _lang.get('Convertir vos') + ' ' + response.labelPoint
8124              })));
8125              $modalConfirmConvertPoints.modal();
8126              break;
8127          }
8128        }
8129      }
8130    });
8131  }).on('click', '#modal-confirm-convert-points .confirm-convert-points', function () {
8132    var $container = getModalConfirmConvertPoints().find('.modal
8132-content');
8133    $container.waitMe();
8134    $.ajax({
8135      url: "/ajax/minisite/fidelity/convertPoints.php",
8136      type: "GET",
8137      dataType: "json",
8138      success: function (response) {
8139        $container.waitMe('hide');
8140        if (response.hasOwnProperty('status')) {
8141          switch (true) {
8142            case response.status === 'reload':
8143              location.reload();
8144              break;
8145            case response.status === 'error':
8146              alert(response.error);
8147              break;
8148            case response.status === 'success':
8149              getModalConfirmConvertPoints().modal('hide');
8150              setTimeout(function () {
8151                $.ajax({
8152                  type: "POST",
8153                  url: "/ajax/minisite/panier/add_discount_code.php",
8154                  dataType: 'json',
8155                  data: {
8156                    code_reduc: response.code
8157                  },
8158                  success: function (response) {
8159                    flag = false;
8160                    setTimeout(function () {
8161                      reloadBlockReductionCode(function () {
8162                        if (response.reload_cart) {
8163                          reloadResumeAndPaymentCart(response.resume_cart, response.payment_cart, response.gift_discount_advanced);
8164                        }
8165                        loadCarriers();
8166                      });
8167                    }, 0);
8168                  }
8169                });
8170              }, 0);
8171              break;
8172          }
8173        }
8174      }
8175    });
8176  }).on('click', '.gitf-product-fidelity-points', function () {
8177    var $self = $(this),
8178      $container = $('.block-reduction'),
8179      $modalGiftProductFidelityPoints = getModalGiftProductFidelityPoints();
8180    $container.waitMe();
8181    $.ajax({
8182      url: "/ajax/minisite/fidelity/getListGiftProducts.php",
8183      type: "GET",
8184      dataType: "json",
8185      success: function (response) {
8186        $container.waitMe('hide');
8187        if (response.hasOwnProperty('status')) {
8188          switch (true) {
8189            case response.status === 'reload':
8190              location.reload();
8191              break;
8192            case response.status === 'error':
8193              alert(response.error);
8194              break;
8195            case response.status === 'success':
8196              var $modalGiftProductFidelityPointsBody = $modalGiftProductFidelityPoints.find('.modal-body');
8197              $modalGiftProductFidelityPoints.find('.modal-title').html(_lang.get('Choisissez votre cadeau (solde : {{nbPoints}})').replace('{{nbPoints}}', response.nbPoints + ' ' + response.labelPoint));
8198              $modalGiftProductFidelityPointsBody.html('');
8199              if (response.giftProducts.length === 0) {} else {
8200                var $contentGiftProducts = $('<div />', {
8201                    'class': 'container-gift-products'
8202                  }),
8203                  information = _lang.get('Vous disposez de {{points}}.');
8204                information = information.replace('{{points}}', response.nbPoints + ' ' + response.labelPoint);
8205                $.each(response.giftProducts, function (index, giftProduct) {
8206                  var $radioId = $('<input />', {
8207                    'type': 'radio',
8208                    'id': 'gift_product_id_' + giftProduct.id,
8209                    'name': 'giftProduct[id]',
8210                    'value': giftProduct.id,
8211                    'required': 'required'
8212                  });
8213                  if (!giftProduct.available) {
8214                    $radioId.prop('disabled', true);
8215                  }
8216                  $contentGiftProducts.append($('<div />', {
8217                    'class': 'gift-product__item',
8218                    'for': 'gift_product_id_' + giftProduct.id
8219                  }).append($('<div />', {
8220                    'class': 'gift-product__item__img'
8221                  }).append($('<a />', {
8222                    'target': '_blank',
8223                    'href': giftProduct.link
8224                  }).append($('<div />', {
8225                    'class': 'product-img-square'
8226                  }).append($('<span />', {
8227                    'class': 'img-square'
8228                  }).append($('<span />', {
8229                    'class': 'img-square__content',
8230                    'html': $('<img />', {
8231                      'src': giftProduct.img
8232                    })
8233                  })))))).append($('<div />', {
8234                    'class': 'gift-product__item__title'
8235                  }).append($('<div />', {
8236                    'html': giftProduct.label
8237                  })).append($('<div />', {
8238                    'html': giftProduct.points
8239                  })).append($('<div />', {
8240                    'html': $('<button />', {
8241                      'class': 'button',
8242                      'name': 'giftProduct[btn]',
8243                      'type': 'button',
8244                      'value': giftProduct.id,
8245                      'html': _lang.get('Choisir ce cadeau')
8246                    })
8247                  }))));
8248                  if (!giftProduct.available) {
8249                    $contentGiftProducts.find('[name="giftProduct[btn]"][value="' + giftProduct.id + '"]').prop('disabled', true);
8250                  }
8251                });
8252                $modalGiftProductFidelityPointsBody.append($contentGiftProducts);
8253
8254                // $modalGiftProductFidelityPointsBody.append(
8255                //     $('<div />', {'class': 'gift-product__btn'})
8256                //         .append($('<button />', {'type': 'submit', 'class': 'button', 'name': 'giftProduct[submit]', 'value': '1', 'html': _lang.get('Choisir votre cadeau')}))
8257                // );
8258              }
8259              $modalGiftProductFidelityPoints.modal();
8260              break;
8261          }
8262        }
8263      }
8264    });
8265  }).on('click', '[name="giftProduct[btn]"]', function () {
8266    var $self = $(this),
8267      $form = $self.closest('.modal-body');
8268    if ($self.is(':disabled')) {
8269      return false;
8270    }
8271    $form.waitMe();
8272    $.ajax({
8273      url: "/ajax/minisite/fidelity/giftProductPoints.php",
8274      type: "POST",
8275      data: {
8276        id: $self.val()
8277      },
8278      dataType: "json",
8279      success: function (response) {
8280        $form.waitMe('hide');
8281        if (response.hasOwnProperty('status')) {
8282          switch (true) {
8283            case response.status === 'reload':
8284              location.reload();
8285              break;
8286            case response.status === 'error':
8287              alert(response.error);
8288              break;
8289            case response.status === 'success':
8290              getModalGiftProductFidelityPoints().modal('hide');
8291              setTimeout(function () {
8292                $.ajax({
8293                  type: "POST",
8294                  url: "/ajax/minisite/panier/add_discount_code.php",
8295                  dataType: 'json',
8296                  data: {
8297                    code_reduc: response.code
8298                  },
8299                  success: function (response) {
8300                    flag = false;
8301                    if (response.status === 'success') {
8302                      reloadBlockReductionCode(function () {
8303                        if (response.reload_cart) {
8304                          reloadResumeAndPaymentCart(response.resume_cart, response.payment_cart, response.gift_discount_advanced);
8305                        }
8306                        loadCarriers();
8307                      });
8308                    }
8309                  }
8310                });
8311              }, 0);
8312              break;
8313          }
8314        }
8315      }
8316    });
8317    return false;
8318  }).on('click', '[name=submit_code_reduc]', function () {
8319    var $block = $(this).closest('.block-reduction-code');
8320    var code_reduc = $block.find('[name=code_reduc]');
8321    if (!flag) {
8322      flag = true;
8323      var block_code_reduction_notification = $block.find(".block-code-reduction-notification");
8324      block_code_reduction_notification.html('');
8325      if (code_reduc.val() === "") {
8326        flag = false;
8327        block_code_reduction_notification.append($('<div />', {
8328          'class': 'alert alert-danger',
8329          'html': "Veuillez entrer un code !",
8330          'style': 'margin-top:10px;'
8331        }));
8332      } else {
8333        $.ajax({
8334          type: "POST",
8335          url: "/ajax/minisite/panier/add_discount_code.php",
8336          dataType: 'json',
8337          data: {
8338            code_reduc: code_reduc.val()
8339          },
8340          success: function (response) {
8341            flag = false;
8342            if (response.status === 'success') {
8343              reloadBlockReductionCode(function () {
8344                if (response.reload_cart) {
8345                  reloadResumeAndPaymentCart(response.resume_cart, response.payment_cart, response.gift_discount_advanced);
8346                }
8347                loadCarriers();
8348              });
8349            } else {
8350              block_code_reduction_notification.append($('<div />', {
8351                'class': 'alert alert-danger',
8352                'html': response.msg,
8353                'style': 'margin-top:10px;'
8354              }));
8355            }
8356          }
8357        });
8358      }
8359    }
8360    return false;
8361  }).on('click', '.add_code_reduc', function () {
8362    var self = $(this),
8363      id_code = self.attr('data-id');
8364    if (!flag) {
8365      flag = true;
8366      var block_code_reduction_notification = $(".block-code-reduction-notification");
8367      block_code_reduction_notification.html('');
8368      $.ajax({
8369        type: "POST",
8370        url: "/ajax/minisite/panier/add_discount_by_id_code.php",
8371        dataType: 'json',
8372        data: {
8373          id_code: id_code
8374        },
8375        success: function (response) {
8376          flag = false;
8377          if (response.status == 'success') {
8378            if (response.reload_cart) {
8379              reloadResumeAndPaymentCart(response.resume_cart, response.payment_cart, response.gift_discount_advanced);
8380            }
8381            reloadBlockReductionCode();
8382            loadCarriers();
8383          } else {
8384            block_code_reduction_notification.append($('<div />', {
8385              'class': 'alert alert-danger',
8386              'html': response.msg,
8387              'style': 'margin-top:10px;'
8388            }));
8389          }
8390        }
8391      });
8392    }
8393  }).on('click', '.remove_code_reduc', function () {
8394    var self = $(this),
8395      id_code = self.attr('data-id');
8396    if (!flag) {
8397      flag = true;
8398      var block_code_reduction_notification = $(".block-code-reduction-notification");
8399      block_code_reduction_notification.html('');
8400      $.ajax({
8401        type: "POST",
8402        url: "/ajax/minisite/panier/remove_discount_by_id_code.php",
8403        dataType: 'json',
8404        data: {
8405          id_code: id_code
8406        },
8407        success: function (response) {
8408          flag = false;
8409          if (response.status == 'success') {
8410            if (response.reload_cart) {
8411              reloadResumeAndPaymentCart(response.resume_cart, response.payment_cart, response.gift_discount_advanced);
8412            }
8413            reloadBlockReductionCode(function () {
8414              var block_code_reduction_notification = $(".block-code-reduction-notification");
8415              var alert = $('<div />', {
8416                'class': 'alert alert-success',
8417                'html': response.msg,
8418                'style': 'margin-top:10px;'
8419              });
8420              block_code_reduction_notification.append(alert);
8421              setTimeout(function () {
8422                alert.remove();
8423              }, 4000);
8424            });
8425            loadCarriers();
8426          } else {
8427            block_code_reduction_notification.append($('<div />', {
8428              'class': 'alert alert-danger',
8429              'html': response.msg,
8430              'style': 'margin-top:10px;'
8431            }));
8432          }
8433        }
8434      });
8435    }
8436  });
8437  function reloadResumeAndPaymentCartAjax() {
8438    $.ajax({
8439      type: "POST",
8440      url: "/ajax/minisite/panier/reload_block_resume_payment_cart.php",
8441      dataType: 'json',
8442      success: function (response) {
8443        if (response.status == 'success') {
8444          if (response.tracking_cart) {
8445            window.CmonSiteTrackingCart = response.tracking_cart;
8446          }
8447          reloadResumeAndPaymentCart(response.resume_cart, response.payment_cart, response.gift_discount_advanced);
8448        }
8449      }
8450    });
8451  }
8452  var panier = $(document.getElementById('panier')),
8453    isFirstUpdate = true;
8454  panier.on('isUpdate', function () {
8455    if (!isFirstUpdate) {
8456      reloadBlockReductionCode();
8457      reloadResumeAndPaymentCartAjax();
8458      loadCarriers();
8459    }
8460    isFirstUpdate = false;
8461  });
8462  function reloadResumeAndPaymentCart(resume_cart, payment_cart, gift_discount_advanced) {
8463    var $block_resume_cart = $('.block-resume-cart');
8464    var $block_payment_cart = $('.block-payment-cart');
8465    $block_resume_cart.html(resume_cart);
8466    $block_payment_cart.html(payment_cart);
8467    if ($('.block-resume-cart .resume-cart-item').length == 0) {
8468      location.reload();
8469    }
8470    if (typeof gift_discount_advanced !== 'undefined' && gift_discount_advanced !== lastGiftDiscountHtml) {
8471      lastGiftDiscountHtml = gift_discount_advanced;
8472
8473      // Le slider doit être détruit tant que son DOM est encore attaché, et sa
8474      // position relue pour la restaurer après le nouveau rendu du serveur.
8475      var giftDiscountIndex = destroyGiftDiscountSwiper();
8476      $('.gift-discount-advanced').html(gift_discount_advanced);
8477      loadGiftDiscountSwiper(giftDiscountIndex);
8478    }
8479    $body.trigger('reloadResumeAndPaymentCart');
8480  }
8481  function reloadBlockReductionCode(callback) {
8482    if (typeof callback == 'undefined') {
8483      callback = function () {};
8484    }
8485    $.ajax({
8486      type: "POST",
8487      url: "/ajax/minisite/panier/reload_block_reduction_code.php",
8488      dataType: 'json',
8489      success: function (response) {
8490        if (response.status === 'success') {
8491          $('.block-reduction').html(response.html);
8492          callback();
8493        }
8494      }
8495    });
8496  }
8497  function validFormAddress() {
8498    $('.form-group').removeClass('error');
8499    var fieldAddressBilling = ['nom', 'prenom', 'tel', 'adresse', 'cp', 'ville', 'pays'],
8500      fieldAddressDelivery = ['nom_livraison', 'prenom_livraison', 'tel_livraison', 'adresse_livraison', 'email_livraison', 'cp_livraison', 'ville_livraison', 'pays_livraison'],
8501      fieldAddressBillingError = [],
8502      fieldAddressDeliveryError = [];
8503    $.each(fieldAddressBilling, function (index, value) {
8504      if ($('[name=' + value + ']').validationEngine('validate')) {
8505        fieldAddressBillingError.push(value);
8506      }
8507    });
8508    if ($('[name=address_billing_same_delivery]:checked').val() == 0) {
8509      $.each(fieldAddressDelivery, function (index, value) {
8510        if ($('[name=' + value + ']').validationEngine('validate')) {
8511          fieldAddressDeliveryError.push(value);
8512        }
8513      });
8514    }
8515    if (fieldAddressBillingError.length == 0 && fieldAddressDeliveryError.length == 0) {
8516      return true;
8517    }
8518    $.each(fieldAddressBillingError, function (index, value) {
8519      $('[name=' + value + ']').parents('.form-group').addClass('error');
8520    });
8521    $.each(fieldAddressDeliveryError, function (index, value) {
8522      $('[name=' + value + ']').parents('.form-group').addClass('error');
8523    });
8524    var $firstBlockError = $('.cart-step-2').find('.form-group.error').first();
8525    if ($firstBlockError.length > 0) {
8526      $('html, body').animate({
8527        scrollTop: $firstBlockError.offset().top - 150
8528      }, 500);
8529    }
8530    return false;
8531  }
8532  function changeSideBar(href) {
8533    if ($(href).length > 0) {
8534      $('.contents-tabs .content-tab').removeClass('active');
8535      $(href).addClass('active');
8536      $('.side-tabs .element-sidebar, .side-tabs li').removeClass('active', 'step-done');
8537      $('.element-sidebar[href="' + href + '"]').addClass('active').closest('li').addClass('active').prevAll('li').addClass('step-done');
8538      $('html,body').animate({
8539        scrollTop: $(href).offset().top
8540      }, vitesse_scroll, function () {
8541        if (history.pushState) {
8542          history.pushState(null, null, href);
8543        } else {
8544          location.hash = href;
8545        }
8546      });
8547      return false;
8548    }
8549    return false;
8550  }
8551  function saveAddr(callback) {
8552    cart_step_2.waitMe();
8553    $.ajax({
8554      type: "POST",
8555      url: "/ajax/minisite/panier/save_addr.php",
8556      data: {
8557        'order_as_guest': $('.cart-step-2 [name="order_as_quest"]').length ? $('.cart-step-2 [name="order_as_quest"]').val() : 0,
8558        'birthday': $('.cart-step-2 #birthday').val(),
8559        'address_rgpd_checkbox': $('.cart-step-2 [name="address_rgpd_checkbox"]').is(':checked') ? 1 : null,
8560        'address_billing_same_delivery': $('.cart-step-2 [name="address_billing_same_delivery"]:checked').val(),
8561        'billing_address': {
8562          'billing_nom': $('.cart-step-2 #nom').val(),
8563          'billing_prenom': $('.cart-step-2 #prenom').val(),
8564          'billing_telephone': $('.cart-step-2 #tel').val(),
8565          'billing_adresse': $('.cart-step-2 #adresse').val(),
8566          'billing_code_postal': $('.cart-step-2 #cp').val(),
8567          'billing_ville': $('.cart-step-2 #ville').val(),
8568          'billing_pays': $('.cart-step-2 [name="pays"]').val(),
8569          'billing_commentaire': $('.cart-step-2 #commentaires').val()
8570        },
8571        'delivery_address': {
8572          'delivery_nom': $('.cart-step-2 #nom_livraison').val(),
8573          'delivery_societe': $('.cart-step-2 #societe_livraison').val(),
8574          'delivery_prenom': $('.cart-step-2 #prenom_livraison').val(),
8575          'delivery_telephone': $('.cart-step-2 #tel_livraison').val(),
8576          'delivery_adresse': $('.cart-step-2 #adresse_livraison').val(),
8577          'delivery_code_postal': $('.cart-step-2 #cp_livraison').val(),
8578          'delivery_ville': $('.cart-step-2 #ville_livraison').val(),
8579          'delivery_pays': $('.cart-step-2 [name="pays_livraison"]').val(),
8580          'delivery_commentaire': $('.cart-step-2 #commentaires_livraison').val()
8581        }
8582      },
8583      dataType: 'json',
8584      success: function (json) {
8585        if (json.hasOwnProperty('reload')) {
8586          location.reload();
8587        }
8588        var $addressNotification = $('.address-notification');
8589        $addressNotification.html('');
8590        switch (true) {
8591          case json.hasOwnProperty('reload'):
8592            location.reload();
8593            break;
8594          case json.hasOwnProperty('error'):
8595            cart_step_2.waitMe('hide');
8596            $addressNotification.html($('<div />', {
8597              'class': 'alert alert-danger',
8598              'html': json.error
8599            }));
8600            $('html, body').animate({
8601              scrollTop: $addressNotification.offset().top - 150
8602            }, 500);
8603            break;
8604          case json.hasOwnProperty('status') && json.status === 'success':
8605            if (json.hasOwnProperty('billing_pays')) {
8606              $('.cart-step-2 [name="pays"]').val(json.billing_pays);
8607            }
8608            if (json.hasOwnProperty('delivery_pays')) {
8609              $('.cart-step-2 [name="pays_livraison"]').val(json.delivery_pays);
8610            }
8611            cart_step_2.waitMe('hide');
8612            if (typeof callback === 'function') {
8613              callback();
8614            }
8615            reloadResumeAndPaymentCartAjax();
8616            break;
8617        }
8618      }
8619    });
8620  }
8621  $body.on('change', '.form-option-price', function () {
8622    calculOptions();
8623  });
8624  $body.on('click', '.payment_item__payment-token-remove', function () {
8625    var $self = $(this),
8626      $item = $self.closest('.payment_item');
8627    var $modalConfirmPaymentTokenRemove = getModalConfirmPaymentTokenRemove();
8628    $modalConfirmPaymentTokenRemove.find('[name="id_payment_token_remove"]').val($self.attr('data-token'));
8629    $modalConfirmPaymentTokenRemove.modal();
8630  }).on('submit', '[name="form-payment-token-remove"]', function (event) {
8631    event.preventDefault();
8632    var $form = $(this),
8633      token = $form.find('[name="id_payment_token_remove"]').val();
8634    $.ajax({
8635      type: "POST",
8636      url: "/ajax/minisite/payment_token/remove.php",
8637      data: {
8638        'token': $form.find('[name="id_payment_token_remove"]').val(),
8639        'page': 'order'
8640      },
8641      dataType: 'json',
8642      success: function (json) {
8643        switch (true) {
8644          case json.status === 'reload':
8645            location.reload();
8646            break;
8647          case json.status === 'redirect':
8648            location.href = json.redirect;
8649            break;
8650          case json.status === 'success':
8651            $('#paiementchoix .payment_item .payment_item__payment-token-remove[data-token="' + token + '"]').closest('.line_payment').remove();
8652            $form.waitMe('hide');
8653            var $modalConfirmPaymentTokenRemove = getModalConfirmPaymentTokenRemove();
8654            $modalConfirmPaymentTokenRemove.modal('hide');
8655            break;
8656        }
8657      }
8658    });
8659  });
8660  function getModalConfirmPaymentTokenRemove() {
8661    var $modalConfirmPaymentTokenRemove = $('#modal-confirm-payment-token-remove');
8662    if ($modalConfirmPaymentTokenRemove.length === 0) {
8663      $modalConfirmPaymentTokenRemove = $('<div />', {
8664        'class': 'modal fade',
8665        'id': 'modal-confirm-payment-token-remove',
8666        'tabindex': '-1',
8667        'role': 'dialog'
8668      }).append($('<div />', {
8669        'class': 'modal-dialog',
8670        'role': 'document'
8671      }).append($('<div />', {
8672        'class': 'modal-content'
8673      }).append($('<div />', {
8674        'class': 'modal-header'
8675      }).append($('<button />', {
8676        'type': 'button',
8677        'class': 'close',
8678        'data-dismiss': 'modal',
8679        'aria-label': 'Close',
8680        'html': $('<span />', {
8681          'aria-hidden': 'true',
8682          'html': '&times;'
8683        })
8684      })).append($('<h4 />', {
8685        'class': 'modal-title',
8686        'html': _lang.get('Supprimer mes informations de paiement')
8687      }))).append($('<div />', {
8688        'class': 'modal-body'
8689      }).append($('<form />', {
8690        'method': 'post',
8691        'name': 'form-payment-token-remove'
8692      }).append($('<input />', {
8693        'type': 'hidden',
8694        'name': 'id_payment_token_remove',
8695        'value': ''
8696      })).append($('<div />', {
8697        'class': 'text-center',
8698        'html': _lang.get('Souhaitez-vous supprimer ces informations de paiement ?')
8699      })).append($('<div />', {
8700        'class': 'text-center'
8701      }).append($('<button />', {
8702        'name': 'submit_form',
8703        'value': 1,
8704        'class': 'button',
8705        'html': _lang.get('Supprimer')
8706      })))))));
8707      $body.find('#main-conteneur').append($modalConfirmPaymentTokenRemove);
8708    }
8709    return $modalConfirmPaymentTokenRemove;
8710  }
8711  function calculOptions() {
8712    var checkbox = $('[type="checkbox"].form-option-price:checked'),
8713      /* Selectioner les checkbox */
8714      select = $('select.form-option-price'),
8715      /* Selectioner les select */
8716      radio = $('[type="radio"].form-option-price:checked'),
8717      price = 0,
8718      price_currency = 0;
8719    /* Selectioner les radio */
8720
8721    $.each(checkbox, function (index, value) {
8722      var $value = $(value),
8723        attr = $value.attr('data-price'),
8724        price_value,
8725        attr_currency = $value.attr('data-price-convert'),
8726        price_value_currency;
8727      if (typeof attr !== typeof undefined && attr !== false) {
8728        price_value = attr;
8729        price_value = parseFloat(price_value) || 0.00;
8730        price_value_currency = attr_currency;
8731        price_value_currency = parseFloat(price_value_currency) || 0.00;
8732        if (price_value > 0) {
8733          price += price_value;
8734        }
8735        if (price_value_currency > 0) {
8736          price_currency += price_value_currency;
8737        }
8738      }
8739    });
8740    $.each(radio, function (index, value) {
8741      var $value = $(value),
8742        attr = $value.attr('data-price'),
8743        price_value,
8744        attr_currency = $value.attr('data-price-convert'),
8745        price_value_currency;
8746      if (typeof attr !== typeof undefined && attr !== false) {
8747        price_value = attr;
8748        price_value = parseFloat(price_value) || 0.00;
8749        price_value_currency = attr_currency;
8750        price_value_currency = parseFloat(price_value_currency) || 0.00;
8751        if (price_value > 0) {
8752          price += price_value;
8753        }
8754        if (price_value_currency > 0) {
8755          price_currency += price_value_currency;
8756        }
8757      }
8758    });
8759    $.each(select, function (index, value) {
8760      var $value = $(value),
8761        price_value,
8762        price_value_currency;
8763      if ($value.val() > 0) {
8764        var $opt = $value.find('option[value="' + $value.val() + '"]'),
8765          attr = $opt.attr('data-price'),
8766          attr_currency = $opt.attr('data-price-convert');
8767        if ($opt.length == 1 && typeof attr !== typeof undefined && attr !== false) {
8768          price_value = attr;
8769          price_value = parseFloat(price_value) || 0.00;
8770          price_value_currency = attr_currency;
8771          price_value_currency = parseFloat(price_value_currency) || 0.00;
8772          if (price_value > 0) {
8773            price += price_value;
8774          }
8775          if (price_value_currency > 0) {
8776            price_currency += price_value_currency;
8777          }
8778        }
8779      }
8780    });
8781    options_price = price;
8782    options_price_currency = price_currency;
8783    calculatePrice();
8784  }
8785});
8786}();
8787/******/ })()
8788;
8789//# sourceMappingURL=../paniercommande.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.