PageSourceSearch

https://www.gresb.com/wp-content/themes/framework/assets/js/components/_2_menu-bar.js?ver=1790268989

js gresb.com collected 2026-09-24 17:12:38 UTC 6,515 bytes, 152 lines download raw bytes

1// File#: _2_menu-bar
2// Usage: codyhouse.co/license
3(function() {
4  var MenuBar = function(element) {
5    this.element = element;
6    this.items = Util.getChildrenByClassName(this.element, 'menu-bar__item');
7    this.mobHideItems = this.element.getElementsByClassName('menu-bar__item--hide');
8    this.moreItemsTrigger = this.element.getElementsByClassName('js-menu-bar__trigger');
9    initMenuBar(this);
10  };
11
12  function initMenuBar(menu) {
13    setMenuTabIndex(menu); // set correct tabindexes for menu item
14    initMenuBarMarkup(menu); // create additional markup
15    checkMenuLayout(menu); // set menu layout
16    Util.addClass(menu.element, 'menu-bar--loaded'); // reveal menu
17
18    // custom event emitted when window is resized
19    menu.element.addEventListener('update-menu-bar', function(event){
20      checkMenuLayout(menu);
21      if(menu.menuInstance) menu.menuInstance.toggleMenu(false, false); // close dropdown
22    });
23
24    // keyboard events 
25    // open dropdown when pressing Enter on trigger element
26    if(menu.moreItemsTrigger.length > 0) {
27      menu.moreItemsTrigger[0].addEventListener('keydown', function(event) {
28        if( (event.keyCode && event.keyCode == 13) || (event.key && event.key.toLowerCase() == 'enter') ) {
29          if(!menu.menuInstance) return;
30          menu.menuInstance.selectedTrigger = menu.moreItemsTrigger[0];
31          menu.menuInstance.toggleMenu(!Util.hasClass(menu.subMenu, 'menu--is-visible'), true);
32        }
33      });
34
35      // close dropdown on esc
36      menu.subMenu.addEventListener('keydown', function(event) {
37        if((event.keyCode && event.keyCode == 27) || (event.key && event.key.toLowerCase() == 'escape')) { // close submenu on esc
38          if(menu.menuInstance) menu.menuInstance.toggleMenu(false, true);
39        }
40      });
41    }
42    
43    // navigate menu items using left/right arrows
44    menu.element.addEventListener('keydown', function(event) {
45      if( (event.keyCode && event.keyCode == 39) || (event.key && event.key.toLowerCase() == 'arrowright') ) {
46        navigateItems(menu.items, event, 'next');
47      } else if( (event.keyCode && event.keyCode == 37) || (event.key && event.key.toLowerCase() == 'arrowleft') ) {
48        navigateItems(menu.items, event, 'prev');
49      }
50    });
51  };
52
53  function setMenuTabIndex(menu) { // set tabindexes for the menu items to allow keyboard navigation
54    var nextItem = false;
55    for(var i = 0; i < menu.items.length; i++ ) {
56      if(i == 0 || nextItem) menu.items[i].setAttribute('tabindex', '0');
57      else menu.items[i].setAttribute('tabindex', '-1');
58      if(i == 0 && menu.moreItemsTrigger.length > 0) nextItem = true;
59      else nextItem = false;
60    }
61  };
62
63  function initMenuBarMarkup(menu) {
64    if(menu.mobHideItems.length == 0 ) { // no items to hide on mobile - remove trigger
65      if(menu.moreItemsTrigger.length > 0) menu.element.removeChild(menu.moreItemsTrigger[0]);
66      return;
67    }
68
69    if(menu.moreItemsTrigger.length == 0) return;
70
71    // create the markup for the Menu element
72    var content = '';
73    menu.menuControlId = 'submenu-bar-'+Date.now();
74    for(var i = 0; i < menu.mobHideItems.length; i++) {
75      var item = menu.mobHideItems[i].cloneNode(true),
76        svg = item.getElementsByTagName('svg')[0],
77        label = item.getElementsByClassName('menu-bar__label')[0];
78
79      svg.setAttribute('class', 'icon menu__icon');
80      content = content + '<li role="menuitem"><span class="menu__content js-menu__content">'+svg.outerHTML+'<span>'+label.innerHTML+'</span></span></li>';
81    }
82
83    Util.setAttributes(menu.moreItemsTrigger[0], {'role': 'button', 'aria-expanded': 'false', 'aria-controls': menu.menuControlId, 'aria-haspopup': 'true'});
84
85    var subMenu = document.createElement('menu'),
86      customClass = menu.element.getAttribute('data-menu-class');
87    Util.setAttributes(subMenu, {'id': menu.menuControlId, 'class': 'menu js-menu '+customClass});
88    subMenu.innerHTML = content;
89    document.body.appendChild(subMenu);
90
91    menu.subMenu = subMenu;
92    menu.subItems = subMenu.getElementsByTagName('li');
93
94    menu.menuInstance = new Menu(menu.subMenu); // this will handle the dropdown behaviour
95  };
96
97  function checkMenuLayout(menu) { // switch from compressed to expanded layout and viceversa
98    var layout = getComputedStyle(menu.element, ':before').getPropertyValue('content').replace(/\'|"/g, '');
99    Util.toggleClass(menu.element, 'menu-bar--collapsed', layout == 'collapsed');
100  };
101
102  function navigateItems(list, event, direction, prevIndex) { // keyboard navigation among menu items
103    event.preventDefault();
104    var index = (typeof prevIndex !== 'undefined') ? prevIndex : Util.getIndexInArray(list, event.target),
105      nextIndex = direction == 'next' ? index + 1 : index - 1;
106    if(nextIndex < 0) nextIndex = list.length - 1;
107    if(nextIndex > list.length - 1) nextIndex = 0;
108    // check if element is visible before moving focus
109    (list[nextIndex].offsetParent === null) ? navigateItems(list, event, direction, nextIndex) : Util.moveFocus(list[nextIndex]);
110  };
111
112  function checkMenuClick(menu, target) { // close dropdown when clicking outside the menu element
113    if(menu.menuInstance && !menu.moreItemsTrigger[0].contains(target) && !menu.subMenu.contains(target)) menu.menuInstance.toggleMenu(false, false);
114  };
115
116  // init MenuBars objects
117  var menuBars = document.getElementsByClassName('js-menu-bar');
118  if( menuBars.length > 0 ) {
119    var j = 0,
120      menuBarArray = [];
121    for( var i = 0; i < menuBars.length; i++) {
122      var beforeContent = getComputedStyle(menuBars[i], ':before').getPropertyValue('content');
123      if(beforeContent && beforeContent !='' && beforeContent !='none') {
124        (function(i){menuBarArray.push(new MenuBar(menuBars[i]));})(i);
125        j = j + 1;
126      }
127    }
128    
129    if(j > 0) {
130      var resizingId = false,
131        customEvent = new CustomEvent('update-menu-bar');
132      // update Menu Bar layout on resize  
133      window.addEventListener('resize', function(event){
134        clearTimeout(resizingId);
135        resizingId = setTimeout(doneResizing, 150);
136      });
137
138      // close menu when clicking outside it
139      window.addEventListener('click', function(event){
140        menuBarArray.forEach(function(element){
141          checkMenuClick(element, event.target);
142        });
143      });
144
145      function doneResizing() {
146        for( var i = 0; i < menuBars.length; i++) {
147          (function(i){menuBars[i].dispatchEvent(customEvent)})(i);
148        };
149      };
150    }
151  }
152}());

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.