From 240b00dd684713ade2e208c89645648ced703896 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Sun, 20 Nov 2016 10:42:06 -0500 Subject: [PATCH] custom events --- compiler/generate/index.js | 49 ++++++++++--------- compiler/generate/utils/contextualise.js | 6 ++- test/compiler/event-handler-custom/_config.js | 17 +++++++ .../compiler/event-handler-custom/main.svelte | 29 +++++++++++ 4 files changed, 77 insertions(+), 24 deletions(-) create mode 100644 test/compiler/event-handler-custom/_config.js create mode 100644 test/compiler/event-handler-custom/main.svelte diff --git a/compiler/generate/index.js b/compiler/generate/index.js index bfff70b9ae..caaad6623d 100644 --- a/compiler/generate/index.js +++ b/compiler/generate/index.js @@ -199,14 +199,12 @@ export default function generate ( parsed, template ) { else if ( attribute.type === 'EventHandler' ) { // TODO verify that it's a valid callee (i.e. built-in or declared method) - const handler = current.counter( `${attribute.name}Handler` ); - addSourcemapLocations( attribute.expression ); code.insertRight( attribute.expression.start, 'component.' ); const usedContexts = new Set(); attribute.expression.arguments.forEach( arg => { - const contexts = contextualise( code, arg, current.contexts, current.indexes, helpers ); + const contexts = contextualise( code, arg, current.contexts, current.indexes, helpers, true ); contexts.forEach( context => { usedContexts.add( context ); @@ -215,38 +213,43 @@ export default function generate ( parsed, template ) { }); // TODO hoist event handlers? can do `this.__component.method(...)` - if ( usedContexts.size ) { - const declarations = [...usedContexts].map( name => { - if ( name === 'root' ) return 'var root = this.__svelte.root; // 2'; + const declarations = [...usedContexts].map( name => { + if ( name === 'root' ) return 'var root = this.__svelte.root;'; - const listName = current.listNames[ name ]; - const indexName = current.indexNames[ name ]; + const listName = current.listNames[ name ]; + const indexName = current.indexNames[ name ]; - return `var ${listName} = this.__svelte.${listName}, ${indexName} = this.__svelte.${indexName}, ${name} = ${listName}[${indexName}]`; - }); + return `var ${listName} = this.__svelte.${listName}, ${indexName} = this.__svelte.${indexName}, ${name} = ${listName}[${indexName}]`; + }); - initStatements.push( deindent` - function ${handler} ( event ) { - ${declarations} + const handlerName = current.counter( `${attribute.name}Handler` ); + const handlerBody = ( declarations.length ? declarations.join( '\n' ) + '\n\n' : '' ) + `[✂${attribute.expression.start}-${attribute.expression.end}✂];`; - [✂${attribute.expression.start}-${attribute.expression.end}✂]; - } + const customEvent = templateProperties.events && templateProperties.events.properties.find( prop => prop.key.name === attribute.name ); - ${name}.addEventListener( '${attribute.name}', ${handler}, false ); + if ( customEvent ) { + initStatements.push( deindent` + const ${handlerName} = template.events.${attribute.name}( ${name}, function ( event ) { + ${handlerBody} + }); + ` ); + + teardownStatements.push( deindent` + ${handlerName}.teardown(); ` ); } else { initStatements.push( deindent` - function ${handler} ( event ) { - [✂${attribute.expression.start}-${attribute.expression.end}✂]; + function ${handlerName} ( event ) { + ${handlerBody} } - ${name}.addEventListener( '${attribute.name}', ${handler}, false ); + ${name}.addEventListener( '${attribute.name}', ${handlerName}, false ); ` ); - } - teardownStatements.push( deindent` - ${name}.removeEventListener( '${attribute.name}', ${handler}, false ); - ` ); + teardownStatements.push( deindent` + ${name}.removeEventListener( '${attribute.name}', ${handlerName}, false ); + ` ); + } } else if ( attribute.type === 'Binding' ) { diff --git a/compiler/generate/utils/contextualise.js b/compiler/generate/utils/contextualise.js index b670aa4797..19fef8ba01 100644 --- a/compiler/generate/utils/contextualise.js +++ b/compiler/generate/utils/contextualise.js @@ -2,7 +2,7 @@ import { walk } from 'estree-walker'; import isReference from './isReference.js'; import flattenReference from './flattenReference.js'; -export default function contextualise ( code, expression, contexts, indexes, helpers ) { +export default function contextualise ( code, expression, contexts, indexes, helpers, isEventHandler ) { const usedContexts = []; walk( expression, { @@ -15,6 +15,10 @@ export default function contextualise ( code, expression, contexts, indexes, hel return; } + if ( name === 'event' && isEventHandler ) { + return; + } + if ( contexts[ name ] ) { if ( !~usedContexts.indexOf( name ) ) usedContexts.push( name ); } else if ( indexes[ name ] ) { diff --git a/test/compiler/event-handler-custom/_config.js b/test/compiler/event-handler-custom/_config.js new file mode 100644 index 0000000000..c7b4d8cfa1 --- /dev/null +++ b/test/compiler/event-handler-custom/_config.js @@ -0,0 +1,17 @@ +import * as assert from 'assert'; + +export default { + html: '', + test ( component, target, window ) { + const event = new window.MouseEvent( 'click', { + clientX: 42, + clientY: 42 + }); + + const button = target.querySelector( 'button' ); + + button.dispatchEvent( event ); + + assert.equal( target.innerHTML, '' ); + } +}; diff --git a/test/compiler/event-handler-custom/main.svelte b/test/compiler/event-handler-custom/main.svelte new file mode 100644 index 0000000000..b56b4f403b --- /dev/null +++ b/test/compiler/event-handler-custom/main.svelte @@ -0,0 +1,29 @@ + + +