Pre Release New Changes
This commit is contained in:
@@ -69,6 +69,59 @@ export const NAV_RUNTIME = String.raw`
|
||||
return rel.indexOf("external") === -1;
|
||||
}
|
||||
|
||||
function currentDocumentNonce() {
|
||||
var node = document.querySelector("script[nonce],style[nonce]");
|
||||
if (!node) return "";
|
||||
return node.nonce || node.getAttribute("nonce") || "";
|
||||
}
|
||||
|
||||
function syncWrnStyles(nextDocument) {
|
||||
var current = Array.prototype.slice.call(
|
||||
document.querySelectorAll("style[data-wrnexus-style-id]"),
|
||||
);
|
||||
var next = Array.prototype.slice.call(
|
||||
nextDocument.querySelectorAll("style[data-wrnexus-style-id]"),
|
||||
);
|
||||
var currentById = Object.create(null);
|
||||
var nextIds = Object.create(null);
|
||||
var nonce = currentDocumentNonce();
|
||||
|
||||
current.forEach(function (style) {
|
||||
var id = style.getAttribute("data-wrnexus-style-id");
|
||||
if (id) currentById[id] = style;
|
||||
});
|
||||
|
||||
next.forEach(function (nextStyle) {
|
||||
var id = nextStyle.getAttribute("data-wrnexus-style-id");
|
||||
if (!id) return;
|
||||
nextIds[id] = true;
|
||||
|
||||
var currentStyle = currentById[id];
|
||||
if (!currentStyle) {
|
||||
currentStyle = document.createElement("style");
|
||||
currentStyle.setAttribute("data-wrnexus-style-id", id);
|
||||
}
|
||||
|
||||
["data-wrnexus-style-owner", "data-wrnexus-style-kind"].forEach(function (name) {
|
||||
var value = nextStyle.getAttribute(name);
|
||||
if (value == null) currentStyle.removeAttribute(name);
|
||||
else currentStyle.setAttribute(name, value);
|
||||
});
|
||||
|
||||
if (nonce) currentStyle.setAttribute("nonce", nonce);
|
||||
if (currentStyle.textContent !== nextStyle.textContent) {
|
||||
currentStyle.textContent = nextStyle.textContent;
|
||||
}
|
||||
|
||||
document.head.appendChild(currentStyle);
|
||||
});
|
||||
|
||||
current.forEach(function (style) {
|
||||
var id = style.getAttribute("data-wrnexus-style-id");
|
||||
if (id && !nextIds[id]) style.remove();
|
||||
});
|
||||
}
|
||||
|
||||
function loadedScriptPaths() {
|
||||
var loaded = {};
|
||||
|
||||
@@ -317,6 +370,8 @@ export const NAV_RUNTIME = String.raw`
|
||||
document.title = doc.title;
|
||||
}
|
||||
|
||||
syncWrnStyles(doc);
|
||||
|
||||
var importedNodes = [];
|
||||
|
||||
for (
|
||||
|
||||
@@ -126,3 +126,24 @@ test("unmounts and remounts package runtimes during client navigation", async ()
|
||||
expect(mounts).toBe(1);
|
||||
expect(win.document.getElementById("app").textContent).toContain("New");
|
||||
});
|
||||
|
||||
test("synchronizes page styles during client navigation and preserves the current nonce", async () => {
|
||||
install(
|
||||
`<script nonce="current-nonce"></script>` +
|
||||
`<style data-wrnexus-style-id="home" data-wrnexus-style-kind="page" nonce="current-nonce">.page{color:red}</style>` +
|
||||
`<div id="app"><a href="/about" id="lnk">About</a></div>`,
|
||||
);
|
||||
nextHtml =
|
||||
`<html><head>` +
|
||||
`<style data-wrnexus-style-id="about" data-wrnexus-style-owner="About" data-wrnexus-style-kind="page" nonce="response-nonce">.page{color:blue}</style>` +
|
||||
`</head><body><div id="app"><h1 class="page">About</h1></div></body></html>`;
|
||||
|
||||
win.document.getElementById("lnk").click();
|
||||
await flush();
|
||||
|
||||
expect(win.document.querySelector('style[data-wrnexus-style-id="home"]')).toBeNull();
|
||||
const style = win.document.querySelector('style[data-wrnexus-style-id="about"]');
|
||||
expect(style).not.toBeNull();
|
||||
expect(style.textContent).toContain("color:blue");
|
||||
expect(style.getAttribute("nonce")).toBe("current-nonce");
|
||||
});
|
||||
|
||||
@@ -333,3 +333,39 @@ test("data-for preserves arrays of objects from encoded component scope", () =>
|
||||
"Four",
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
test("$emit inside component functions does not depend on a global browser event", () => {
|
||||
const behavior = Buffer.from(
|
||||
JSON.stringify({
|
||||
functions: `
|
||||
function showOverlay(sourceEvent) {
|
||||
visible = true
|
||||
$emit("open", { source: sourceEvent.type })
|
||||
}
|
||||
`,
|
||||
watches: [],
|
||||
lifecycle: {},
|
||||
}),
|
||||
).toString("base64");
|
||||
|
||||
delete (globalThis as Record<string, unknown>).event;
|
||||
|
||||
const win = mount(
|
||||
`<div data-scope="visible: false" data-wrn-events="open" data-wrn-behavior="${behavior}">
|
||||
<button data-on-click="showOverlay(event)">Open overlay</button>
|
||||
<span>{visible}</span>
|
||||
</div>`,
|
||||
);
|
||||
|
||||
const root = win.document.querySelector("[data-wrn-events]")!;
|
||||
let detail: Record<string, unknown> | undefined;
|
||||
root.addEventListener("open", (event) => {
|
||||
detail = (event as unknown as CustomEvent).detail;
|
||||
});
|
||||
|
||||
win.document.querySelector("button")!.click();
|
||||
|
||||
expect(win.document.querySelector("span")!.textContent).toBe("true");
|
||||
expect(detail).toEqual({ source: "click" });
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user