diff --git a/src/generators/nodes/Window.ts b/src/generators/nodes/Window.ts index 7a1f70376b3a..40138913e67c 100644 --- a/src/generators/nodes/Window.ts +++ b/src/generators/nodes/Window.ts @@ -51,6 +51,8 @@ export default class Window extends Node { // TODO verify that it's a valid callee (i.e. built-in or declared method) generator.addSourcemapLocations(attribute.expression); + const isCustomEvent = generator.events.has(attribute.name); + let usesState = false; attribute.expression.arguments.forEach((arg: Node) => { @@ -74,16 +76,39 @@ export default class Window extends Node { [✂${attribute.expression.start}-${attribute.expression.end}✂]; `; - block.builders.init.addBlock(deindent` - function ${handlerName}(event) { - ${handlerBody} + if (isCustomEvent) { + // TODO dry this out + block.addVariable(handlerName); + + block.builders.hydrate.addBlock(deindent` + ${handlerName} = %events-${attribute.name}.call(#component, window, function(event) { + ${handlerBody} + }); + `); + + if (generator.options.dev) { + block.builders.hydrate.addBlock(deindent` + if (${handlerName}.teardown) { + console.warn("Return 'destroy()' from custom event handlers. Returning 'teardown()' has been deprecated and will be unsupported in Svelte 2"); + } + `); } - window.addEventListener("${attribute.name}", ${handlerName}); - `); - block.builders.destroy.addBlock(deindent` - window.removeEventListener("${attribute.name}", ${handlerName}); - `); + block.builders.destroy.addLine(deindent` + ${handlerName}[${handlerName}.destroy ? 'destroy' : 'teardown'](); + `); + } else { + block.builders.init.addBlock(deindent` + function ${handlerName}(event) { + ${handlerBody} + } + window.addEventListener("${attribute.name}", ${handlerName}); + `); + + block.builders.destroy.addBlock(deindent` + window.removeEventListener("${attribute.name}", ${handlerName}); + `); + } } if (attribute.type === 'Binding') { diff --git a/src/validate/html/validateWindow.ts b/src/validate/html/validateWindow.ts index 36ed43a5a65b..5285457c808f 100644 --- a/src/validate/html/validateWindow.ts +++ b/src/validate/html/validateWindow.ts @@ -51,6 +51,7 @@ export default function validateWindow(validator: Validator, node: Node, refs: M } } } else if (attribute.type === 'EventHandler') { + validator.used.events.add(attribute.name); validateEventHandler(validator, attribute, refCallees); } }); diff --git a/test/runtime/samples/window-event-custom/_config.js b/test/runtime/samples/window-event-custom/_config.js new file mode 100644 index 000000000000..a615482f929c --- /dev/null +++ b/test/runtime/samples/window-event-custom/_config.js @@ -0,0 +1,15 @@ +export default { + html: `
escaped: false
`, + + test(assert, component, target, window) { + const event = new window.KeyboardEvent('keydown', { + which: 27 + }); + + window.dispatchEvent(event); + + assert.htmlEqual(target.innerHTML, ` +escaped: true
+ `); + }, +}; diff --git a/test/runtime/samples/window-event-custom/main.html b/test/runtime/samples/window-event-custom/main.html new file mode 100644 index 000000000000..af33d08d975a --- /dev/null +++ b/test/runtime/samples/window-event-custom/main.html @@ -0,0 +1,25 @@ +<:Window on:esc="set({ escaped: true })" /> + +escaped: {{escaped}}
+ + \ No newline at end of file