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: `