PageSourceSearch

https://finite.solutions/front-v2.2.1/assets/vendor/hs-megamenu/src/hs.megamenu.js

js finite.solutions collected 2026-09-29 15:49:09 UTC 23,720 bytes, 999 lines download raw bytes

1/*
2 * HS Mega Menu - jQuery Plugin
3 * @version: 1.0.0 (Sun, 26 Feb 2017)
4 * @requires: jQuery v1.6 or later
5 * @author: HtmlStream
6 * @event-namespace: .HSMegaMenu
7 * @browser-support: IE9+
8 * @license:
9 *
10 * Copyright 2017 HtmlStream
11 *
12 */
13;(function ($) {
14  'use strict';
15
16  /**
17   * Creates a mega menu.
18   *
19   * @constructor
20   * @param {HTMLElement|jQuery} element - The element to create the mega menu for.
21   * @param {Object} options - The options
22   */
23
24  var MegaMenu = window.MegaMenu || {};
25
26  MegaMenu = (function () {
27
28    function MegaMenu(element, options) {
29
30      var self = this;
31
32      /**
33       * Current element.
34       *
35       * @public
36       */
37      this.$element = $(element);
38
39      /**
40       * Current options set by the caller including defaults.
41       *
42       * @public
43       */
44      this.options = $.extend(true, {}, MegaMenu.defaults, options);
45
46
47      /**
48       * Collection of menu elements.
49       *
50       * @private
51       */
52      this._items = $();
53
54
55      Object.defineProperties(this, {
56
57        /**
58         * Contains composed selector of menu items.
59         *
60         * @public
61         */
62        itemsSelector: {
63          get: function () {
64            return self.options.classMap.hasSubMenu + ',' +
65              self.options.classMap.hasMegaMenu;
66          }
67        },
68
69        /**
70         * Contains chain of active items.
71         *
72         * @private
73         */
74        _tempChain: {
75          value: null,
76          writable: true
77        },
78
79        /**
80         * Contains current behavior state.
81         *
82         * @public
83         */
84        state: {
85          value: null,
86          writable: true
87        }
88
89      });
90
91      this.initialize();
92
93    }
94
95    return MegaMenu;
96
97  }());
98
99
100  /**
101   * Default options of the mega menu.
102   *
103   * @public
104   */
105  MegaMenu.defaults = {
106    event: 'hover',
107    direction: 'horizontal',
108    breakpoint: 991,
109    animationIn: false,
110    animationOut: false,
111
112    rtl: false,
113    hideTimeOut: 300,
114
115    // For 'vertical' direction only
116    sideBarRatio: 1 / 4,
117    pageContainer: $('body'),
118
119    classMap: {
120      initialized: '.hs-menu-initialized',
121      mobileState: '.hs-mobile-state',
122
123      subMenu: '.hs-sub-menu',
124      hasSubMenu: '.hs-has-sub-menu',
125      hasSubMenuActive: '.hs-sub-menu-opened',
126
127      megaMenu: '.hs-mega-menu',
128      hasMegaMenu: '.hs-has-mega-menu',
129      hasMegaMenuActive: '.hs-mega-menu-opened'
130    },
131
132    mobileSpeed: 400,
133    mobileEasing: 'linear',
134
135    isMenuOpened: false,
136
137    beforeOpen: function () {},
138    beforeClose: function () {},
139    afterOpen: function () {},
140    afterClose: function () {}
141  };
142
143  /**
144   * Initialization of the plugin.
145   *
146   * @protected
147   */
148  MegaMenu.prototype.initialize = function () {
149    var self = this,
150      $w = $(window);
151
152    if (this.options.rtl) this.$element.addClass('hs-rtl');
153
154    this.$element
155      .addClass(this.options.classMap.initialized.slice(1))
156      .addClass('hs-menu-' + this.options.direction);
157
158
159    // Independent events
160    $w.on('resize.HSMegaMenu', function (e) {
161
162      if (self.resizeTimeOutId) clearTimeout(self.resizeTimeOutId);
163
164      self.resizeTimeOutId = setTimeout(function () {
165
166        if (window.innerWidth <= self.options.breakpoint && self.state === 'desktop') self.initMobileBehavior();
167        else if (window.innerWidth > self.options.breakpoint && self.state === 'mobile') self.initDesktopBehavior();
168
169        self.refresh();
170
171      }, 50);
172
173    });
174
175    if(window.innerWidth >= 768) {
176
177      $(document).on('click.HSMegaMenu touchstart.HSMegaMenu', 'body', function (e) {
178
179        var $parents = $(e.target).parents(self.itemsSelector);
180
181        self.closeAll($parents.add($(e.target)));
182
183      });
184
185    }
186
187    $w.on('keyup.HSMegaMenu', function (e) {
188
189      if (e.keyCode && e.keyCode === 27) {
190
191        self.closeAll();
192
193        self.options.isMenuOpened = false;
194      }
195
196    });
197
198    if (window.innerWidth <= this.options.breakpoint) this.initMobileBehavior();
199    else if (window.innerWidth > this.options.breakpoint) this.initDesktopBehavior();
200
201    this.smartPositions();
202
203    return this;
204
205  };
206
207  MegaMenu.prototype.smartPositions = function () {
208
209    var self = this,
210      $submenus = this.$element.find(this.options.classMap.subMenu);
211
212    $submenus.each(function (i, el) {
213
214      MenuItem.smartPosition($(el), self.options);
215
216    });
217
218  };
219
220  /**
221   * Binding events to menu elements.
222   *
223   * @protected
224   */
225  MegaMenu.prototype.bindEvents = function () {
226
227    var self = this,
228      selector;
229
230    // Hover case
231    if (this.options.event === 'hover' && !_isTouch()) {
232      this.$element
233        .on(
234          'mouseenter.HSMegaMenu',
235          this.options.classMap.hasMegaMenu + ':not([data-event="click"]),' +
236          this.options.classMap.hasSubMenu + ':not([data-event="click"])',
237          function (e) {
238
239            var $this = $(this),
240              $chain = $this.parents(self.itemsSelector);
241
242            // Lazy initialization
243            if (!$this.data('HSMenuItem')) {
244              self.initMenuItem($this, self.getType($this));
245            }
246
247            $chain = $chain.add($this);
248
249            self.closeAll($chain);
250
251            $chain.each(function (i, el) {
252
253              var HSMenuItem = $(el).data('HSMenuItem');
254
255              if (HSMenuItem.hideTimeOutId) clearTimeout(HSMenuItem.hideTimeOutId);
256              HSMenuItem.desktopShow();
257
258            });
259
260            self._items = self._items.not($chain);
261            self._tempChain = $chain;
262
263            e.preventDefault();
264            e.stopPropagation();
265          }
266        )
267        .on(
268          'mouseleave.HSMegaMenu',
269          this.options.classMap.hasMegaMenu + ':not([data-event="click"]),' +
270          this.options.classMap.hasSubMenu + ':not([data-event="click"])',
271          function (e) {
272
273            if (!$(this).data('HSMenuItem')) return;
274
275            var $this = $(this),
276              HSMenuItem = $this.data('HSMenuItem'),
277              $chain = $(e.relatedTarget).parents(self.itemsSelector);
278
279            HSMenuItem.hideTimeOutId = setTimeout(function () {
280              self.closeAll($chain);
281            }, self.options.hideTimeOut);
282
283            self._items = self._items.add(self._tempChain);
284            self._tempChain = null;
285
286            e.preventDefault();
287            e.stopPropagation();
288          }
289        )
290        .on(
291          'click.HSMegaMenu touchstart.HSMegaMenu',
292          this.options.classMap.hasMegaMenu + '[data-event="click"] > a, ' +
293          this.options.classMap.hasSubMenu + '[data-event="click"] > a',
294          function (e) {
295
296            var $this = $(this).parent('[data-event="click"]'),
297              HSMenuItem;
298
299            // Lazy initialization
300            if (!$this.data('HSMenuItem')) {
301              self.initMenuItem($this, self.getType($this));
302            }
303
304
305            self.closeAll($this.add(
306              $this.parents(self.itemsSelector)
307            ));
308
309            HSMenuItem = $this
310              .data('HSMenuItem');
311
312            if (HSMenuItem.isOpened) {
313              HSMenuItem.desktopHide();
314            } else {
315              HSMenuItem.desktopShow();
316            }
317
318
319            e.preventDefault();
320            e.stopPropagation();
321
322          }
323        );
324    }
325    // Click case
326    else {
327
328      this.$element
329        .on(
330          'click.HSMegaMenu',
331          (_isTouch() ?
332            this.options.classMap.hasMegaMenu + ' > a, ' +
333            this.options.classMap.hasSubMenu + ' > a' :
334            this.options.classMap.hasMegaMenu + ':not([data-event="hover"]) > a,' +
335            this.options.classMap.hasSubMenu + ':not([data-event="hover"]) > a'),
336          function (e) {
337
338            var $this = $(this).parent(),
339              HSMenuItem,
340              $parents = $this.parents(self.itemsSelector);
341
342            // Lazy initialization
343            if (!$this.data('HSMenuItem')) {
344              self.initMenuItem($this, self.getType($this));
345            }
346
347            self.closeAll($this.add(
348              $this.parents(self.itemsSelector)
349            ));
350
351            HSMenuItem = $this
352              .addClass('hs-event-prevented')
353              .data('HSMenuItem');
354
355            if (HSMenuItem.isOpened) {
356              HSMenuItem.desktopHide();
357            } else {
358              HSMenuItem.desktopShow();
359            }
360
361            e.preventDefault();
362            e.stopPropagation();
363          }
364        );
365
366      if (!_isTouch()) {
367        this.$element
368          .on(
369            'mouseenter.HSMegaMenu',
370            this.options.classMap.hasMegaMenu + '[data-event="hover"],' +
371            this.options.classMap.hasSubMenu + '[data-event="hover"]',
372            function (e) {
373
374              var $this = $(this),
375                $parents = $this.parents(self.itemsSelector);
376
377              // Lazy initialization
378              if (!$this.data('HSMenuItem')) {
379                self.initMenuItem($this, self.getType($this));
380              }
381
382              self.closeAll($this.add($parents));
383
384              $parents.add($this).each(function (i, el) {
385
386                var HSMenuItem = $(el).data('HSMenuItem');
387
388                if (HSMenuItem.hideTimeOutId) clearTimeout(HSMenuItem.hideTimeOutId);
389                HSMenuItem.desktopShow();
390
391              });
392
393              e.preventDefault();
394              e.stopPropagation();
395            }
396          )
397          .on(
398            'mouseleave.HSMegaMenu',
399            this.options.classMap.hasMegaMenu + '[data-event="hover"],' +
400            this.options.classMap.hasSubMenu + '[data-event="hover"]',
401            function (e) {
402
403              var $this = $(this),
404                HSMenuItem = $this.data('HSMenuItem');
405
406              HSMenuItem.hideTimeOutId = setTimeout(function () {
407
408                self.closeAll(
409                  $(e.relatedTarget).parents(self.itemsSelector)
410                );
411
412              }, self.options.hideTimeOut);
413
414              e.preventDefault();
415              e.stopPropagation();
416            }
417          )
418      }
419    }
420
421    this.$element.on('keydown.HSMegaMenu',
422      this.options.classMap.hasMegaMenu + ' > a,' +
423      this.options.classMap.hasSubMenu + ' > a',
424      function (e) {
425
426        var $this = $(this),
427          $parent = $this.parent(),
428          HSMenuItem;
429
430        // Lazy initialization
431        if (!$parent.data('HSMenuItem')) {
432
433          self.initMenuItem($parent, self.getType($parent));
434
435        }
436
437        HSMenuItem = $parent.data('HSMenuItem');
438
439        if ($this.is(':focus')) {
440
441          if (e.keyCode && e.keyCode === 40) {
442
443            e.preventDefault();
444
445            HSMenuItem.desktopShow();
446
447            self.options.isMenuOpened = true;
448
449          }
450
451          if (e.keyCode && e.keyCode === 13) {
452
453            if (self.options.isMenuOpened === true) {
454
455              HSMenuItem.desktopHide();
456
457              self.options.isMenuOpened = false;
458
459            } else {
460
461              HSMenuItem.desktopShow();
462
463              self.options.isMenuOpened = true;
464
465            }
466
467          }
468
469        }
470
471        $this.on('focusout', function () {
472
473          self.options.isMenuOpened = false;
474
475        });
476
477        HSMenuItem.menu.find('a').on('focusout', function () {
478
479          setTimeout(function () {
480
481            if (!HSMenuItem.menu.find('a').is(':focus')) {
482
483              HSMenuItem.desktopHide();
484
485              self.options.isMenuOpened = false;
486
487            }
488
489          });
490
491        });
492
493      })
494  };
495
496  /**
497   * Initialization of certain menu item.
498   *
499   * @protected
500   */
501  MegaMenu.prototype.initMenuItem = function (element, type) {
502
503    var self = this,
504      Item = new MenuItem(
505        element,
506        element.children(
507          self.options.classMap[type === 'mega-menu' ? 'megaMenu' : 'subMenu']
508        ),
509        $.extend(true, {type: type}, self.options, element.data()),
510        self.$element
511      );
512
513    element.data('HSMenuItem', Item);
514    this._items = this._items.add(element);
515
516  };
517
518  /**
519   * Destroys of desktop behavior, then makes initialization of mobile behavior.
520   *
521   * @protected
522   */
523  MegaMenu.prototype.initMobileBehavior = function () {
524
525    var self = this;
526
527    this.state = 'mobile';
528
529    this.$element
530      .off('.HSMegaMenu')
531      .addClass(this.options.classMap.mobileState.slice(1))
532      .on('click.HSMegaMenu', self.options.classMap.hasSubMenu + ' > a, ' + self.options.classMap.hasMegaMenu + ' > a', function (e) {
533
534        var $this = $(this).parent(),
535          MenuItemInstance;
536
537        // Lazy initialization
538        if (!$this.data('HSMenuItem')) {
539          self.initMenuItem($this, self.getType($this));
540        }
541
542        self.closeAll($this.parents(self.itemsSelector).add($this));
543
544        MenuItemInstance = $this
545          .data('HSMenuItem');
546
547        if (MenuItemInstance.isOpened) {
548          MenuItemInstance.mobileHide();
549        } else {
550          MenuItemInstance.mobileShow();
551        }
552
553        e.preventDefault();
554        e.stopPropagation();
555
556      })
557      .find(this.itemsSelector)
558      .not(
559        this.options.classMap.hasSubMenuActive + ',' +
560        this.options.classMap.hasMegaMenuActive
561      )
562      .children(
563        this.options.classMap.subMenu + ',' +
564        this.options.classMap.megaMenu
565      )
566      .hide();
567
568  };
569
570  /**
571   * Destroys of mobile behavior, then makes initialization of desktop behavior.
572   *
573   * @protected
574   */
575  MegaMenu.prototype.initDesktopBehavior = function () {
576
577    this.state = 'desktop';
578
579    this.$element
580      .removeClass(this.options.classMap.mobileState.slice(1))
581      .off('.HSMegaMenu')
582      .find(this.itemsSelector)
583      .not(
584        this.options.classMap.hasSubMenuActive + ',' +
585        this.options.classMap.hasMegaMenuActive
586      )
587      .children(
588        this.options.classMap.subMenu + ',' +
589        this.options.classMap.megaMenu
590      )
591      .hide();
592
593    this.bindEvents();
594
595  };
596
597  /**
598   * Hides all of opened submenus/megamenus.
599   *
600   * @param {jQuery} except - collection of elements, which shouldn't be closed.
601   * @return {jQuery}
602   * @public
603   */
604  MegaMenu.prototype.closeAll = function (except) {
605
606    var self = this;
607
608    return this._items.not(except && except.length ? except : $()).each(function (i, el) {
609
610      $(el)
611        .removeClass('hs-event-prevented')
612        .data('HSMenuItem')[self.state === 'mobile' ? 'mobileHide' : 'desktopHide']();
613
614    });
615
616  };
617
618  /**
619   * Returns type of sub menu based on specified menu item.
620   *
621   * @param {jQuery} item
622   * @return {String|null}
623   * @public
624   */
625  MegaMenu.prototype.getType = function (item) {
626
627    if (!item || !item.length) return null;
628
629    return item.hasClass(this.options.classMap.hasSubMenu.slice(1)) ? 'sub-menu' :
630      (item.hasClass(this.options.classMap.hasMegaMenu.slice(1)) ? 'mega-menu' : null);
631
632  };
633
634  /**
635   * Returns current menu state.
636   *
637   * @return {String}
638   * @public
639   */
640  MegaMenu.prototype.getState = function () {
641    return this.state;
642  };
643
644  /**
645   * Updates bounds of all menu items.
646   *
647   * @return {jQuery}
648   * @public
649   */
650  MegaMenu.prototype.refresh = function () {
651
652    return this._items.add(this._tempChain).each(function (i, el) {
653      $(el).data('HSMenuItem')._updateMenuBounds();
654    });
655
656  };
657
658
659  /**
660   * Creates a mega-menu element.
661   *
662   * @param {jQuery} element
663   * @param {jQuery} menu
664   * @param {Object} options
665   * @param {jQuery} container
666   * @constructor
667   */
668  function MenuItem(element, menu, options, container) {
669
670    var self = this;
671
672    /**
673     * Current menu item element.
674     *
675     * @public
676     */
677    this.$element = element;
678
679    /**
680     * Current mega menu element.
681     *
682     * @public
683     */
684    this.menu = menu;
685
686    /**
687     * Item options.
688     *
689     * @public
690     */
691    this.options = options;
692
693
694    /**
695     * MegaMenu container.
696     *
697     * @public
698     */
699    this.$container = container;
700
701    Object.defineProperties(this, {
702
703      /**
704       * Contains css class of menu item element.
705       *
706       * @public
707       */
708      itemClass: {
709        get: function () {
710          return self.options.type === 'mega-menu' ?
711            self.options.classMap.hasMegaMenu :
712            self.options.classMap.hasSubMenu;
713        }
714      },
715
716      /**
717       * Contains css active-class of menu item element.
718       *
719       * @public
720       */
721      activeItemClass: {
722        get: function () {
723          return self.options.type === 'mega-menu' ?
724            self.options.classMap.hasMegaMenuActive :
725            self.options.classMap.hasSubMenuActive;
726        }
727      },
728
729      /**
730       * Contains css class of menu element.
731       *
732       * @public
733       */
734      menuClass: {
735        get: function () {
736          return self.options.type === 'mega-menu' ?
737            self.options.classMap.megaMenu :
738            self.options.classMap.subMenu;
739        }
740      },
741
742      isOpened: {
743        get: function () {
744          return this.$element.hasClass(this.activeItemClass.slice(1));
745        }
746      }
747
748    });
749
750
751    this.menu.addClass('animated').on('click.HSMegaMenu', function (e) {
752      self._updateMenuBounds();
753    });
754
755    if (this.$element.data('max-width')) this.menu.css('max-width', this.$element.data('max-width'));
756    if (this.$element.data('position')) this.menu.addClass('hs-position-' + this.$element.data('position'));
757
758
759    if (this.options.animationOut) {
760
761      this.menu.on('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function (e) {
762
763        if (self.menu.hasClass(self.options.animationOut)) {
764          self.$element.removeClass(self.activeItemClass.slice(1));
765          self.options.afterClose.call(self, self.$element, self.menu);
766        }
767
768        if (self.menu.hasClass(self.options.animationIn)) {
769          self.options.afterOpen.call(self, self.$element, self.menu);
770        }
771
772        e.stopPropagation();
773        e.preventDefault();
774      });
775    }
776
777  }
778
779  /**
780   * Shows the mega-menu item.
781   *
782   * @public
783   * @return {MenuItem}
784   */
785  MenuItem.prototype.desktopShow = function () {
786    if (!this.menu.length) return this;
787
788    this.$element.addClass(this.activeItemClass.slice(1));
789
790    this._updateMenuBounds();
791
792    this.menu.show();
793
794    if (this.options.direction === 'horizontal') this.smartPosition(this.menu, this.options);
795
796    if (this.options.animationOut) {
797      this.menu.removeClass(this.options.animationOut);
798    } else {
799      this.options.afterOpen.call(this, this.$element, this.menu);
800    }
801
802    if (this.options.animationIn) {
803      this.menu.addClass(this.options.animationIn)
804    }
805
806    return this;
807  }
808
809  /**
810   * Hides the mega-menu item.
811   *
812   * @public
813   * @return {MenuItem}
814   */
815  MenuItem.prototype.desktopHide = function () {
816
817    var self = this;
818
819    if (!this.menu.length) return this;
820
821    this.$element.removeClass(this.activeItemClass.slice(1));
822
823    this.menu.hide();
824
825    if (this.options.animationIn) {
826      this.menu.removeClass(this.options.animationIn);
827    }
828    if (this.options.animationOut) {
829      this.menu.addClass(this.options.animationOut);
830    } else {
831      this.options.afterClose.call(this, this.$element, this.menu);
832    }
833
834    return this;
835  }
836
837  /**
838   * Shows the mega-menu item.
839   *
840   * @public
841   * @return {MenuItem}
842   */
843  MenuItem.prototype.mobileShow = function () {
844    var self = this;
845
846    if (!this.menu.length) return this;
847
848
849    this.menu
850      .removeClass(this.options.animationIn)
851      .removeClass(this.options.animationOut)
852      .stop()
853      .slideDown({
854        duration: self.options.mobileSpeed,
855        easing: self.options.mobileEasing,
856        complete: function () {
857          self.options.afterOpen.call(self, self.$element, self.menu);
858        }
859      });
860
861    this.$element.addClass(this.activeItemClass.slice(1));
862
863    return this;
864  };
865
866  /**
867   * Hides the mega-menu item.
868   *
869   * @public
870   * @return {MenuItem}
871   */
872  MenuItem.prototype.mobileHide = function () {
873    var self = this;
874
875    if (!this.menu.length) return this;
876
877    this.menu.stop().slideUp({
878      duration: self.options.mobileSpeed,
879      easing: self.options.mobileEasing,
880      complete: function () {
881        self.options.afterClose.call(self, self.$element, self.menu);
882      }
883    });
884
885    this.$element.removeClass(this.activeItemClass.slice(1));
886
887    return this;
888  };
889
890  /**
891   * Check, if element is in viewport.
892   *
893   * @param {jQuery} element
894   * @param {Object} options
895   * @public
896   */
897  MenuItem.prototype.smartPosition = function (element, options) {
898
899    MenuItem.smartPosition(element, options);
900
901  };
902
903  /**
904   * Check, if element is in viewport.
905   *
906   * @param {jQuery} element
907   * @param {Object} options
908   * @static
909   * @public
910   */
911  MenuItem.smartPosition = function (element, options) {
912    if (!element && !element.length) return;
913
914    var $w = $(window);
915
916    element.removeClass('hs-reversed');
917
918    if (!options.rtl) {
919
920      if (element.offset().left + element.outerWidth() > window.innerWidth) {
921        element.addClass('hs-reversed');
922      }
923
924    } else {
925
926      if (element.offset().left < 0) {
927        element.addClass('hs-reversed');
928      }
929
930    }
931  };
932
933  /**
934   * Updates bounds of current opened menu.
935   *
936   * @private
937   */
938  MenuItem.prototype._updateMenuBounds = function () {
939
940    var width = 'auto';
941
942    if (this.options.direction === 'vertical' && this.options.type === 'mega-menu') {
943
944      if (this.$container && this.$container.data('HSMegaMenu').get
944State() === 'desktop') {
945        if (!this.options.pageContainer.length) this.options.pageContainer = $('body');
946        width = this.options.pageContainer.outerWidth() * (1 - this.options.sideBarRatio);
947      } else {
948        width = 'auto';
949      }
950
951
952      this.menu.css({
953        'width': width,
954        'height': 'auto'
955      });
956
957      if (this.menu.outerHeight() > this.$container.outerHeight()) {
958        return;
959      }
960
961      this.menu.css('height', '100%');
962    }
963
964  };
965
966  /**
967   * The jQuery plugin for the MegaMenu.
968   *
969   * @public
970   */
971
972  $.fn.HSMegaMenu = function () {
973    var _ = this,
974      opt = arguments[0],
975      args = Array.prototype.slice.call(arguments, 1),
976      l = _.length,
977      i,
978      ret;
979    for (i = 0; i < l; i++) {
980      if (typeof opt === 'object' || typeof opt === 'undefined')
981        _[i].MegaMenu = new MegaMenu(_[i], opt);
982      else
983        ret = _[i].MegaMenu[opt].apply(_[i].MegaMenu, args);
984      if (typeof ret != 'undefined') return ret;
985    }
986    return _;
987  };
988
989  /**
990   * Helper function for detect touch events in the environment.
991   *
992   * @return {Boolean}
993   * @private
994   */
995  function _isTouch() {
996    return ('ontouchstart' in window);
997  }
998
999})(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.