PageSourceSearch

https://finite.solutions/front-v2.2.1/assets/js/components/hs.unfold.js

js finite.solutions collected 2026-09-29 15:49:18 UTC 15,185 bytes, 632 lines download raw bytes

1/**
2 * Unfold Content component.
3 *
4 * @author Htmlstream
5 * @version 1.0
6 */
7;
8(function ($) {
9  'use strict';
10
11  $.HSCore.components.HSUnfold = {
12
13    /**
14     * Base configuration of the component.
15     *
16     * @private
17     */
18    _baseConfig: {
19      unfoldEvent: 'click',
20      unfoldType: 'simple',
21      unfoldDuration: 300,
22      unfoldEasing: 'linear',
23      unfoldAnimationIn: 'fadeIn',
24      unfoldAnimationOut: 'fadeOut',
25      unfoldHideOnScroll: true,
26      unfoldHideOnBlur: false,
27      unfoldDelay: 350,
28      unfoldOpenedElement: 'init',
29      afterOpen: function (invoker) {},
30      beforeClose: function (invoker) {},
31      afterClose: function (invoker) {}
32    },
33
34    /**
35     * Collection of all initialized items on the page.
36     *
37     * @private
38     */
39    _pageCollection: $(),
40
41    /**
42     * Initialization.
43     *
44     * @param {jQuery} collection
45     * @param {Object} config
46     *
47     * @public
48     * @return {jQuery}
49     */
50    init: function (collection, config) {
51
52      var self;
53
54      if (!collection || !collection.length) return;
55
56      self = this;
57
58      var fieldsQty;
59
60      collection.each(function (i, el) {
61
62        var $this = $(el), itemConfig;
63
64        if ($this.data('HSUnfold')) return;
65
66        itemConfig = config && $.isPlainObject(config) ?
67          $.extend(true, {}, self._baseConfig, config, $this.data()) :
68          $.extend(true, {}, self._baseConfig, $this.data());
69
70        switch (itemConfig.unfoldType) {
71
72          case 'css-animation' :
73
74            $this.data('HSUnfold', new UnfoldCSSAnimation($this, itemConfig));
75
76            break;
77
78          case 'jquery-slide' :
79
80            $this.data('HSUnfold', new UnfoldJSlide($this, itemConfig));
81
82            break;
83
84          default :
85
86            $this.data('HSUnfold', new UnfoldSimple($this, itemConfig));
87
88        }
89
90        self._pageCollection = self._pageCollection.add($this);
91        self._bindEvents($this, itemConfig.unfoldEvent, itemConfig.unfoldDelay);
92        var UnFold = $(el).data('HSUnfold');
93
94        fieldsQty = $(UnFold.target).find('input, textarea').length;
95
96        if ($(UnFold.target).find('[data-unfold-target]').length) {
97
98          $this.addClass('target-of-invoker-has-unfolds');
99
100        }
101
102      });
103
104      $(document).on('click touchstart', 'body', function (e) {
105
106        if (e.target.id == self._baseConfig.unfoldOpenedElement) return;
107
108        if ($(e.target).closest('#' + self._baseConfig.unfoldOpenedElement).length) return;
109
110        self._pageCollection.each(function (i, el) {
111
112          var windW = window.innerWidth,
113            optIsMobileOnly = Boolean($(el).data('is-mobile-only'));
114
115          if (!optIsMobileOnly) {
116
117            $(el).data('HSUnfold').hide();
118
119          } else if (optIsMobileOnly && windW < 769) {
120
121            $(el).data('HSUnfold').hide();
122
123          }
124
125          $(el).data('HSUnfold').config.beforeClose.call(self.target, self.element);
126
127        });
128
129      });
130
131      $(window).on('scroll.HSUnfold', function () {
132
133        self._pageCollection.each(function (i, el) {
134
135          var UnFold = $(el).data('HSUnfold');
136
137          if (UnFold.getOption('unfoldHideOnScroll') && fieldsQty === 0) {
138
139            UnFold.hide();
140
141          } else if (UnFold.getOption('unfoldHideOnScroll') && !(/iPhone|iPad|iPod/i.test(navigator.userAgent))) {
142
143            UnFold.hide();
144
145          }
146
147        });
148
149      });
150
151      $(window).on('resize.HSUnfold', function () {
152
153        if (self._resizeTimeOutId) clearTimeout(self._resizeTimeOutId);
154
155        self._resizeTimeOutId = setTimeout(function () {
156
157          self._pageCollection.each(function (i, el) {
158
159            var UnFold = $(el).data('HSUnfold');
160
161            UnFold.smartPosition(UnFold.target);
162
163          });
164
165        }, 50);
166
167      });
168
169      $(document).on('keydown.HSUnfold', function (e) {
170
171        if ($('body').hasClass('u-unfold-opened')) {
172
173          if (e.keyCode && e.keyCode === 38 || e.keyCode && e.keyCode === 40) {
174
175            e.preventDefault();
176
177          }
178
179        }
180
181      });
182
183      return collection;
184
185    },
186
187    /**
188     * Binds necessary events.
189     *
190     * @param {jQuery} $invoker
191     * @param {String} eventType
192     * @param {Number} delay
193     * @private
194     */
195    _bindEvents: function ($invoker, eventType, delay) {
196
197      var self = this,
198        $unfold = $($invoker.data('unfold-target'));
199
200      if (eventType === 'hover' && !_isTouch()) {
201
202        $invoker.on('mouseenter.HSUnfold', function () {
203
204          var $invoker = $(this),
205            HSUnfold = $invoker.data('HSUnfold');
206
207          if (!HSUnfold) return;
208
209          if (HSUnfold.unfoldTimeOut) clearTimeout(HSUnfold.unfoldTimeOut);
210          HSUnfold.show();
211          $('body').addClass('u-unfold-opened');
212
213        })
214          .on('mouseleave.HSUnfold', function () {
215
216            var $invoker = $(this),
217              HSUnfold = $invoker.data('HSUnfold');
218
219            if (!HSUnfold) return;
220
221            HSUnfold.unfoldTimeOut = setTimeout(function () {
222
223              HSUnfold.hide();
224              $('body').removeClass('u-unfold-opened');
225
226            }, delay);
227
228          });
229
230        if ($unfold.length) {
231
232          $unfold.on('mouseenter.HSUnfold', function () {
233
234            var HSUnfold = $invoker.data('HSUnfold');
235
236            if (HSUnfold.unfoldTimeOut) clearTimeout(HSUnfold.unfoldTimeOut);
237            HSUnfold.show();
238
239          })
240            .on('mouseleave.HSUnfold', function () {
241
242              var HSUnfold = $invoker.data('HSUnfold');
243
244              HSUnfold.unfoldTimeOut = setTimeout(function () {
245                HSUnfold.hide();
246              }, delay);
247
248            });
249        }
250
251      } else {
252
253        $invoker.on('click.HSUnfold', function (e) {
254
255          var $curInvoker = $(this),
256            $unfoldNotHasInnerUnfolds = $('[data-unfold-target].active:not(.target-of-invoker-has-unfolds)'),
257            $unfoldHasInnerUnfold = $('[data-unfold-target].active.target-of-invoker-has-unfolds');
258
259          self._baseConfig.unfoldOpenedElement = $curInvoker.data('HSUnfold').target[0].id;
260
261          if (!$curInvoker.data('HSUnfold')) return;
262
263          if (!$curInvoker.hasClass('target-of-invoker-has-unfolds')) {
264
265            if ($unfoldNotHasInnerUnfolds.length) {
266
267              $unfoldNotHasInnerUnfolds.data('HSUnfold').toggle();
268
269            }
270
271          } else {
272
273            if ($unfoldHasInnerUnfold.length) {
274
275              $unfoldHasInnerUnfold.data('HSUnfold').toggle();
276
277            }
278
279          }
280
281          $curInvoker.data('HSUnfold').toggle();
282
283          e.stopPropagation();
284
285          e.preventDefault();
286
287        });
288
289        if (Boolean($invoker.data('unfold-target-is-menu'))) {
290
291          var $target = $($invoker.data('unfold-target')),
292            $targetItems = $target.children();
293
294          $targetItems.on('click', function () {
295
296            $invoker.data('HSUnfold').toggle();
297
298          });
299
300        }
301
302      }
303
304    }
305  };
306
307  function _isTouch() {
308    return 'ontouchstart' in window;
309  }
310
311  /**
312   * Abstract Unfold class.
313   *
314   * @param {jQuery} element
315   * @param {Object} config
316   * @abstract
317   */
318  function AbstractUnfold(element, config) {
319
320    if (!element.length) return false;
321
322    this.element = element;
323    this.config = config;
324
325    this.target = $(this.element.data('unfold-target'));
326
327    this.allInvokers = $('[data-unfold-target="' + this.element.data('unfold-target') + '"]');
328
329    this.toggle = function () {
330      if (!this.target.length) return this;
331
332      if (this.defaultState) {
333        this.show();
334      } else {
335        this.hide();
336      }
337
338      return this;
339    };
340
341    this.smartPosition = function (target) {
342
343      if (target.data('baseDirection')) {
344        target.css(
345          target.data('baseDirection').direction,
346          target.data('baseDirection').value
347        );
348      }
349
350      target.removeClass('u-unfold--reverse-y');
351
352      var $w = $(window),
353        styles = getComputedStyle(target.get(0)),
354        direction = Math.abs(parseInt(styles.left, 10)) < 40 ? 'left' : 'right',
355        targetOuterGeometry = target.offset();
356
357      // horizontal axis
358      if (direction === 'right') {
359
360        if (!target.data('baseDirection')) target.data('baseDirection', {
361          direction: 'right',
362          value: parseInt(styles.right, 10)
363        });
364
365        if (targetOuterGeometry.left < 0) {
366
367          target.css(
368            'right',
369            (parseInt(target.css('right'), 10) - (targetOuterGeometry.left - 10)) * -1
370          );
371
372        }
373
374      } else {
375
376        if (!target.data('baseDirection')) target.data('baseDirection', {
377          direction: 'left',
378          value: parseInt(styles.left, 10)
379        });
380
381        if (targetOuterGeometry.left + target.outerWidth() > $w.width()) {
382
383          target.css(
384            'left',
385            (parseInt(target.css('left'), 10) - (targetOuterGeometry.left + target.outerWidth() + 10 - $w.width()))
386          );
387
388        }
389
390      }
391
392      // vertical axis
393      if (targetOuterGeometry.top + target.outerHeight() - $w.scrollTop() > $w.height()) {
394
395        target.addClass('u-unfold--reverse-y');
396
397      }
398
399    };
400
401    this.getOption = function (option) {
402      return this.config[option] ? this.config[option] : null;
403    };
404
405    return true;
406  }
407
408
409  /**
410   * UnfoldSimple constructor.
411   *
412   * @param {jQuery} element
413   * @param {Object} config
414   * @constructor
415   */
416  function UnfoldSimple(element, config) {
417    if (!AbstractUnfold.call(this, element, config)) return;
418
419    Object.defineProperty(this, 'defaultState', {
420      get: function () {
421        return this.target.hasClass('u-unfold--hidden');
422      }
423    });
424
425    this.target.addClass('u-unfold--simple');
426
427    this.hide();
428  }
429
430  /**
431   * Shows Unfold.
432   *
433   * @public
434   * @return {UnfoldSimple}
435   */
436  UnfoldSimple.prototype.show = function () {
437
438    var activeEls = $(this)[0].config.unfoldTarget;
439
440    $('[data-unfold-target="' + activeEls + '"]').addClass('active');
441
442    this.smartPosition(this.target);
443
444    this.target.removeClass('u-unfold--hidden');
445    if (this.allInvokers.length) this.allInvokers.attr('aria-expanded', 'true');
446    this.config.afterOpen.call(this.target, this.element);
447
448    return this;
449  };
450
451  /**
452   * Hides Unfold.
453   *
454   * @public
455   * @return {UnfoldSimple}
456   */
457  UnfoldSimple.prototype.hide = function () {
458
459    var activeEls = $(this)[0].config.unfoldTarget;
460
461    $('[data-unfold-target="' + activeEls + '"]').removeClass('active');
462
463    this.target.addClass('u-unfold--hidden');
464    if (this.allInvokers.length) this.allInvokers.attr('aria-expanded', 'false');
465    this.config.afterClose.call(this.target, this.element);
466
467    return this;
468  };
469
470  /**
471   * UnfoldCSSAnimation constructor.
472   *
473   * @param {jQuery} element
474   * @param {Object} config
475   * @constructor
476   */
477  function UnfoldCSSAnimation(element, config) {
478    if (!AbstractUnfold.call(this, element, config)) return;
479
480    var self = this;
481
482    this.target
483      .addClass('u-unfold--css-animation u-unfold--hidden')
484      .css('animation-duration', self.config.unfoldDuration + 'ms');
485
486    Object.defineProperty(this, 'defaultState', {
487      get: function () {
488        return this.target.hasClass('u-unfold--hidden');
489      }
490    });
491
492    if (this.target.length) {
493
494      this.target.on('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function (e) {
495
496        if (self.target.hasClass(self.config.unfoldAnimationOut)) {
497
498          self.target.removeClass(self.config.unfoldAnimationOut)
499            .addClass('u-unfold--hidden');
500
501
502          if (self.allInvokers.length) self.allInvokers.attr('aria-expanded', 'false');
503
504          self.config.afterClose.call(self.target, self.element);
505        }
506
507        if (self.target.hasClass(self.config.unfoldAnimationIn)) {
508
509          if (self.allInvokers.length) self.allInvokers.attr('aria-expanded', 'true');
510
511          self.config.afterOpen.call(self.target, self.element);
512        }
513
514        e.preventDefault();
515        e.stopPropagation();
516      });
517
518    }
519  }
520
521  /**
522   * Shows Unfold.
523   *
524   * @public
525   * @return {UnfoldCSSAnimation}
526   */
527  UnfoldCSSAnimation.prototype.show = function () {
528
529    var self = this;
530
531    var activeEls = $(this)[0].config.unfoldTarget;
532
533    $('[data-unfold-target="' + activeEls + '"]').addClass('active');
534
535    this.smartPosition(this.target);
536
537    this.target.removeClass('u-unfold--hidden')
538      .removeClass(this.config.unfoldAnimationOut)
539      .addClass(this.config.unfoldAnimationIn);
540
541    self.config.afterOpen.call(self.target, self.element);
542
543  };
544
545  /**
546   * Hides Unfold.
547   *
548   * @public
549   * @return {UnfoldCSSAnimation}
550   */
551  UnfoldCSSAnimation.prototype.hide = function () {
552
553    var activeEls = $(this)[0].config.unfoldTarget;
554
555    $('[data-unfold-target="' + activeEls + '"]').removeClass('active');
556
557    this.target.removeClass(this.config.unfoldAnimationIn)
558      .addClass(this.config.unfoldAnimationOut);
559
560  };
561
562  /**
563   * UnfoldSlide constructor.
564   *
565   * @param {jQuery} element
566   * @param {Object} config
567   * @constructor
568   */
569  function UnfoldJSlide(element, config) {
570    if (!AbstractUnfold.call(this, element, config)) return;
571
572    this.target.addClass('u-unfold--jquery-slide u-unfold--hidden').hide();
573
574    Object.defineProperty(this, 'defaultState', {
575      get: function () {
576        return this.target.hasClass('u-unfold--hidden');
577      }
578    });
579  }
580
581  /**
582   * Shows Unfold.
583   *
584   * @public
585   * @return {UnfoldJSlide}
586   */
587  UnfoldJSlide.prototype.show = function () {
588
589    var self = this;
590
591    var activeEls = $(this)[0].config.unfoldTarget;
592
593    $('[data-unfold-target="' + activeEls + '"]').addClass('active');
594
595    this.smartPosition(this.target);
596
597    this.target.removeClass('u-unfold--hidden').stop().slideDown({
598      duration: self.config.unfoldDuration,
599      easing: self.config.unfoldEasing,
600      complete: function () {
601        self.config.afterOpen.call(self.target, self.element);
602      }
603    });
604
605  };
606
607  /**
608   * Hides Unfold.
609   *
610   * @public
611   * @return {UnfoldJSlide}
612   */
613  UnfoldJSlide.prototype.hide = function () {
614
615    var self = this;
616
617    var activeEls = $(this)[0].config.unfoldTarget;
618
619    $('[data-unfold-target="' + activeEls + '"]').removeClass('active');
620
621    this.target.slideUp({
622      duration: self.config.unfoldDuration,
623      easing: self.config.unfoldEasing,
624      complete: function () {
625        self.config.afterClose.call(self.target, self.element);
626        self.target.addClass('u-unfold--hidden');
627      }
628    });
629
630  }
631
632})(jQuery);

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.