PageSourceSearch

https://www.airgigs.com/resources/js/nav_small.js?1776998730

js airgigs.com collected 2026-09-25 18:55:39 UTC 17,290 bytes, 568 lines download raw bytes

1// CLASSIE class helper
2(function (window) {
3  "use strict";
4
5  function classReg(className) {
6    return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
7  }
8
9  // classList support for class management
10  // altho to be fair, the api sucks because it won't accept multiple classes at once
11  var hasClass, addClass, removeClass;
12
13  if ("classList" in document.documentElement) {
14    hasClass = function (elem, c) {
15      return elem.classList.contains(c);
16    };
17    addClass = function (elem, c) {
18      elem.classList.add(c);
19    };
20    removeClass = function (elem, c) {
21      elem.classList.remove(c);
22    };
23  } else {
24    hasClass = function (elem, c) {
25      return classReg(c).test(elem.className);
26    };
27    addClass = function (elem, c) {
28      if (!hasClass(elem, c)) {
29        elem.className = elem.className + " " + c;
30      }
31    };
32    removeClass = function (elem, c) {
33      elem.className = elem.className.replace(classReg(c), " ");
34    };
35  }
36
37  function toggleClass(elem, c) {
38    var fn = hasClass(elem, c) ? removeClass : addClass;
39    fn(elem, c);
40  }
41
42  var classie = {
43    // full names
44    hasClass: hasClass,
45    addClass: addClass,
46    removeClass: removeClass,
47    toggleClass: toggleClass,
48    // short names
49    has: hasClass,
50    add: addClass,
51    remove: removeClass,
52    toggle: toggleClass,
53  };
54
55  // transport
56  if (typeof define === "function" && define.amd) {
57    // AMD
58    define(classie);
59  } else if (typeof exports === "object") {
60    // CommonJS
61    module.exports = classie;
62  } else {
63    // browser global
64    window.classie = classie;
65  }
66})(window);
67
68if ("NodeList" in window && !NodeList.prototype.forEach) {
69  console.info("forEach polyfill for IE11");
70  NodeList.prototype.forEach = function (callback, thisArg) {
71    thisArg = thisArg || window;
72    for (var i = 0; i < this.length; i++) {
73      callback.call(thisArg, this[i], i, this);
74    }
75  };
76}
77
78//////// MENU JS
79(function (window) {
80  "use strict";
81
82  var support = { animations: true },
83    animEndEventNames = {
84      WebkitAnimation: "webkitAnimationEnd",
85      OAnimation: "oAnimationEnd",
86      msAnimation: "MSAnimationEnd",
87      animation: "animationend",
88    },
89    animEndEventName = "animationend", //animEndEventNames[Modernizr.prefixed("animation")],
90    onEndAnimation = function (el, callback) {
91      var onEndCallbackFn = function (ev) {
92        if (support.animations) {
93          if (ev.target != this) return;
94          this.removeEventListener(animEndEventName, onEndCallbackFn);
95        }
96        if (callback && typeof callback === "function") {
97          callback.call();
98        }
99      };
100      if (support.animations) {
101        el.addEventListener(animEndEventName, onEndCallbackFn);
102      } else {
103        onEndCallbackFn();
104      }
105    };
106
107  function extend(a, b) {
108    for (var key in b) {
109      if (b.hasOwnProperty(key)) {
110        a[key] = b[key];
111      }
112    }
113    return a;
114  }
115
116  function MLMenu(el, options) {
117    this.el = el;
118    this.options = extend({}, this.options);
119    extend(this.options, options);
120
121    // the menus (<ul>´s)
122    this.menus = [].slice.call(this.el.querySelectorAll(".AG__menu__level"));
123
124    // index of current menu
125    // Each level is actually a different menu so 0 is root, 1 is sub-1, 2 sub-2, etc.
126    this.current_menu = 0;
127
128    /* Determine what current menu actually is */
129    var current_menu;
130    this.menus.forEach(function (menuEl, pos) {
131      var items = menuEl.querySelectorAll(".AG__menu__item");
132      var _items = [].slice.call(items);
133      _items.forEach(function (itemEl, iPos) {
134        var currentLink = itemEl.querySelector(".AG__menu__link--current");
135        if (currentLink) {
136          // This is the actual menu__level that should have current
137          current_menu = pos;
138        }
139      });
140    });
141
142    if (current_menu) {
143      this.current_menu = current_menu;
144    }
145
146    this._init();
147  }
148
149  MLMenu.prototype.options = {
150    // show breadcrumbs
151    breadcrumbsCtrl: true,
152    // initial breadcrumb text
153    initialBreadcrumb: "all",
154    // show back button
155    backCtrl: true,
156    // delay between each menu item sliding animation
157    itemsDelayInterval: 60,
158    // direction
159    direction: "r2l",
160    // callback: item that doesn´t have a submenu gets clicked
161    // onItemClick([event], [inner HTML of the clicked item])
162    onItemClick: function (ev, itemName) {
163      return false;
164    },
165  };
166
167  MLMenu.prototype._init = function () {
168    // iterate the existing menus and create an array of menus,
169    // more specifically an array of objects where each one holds the info of each menu element and its menu items
170    this.menusArr = [];
171    this.breadCrumbs = false;
172    var self = this;
173    var submenus = [];
174
175    /* Loops over root level menu items */
176
177    this.menus.forEach(function (menuEl, pos) {
178      var menu = {
179        menuEl: menuEl,
180        menuItems: [].slice.call(menuEl.querySelectorAll(".AG__menu__item")),
181      };
182
183      self.menusArr.push(menu);
184
185      // set current menu class
186      if (pos === self.current_menu) {
187        classie.add(menuEl, "AG__menu__level--current");
188      }
189
190      var menu_x = menuEl.getAttribute("data-menu");
191      var links = menuEl.querySelectorAll(".AG__menu__link");
192      var _links = [].slice.call(links);
193      _links.forEach(function (linkEl, lPos) {
194        var _submenu = linkEl.getAttribute("data-submenu");
195        var _name = linkEl.getAttribute("data-name");
196        if (_submenu) {
197          var pushMe = { menu: _submenu, name: _name };
198          if (submenus[pos]) {
199            submenus[pos].push(pushMe);
200          } else {
201            submenus[pos] = [];
202            submenus[pos].push(pushMe);
203          }
204        }
205      });
206    });
207
208    /* For each MENU, find their parent MENU */
209
210    this.menus.forEach(function (menuEl, pos) {
211      var menu_x = menuEl.getAttribute("data-menu");
212      submenus.forEach(function (subMenuEl, menu_root) {
213        subMenuEl.forEach(function (subMenuItem, subPos) {
214          if (subMenuItem.menu == menu_x) {
215            self.menusArr[pos].backIdx = menu_root;
216            self.menusArr[pos].name = subMenuItem.name;
217          }
218        });
219      });
220    });
221
222    // create breadcrumbs
223    if (self.options.breadcrumbsCtrl) {
224      this.breadcrumbsCtrl = document.createElement("nav");
225      this.breadcrumbsCtrl.className = "AG__menu__breadcrumbs";
226      this.breadcrumbsCtrl.setAttribute("aria-label", "You are here");
227      this.el.insertBefore(this.breadcrumbsCtrl, this.el.firstChild);
228      // add initial breadcrumb
229      this._addBreadcrumb(0);
230
231      // Need to add breadcrumbs for all parents of current submenu
232      if (
233        self.menusArr[self.current_menu].backIdx != 0 &&
234        self.current_menu != 0
235      ) {
236        this._crawlCrumbs(
237          self.menusArr[self.current_menu].backIdx,
238          self.menusArr
239        );
240        this.breadCrumbs = true;
241      }
242
243      // Create current submenu breadcrumb
244      if (self.current_menu != 0) {
245        this._addBreadcrumb(self.current_menu);
246        this.breadCrumbs = true;
247      }
248    }
249
250    // create back button
251    if (this.options.backCtrl) {
252      this.backCtrl = document.createElement("button");
253      if (this.breadCrumbs) {
254        this.backCtrl.className = "AG__menu__back";
255      } else {
256        this.backCtrl.className = "AG__menu__back AG__menu__back--hidden";
257      }
258      this.backCtrl.setAttribute("aria-label", "Go back");
259      this.backCtrl.innerHTML =
260        '<svg xmlns="http://www.w3.org/2000/svg" width="9" height="15"><path fill="#f56853" fill-rule="evenodd" d="M5.389 7.51L0 13.166 1.892 15 9 7.51 1.892 0 0 1.834z"/></svg><span>Back</span>';
261
262      this.el.insertBefore(this.backCtrl, this.el.firstChild);
263    }
264
265    // event binding
266    this._initEvents();
267  };
268
269  MLMenu.prototype._initEvents = function () {
270    var self = this;
271
272    for (var i = 0, len = this.menusArr.length; i < len; ++i) {
273      this.menusArr[i].menuItems.forEach(function (item, pos) {
274        var itemsClick = item.querySelectorAll(".AG__menu__link");
275        var _itemsClick = [].slice.call(itemsClick);
276        _itemsClick.forEach(function (item) {
277          item.addEventListener("click", function (ev) {
278            var submenu = ev.target.getAttribute("data-submenu"),
279              itemName = ev.target.getAttribute("data-name"),
280              subMenuEl = self.el.querySelector(
281                'ul[data-menu="' + submenu + '"]'
282              );
283
284            // check if there's a sub menu for this item
285            if (submenu && subMenuEl) {
286              ev.preventDefault();
287              // open it
288              self._openSubMenu(subMenuEl, pos, itemName);
289            } else {
290              // add class current
291              var currentlink = self.el.querySelector(
292                ".AG__menu__link--current"
293              );
294              if (currentlink) {
295                classie.remove(
296                  self.el.querySelector(".AG__menu__link--current"),
297                  "AG__menu__link--current"
298                );
299              }
300              classie.add(ev.target, "AG__menu__link--current");
301
302              // callback
303              self.options.onItemClick(ev, itemName);
304            }
305          });
306        });
307      });
308    }
309
310    // back navigation
311    if (this.options.backCtrl) {
312      this.backCtrl.addEventListener("click", function () {
313        self._back();
314      });
315    }
316  };
317
318  MLMenu.prototype._openSubMenu = function (
319    subMenuEl,
320    clickPosition,
321    subMenuName
322  ) {
323    if (this.isAnimating) {
324      return false;
325    }
326    this.isAnimating = true;
327
328    // save "parent" menu index for back navigation
329    this.menusArr[this.menus.indexOf(subMenuEl)].backIdx = this.current_menu;
330    // save "parent" menu´s name
331    this.menusArr[this.menus.indexOf(subMenuEl)].name = subMenuName;
332    // current menu slides out
333    this._menuOut(clickPosition);
334    // next menu (submenu) slides in
335    this._menuIn(subMenuEl, clickPosition);
336  };
337
338  MLMenu.prototype._back = function () {
339    if (this.isAnimating) {
340      return false;
341    }
342    this.isAnimating = true;
343
344    // current menu slides out
345    this._menuOut();
346    // next menu (previous menu) slides in
347    var backMenu =
348      this.menusArr[this.menusArr[this.current_menu].backIdx].menuEl;
349    this._menuIn(backMenu);
350
351    // remove last breadcrumb
352    if (this.options.breadcrumbsCtrl) {
353      this.breadcrumbsCtrl.removeChild(this.breadcrumbsCtrl.lastElementChild);
354    }
355  };
356
357  MLMenu.prototype._menuOut = function (clickPosition) {
358    // the current menu
359    var self = this,
360      currentMenu = this.menusArr[this.current_menu].menuEl,
361      isBackNavigation = typeof clickPosition == "undefined" ? true : false;
362
363    // slide out current menu items - first, set the delays for the items
364    this.menusArr[this.current_menu].menuItems.forEach(function (item, pos) {
365      item.style.WebkitAnimationDelay = item.style.animationDelay =
366        isBackNavigation
367          ? parseInt(pos * self.options.itemsDelayInterval) + "ms"
368          : parseInt(
369              Math.abs(clickPosition - pos) * self.options.itemsDelayInterval
370            ) + "ms";
371    });
372    // animation class
373    if (this.options.direction === "r2l") {
374      classie.add(
375        currentMenu,
376        !isBackNavigation ? "animate-outToLeft" : "animate-outToRight"
377      );
378    } else {
379      classie.add(
380        currentMenu,
381        isBackNavigation ? "animate-outToLeft" : "animate-outToRight"
382      );
383    }
384  };
385
386  MLMenu.prototype._menuIn = function (nextMenuEl, clickPosition) {
387    var self = this,
388      // the current menu
389      currentMenu = this.menusArr[this.current_menu].menuEl,
390      isBackNavigation = typeof clickPosition == "undefined" ? true : false,
391      // index of the nextMenuEl
392      nextMenuIdx = this.menus.indexOf(nextMenuEl),
393      nextMenu = this.menusArr[nextMenuIdx],
394      nextMenuEl = nextMenu.menuEl,
395      nextMenuItems = nextMenu.menuItems,
396      nextMenuItemsTotal = nextMenuItems.length;
397
398    // slide in next menu items - first, set the delays for the items
399    nextMenuItems.forEach(function (item, pos) {
400      item.style.WebkitAnimationDelay = item.style.animationDelay =
401        isBackNavigation
402          ? parseInt(pos * self.options.itemsDelayInterval) + "ms"
403          : parseInt(
404              Math.abs(clickPosition - pos) * self.options.itemsDelayInterval
405            ) + "ms";
406
407      // we need to reset the classes once the last item animates in
408      // the "last item" is the farthest from the clicked item
409      // let's calculate the index of the farthest item
410      var farthestIdx =
411        clickPosition <= nextMenuItemsTotal / 2 || isBackNavigation
412          ? nextMenuItemsTotal - 1
413          : 0;
414
415      if (pos === farthestIdx) {
416        onEndAnimation(item, function () {
417          // reset classes
418          if (self.options.direction === "r2l") {
419            classie.remove(
420              currentMenu,
421              !isBackNavigation ? "animate-outToLeft" : "animate-outToRight"
422            );
423            classie.remove(
424              nextMenuEl,
425              !isBackNavigation ? "animate-inFromRight" : "animate-inFromLeft"
426            );
427          } else {
428            classie.remove(
429              currentMenu,
430              isBackNavigation ? "animate-outToLeft" : "animate-outToRight"
431            );
432            classie.remove(
433              nextMenuEl,
434              isBackNavigation ? "animate-inFromRight" : "animate-inFromLeft"
435            );
436          }
437          classie.remove(currentMenu, "AG__menu__level--current");
438          classie.add(nextMenuEl, "AG__menu__level--current");
439
440          //reset current
441          self.current_menu = nextMenuIdx;
442
443          // control back button and breadcrumbs navigation elements
444          if (!isBackNavigation) {
445            // show back button
446            if (self.options.backCtrl) {
447              classie.remove(self.backCtrl, "AG__menu__back--hidden");
448            }
449
450            // add breadcrumb
451            self._addBreadcrumb(nextMenuIdx);
452          } else if (self.current_menu === 0 && self.options.backCtrl) {
453            // hide back button
454            classie.add(self.backCtrl, "AG__menu__back--hidden");
455          }
456
457          // we can navigate again..
458          self.isAnimating = false;
459
460          // focus retention
461          nextMenuEl.focus();
462        });
463      }
464    });
465
466    // animation class
467    if (this.options.direction === "r2l") {
468      classie.add(
469        nextMenuEl,
470        !isBackNavigation ? "animate-inFromRight" : "animate-inFromLeft"
471      );
472    } else {
473      classie.add(
474        nextMenuEl,
475        isBackNavigation ? "animate-inFromRight" : "animate-inFromLeft"
476      );
477    }
478  };
479
480  MLMenu.prototype._addBreadcrumb = function (idx) {
481    if (!this.options.breadcrumbsCtrl) {
482      return false;
483    }
484
485    var bc = document.createElement("a");
486    bc.href = "#"; // make it focusable
487    bc.innerHTML = idx
488      ? this.menusArr[idx].name
489      : this.options.initialBreadcrumb;
490    this.breadcrumbsCtrl.appendChild(bc);
491
492    var self = this;
493    bc.addEventListener("click", function (ev) {
494      ev.preventDefault();
495
496      // do nothing if this breadcrumb is the last one in the list of breadcrumbs
497      if (!bc.nextSibling || self.isAnimating) {
498        return false;
499      }
500      self.isAnimating = true;
501
502      // current menu slides out
503      self._menuOut();
504      // next menu slides in
505      var nextMenu = self.menusArr[idx].menuEl;
506      self._menuIn(nextMenu);
507
508      // remove breadcrumbs that are ahead
509      var siblingNode;
510      while ((siblingNode = bc.nextSibling)) {
511        self.breadcrumbsCtrl.removeChild(siblingNode);
512      }
513    });
514  };
515
516  MLMenu.prototype._crawlCrumbs = function (currentMenu, menuArray) {
517    if (menuArray[currentMenu].backIdx != 0) {
518      this._crawlCrumbs(menuArray[currentMenu].backIdx, menuArray);
519    }
520    // create breadcrumb
521    this._addBreadcrumb(currentMenu);
522  };
523
524  window.MLMenu = MLMenu;
525})(window);
526
527/// Airgigs Small Menu
528var NavSmall = {
529  toggleGroove: function (){
530    var groove = document.getElementById("grooveLoader");
531    if (!groove) return;
532    
533    if (groove.style.display === "none") {
534      groove.style.display = "inline-flex";
535    } else {
536      groove.style.display = "none";
537    }
538  },
539  toggleMenu: function (elem) {
540    elem.classList.toggle("is-active");
541
542    // Keep Helpy hidden on mobile unless hamburger menu is open.
543    // CSS listens to body.ag-menu-open.
544    if (document && document.body) {
545      document.body.classList.toggle("ag-menu-open", elem.classList.contains("is-active"));
546    }
547
548    NavSmall.toggleGroove();
549  },
550  lockScroll: function () {},
551  init: function () {
552    console.log("init Nav Small");
553    var menuEl = document.getElementById("AG__menu");
554
555    var mlmenu = new MLMenu(menuEl, {
556      breadcrumbsCtrl: false, // show breadcrumbs
557      backCtrl: true, // show back button
558      itemsDelayInterval: 0, // delay between each menu item sliding animation
559    });
560
561    // mobile menu toggle
562    var triggerMenuCtrl = document.getElementById("AG__menu--trigger");
563    triggerMenuCtrl.addEventListener("click", function () {
564      this.classList.toggle("is-active");
565      NavSmall.toggleMenu(menuEl);
566    });
567  },
568};

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.