1(function () { 2 "use strict"; 3 4 const STORAGE_KEY = "aiNewsRadarViewV2"; 5 const LEGACY_STORAGE_KEY = "aiNewsRadarView"; 6 const MOBILE_OVERRIDE_KEY = "aiNewsRadarMobileViewOnce"; 7 const MOBILE_BREAKPOINT = "(max-width: 760px)"; 8 const VALID_VIEWS = new Set(["mobile", "classic"]); 9 const script = document.currentScript; 10 const rootHint = script?.dataset.root || "./"; 11 const rootUrl = new URL(rootHint, window.location.href); 12 const currentView = document.documentElement.dataset.radarView || "mobile"; 13 const params = new URLSearchParams(window.location.search); 14 const requestedView = params.get("view") || ""; 15 const isMobileViewport = window.matchMedia(MOBILE_BREAKPOINT).matches; 16 17 try { 18 window.localStorage.removeItem(LEGACY_STORAGE_KEY); 19 } catch { 20 // Storage can be unavailable in private or hardened browser contexts. 21 } 22 23 function readPreference() { 24 try { 25 const value = window.localStorage.getItem(STORAGE_KEY) || ""; 26 return VALID_VIEWS.has(value) ? value : ""; 27 } catch { 28 return ""; 29 } 30 } 31 32 function writePreference(view) { 33 try { 34 if (VALID_VIEWS.has(view)) { 35 window.localStorage.setItem(STORAGE_KEY, view); 36 } else { 37 window.localStorage.removeItem(STORAGE_KEY); 38 } 39 } catch { 40 // Storage can be unavailable in private or hardened browser contexts. 41 } 42 } 43 44 function readMobileOverride() { 45 try { 46 const value = window.sessionStorage.getItem(MOBILE_OVERRIDE_KEY) || ""; 47 window.sessionStorage.removeItem(MOBILE_OVERRIDE_KEY); 48 return VALID_VIEWS.has(value) ? value : ""; 49 } catch { 50 return ""; 51 } 52 } 53 54 function writeMobileOverride(view) { 55 try { 56 if (VALID_VIEWS.has(view)) { 57 window.sessionStorage.setItem(MOBILE_OVERRIDE_KEY, view); 58 } else { 59 window.sessionStorage.removeItem(MOBILE_OVERRIDE_KEY); 60 } 61 } catch { 62 // Storage can be unavailable in private or hardened browser contexts. 63 } 64 } 65 66 if (requestedView === "auto") { 67 writePreference(""); 68 writeMobileOverride(""); 69 } else if (!isMobileViewport && VALID_VIEWS.has(requestedView)) { 70 writePreference(requestedView); 71 } 72 73 const mobileOverride = isMobileViewport ? readMobileOverride() : ""; 74 const preference = isMobileViewport 75 ? mobileOverride 76 : (requestedView === "auto" 77 ? "" 78 : (VALID_VIEWS.has(requestedView) ? requestedView : readPreference())); 79 const deviceDefault = "mobile"; 80 const targetView = preference || deviceDefault; 81 82 function destination(view) { 83 const url = new URL(view === "classic" ? "classic/" : "./", rootUrl); 84 const passthrough = new URLSearchParams(window.location.search); 85 passthrough.delete("view"); 86 url.search = passthrough.toString(); 87 url.hash = window.location.hash; 88 return url; 89 } 90 91 function cleanViewQuery() { 92 if (!requestedView) return; 93 const cleanUrl = destination(currentView); 94 window.history.replaceState(null, "", `${cleanUrl.pathname}${cleanUrl.search}${cleanUrl.hash}`); 95 } 96 97 function chooseView(view) { 98 if (!VALID_VIEWS.has(view)) return; 99 if (isMobileViewport) writeMobileOverride(view); 100 else writePreference(view); 101 if (view === currentView) return; 102 window.location.assign(destination(view).href); 103 } 104 105 if (targetView !== currentView) { 106 window.location.replace(destination(targetView).href); 107 return; 108 } 109 110 cleanViewQuery(); 111 112 function mountSwitches() { 113 document.querySelectorAll("[data-radar-view-target]").forEach((button) => { 114 const view = button.dataset.radarViewTarget || ""; 115 const active = view === currentView; 116 button.classList.toggle("is-active", active); 117 button.setAttribute("aria-pressed", active ? "true" : "false"); 118 if (active) button.setAttribute("aria-current", "page"); 119 else button.removeAttribute("aria-current"); 120 button.addEventListener("click", () => chooseView(view)); 121 }); 122 } 123 124 if (document.readyState === "loading") { 125 document.addEventListener("DOMContentLoaded", mountSwitches, { once: true }); 126 } else { 127 mountSwitches(); 128 } 129 130 window.AINewsRadarView = { 131 current: currentView, 132 preference: preference || "auto",
133 choose: chooseView, 134 reset() { 135 writePreference(""); 136 writeMobileOverride(""); 137 window.location.replace(destination(deviceDefault).href); 138 }, 139 }; 140})();
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.