1/** 2 * Copyright 2026 Nametag Inc. 3 * 4 * All information contained herein is the property of Nametag Inc.. The 5 * intellectual and technical concepts contained herein are proprietary, trade 6 * secrets, and/or confidential to Nametag, Inc. and may be covered by U.S. 7 * and Foreign Patents, patents in process, and are protected by trade secret or 8 * copyright law. Reproduction or distribution, in whole or in part, is 9 * forbidden except by express written permission of Nametag, Inc. 10 */ 11 12/* ð¤ ross â front-end behavior for the redesigned docs: 13 * - âK command palette over the topic index 14 * - smooth-scroll + scroll-spy for the "on this page" TOC (and the legacy 15 * left-rail TableOfContents used by kb / legal / techblog) 16 * - code-block copy chrome 17 * - callout icons on blockquotes 18 * - mobile sidebar drawer 19 */ 20(function () { 21 "use strict"; 22 23 var HEADER_OFFSET = 84; 24 25 /* ð¤ Shared focus helpers for the palette + mobile popover. */ 26 var FOCUSABLE = 27 'a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'; 28 function focusable(container) { 29 return Array.prototype.filter.call(container.querySelectorAll(FOCUSABLE), function (el) { 30 return el.offsetWidth > 0 || el.offsetHeight > 0 || el === document.activeElement; 31 }); 32 } 33 function trapTab(container, e) { 34 if (e.key !== "Tab") return; 35 var items = focusable(container); 36 if (!items.length) return; 37 var first = items[0]; 38 var last = items[items.length - 1]; 39 if (e.shiftKey && document.activeElement === first) { 40 e.preventDefault(); 41 last.focus(); 42 } else if (!e.shiftKey && document.activeElement === last) { 43 e.preventDefault(); 44 first.focus(); 45 } 46 } 47 48 /* ---------------- Command palette ---------------- */ 49 function initPalette() { 50 var palette = document.getElementById("nt-palette"); 51 if (!palette) return; 52 53 var index = window.ntSearchIndex || []; 54 55 var input = palette.querySelector(".nt-palette__input"); 56 var resultsEl = palette.querySelector(".nt-palette__results"); 57 var countEl = palette.querySelector(".nt-palette__count"); 58 var active = -1; 59 var current = []; 60 61 function render() { 62 var q = input.value.trim().toLowerCase(); 63 var matched = q 64 ? index.filter(function (t) { 65 return (t.title + " " + t.desc + " " + t.group).toLowerCase().indexOf(q) !== -1; 66 }) 67 : index.slice(0, 7); 68 current = matched.slice(0, 8); 69 active = current.length ? 0 : -1; 70 71 resultsEl.innerHTML = ""; 72 if (q && current.length === 0) { 73 var empty = document.createElement("div"); 74 empty.className = "nt-palette__empty"; 75 empty.textContent = 'No results for "' + input.value + '".'; 76 resultsEl.appendChild(empty); 77 } else { 78 current.forEach(function (t, i) { 79 var a = document.createElement("a"); 80 a.className = "nt-palette__result" + (i === active ? " is-active" : ""); 81 a.href = t.href; 82 a.innerHTML = 83 '<span class="ms">' + 84 escapeHtml(t.icon || "description") + 85 "</span>" + 86 '<span class="nt-palette__result-text">' + 87 '<span class="nt-palette__result-title"></span>' + 88 '<span class="nt-palette__result-sub"></span>' + 89 "</span>" + 90 '<span class="ms nt-palette__result-arrow">arrow_forward</span>'; 91 a.querySelector(".nt-palette__result-title").textContent = t.title; 92 a.querySelector(".nt-palette__result-sub").textContent = t.group + " · " + t.desc; 93 a.addEventListener("mousemove", function () {
94 setActive(i); 95 }); 96 resultsEl.appendChild(a); 97 }); 98 } 99 if (countEl) countEl.textContent = matched.length + " result" + (matched.length === 1 ? "" : "s"); 100 } 101 102 function setActive(i) { 103 active = i; 104 var rows = resultsEl.querySelectorAll(".nt-palette__result"); 105 rows.forEach(function (r, idx) { 106 r.classList.toggle("is-active", idx === active); 107 }); 108 } 109 110 var lastTrigger = null; 111 var suppressAutoOpen = false; // ð¤ stop focus-return from re-opening the palette 112 113 function open(trigger) { 114 if (trigger) lastTrigger = trigger; 115 palette.hidden = false; 116 input.value = ""; 117 render(); 118 setTimeout(function () { 119 try { 120 input.focus(); 121 } catch (e) {} 122 }, 30); 123 } 124 function close() { 125 if (palette.hidden) return; 126 palette.hidden = true; 127 // ð¤ return focus to whatever opened the palette (a11y), without re-triggering 128 // the focus-to-open behavior on the search buttons. 129 if (lastTrigger) { 130 suppressAutoOpen = true; 131 try { 132 lastTrigger.focus(); 133 } catch (e) {} 134 setTimeout(function () { 135 suppressAutoOpen = false; 136 }, 120); 137 } 138 } 139 function isOpen() { 140 return !palette.hidden; 141 } 142 143 input.addEventListener("input", render); 144 145 // ð¤ focus trap: keep Tab within the modal panel while it's open. 146 palette.addEventListener("keydown", function (e) { 147 if (isOpen() && panel) trapTab(panel, e); 148 }); 149 150 input.addEventListener("keydown", function (e) { 151 if (e.key === "ArrowDown") { 152 e.preventDefault(); 153 if (current.length) setActive((active + 1) % current.length); 154 scrollActiveIntoView(); 155 } else if (e.key === "ArrowUp") { 156 e.preventDefault(); 157 if (current.length) setActive((active - 1 + current.length) % current.length); 158 scrollActiveIntoView(); 159 } else if (e.key === "Enter") { 160 e.preventDefault(); 161 var rows = resultsEl.querySelectorAll(".nt-palette__result"); 162 if (rows[active]) window.location.href = rows[active].href; 163 } 164 }); 165 166 function scrollActiveIntoView() { 167 var row = resultsEl.querySelectorAll(".nt-palette__result")[active]; 168 if (row) row.scrollIntoView({ block: "nearest" }); 169 } 170 171 // backdrop click closes; clicks on the panel are contained 172 palette.addEventListener("click", function (e) { 173 if (e.target === palette) close(); 174 }); 175 var panel = palette.querySelector(".nt-palette__panel"); 176 if (panel) 177 panel.addEventListener("click", function (e) { 178 e.stopPropagation(); 179 }); 180 181 // global key handling + triggers 182 window.addEventListener("keydown", function (e) { 183 if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") { 184 e.preventDefault(); 185 isOpen() ? close() : open(document.activeElement); 186 } else if (e.key === "Escape" && isOpen()) { 187 close(); 188 } 189 }); 190 191 Array.prototype.forEach.call(document.querySelectorAll("[data-nt-palette-open]"), function (btn) { 192 btn.addEventListener("click", function (e) { 193 e.preventDefault(); 194 open(btn); 195 }); 196 }); 197 198 // ð¤ The input-style search buttons auto-launch the modal on focus (keyboard
199 // tab-in or click). Guarded so restoring focus on close doesn't re-open it. 200 Array.prototype.forEach.call(document.querySelectorAll(".nt-topnav__search, .nt-home__search"), function (btn) { 201 btn.addEventListener("focus", function () { 202 if (suppressAutoOpen || isOpen()) return; 203 open(btn); 204 }); 205 }); 206 } 207 208 function escapeHtml(s) { 209 return String(s).replace(/[&<>"']/g, function (c) { 210 return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]; 211 }); 212 } 213 214 /* ---------------- TOC smooth-scroll + scroll-spy ---------------- */ 215 function scrollToId(id) { 216 var el = document.getElementById(id); 217 if (!el) return; 218 window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - HEADER_OFFSET, behavior: "smooth" }); 219 } 220 221 function initToc() { 222 // Right-rail docs TOC uses data-sec; legacy left rail uses #anchor hrefs. 223 var links = []; 224 Array.prototype.forEach.call(document.querySelectorAll(".nt-toc__link[data-sec]"), function (a) { 225 links.push({ a: a, id: a.getAttribute("data-sec") }); 226 a.addEventListener("click", function (e) { 227 e.preventDefault(); 228 scrollToId(a.getAttribute("data-sec")); 229 history.replaceState(null, "", "#" + a.getAttribute("data-sec")); 230 }); 231 }); 232 Array.prototype.forEach.call(document.querySelectorAll("#TableOfContents a[href^='#']"), function (a) { 233 var id = a.getAttribute("href").slice(1); 234 links.push({ a: a, id: id }); 235 a.addEventListener("click", function (e) { 236 e.preventDefault(); 237 scrollToId(id); 238 history.replaceState(null, "", "#" + id); 239 }); 240 }); 241 if (!links.length) return; 242 243 var activeClass = "is-active"; 244 function spy() { 245 var best = -1; 246 for (var i = 0; i < links.length; i++) { 247 var el = document.getElementById(links[i].id); 248 if (el && el.getBoundingClientRect().top < HEADER_OFFSET + 16) best = i; 249 } 250 if (best < 0) best = 0; 251 links.forEach(function (l, i) { 252 l.a.classList.toggle(activeClass, i === best); 253 l.a.classList.toggle("active", i === best); // legacy TOC styling hook 254 }); 255 } 256 window.addEventListener("scroll", spy, { passive: true }); 257 spy(); 258 } 259 260 /* ---------------- Code-block copy chrome ---------------- */ 261 function initCodeCopy() { 262 Array.prototype.forEach.call(document.querySelectorAll(".contents pre"), function (pre) {
263 if (pre.closest(".nt-codeblock")) return; 264 var wrap = document.createElement("div"); 265 wrap.className = "nt-codeblock"; 266 var bar = document.createElement("div"); 267 bar.className = "nt-codeblock__bar"; 268 269 var code = pre.querySelector("code"); 270 var lang = ""; 271 if (code) { 272 var m = (code.className || "").match(/language-([\w-]+)/); 273 if (m) lang = m[1]; 274 } 275 var label = document.createElement("span"); 276 label.className = "nt-codeblock__lang"; 277 label.textContent = lang || "code"; 278 279 var btn = document.createElement("button"); 280 btn.className = "nt-codeblock__copy"; 281 btn.type = "button"; 282 btn.innerHTML = '<span class="ms">content_copy</span><span>Copy</span>'; 283 btn.addEventListener("click", function () { 284 var text = (code || pre).innerText; 285 var done = function () { 286 btn.querySelector("span:last-child").textContent = "Copied"; 287 btn.querySelector(".ms").textContent = "check"; 288 setTimeout(function () { 289 btn.querySelector("span:last-child").textContent = "Copy"; 290 btn.querySelector(".ms").textContent = "content_copy"; 291 }, 1600); 292 }; 293 if (navigator.clipboard && navigator.clipboard.writeText) { 294 navigator.clipboard.writeText(text).then(done, function () {}); 295 } 296 }); 297 298 bar.appendChild(label); 299 bar.appendChild(btn); 300 pre.parentNode.insertBefore(wrap, pre); 301 wrap.appendChild(bar); 302 wrap.appendChild(pre); 303 }); 304 } 305 306 /* ---------------- Callout icons on blockquotes ---------------- */ 307 function initCallouts() { 308 var infoIcon = 309 '<svg aria-hidden="true" focusable="false" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16Zm0-1.6A6.4 6.4 0 1 0 10 3.6a6.4 6.4 0 0 0 0 12.8ZM9.1 8.8h1.8v5H9.1v-5Zm.9-3.1a1.05 1.05 0 1 1 0 2.1 1.05 1.05 0 0 1 0-2.1Z" fill="currentColor"/></svg>'; // ð¤ decorative 310 Array.prototype.forEach.call(document.querySelectorAll(".contents blockquote"), function (bq) { 311 if (bq.querySelector(":scope > svg")) return; 312 var wrapper = document.createElement("div"); 313 while (bq.firstChild) wrapper.appendChild(bq.firstChild); 314 var span = document.createElement("span"); 315 span.innerHTML = infoIcon; 316 bq.appendChild(span.firstChild); 317 bq.appendChild(wrapper); 318 }); 319 } 320 321 /* ---------------- Mobile popover menu + article-nav drawer ---------------- */ 322 function initMobileNav() { 323 // ð¤ Article side-nav drawer (docs article pages) â its own toggle button. 324 var navBtn = document.querySelector(".nt-topnav__nav-btn"); 325 if (navBtn) { 326 navBtn.addEventListener("click", function () { 327 var open = document.body.classList.toggle("nt-nav-open"); 328 navBtn.setAttribute("aria-expanded", open ? "true" : "false"); 329 }); 330 } 331 332 // ð¤ "Toggle navigation" popover: search launcher + section actions, focus-trapped. 333 var menuBtn = document.querySelector(".nt-topnav__menu-btn"); 334 var popover = document.getElementById("nt-nav-popover"); 335 if (!menuBtn || !popover) return; 336 337 function openPopover() { 338 popover.hidden = false; 339 menuBtn.setAttribute("aria-expanded", "true"); 340 var items = focusable(popover); 341 if (items.length) items[0].focus(); 342 document.addEventListener("click", onDocClick, true); 343 } 344 function closePopover(restoreFocus) { 345 if (popover.hidden) return; 346 popover.hidden = true; 347 menuBtn.setAttribute("aria-expanded", "false"); 348 document.removeEventListener("click", onDocClick, true); 349 if (restoreFocus !== false) menuBtn.focus(); 350 } 351 function onDocClick(e) { 352 if (popover.contains(e.target) || menuBtn.contains(e.target)) return; 353 closePopover(false); 354 } 355 356 menuBtn.addEventListener("click", function () { 357 popover.hidden ? openPopover() : closePopover(); 358 }); 359 popover.addEventListener("keydown", function (e) { 360 if (popover.hidden) return; 361 if (e.key === "Escape") { 362 e.preventDefault(); 363 closePopover(); 364 } else { 365 trapTab(popover, e); 366 } 367 }); 368 } 369 370 /* ---------------- Skip navigation ---------------- */ 371 function initSkipNav() { 372 // ð¤ Move focus (and scroll) to the article main region. 373 Array.prototype.forEach.call(document.querySelectorAll("[data-nt-skip-nav]"), function (btn) { 374 btn.addEventListener("click", function () { 375 var main = document.getElementById("nt-doc-main") || document.querySelector(".nt-doc-main"); 376 if (!main) return; 377 document.body.classList.remove("nt-nav-open"); 378 main.focus(); 379 main.scrollIntoView(); 380 }); 381 }); 382 } 383
384 function init() { 385 initPalette(); 386 initCallouts(); 387 initCodeCopy(); 388 initToc(); 389 initMobileNav(); 390 initSkipNav(); 391 } 392 393 if (document.readyState === "loading") { 394 document.addEventListener("DOMContentLoaded", init); 395 } else { 396 init(); 397 } 398})();
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.