From 9f832c2e37e6fcca06cf0ff01dad9cba43247246 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Sun, 19 Mar 2017 12:06:21 -0400 Subject: [PATCH] implement :Window events --- src/generators/dom/visitors/Element.js | 13 ++++++++ src/generators/dom/visitors/meta/Window.js | 32 +++++++++++++++++++ test/generator/index.js | 2 ++ .../generator/samples/window-event/_config.js | 26 +++++++++++++++ test/generator/samples/window-event/main.html | 3 ++ 5 files changed, 76 insertions(+) create mode 100644 src/generators/dom/visitors/meta/Window.js create mode 100644 test/generator/samples/window-event/_config.js create mode 100644 test/generator/samples/window-event/main.html diff --git a/src/generators/dom/visitors/Element.js b/src/generators/dom/visitors/Element.js index 0e76e0d708..7b359b1d90 100644 --- a/src/generators/dom/visitors/Element.js +++ b/src/generators/dom/visitors/Element.js @@ -2,9 +2,18 @@ import CodeBuilder from '../../../utils/CodeBuilder.js'; import deindent from '../../../utils/deindent.js'; import addElementAttributes from './attributes/addElementAttributes.js'; import Component from './Component.js'; +import Window from './meta/Window.js'; + +const meta = { + ':Window': Window +}; export default { enter ( generator, node ) { + if ( node.name in meta ) { + return meta[ node.name ].enter( generator, node ); + } + const isComponent = node.name in generator.components || node.name === ':Self'; if ( isComponent ) { return Component.enter( generator, node ); @@ -100,6 +109,10 @@ export default { }, leave ( generator, node ) { + if ( node.name in meta ) { + return meta[ node.name ].leave( generator, node ); + } + const isComponent = node.name in generator.components; if ( isComponent ) { return Component.leave( generator, node ); diff --git a/src/generators/dom/visitors/meta/Window.js b/src/generators/dom/visitors/meta/Window.js new file mode 100644 index 0000000000..dcda89c247 --- /dev/null +++ b/src/generators/dom/visitors/meta/Window.js @@ -0,0 +1,32 @@ +import flattenReference from '../../../../utils/flattenReference.js'; +import deindent from '../../../../utils/deindent.js'; + +export default { + enter ( generator, node ) { + node.attributes.forEach( attribute => { + if ( attribute.type === 'EventHandler' ) { + // TODO verify that it's a valid callee (i.e. built-in or declared method) + generator.addSourcemapLocations( attribute.expression ); + + const flattened = flattenReference( attribute.expression.callee ); + if ( flattened.name !== 'event' && flattened.name !== 'this' ) { + // allow event.stopPropagation(), this.select() etc + generator.code.prependRight( attribute.expression.start, 'component.' ); + } + + const handlerName = generator.current.getUniqueName( `onwindow${attribute.name}` ); + + generator.current.builders.init.addBlock( deindent` + var ${handlerName} = function ( event ) { + [✂${attribute.expression.start}-${attribute.expression.end}✂]; + }; + window.addEventListener( '${attribute.name}', ${handlerName} ); + ` ); + + generator.current.builders.teardown.addBlock( deindent` + window.removeEventListener( '${attribute.name}', ${handlerName} ); + ` ); + } + }); + } +}; diff --git a/test/generator/index.js b/test/generator/index.js index f52831b7c2..04599c6f2b 100644 --- a/test/generator/index.js +++ b/test/generator/index.js @@ -93,6 +93,8 @@ describe( 'generate', () => { return env() .then( window => { + global.window = window; + // Put the constructor on window for testing window.SvelteComponent = SvelteComponent; diff --git a/test/generator/samples/window-event/_config.js b/test/generator/samples/window-event/_config.js new file mode 100644 index 0000000000..89dfd2057c --- /dev/null +++ b/test/generator/samples/window-event/_config.js @@ -0,0 +1,26 @@ +export default { + html: `
undefinedxundefined
`, + + test ( assert, component, target, window ) { + const event = new window.Event( 'resize' ); + + // JSDOM executes window event listeners with `global` rather than + // `window` (bug?) so we need to do this + Object.defineProperties( global, { + innerWidth: { + value: 567, + configurable: true + }, + innerHeight: { + value: 456, + configurable: true + } + }); + + window.dispatchEvent( event ); + + assert.htmlEqual( target.innerHTML, ` +
567x456
+ `); + } +}; \ No newline at end of file diff --git a/test/generator/samples/window-event/main.html b/test/generator/samples/window-event/main.html new file mode 100644 index 0000000000..b6679a0e44 --- /dev/null +++ b/test/generator/samples/window-event/main.html @@ -0,0 +1,3 @@ +<:Window on:resize='set({ width: this.innerWidth, height: this.innerHeight })'/> + +
{{width}}x{{height}}
\ No newline at end of file