PageSourceSearch

https://shop.nait.ca/eSolution_config/themes/Arrow/js/arrow-flyoutnav.js

js nait.ca collected 2026-09-24 18:25:58 UTC 5,321 bytes, 170 lines download raw bytes

1(function () {
2
3    var desktop = document.getElementById('flyoutnavDesktop');
4    var track   = document.getElementById('flyoutnavTrack');
5
6    if (!desktop || !track) return;
7
8    var activeTab = null;
9    var stack = [];
10
11    function childrenLis(ul) {
12        return Array.from(ul.children).filter(function (n) { return n.tagName === 'LI'; });
13    }
14    function titleOf(li) {
15        var a = li.querySelector(':scope > a');
16        return a ? a.textContent.trim() : '';
17    }
18    function hrefOf(li) {
19        var a = li.querySelector(':scope > a');
20        return a ? (a.getAttribute('href') || '#') : '#';
21    }
22    function childUL(li) {
23        return li.querySelector(':scope > ul');
24    }
25
26    function makePanel(ul) {
27        var entries = [];
28        childrenLis(ul).forEach(function (li) {
29            var sub = childUL(li);
30            entries.push({
31                title: titleOf(li),
32                href: hrefOf(li),
33                childUL: sub
34            });
35        });
36        return entries;
37    }
38    //helpers to ensure active tab is greyed out when its menu is open
39    function markActiveTab(tabLi) {
40        // Remove from any previous tab
41        document
42            .querySelectorAll('.flyoutnav-tab > a.nav-link.flyoutnav-active')
43            .forEach(a => a.classList.remove('flyoutnav-active'));
44
45        if (!tabLi) return;
46
47        var link = tabLi.querySelector(':scope > a.nav-link');
48        if (link) {
49            link.classList.add('flyoutnav-active');
50        }
51    }
52
53    function clearActiveTab() {
54        document
55            .querySelectorAll('.flyoutnav-tab > a.nav-link.flyoutnav-active')
56            .forEach(a => a.classList.remove('flyoutnav-active'));
57    }
58
59
60    function renderAll() {
61        track.innerHTML = '';
62
63        stack.forEach(function (panelEntries, idx) {
64            var col = document.createElement('div');
65            col.className = 'flyoutnav-panel';
66
67            var list = document.createElement('ul');
68            list.className = 'flyoutnav-list';
69
70            panelEntries.forEach(function (item) {
71                var li = document.createElement('li');
72
73                if (item.childUL) {
74                    // Parent: clickable but DOES NOT navigate
75                    var row = document.createElement('button');
76                    row.type = 'button';
77                    row.className = 'flyoutnav-row has-children';
78                    row.innerHTML = '<span>' + item.title + '</span><span class="flyoutnav-chev">›</span>';
79
80                    row.addEventListener('click', function (e) {
81                        e.preventDefault();
82                        // trim stack to this column, then add next
83                        stack.splice(idx + 1);
84                        stack.push(makePanel(item.childUL));
85                        renderAll();
86                    });
87
88                    li.appendChild(row);
89                } else {
90                    // Leaf: normal navigation
91                    var a = document.createElement('a');
92                    a.className = 'flyoutnav-row';
93                    a.href = item.href || '#';
94                    a.textContent = item.title;
95                    li.appendChild(a);
96                }
97
98                list.appendChild(li);
99            });
100
101            col.appendChild(list);
102            track.appendChild(col);
103        });
104    }
105
106    function openForTab(tabLi) {
107        activeTab = tabLi;
108
109        var source = tabLi.querySelector(':scope > ul.flyoutnav-source');
110        if (!source) {
111            closeFlyout();
112            return;
113        }
114
115        stack = [ makePanel(source) ];
116        renderAll();
117
118        desktop.classList.add('active');
119        desktop.setAttribute('aria-hidden', 'false');
120
121        markActiveTab(tabLi);
122
123        // Position under the navbar
124        var rect = tabLi.getBoundingClientRect();
125        desktop.style.left = '0px';
126        desktop.style.top = (tabLi.offsetTop + tabLi.offsetHeight) + 'px';
127    }
128
129    function closeFlyout() {
130        activeTab = null;
131        stack = [];
132        track.innerHTML = '';
133        desktop.classList.remove('active');
134        desktop.setAttribute('aria-hidden', 'true');
135
136        clearActiveTab();
137    }
138
139    // Hover behavior on top-level tabs
140    document.querySelectorAll('.flyoutnav-tab').forEach(function (tabLi) {
141        tabLi.addEventListener('mouseenter', function () {
142            openForTab(tabLi);
143        });
144    });
145
146    // Keep open when mouse is over flyout
147    desktop.addEventListener('mouseenter', function () {
148        // do nothing
149    });
150
151    // Close when leaving both tab area + flyout
152    desktop.addEventListener('mouseleave', closeFlyout);
153
154    // Close if user leaves nav entirely
155    var nav = document.querySelector('.primary-navigation');
156    nav && nav.addEventListener('mouseleave', function () {
157        // small delay helps cursor move from tab into panel
158        setTimeout(function () {
159            if (!desktop.matches(':hover') && !(activeTab && activeTab.matches(':hover'))) {
160                closeFlyout();
161            }
162        }, 150);
163    });
164    const flyout = document.getElementById('flyoutnavDesktop');
165    if (!flyout) return;
166
167    // Move flyout OUT of header/container for a full width dropdown menu
168    document.body.appendChild(flyout);
169
170})();

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.