Merge pull request #170 from sveltejs/gh-162

Allow event handlers to call methods of `event` and `this`
pull/173/head
Rich Harris 8 years ago committed by GitHub
commit 72dc86aa5e

@ -1,6 +1,7 @@
import attributeLookup from './lookup.js'; import attributeLookup from './lookup.js';
import createBinding from './binding/index.js'; import createBinding from './binding/index.js';
import deindent from '../../../utils/deindent.js'; import deindent from '../../../utils/deindent.js';
import flattenReference from '../../../utils/flattenReference.js';
export default function addElementAttributes ( generator, node, local ) { export default function addElementAttributes ( generator, node, local ) {
node.attributes.forEach( attribute => { node.attributes.forEach( attribute => {
@ -114,7 +115,12 @@ export default function addElementAttributes ( generator, node, local ) {
else if ( attribute.type === 'EventHandler' ) { else if ( attribute.type === 'EventHandler' ) {
// TODO verify that it's a valid callee (i.e. built-in or declared method) // TODO verify that it's a valid callee (i.e. built-in or declared method)
generator.addSourcemapLocations( attribute.expression ); generator.addSourcemapLocations( attribute.expression );
generator.code.prependRight( attribute.expression.start, 'component.' );
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 usedContexts = new Set(); const usedContexts = new Set();
attribute.expression.arguments.forEach( arg => { attribute.expression.arguments.forEach( arg => {

@ -7,10 +7,10 @@ export default function flatten ( node ) {
node = node.object; node = node.object;
} }
if ( node.type !== 'Identifier' ) return null; const name = node.type === 'Identifier' ? node.name : node.type === 'ThisExpression' ? 'this' : null;
const name = node.name; if ( !name ) return null;
parts.unshift( name );
parts.unshift( name );
return { name, keypath: parts.join( '.' ) }; return { name, keypath: parts.join( '.' ) };
} }

@ -0,0 +1,12 @@
export default {
test ( assert, component, target, window ) {
const allow = target.querySelector( '.allow-propagation' );
const stop = target.querySelector( '.stop-propagation' );
allow.dispatchEvent( new window.MouseEvent( 'click', { bubbles: true }) );
stop.dispatchEvent( new window.MouseEvent( 'click', { bubbles: true }) );
assert.equal( component.get( 'foo' ), true );
assert.equal( component.get( 'bar' ), false );
}
};

@ -0,0 +1,18 @@
<div on:click='set({ foo: true })'>
<button class='allow-propagation'>click me</button>
</div>
<div on:click='set({ bar: true })'>
<button class='stop-propagation' on:click='event.stopPropagation()'>click me</button>
</div>
<script>
export default {
data () {
return {
foo: false,
bar: false
};
}
};
</script>

@ -0,0 +1,16 @@
export default {
test ( assert, component, target, window ) {
// Click events don't focus elements in JSDOM obviously they would
// in real browsers. More realistically, you'd use this for e.g.
// this.select(), but that's harder to test than this.focus()
const wont = target.querySelector( '.wont-focus' );
const will = target.querySelector( '.will-focus' );
wont.dispatchEvent( new window.MouseEvent( 'click' ) );
assert.equal( window.document.activeElement, window.document.body );
will.dispatchEvent( new window.MouseEvent( 'click' ) );
assert.equal( window.document.activeElement, will );
}
};

@ -0,0 +1,2 @@
<input class='wont-focus'>
<input class='will-focus' on:click='this.focus()'>
Loading…
Cancel
Save