fix(csr): prevent native output recursion
This commit is contained in:
@@ -2512,6 +2512,11 @@ export const REACTIVE_RUNTIME = String.raw`
|
|||||||
|
|
||||||
var stmt = attr.value;
|
var stmt = attr.value;
|
||||||
var listener = function (event) {
|
var listener = function (event) {
|
||||||
|
// An unbound output falls back to a same-named CustomEvent for
|
||||||
|
// external consumers. Do not feed that synthetic event back into
|
||||||
|
// the component's own declarative DOM handler (for example,
|
||||||
|
// @click="output.click()"), which would recurse indefinitely.
|
||||||
|
if (event && event.__wrnexusComponentOutput) return;
|
||||||
var locals =
|
var locals =
|
||||||
decodeLoopLocals(node);
|
decodeLoopLocals(node);
|
||||||
|
|
||||||
@@ -4167,6 +4172,7 @@ export const REACTIVE_RUNTIME = String.raw`
|
|||||||
bubbles: true,
|
bubbles: true,
|
||||||
detail: detail || {},
|
detail: detail || {},
|
||||||
});
|
});
|
||||||
|
event.__wrnexusComponentOutput = true;
|
||||||
root.dispatchEvent(event);
|
root.dispatchEvent(event);
|
||||||
// Compatibility for applications using the former prefixed contract.
|
// Compatibility for applications using the former prefixed contract.
|
||||||
root.dispatchEvent(new EventConstructor("wrnexus:" + String(name), {
|
root.dispatchEvent(new EventConstructor("wrnexus:" + String(name), {
|
||||||
|
|||||||
@@ -781,6 +781,26 @@ test("development runtime allows an output with no parent binding", () => {
|
|||||||
expect(warnings).toHaveLength(0);
|
expect(warnings).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("an unbound native-named output does not re-enter its DOM handler", () => {
|
||||||
|
const win = mount(
|
||||||
|
`<div data-scope="" data-wrn-events="click">` +
|
||||||
|
`<button data-on-click="output.click()">go</button>` +
|
||||||
|
`</div>`,
|
||||||
|
);
|
||||||
|
const root = win.document.querySelector("[data-wrn-events]") as unknown as HTMLElement;
|
||||||
|
let outputs = 0;
|
||||||
|
root.addEventListener("click", (event) => {
|
||||||
|
if ((event as Event & { __wrnexusComponentOutput?: boolean }).__wrnexusComponentOutput) {
|
||||||
|
outputs += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(() =>
|
||||||
|
(win.document.querySelector("button") as unknown as HTMLElement).click(),
|
||||||
|
).not.toThrow();
|
||||||
|
expect(outputs).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
test("development runtime warns when a component binding names a missing function", () => {
|
test("development runtime warns when a component binding names a missing function", () => {
|
||||||
const win = new Window() as unknown as Window & Record<string, unknown>;
|
const win = new Window() as unknown as Window & Record<string, unknown>;
|
||||||
win.document.body.innerHTML =
|
win.document.body.innerHTML =
|
||||||
|
|||||||
Reference in New Issue
Block a user