https://hakeem.tech/wp-content/plugins/keydesign-framework/include…/assets/js/mega-menu.js?ver=1.0.0
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.