| 1 |
(function() { |
| 2 |
"use strict"; |
| 3 |
const NONCE_HEADER = "X-WP-Nonce"; |
| 4 |
function injectRestNonce(input, init) { |
| 5 |
const nonce = readRestNonce(); |
| 6 |
if (!nonce) { |
| 7 |
return init; |
| 8 |
} |
| 9 |
const url = resolveUrl(input); |
| 10 |
if (!url || !isSameOriginRestUrl(url)) { |
| 11 |
return init; |
| 12 |
} |
| 13 |
const baseHeaders = init?.headers ?? (typeof Request !== "undefined" && input instanceof Request ? input.headers : void 0); |
| 14 |
const headers = new Headers(baseHeaders ?? {}); |
| 15 |
if (headers.has(NONCE_HEADER)) { |
| 16 |
return init; |
| 17 |
} |
| 18 |
headers.set(NONCE_HEADER, nonce); |
| 19 |
return { ...init ?? {}, headers }; |
| 20 |
} |
| 21 |
function readRestNonce() { |
| 22 |
if (typeof window === "undefined") { |
| 23 |
return void 0; |
| 24 |
} |
| 25 |
const cfg = window.desktopModeConfig; |
| 26 |
const value = cfg?.restNonce; |
| 27 |
return typeof value === "string" && value.length > 0 ? value : void 0; |
| 28 |
} |
| 29 |
function resolveUrl(input) { |
| 30 |
try { |
| 31 |
const base = typeof window !== "undefined" && window.location ? window.location.href : void 0; |
| 32 |
if (typeof input === "string") { |
| 33 |
return new URL(input, base); |
| 34 |
} |
| 35 |
if (input instanceof URL) { |
| 36 |
return input; |
| 37 |
} |
| 38 |
if (typeof Request !== "undefined" && input instanceof Request) { |
| 39 |
return new URL(input.url, base); |
| 40 |
} |
| 41 |
return null; |
| 42 |
} catch { |
| 43 |
return null; |
| 44 |
} |
| 45 |
} |
| 46 |
function isSameOriginRestUrl(url) { |
| 47 |
if (typeof window === "undefined" || !window.location || url.origin !== window.location.origin) { |
| 48 |
return false; |
| 49 |
} |
| 50 |
if (url.pathname.includes("/wp-json/")) { |
| 51 |
return true; |
| 52 |
} |
| 53 |
if (url.searchParams.has("rest_route")) { |
| 54 |
return true; |
| 55 |
} |
| 56 |
return false; |
| 57 |
} |
| 58 |
function trackedFetch(input, init, opts = {}) { |
| 59 |
const fn = window.wp?.desktop?.fetch; |
| 60 |
if (typeof fn === "function") { |
| 61 |
return fn(input, init, opts); |
| 62 |
} |
| 63 |
const finalInit = injectRestNonce(input, init); |
| 64 |
return fetch(input, finalInit); |
| 65 |
} |
| 66 |
const WIDGET_ID = "desktop-mode/starter"; |
| 67 |
const mount = async (container, ctx) => { |
| 68 |
let destroyed = false; |
| 69 |
const root = document.createElement("div"); |
| 70 |
root.className = "dm-starter"; |
| 71 |
const header = document.createElement("div"); |
| 72 |
header.className = "dm-starter__header"; |
| 73 |
header.textContent = "Starter Widget"; |
| 74 |
const body = document.createElement("div"); |
| 75 |
body.className = "dm-starter__body"; |
| 76 |
body.textContent = "Loading…"; |
| 77 |
root.appendChild(header); |
| 78 |
root.appendChild(body); |
| 79 |
container.appendChild(root); |
| 80 |
const clickCount = ctx.storage.get("clicks") ?? 0; |
| 81 |
const counter = document.createElement("button"); |
| 82 |
counter.className = "dm-starter__counter"; |
| 83 |
counter.textContent = `Clicked ${clickCount} ${clickCount === 1 ? "time" : "times"}`; |
| 84 |
const onClick = () => { |
| 85 |
const current = ctx.storage.get("clicks") ?? 0; |
| 86 |
const next = current + 1; |
| 87 |
ctx.storage.set("clicks", next); |
| 88 |
counter.textContent = `Clicked ${next} ${next === 1 ? "time" : "times"}`; |
| 89 |
}; |
| 90 |
counter.addEventListener("click", onClick); |
| 91 |
root.appendChild(counter); |
| 92 |
const rootUrl = window.wpApiSettings?.root ?? "/wp-json/"; |
| 93 |
const loadData = async () => { |
| 94 |
if (destroyed) { |
| 95 |
return; |
| 96 |
} |
| 97 |
try { |
| 98 |
const res = await trackedFetch( |
| 99 |
rootUrl.replace(/\/$/, "") + "/wp/v2/posts?per_page=1&orderby=date&order=desc&_fields=id,title", |
| 100 |
{ credentials: "same-origin" }, |
| 101 |
{ source: "desktop-mode/starter", silent: true } |
| 102 |
); |
| 103 |
if (destroyed) { |
| 104 |
return; |
| 105 |
} |
| 106 |
if (!res.ok) { |
| 107 |
body.textContent = "Could not load posts (" + res.status + ")."; |
| 108 |
return; |
| 109 |
} |
| 110 |
const posts = await res.json(); |
| 111 |
if (destroyed) { |
| 112 |
return; |
| 113 |
} |
| 114 |
body.textContent = posts.length > 0 ? "Latest post: " + posts[0].title.rendered : "No posts found."; |
| 115 |
} catch { |
| 116 |
if (!destroyed) { |
| 117 |
body.textContent = "Could not load data."; |
| 118 |
} |
| 119 |
} |
| 120 |
}; |
| 121 |
await loadData(); |
| 122 |
const intervalId = setInterval(loadData, 6e4); |
| 123 |
return () => { |
| 124 |
destroyed = true; |
| 125 |
clearInterval(intervalId); |
| 126 |
counter.removeEventListener("click", onClick); |
| 127 |
}; |
| 128 |
}; |
| 129 |
const w = window; |
| 130 |
w.desktopModeWidgets = w.desktopModeWidgets ?? {}; |
| 131 |
w.desktopModeWidgets[WIDGET_ID] = mount; |
| 132 |
})(); |
| 133 |
|