PageSourceSearch

https://markmetric.in/modules/marketplace/assets/javascripts/topnav_header.js?v=1790861973

js markmetric.in collected 2026-10-09 22:55:59 UTC 13,373 bytes, 378 lines download raw bytes

1/**
2 * Top-nav header interactions.
3 * Loaded immediately from _header_topnav.php (not deferred via Assets).
4 */
5(function () {
6  'use strict';
7
8  // Footer accordion (onclick in _footer_optimized_redesign.php). Defined here
9  // because top-nav pages skip header_redesign.js, which previously owned this.
10  // Prefer jQuery slide when available; vanilla fallback for deferred Assets.
11  window.footerMobileLinks = function (element) {
12    if (!element) return;
13    if (window.jQuery) {
14      var $el = window.jQuery(element);
15      var $content = $el.next('.footer-menu');
16      if ($content.is(':visible')) {
17        $content.slideUp();
18        $el.removeClass('active');
19      } else {
20        $content.slideDown();
21        $el.addClass('active');
22      }
23      return;
24    }
25    var content = element.nextElementSibling;
26    if (!content || !content.classList.contains('footer-menu')) return;
27    if (element.classList.contains('active')) {
28      content.style.display = 'none';
29      element.classList.remove('active');
30    } else {
31      content.style.display = 'block';
32      element.classList.add('active');
33    }
34  };
35
36  // Chat is clicked before the idle Intercom loader runs, so Intercom() is missing.
37  window.openSupportChat = function (event) {
38    if (event && event.preventDefault) event.preventDefault();
39
40    window.intercomSettings = window.intercomSettings || { app_id: 'ld9mkn53' };
41
42    if (typeof window.Intercom !== 'function') {
43      var queued = function () { queued.c(arguments); };
44      queued.q = [];
45      queued.c = function (args) { queued.q.push(args); };
46      window.Intercom = queued;
47    }
48
49    if (!document.querySelector('script[src*="widget.intercom.io/widget/ld9mkn53"]')) {
50      var script = document.createElement('script');
51      script.type = 'text/javascript';
52      script.async = true;
53      script.src = 'https://widget.intercom.io/widget/ld9mkn53';
54      document.head.appendChild(script);
55    }
56
57    window.Intercom('show');
58  };
59
60  if (window.__tnHeaderInit) return;
61  window.__tnHeaderInit = true;
62
63  function ready(fn) {
64    if (document.readyState === 'loading') {
65      document.addEventListener('DOMContentLoaded', fn);
66    } else {
67      fn();
68    }
69  }
70
71  // Account menus (dropdown + drawer). The header HTML is cached at the
72  // Cloudflare edge and shared by all visitors, so login state can't be
73  // rendered server-side. Guess from the jwt_token cookie for a fast first
74  // paint, then confirm with /controllers/sessions.php (uncached), which also
75  // issues a missing jwt. A stale jwt (session expired) is cleared here: the
76  // endpoint's own clear omits path=/ and so misses the root cookie.
77  ready(function () {
78    var authEls = Array.prototype.slice.call(document.querySelectorAll('[data-tn-auth]'));
79    if (!authEls.length) return;
80
81    function applyAuth(loggedIn) {
82      authEls.forEach(function (el) {
83        if ((el.getAttribute('data-tn-auth') === 'in') === loggedIn) {
84          el.style.removeProperty('display');
85        } else {
86          el.style.setProperty('display', 'none', 'important');
87        }
88      });
89    }
90
91    var jwtMatch = document.cookie.match(/(?:^|;\s*)jwt_token=([^;]*)/);
92    var jwt = jwtMatch ? decodeURIComponent(jwtMatch[1]) : '';
93    applyAuth(jwt !== '' && jwt !== 'undefined');
94
95    if (!window.fetch) return;
96    fetch('/controllers/sessions.php', { credentials: 'same-origin', cache: 'no-store' })
97      .then(function (res) { return res.json(); })
98      .then(function (data) {
99        if (!data || !data.success) return;
100        if (!data.token && jwt) {
101          document.cookie = 'jwt_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT';
102        }
103        applyAuth(!!data.token);
104      })
105      .catch(function () {});
106  });
107
108  ready(function () {
109    var header = document.getElementById('tnHeader');
110    if (!header) return;
111
112    document.body.classList.add('has-tn-header');
113
114    var items = Array.prototype.slice.call(header.querySelectorAll('[data-tn-menu]'));
115    var panels = Array.prototype.slice.call(header.querySelectorAll('[data-tn-panel]'));
116    var dropdowns = Array.prototype.slice.call(header.querySelectorAll('.tn-header__dropdown'));
117    var closeTimer = null;
118    var spacer = document.getElementById('tnHeaderSpacer');
119    var SCROLL_THRESHOLD = 80;
120
121    var drawer = document.getElementById('tnDrawer');
122    var backdrop = document.getElementById('tnDrawerBackdrop');
123    var openBtns = Array.prototype.slice.call(document.querySelectorAll('[data-tn-menu-open]'));
124    var closeBtn = document.getElementById('tnMenuClose');
125    var mobileSearchToggle = document.getElementById('tnMobileSearchToggle');
126    // Premium marketplace pages ship their own sticky search bar — don't pin
127    // the site header on scroll (it would overlap that UI).
128    var hasMarketplaceStickySearch = !!document.getElementById('sticky-search-bar')
129      && !!document.getElementById('search-container');
130    var currentPath = window.location.pathname || '';
131    var isRegisterPath = /^\/register(?:\/|$)/.test(currentPath);
132    var isHandRegDealsPath = /^\/hand-reg-deals(?:\/|$)/.test(currentPath);
133    var isTrademarkFilingPath = /^\/trademark-filing(?:\/|$)/.test(currentPath);
134    var isNamePath = /^\/name(?:\/|$)/.test(currentPath);
135    var isDomainAppraisalPath = /^\/domain-appraisal(?:\/|$)/.test(currentPath);
136    var isSellingSettingsPath = /^\/marketplace\/settings\/selling(?:\/|$)/.test(currentPath);
137    var isRegisterTldPath = /^\/register\/tld(?:\/|$)/.test(currentPath);
138    var shouldHideHeaderOnScroll = (isRegisterPath && !isRegisterTldPath) || isHandRegDealsPath;
139    if (hasMarketplaceStickySearch) {
140      document.body.classList.add('has-marketplace-sticky-search');
141    }
142    if (shouldHideHeaderOnScroll) {
143      document.body.classList.add('has-register-scroll-hide');
144    }
145
146    function setMenuOpenExpanded(expanded) {
147      openBtns.forEach(function (btn) {
148        btn.setAttribute('aria-expanded', expanded ? 'true' : 'false');
149      });
150    }
151
152    function closeAllMenus() {
153      items.forEach(function (item) {
154        item.classList.remove('is-open');
155        var btn = item.querySelector('.tn-header__nav-btn');
156        if (btn) btn.setAttribute('aria-expanded', 'false');
157      });
158      panels.forEach(function (panel) {
159        panel.classList.remove('is-open');
160      });
161    }
162
163    function openMenu(key) {
164      items.forEach(function (item) {
165        var isActive = item.getAttribute('data-tn-menu') === key;
166        item.classList.toggle('is-open', isActive);
167        var btn = item.querySelector('.tn-header__nav-btn');
168        if (btn) btn.setAttribute('aria-expanded', isActive ? 'true' : 'false');
169      });
170      panels.forEach(function (panel) {
171        panel.classList.toggle('is-open', panel.getAttribute('data-tn-panel') === key);
172      });
173    }
174
175    function closeAllDropdowns() {
176      dropdowns.forEach(function (dd) {
177        dd.classList.remove('is-open');
178        var toggle = dd.querySelector('.tn-header__dropdown-toggle');
179        if (toggle) toggle.setAttribute('aria-expanded', 'false');
180      });
181    }
182
183    function closeMobileSearch() {
184      header.classList.remove('is-mobile-search-open');
185      if (mobileSearchToggle) mobileSearchToggle.setAttribute('aria-expanded', 'false');
186    }
187
188    function openDrawer(e) {
189      if (e) {
190        e.preventDefault();
191        e.stopPropagation();
192      }
193      if (!drawer || !backdrop) return;
194      closeAllMenus();
195      closeAllDropdowns();
196      closeMobileSearch();
197      drawer.hidden = false;
198      backdrop.hidden = false;
199      void drawer.offsetWidth;
200      drawer.classList.add('is-open');
201      backdrop.classList.add('is-open');
202      drawer.setAttribute('aria-hidden', 'false');
203      setMenuOpenExpanded(true);
204      document.body.classList.add('tn-header-open');
205    }
206
207    function closeDrawer() {
208      if (!drawer || !backdrop) return;
209      drawer.classList.remove('is-open');
210      backdrop.classList.remove('is-open');
211      drawer.setAttribute('aria-hidden', 'true');
212      setMenuOpenExpanded(false);
213      document.body.classList.remove('tn-header-open');
214      setTimeout(function () {
215        if (!drawer.classList.contains('is-open')) {
216          drawer.hidden = true;
217          backdrop.hidden = true;
218        }
219      }, 250);
220    }
221
222    window.tnHeaderOpenDrawer = openDrawer;
223    window.tnHeaderCloseDrawer = closeDrawer;
224
225    document.addEventListener('click', function (e) {
226      if (e.target.closest('.sticky-bar-hamburger')) {
227        e.preventDefault();
228        e.stopPropagation();
229        openDrawer(e);
230      }
231    });
232
233    items.forEach(function (item) {
234      var key = item.getAttribute('data-tn-menu');
235      item.addEventListener('mouseenter', function () {
236        clearTimeout(closeTimer);
237        closeAllDropdowns();
238        openMenu(key);
239      });
240      item.addEventListener('mouseleave', function () {
241        closeTimer = setTimeout(closeAllMenus, 160);
242      });
243      var btn = item.querySelector('.tn-header__nav-btn');
244      if (btn) {
245        btn.addEventListener('click', function (e) {
246          e.preventDefault();
247          e.stopPropagation();
248          closeAllDropdowns();
249          if (item.classList.contains('is-open')) {
250            closeAllMenus();
251          } else {
252            openMenu(key);
253          }
254        });
255      }
256    });
257
258    panels.forEach(function (panel) {
259      panel.addEventListener('mouseenter', function () {
260        clearTimeout(closeTimer);
261      });
262      panel.addEventListener('mouseleave', function () {
263        closeTimer = setTimeout(closeAllMenus, 160);
264      });
265    });
266
267    dropdowns.forEach(function (dd) {
268      var toggle = dd.querySelector('.tn-header__dropdown-toggle');
269      if (!toggle) return;
270      toggle.addEventListener('click', function (e) {
271        e.preventDefault();
272        e.stopPropagation();
273        var willOpen = !dd.classList.contains('is-open');
274        closeAllDropdowns();
275        closeAllMenus();
276        if (willOpen) {
277          dd.classList.add('is-open');
278          toggle.setAttribute('aria-expanded', 'true');
279        }
280      });
281    });
282
283    document.addEventListener('keydown', function (e) {
284      if (e.key === 'Escape') {
285        closeAllMenus();
286        closeAllDropdowns();
287        closeDrawer();
288        closeMobileSearch();
289      }
290    });
291
292    document.addEventListener('click', function (e) {
293      if (!header.contains(e.target)) {
294        closeAllMenus();
295        closeAllDropdowns();
296        closeMobileSearch();
297      }
298    });
299
300    function onScroll() {
301      var scrolled = window.scrollY > SCROLL_THRESHOLD;
302
303      // Keep the top-of-page header (no sticky/fixed) on these landers.
304      if (isTrademarkFilingPath || isNamePath || isDomainAppraisalPath || isSellingSettingsPath || isRegisterTldPath) {
305        header.classList.remove('is-scrolled', 'is-scroll-hidden');
306        if (spacer) spacer.classList.remove('is-active');
307        document.body.classList.remove('tn-header-fixed');
308        return;
309      }
310
311      if (hasMarketplaceStickySearch || shouldHideHeaderOnScroll) {
312        header.classList.toggle('is-scroll-hidden', scrolled);
313        header.classList.remove('is-scrolled');
314        if (spacer) spacer.classList.remove('is-active');
315        document.body.classList.remove('tn-header-fixed');
316      } else {
317        header.classList.remove('is-scroll-hidden');
318        header.classList.toggle('is-scrolled', scrolled);
319        if (spacer) spacer.classList.toggle('is-active', scrolled);
320        document.body.classList.toggle('tn-header-fixed', scrolled);
321      }
322
323      if (scrolled) {
324        closeAllMenus();
325        if (hasMarketplaceStickySearch || shouldHideHeaderOnScroll) closeMobileSearch();
326      }
327    }
328
329    window.addEventListener('scroll', onScroll, { passive: true });
330    onScroll();
331
332    openBtns.forEach(function (btn) {
333      btn.addEventListener('click', openDrawer);
334    });
335    if (closeBtn) closeBtn.addEventListener('click', function (e) {
336      e.preventDefault();
337      e.stopPropagation();
338      closeDrawer();
339    });
340    if (backdrop) backdrop.addEventListener('click', closeDrawer);
341
342    if (mobileSearchToggle) {
343      mobileSearchToggle.addEventListener('click', function (e) {
344        e.preventDefault();
345        e.stopPropagation();
346        closeAllMenus();
347        closeAllDropdowns();
348        var willOpen = !header.classList.contains('is-mobile-search-open');
349        header.classList.toggle('is-mobile-search-open', willOpen);
350        mobileSearchToggle.setAttribute('aria-expanded', willOpen ? 'true' : 'false');
351        if (willOpen) {
352          var searchInput = document.getElementById('tnHeaderSearchInput');
353          if (searchInput) {
354            setTimeout(function () { searchInput.focus(); }, 50);
355          }
356        }
357      });
358    }
359
360    var form = document.getElementById('tnHeaderSearchForm');
361    var input = document.getElementById('tnHeaderSearchInput');
362    if (form && input) {
363      form.addEventListener('submit', function (e) {
364        e.preventDefault();
365        var q = (input.value || '').trim();
366        if (!q) {
367          input.focus();
368          return;
369        }
370
371        window.location.href = '/premium-domains-for-sale/q/' + encodeURIComponent(q);
372      });
373    }
374
375    var sticky = document.getElementById('stickySearchBar');
376    if (sticky) sticky.style.display = 'none';
377  });
378})();

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.