custom events

pull/31/head
Rich-Harris 8 years ago
parent d7dc941ae8
commit 240b00dd68

@ -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' ) {

@ -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 ] ) {

@ -0,0 +1,17 @@
import * as assert from 'assert';
export default {
html: '<button>0, 0</button>',
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, '<button>42, 42</button>' );
}
};

@ -0,0 +1,29 @@
<button on:tap='set({ x: event.x, y: event.y })'>{{x}}, {{y}}</button>
<script>
export default {
data: () => ({
x: 0,
y: 0
}),
events: {
tap ( node, callback ) {
function clickHandler ( event ) {
callback({
x: event.clientX,
y: event.clientY
});
}
node.addEventListener( 'click', clickHandler, false );
return {
teardown () {
node.addEventListener( 'click', clickHandler, false );
}
};
}
}
};
</script>
Loading…
Cancel
Save