PageSourceSearch

https://hakeem.tech/wp-content/plugins/keydesign-framework/include…/assets/js/mega-menu.js?ver=1.0.0

js hakeem.tech collected 2026-10-08 08:47:31 UTC 5,540 bytes, 175 lines download raw bytes

1(function ($) {
2    'use strict';
3  
4    class MegaMenuOffset {
5      constructor() {
6        this.$win = $(window);
7        this.$full = $('.keydesign-mega-menu-full-width');
8        this.$contained = $('.keydesign-mega-menu-contained');
9        this.containerWidth = this.readContainerWidth();
10        this.scrollbarWidth = this.getScrollbarWidth();
11        this.ticking = false;
12        this.activeCount = 0;
13        this.bindEvents();
14        this.calculateOffsets();
15      }
16  
17      bindEvents() {
18        const onResize = this.debounce(() => {
19          this.containerWidth = this.readContainerWidth();
20          this.scrollbarWidth = this.getScrollbarWidth();
21          this.calculateOffsets();
22        }, 150);
23  
24        window.addEventListener('resize', onResize);
25        window.addEventListener('orientationchange', onResize);
26  
27        const parents = $([].concat(this.$full.toArray(), this.$contained.toArray())).map(function () {
28          return $(this).closest('li')[0];
29        }).get().filter(Boolean);
30  
31        const onEnter = () => {
32          this.activeCount++;
33          if (this.activeCount === 1) this.enableScroll();
34          this.calculateOffsets();
35        };
36        const onLeave = () => {
37          this.activeCount = Math.max(0, this.activeCount - 1);
38          if (this.activeCount === 0) this.disableScroll();
39        };
40  
41        parents.forEach(li => {
42          li.addEventListener('mouseenter', onEnter, { passive: true });
43          li.addEventListener('focusin', onEnter);
44          li.addEventListener('mouseleave', onLeave, { passive: true });
45          li.addEventListener('focusout', onLeave);
46        });
47      }
48  
49      enableScroll() {
50        if (this._scrollOn) return;
51        this._scrollOn = true;
52        this._onScroll = () => {
53          if (this.ticking) return;
54          this.ticking = true;
55          requestAnimationFrame(() => {
56            this.ticking = false;
57            this.calculateOffsets();
58          });
59        };
60        window.addEventListener('scroll', this._onScroll, { passive: true });
61      }
62  
63      disableScroll() {
64        if (!this._scrollOn) return;
65        this._scrollOn = false;
66        window.removeEventListener('scroll', this._onScroll);
67        this._onScroll = null;
68      }
69  
70      calculateOffsets() {
71        if (!this.$full.length && !this.$contained.length) return;
72  
73        const vw = window.innerWidth;
74        const sl = window.pageXOffset;
75  
76        for (let i = 0; i < this.$full.length; i++) {
77          this.calcFull($(this.$full[i]), vw, sl);
78        }
79        for (let i = 0; i < this.$contained.length; i++) {
80          this.calcContained($(this.$contained[i]), vw, sl);
81        }
82      }
83  
84      calcFull($menu, vw, sl) {
85        const li = $menu.closest('li')[0];
86        if (!li) return;
87  
88        const r = li.getBoundingClientRect();
89        const left = r.left + sl - sl;
90        const width = r.width;
91        const right = left + width;
92  
93        let dx = -left;
94        if (right > vw) dx = vw - right;
95
96        dx -= this.scrollbarWidth / 2;
97
98        const el = $menu[0];
99        el.style.left = '0px';
100        el.style.transform = 'translateX(' + dx + 'px)';
101      }
102  
103      calcContained($menu, vw, sl) {
104        const li = $menu.closest('li')[0];
105        if (!li) return;
106  
107        const r = li.getBoundingClientRect();
108        const left = r.left + sl - sl;
109        const width = r.width;
110  
111        const cw = this.containerWidth;
112        const vc = vw / 2;
113        const cLeft = vc - (cw / 2);
114        const menuInC = left - cLeft;
115  
116        let dx = -menuInC;
117        if (menuInC < 0) dx = -left;
118        else if (menuInC + width > cw) dx = cw - (menuInC + width);
119
120        dx -= this.scrollbarWidth / 2;
121
122        const el = $menu[0];
123        el.style.left = '0px';
124        el.style.transform = 'translateX(' + dx + 'px)';
125      }
126  
127      readContainerWidth() {
128        const v = this.getCSSVariable('--container-max-width');
129        const n = parseInt(v, 10);
130        return Number.isFinite(n) ? n : 1200;
131      }
132  
133      getCSSVariable(name) {
134        return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
135      }
136
137      getScrollbarWidth() {
138        const outer = document.createElement('div');
139        outer.style.visibility = 'hidden';
140        outer.style.overflow = 'scroll';
141        outer.style.msOverflowStyle = 'scrollbar';
142        document.body.appendChild(outer);
143
144        const inner = document.createElement('div');
145        outer.appendChild(inner);
146
147        const scrollbarWidth = outer.offsetWidth - inner.offsetWidth;
148
149        outer.parentNode.removeChild(outer);
150
151        return scrollbarWidth;
152      }
153
154      debounce(fn, wait) {
155        let t;
156        return (...args) => {
157          clearTimeout(t);
158          t = setTimeout(() => fn.apply(this, args), wait);
159        };
160      }
161    }
162  
163    $(function () {
164      if (!window.kdMegaMenuOffset) window.kdMegaMenuOffset = new MegaMenuOffset();
165    });
166  
167    $(function () {
168      if (typeof elementorFrontend !== 'undefined' && elementorFrontend.hooks && typeof elementorFrontend.hooks.addAction === 'function') {
169        elementorFrontend.hooks.addAction('frontend/element_ready/global', () => {
170          if (window.kdMegaMenuOffset) window.kdMegaMenuOffset.calculateOffsets();
171        });
172      }
173    });
174  })(jQuery);
175  

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.