PageSourceSearch

https://backend.stage32.com/nav/v3/s32-nav-preview.js

js stage32.com collected 2026-09-24 08:58:01 UTC 4,531 bytes, 96 lines download raw bytes

1/*
2 * Stage 32 shared-nav PREVIEW loader — drop-in for the legacy (Drupal) and Next.js sites.
3 *
4 * Adds the new shared nav/footer to a page ONLY when the viewer has opted in with the `?nav=new`
5 * preview flag. Dark by default: with no flag it does NOTHING, so the site keeps its current live
6 * menu untouched. This is the client-side, cache-safe preview from
7 * _docs/20260807-unified-nav/README.md §4a — every cached page stays byte-identical for all users.
8 *
9 * ONE line to add (keep the existing site menu exactly as is):
10 *
11 *   <script src="https://backend.stage32.com/nav/v3/s32-nav-preview.js"
12 *           data-hide="#site-navbar, #site-footer" defer></script>
13 *
14 *   data-hide : CSS selector(s) for the site's CURRENT nav + footer, hidden only while previewing.
15 *   data-api  : (optional) override the menu API base. Defaults to the production endpoint.
16 *
17 * Turn on:  add ?nav=new to any URL (sets a cookie on .stage32.com so it sticks across pages/subdomains).
18 * Turn off: add ?nav=off  (or clear cookies).
19 *
20 * Nothing here replaces the live menu. The real cutover (server-rendered, old menu removed) is a
21 * separate, deliberate step — not this preview.
22 */
23(function () {
24  'use strict'
25  var COOKIE = 's32_nav_preview'
26  var BUNDLE = 'https://backend.stage32.com/nav/v3/s32-nav.js'
27  var DEFAULT_API = 'https://backend.stage32.com/api/v2/nav'
28  var script = document.currentScript
29
30  function qp(name) {
31    var m = location.search.match(new RegExp('[?&]' + name + '=([^&]*)'))
32    return m ? decodeURIComponent(m[1]) : null
33  }
34  function getCookie(name) {
35    var m = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;]*)'))
36    return m ? m[1] : null
37  }
38  function setCookie(name, val) {
39    var base = name + '=' + val + ';path=/;max-age=' + (60 * 60 * 24 * 30) + ';SameSite=Lax'
40    // Scope to .stage32.com so the preview survives www -> subdomain hops.
41    document.cookie = /(^|\.)stage32\.com$/.test(location.hostname)
42      ? base + ';domain=.stage32.com' : base
43  }
44
45  // Flag -> cookie. ?nav=new opts in, ?nav=off opts out.
46  var flag = qp('nav')
47  if (flag === 'new') setCookie(COOKIE, '1')
48  if (flag === 'off') setCookie(COOKIE, '0')
49
50  // Dark by default: not opted in -> do nothing, leave the live menu alone.
51  if (getCookie(COOKIE) !== '1') return
52
53  var api = (script && script.getAttribute('data-api')) || DEFAULT_API
54  var hide = (script && script.getAttribute('data-hide')) || ''
55  // Optional site-specific preview-only CSS (applied ONLY while previewing). Use it to fix layout
56  // the hidden nav leaves behind, e.g. Legacy: data-css="#wrap{padding-top:0 !important}".
57  var css = (script && script.getAttribute('data-css')) || ''
58
59  function activate() {
60    // Hide the site's current nav/footer + any layout fix (reversible: it's just a <style>).
61    if (hide || css) {
62      var st = document.createElement('style')
63      st.id = 's32-preview-style'
64      st.textContent = (hide ? hide + '{display:none !important}' : '') + css
65      document.head.appendChild(st)
66    }
67    // Load the shared component bundle (classic script: loads cross-origin, no CORS needed).
68    if (!document.getElementById('s32-nav-bundle')) {
69      var b = document.createElement('script')
70      b.id = 's32-nav-bundle'; b.src = BUNDLE; b.async = true
71      document.head.appendChild(b)
72    }
73    function mount() {
74      if (document.getElementById('s32-nav-preview-el')) return
75      var nav = document.createElement('s32-nav')
76      nav.id = 's32-nav-preview-el'; nav.setAttribute('api', api)
77      document.body.insertBefore(nav, document.body.firstChild)
78      var footer = document.createElement('s32-footer')
79      footer.setAttribute('api', api)
80      document.body.appendChild(footer)
81    }
82    if (document.readyState !== 'loading') mount()
83    else document.addEventListener('DOMContentLoaded', mount)
84  }
85
86  // Respect the global kill switch BEFORE touching the page: if the shared component is disabled
87  // (config/nav.php component_enabled=false), do NOTHING — never hide the site's own nav, or a
88  // previewer would be left with no menu at all. Same credentialed fetch the component uses.
89  fetch(api, { credentials: 'include', headers: { Accept: 'application/json' } })
90    .then(function (r) { return r.ok ? r.json() : null })
91    .then(function (j) {
92      if (j && j.data && j.data.component_enabled === false) return // killed -> leave live menu alone
93      activate()
94    })
95    .catch(function () { /* API unreachable: leave the live menu untouched */ })
96})()

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.