PageSourceSearch

https://fxdworkwear.com.au/cdn/shop/t/135/assets/mega-menu.min.js?v=137368518511133168401788929107

js fxdworkwear.com.au collected 2026-10-08 01:57:44 UTC 12,093 bytes, 442 lines download raw bytes

1Shopify.MegaMenu = {};
2
3Shopify.LoadMegaMenu = function(){
4  this.navigation = [];
5  this.layouts = [];
6  this.templates = {};
7  this.products = [];
8
9  this.selectors = {
10    menuLayoutsData: '[data-mega-menu]',
11    navigationData: '#Navigation > p',
12    htmlTemplates: '[data-template-for]'
13  };
14
15  Shopify.loadElements(this,this.selectors);
16
17  this.menuLayoutsData = this.menuLayoutsData.innerHTML;
18  var navData = []
19  document.querySelectorAll("#Navigation > p").forEach(el => {
20    navData = [
21    	...navData,
22      ...el.children
23    ]
24  })
25  this.navigationData = navData;
26  this.navigationLinks = Array.from(this.navigationData);
27
28  Shopify.MegaMenu = {
29    layouts: []
30  }
31
32  this.parseNavLinks();
33  this.parseMegaMenu();
34  this.parseHtmlTemplates();
35  this.buildMenuLayouts();
36  this.loadMenuProducts();
37  
38};
39
40Shopify.LoadMegaMenu.prototype = {
41  
42  parseNavLinks: function(){
43    const self = this;
44    
45    self.navigationLinks.forEach((item) => {
46
47      var group = {
48        title: item.dataset.title,
49        level: parseInt(item.dataset.level),
50        url: item.dataset.ref,
51        hash: item.dataset.ref == '#' ? '#' : '',
52        handle: '',
53        parentHandle: '',
54        childLinks: []
55      };
56
57      group.handle = item.dataset && item.dataset.handle ? item.dataset.handle : item.innerText.toLowerCase().replaceAll(' ','-').replaceAll('#','');
58
59      let index = parseInt(item.dataset.level);
60      let lastNavItemIndex = self.navigation.length-1;
61      switch(index) {
62        case 1:
63          self.navigation.push(group);
64          break;
65        case 2:
66          group.parentHandle = self.navigation[(lastNavItemIndex)].handle;
67          self.navigation[(lastNavItemIndex)].childLinks.push(group);
68          break;
69        case 3:
70          group.parentHandle = self.navigation[(lastNavItemIndex)].childLinks[(self.navigation[(lastNavItemIndex)].childLinks.length-1)].handle;
71          self.navigation[(lastNavItemIndex)].childLinks[(self.navigation[(lastNavItemIndex)].childLinks.length-1)].childLinks.push(group);
72          break;
73        default:
74          // code block
75      }
76    });
77
78  },
79
80  parseMegaMenu: function(){
81    const self = this;
82
83    const menu = JSON.parse(self.menuLayoutsData);
84    menu.forEach((item)=>{
85      if (item.menu_handle.length > 0){
86        Shopify.MegaMenu.layouts.push(item);
87      }
88    });
89  },
90
91  parseHtmlTemplates: function(){
92    const self = this;
93
94    self.htmlTemplates.forEach((item) => {
95      if (item.dataset.templateFor.includes('mega-menu')){
96        self.templates[item.dataset.templateName] = { 
97          html: item.innerHTML, 
98          blocks: item.dataset.blocks.split(',') 
99        };
100      }
101    });
102
103  },
104
105  loadMenuProducts: async function(){
106    const self = this;
107    let batchArray = [];
108
109    Shopify.MegaMenu.layouts.forEach(async (menu) => {
110
111      if (menu && menu.images){
112        menu.images.map( async (blocks) => {
113          if (blocks.product.length > 0){
114            batchArray.push(self.loadProductData(blocks.product));
115          }
116        });
117      }
118      
119    });
120
121    if (batchArray.length > 0){
122      await Promise.all(batchArray)
123      .then(function() {
124
125        self.buildProductLayouts();
126
127      }).catch(function(error) {
128        console.log(error);
129      });
130    }
131
132  },
133
134  buildGridItem: function(data){
135    const self = this;
136    let template = {};
137
138    template = Object.assign({},self.templates['product-item']);
139
140    return self.setTemplateVariables(template,data.product);
141    
142  },
143
144  buildMenuLayouts: function(){
145    const self = this;
146    Shopify.MegaMenu.layouts.forEach((item)=>{
147
148      item.template = Object.assign({}, self.templates[item.layout]);
149
150      if (!item.navList){
151        item.navList = self.navigation.find((list)=>{
152          if (list.handle == item.menu_handle){
153            return list;
154          }
155        });
156      }
157
158      item.template.blocks.forEach((block)=>{
159        switch(block) {
160          case 'navlist':
161            item.template.html = item.template.html.replaceAll(`{${block}}`,self.buildNavlist(item));
162            break;
163          case 'images':
164            item.template.html = item.template.html.replaceAll(`{${block}}`,self.buildImages(item));
165            break;
166          default:
167            item.template.html = item.template.html.replaceAll(`{${block}}`,item[block]);
168            break;
169        }
170      });
171
172    });
173
174
175  },
176
177  buildProductLayouts: function(){
178    const self = this;
179
180    Shopify.MegaMenu.layouts.forEach((menu) => {
181
182      if (menu && menu.images){
183        menu.images.map((block) => {
184          if (block.product.length > 0){
185            let product = Object.assign(block, self.products.find((item)=> item.handle == block.product));
186
187            console.log("product", product);
188            console.log("menu", menu);
189            console.log("block", block);
190            if (product){
191              if (menu.icon) {
192                product.title = `${menu.icon} ${product.title}`;
193              }
194              let productGridItem = self.buildProductGridItem(product);
195
196              console.log("productGridItem", productGridItem);
197              menu.template.html = menu.template.html.replace('<div data-menu-product></div>',productGridItem);
198
199              const updateMegaMenu = new CustomEvent('update:mega-menu', {
200                bubbles: true,
201                detail: { handle: menu.menu_handle }
202              });
203              document.dispatchEvent(updateMegaMenu);
204            }
205            
206          }
207        });
208      }
209      
210    });
211  },
212
213  buildProductGridItem: function(product){
214    const self = this;
215    let template = Object.assign({}, self.templates['product-item']);
216
217    template.blocks.forEach((block)=>{
218      switch(block) {
219        case 'navlist':
220          template.html = template.html.replaceAll(`{${block}}`,self.buildNavlist(product));
221          break;
222        case 'images':
223          template.html = template.html.replaceAll(`{${block}}`,self.buildImages(product));
224          break;
225        case 'price':
226          template.html = template.html.replaceAll(`{${block}}`,Shopify.formatMoney(product[block]));
227          break;
228        default:
229          template.html = template.html.replaceAll(`{${block}}`,product[block]);
230          break;
231      }
232    });
233
234    return template.html;
235  },
236
237  loadProductData: async function(handle){
238    const self = this;
239
240    return fetch(`${routes.product_url.replace('[handle]',handle)}`)
241    .then((response) => {
242      return response.text();
243    })
244    .then((data) => {
245      self.products.push(JSON.parse(data));
246      return;
247    }).catch(()=>{
248      return '';
249    });
250    
251  },
252
253  buildImages: function(item){
254    const self = this;
255    let imageGrid = '';
256
257    const imageItemTemplate = Object.assign({}, self.templates['image-item']);
258    const emptyProductTemplate = '<div data-menu-product></div>'
259
260    item.images.forEach((imageItem)=>{
261      
262      if (imageItem.product.length == 0){
263        imageGrid = imageGrid + self.setTemplateVariables(imageItemTemplate,imageItem);
264      }
265      else {
266        imageGrid = imageGrid + emptyProductTemplate;
267      }
268  
269    });
270
271    return imageGrid;
272  },
273
274  setTemplateVariables: function(template,item){
275    let output = template.html;
276
277    template.blocks.forEach((block)=>{
278      output = output.replaceAll(`{${block}}`,item[block]);
279    });
280
281    return output;
282  },
283
284  buildNavlist: function(item){
285    const self = this;
286    let output = '';
287    let navlistTemplate = Object.assign({},self.templates['navlist']);
288    let navItemTemplate = Object.assign({},self.templates['navItem']);
289    
290    if (item.navList && item.navList.childLinks.length > 0){
291      item.navList.childLinks.forEach((listItem)=>{
292        let navItemsOutput = '';
293        let navlistOutput = navlistTemplate.html;
294
295        navItemsOutput = navItemsOutput + self.setTemplateVariables(navItemTemplate,listItem);
296
297        listItem.childLinks.forEach((linkItem)=>{
298          if (item.icon) {
299            linkItem.title = `${item.icon} ${linkItem.title}`;
300          }
301          navItemsOutput = navItemsOutput + self.setTemplateVariables(navItemTemplate,linkItem);
302        });
303
304        navlistOutput = navlistOutput.replace('{items}',navItemsOutput);
305        output = output + navlistOutput;
306      });
307    }
308    output = output.replaceAll(`{handle}`,item.handle);
309    return output;
310  },
311  
312};
313
314
315class MegaMenu extends HTMLElement {
316  constructor() {
317    super();
318    this.menus = [];
319
320    this.selectors = {
321      menuItems: '.mega-menu-btn, .mega-menu-link',
322      menuDropdowns: '.mega-menu-dropdown',
323      menuToggles: '[aria-expanded]'
324    };
325
326    Shopify.loadElements(this,this.selectors,this);
327    this.menuDropdowns = Array.from(this.menuDropdowns);
328    
329    this.bindElements();
330    this.buildMenus();
331    this.bindEvents();
332  }
333
334  bindEvents(){
335    const self = this;
336
337    document.addEventListener('update:mega-menu',(evt)=>{
338      let handle = evt.detail.handle;
339      console.log('self.menus', self.menus);
340      console.log('handle', handle);
341      let menu = self.menus.find((menu)=> menu.handle == handle);
342      console.log('menu2', menu);
343      if(menu){
344        self.updateMenu(menu);
345      }
346      else {
347        console.log('Unable to match menu handle, please check all menuItem selectors are set')
348      }
349      
350    })
351
352    this.addEventListener('keydown', (event)=>{this.triggerKeydownHandler(event)});
353  }
354
355  triggerKeydownHandler(event){
356    self = this;
357    if (event.keyCode === 13) {
358      if (event.target.hasAttribute('aria-expanded')){
359        self.closeOtherMenus(event.target);
360        event.target.setAttribute('aria-expanded',!(event.target.getAttribute('aria-expanded') == 'true'));
361      }
362    }
363    if(event.key == 'Escape') {
364      self.closeOtherMenus();
365      event.target.closest('.mega-menu-item').nextElementSibling.focus();
366    }
367  }
368
369  closeOtherMenus(current){
370    for (var i = this.menuToggles.length - 1; i >= 0; i--) {
371      let toggle = this.menuToggles[i];
372      if (current && current == toggle){
373
374      }
375      else {
376        toggle.setAttribute('aria-expanded',false);
377      }
378      
379    }
380  }
381
382  bindElements(){
383    const self = this;
384    let handleCounts = {};
385
386    this.menuItems.forEach((item)=>{
387      let key = item.dataset.menu;
388      let title = item.dataset.item;
389      let scope = item.closest('.mega-menu-item');
390      let dropdown = scope ? scope.querySelector('.mega-menu-dropdown') : undefined;
391      if (dropdown && dropdown.dataset.menu !== key){
392        console.log('Mismatched mega-menu dropdown for item data-menu='+key);
393        dropdown = undefined;
394      }
395      let handleIndex = handleCounts[title] || 0;
396      handleCounts[title] = handleIndex + 1;
397      this.menus.push( {
398        handle: title,
399        handleIndex: handleIndex,
400        button: this.menuItems,
401        dropdown: dropdown
402      });
403    });
404  }
405
406  buildMenus(handle){
407    const self = this;
408
409    self.menus.forEach((menu)=>{
410      self.updateMenu(menu);
411    });
412    
413  }
414
415  updateMenu(menu){
416    const self = this;
417
418    let matches = Shopify.MegaMenu.layouts.filter((item)=> {
419      return item.menu_handle == menu.handle;
420    });
421    let layout = matches[menu.handleIndex] || matches[0];
422    if (layout && layout.template){
423      if (menu.dropdown){
424        menu.dropdown.innerHTML = layout.template.html;
425        setTimeout(function(){
426          menu.dropdown.classList.remove('hidden');
427        }, 500);
428      }
429      else {
430        console.log('unable to find menu dropdown + data-menu='+menu.handle);
431      }
432      
433    }
434  }
435
436}
437
438new Shopify.LoadMegaMenu();
439
440customElements.define('mega-menu', MegaMenu);
441
442

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.