From 20ee8370e46536b86c53e71683f7c66a357b451c Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Sat, 8 Apr 2017 17:41:26 -0400 Subject: [PATCH 1/7] failing test for #433 --- test/js/index.js | 10 ++- .../samples/event-handlers-custom/expected.js | 88 +++++++++++++++++++ .../samples/event-handlers-custom/input.html | 16 ++++ 3 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 test/js/samples/event-handlers-custom/expected.js create mode 100644 test/js/samples/event-handlers-custom/input.html diff --git a/test/js/index.js b/test/js/index.js index cf8ab54bbd..fd5eb102bf 100644 --- a/test/js/index.js +++ b/test/js/index.js @@ -18,11 +18,17 @@ describe( 'js', () => { dir = path.resolve( 'test/js/samples', dir ); const input = fs.readFileSync( `${dir}/input.html`, 'utf-8' ).replace( /\s+$/, '' ); - const actual = svelte.compile( input ).code; + const actual = svelte.compile( input, { + shared: true + }).code; + fs.writeFileSync( `${dir}/_actual.js`, actual ); const expected = fs.readFileSync( `${dir}/expected.js`, 'utf-8' ); - assert.equal( actual.trim(), expected.trim() ); + assert.equal( + actual.trim().replace( /^\s+$/gm, '' ), + expected.trim().replace( /^\s+$/gm, '' ) + ); }); }); }); diff --git a/test/js/samples/event-handlers-custom/expected.js b/test/js/samples/event-handlers-custom/expected.js new file mode 100644 index 0000000000..8131e3bde3 --- /dev/null +++ b/test/js/samples/event-handlers-custom/expected.js @@ -0,0 +1,88 @@ +import { createElement, detachNode, insertNode, createText, appendNode, assign, dispatchObservers, noop, proto } from "svelte/shared.js"; + +var template = (function () { + return { + methods: { + foo ( bar ) { + console.log( bar ); + } + }, + + events: { + foo ( node, callback ) { + // code goes here + } + } + }; +}()); + +function create_main_fragment ( root, component ) { + var button = createElement( 'button' ); + + var foo_handler = template.events.foo.call( component, button, function ( event ) { + var root = component.get(); + + component.foo( root.bar ); + }); + + appendNode( createText( "foo" ), button ); + + return { + mount: function ( target, anchor ) { + insertNode( button, target, anchor ); + }, + + update: noop, + + destroy: function ( detach ) { + foo_handler.teardown(); + + if ( detach ) { + detachNode( button ); + } + } + }; +} + +function SvelteComponent ( options ) { + options = options || {}; + this._state = options.data || {}; + + this._observers = { + pre: Object.create( null ), + post: Object.create( null ) + }; + + this._handlers = Object.create( null ); + + this._root = options._root; + this._yield = options._yield; + + this._torndown = false; + + this._fragment = create_main_fragment( this._state, this ); + if ( options.target ) this._fragment.mount( options.target, null ); +} + +assign( SvelteComponent.prototype, template.methods, proto ); + +SvelteComponent.prototype._set = function _set ( newState ) { + var oldState = this._state; + this._state = assign( {}, oldState, newState ); + + dispatchObservers( this, this._observers.pre, newState, oldState ); + if ( this._fragment ) this._fragment.update( newState, this._state ); + dispatchObservers( this, this._observers.post, newState, oldState ); +}; + +SvelteComponent.prototype.teardown = SvelteComponent.prototype.destroy = function destroy ( detach ) { + this.fire( 'destroy' ); + + this._fragment.destroy( detach !== false ); + this._fragment = null; + + this._state = {}; + this._torndown = true; +}; + +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/event-handlers-custom/input.html b/test/js/samples/event-handlers-custom/input.html new file mode 100644 index 0000000000..00d79363fa --- /dev/null +++ b/test/js/samples/event-handlers-custom/input.html @@ -0,0 +1,16 @@ + + + \ No newline at end of file From 91ad5f77bd4f492f36534d962976be0b9d8d252f Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Sun, 9 Apr 2017 12:11:07 -0400 Subject: [PATCH 2/7] start refactoring element code a bit --- src/generators/dom/visitors/Element.js | 24 ++++------ .../attributes/addElementAttributes.js | 46 +++++++++---------- .../visitors/attributes/addElementBinding.js | 42 ++++++++--------- 3 files changed, 54 insertions(+), 58 deletions(-) diff --git a/src/generators/dom/visitors/Element.js b/src/generators/dom/visitors/Element.js index 7f3b8d4e65..01e347ef59 100644 --- a/src/generators/dom/visitors/Element.js +++ b/src/generators/dom/visitors/Element.js @@ -20,11 +20,13 @@ export default function visitElement ( generator, block, state, node ) { const name = block.getUniqueName( node.name ); - const local = { - name, - namespace: node.name === 'svg' ? 'http://www.w3.org/2000/svg' : state.namespace, - isComponent: false, + const childState = Object.assign( {}, state, { + isTopLevel: false, + parentNode: name, + namespace: node.name === 'svg' ? 'http://www.w3.org/2000/svg' : state.namespace + }); + const local = { allUsedContexts: [], create: new CodeBuilder(), @@ -34,7 +36,7 @@ export default function visitElement ( generator, block, state, node ) { const isToplevel = !state.parentNode; - addElementAttributes( generator, block, node, local ); + addElementAttributes( generator, block, childState, node, local ); if ( local.allUsedContexts.length ) { const initialProps = local.allUsedContexts.map( contextName => { @@ -66,11 +68,11 @@ export default function visitElement ( generator, block, state, node ) { let render; - if ( local.namespace ) { - if ( local.namespace === 'http://www.w3.org/2000/svg' ) { + if ( childState.namespace ) { + if ( childState.namespace === 'http://www.w3.org/2000/svg' ) { render = `var ${name} = ${generator.helper( 'createSvgElement' )}( '${node.name}' )`; } else { - render = `var ${name} = document.createElementNS( '${local.namespace}', '${node.name}' );`; + render = `var ${name} = document.createElementNS( '${childState.namespace}', '${node.name}' );`; } } else { render = `var ${name} = ${generator.helper( 'createElement' )}( '${node.name}' );`; @@ -98,12 +100,6 @@ export default function visitElement ( generator, block, state, node ) { block.createMountStatement( name, state.parentNode ); - const childState = Object.assign( {}, state, { - isTopLevel: false, - parentNode: name, - namespace: local.namespace - }); - node.children.forEach( child => { visit( generator, block, childState, child ); }); diff --git a/src/generators/dom/visitors/attributes/addElementAttributes.js b/src/generators/dom/visitors/attributes/addElementAttributes.js index 8936db3d17..16fc52d085 100644 --- a/src/generators/dom/visitors/attributes/addElementAttributes.js +++ b/src/generators/dom/visitors/attributes/addElementAttributes.js @@ -4,12 +4,12 @@ import deindent from '../../../../utils/deindent.js'; import flattenReference from '../../../../utils/flattenReference.js'; import getStaticAttributeValue from './binding/getStaticAttributeValue.js'; -export default function addElementAttributes ( generator, block, node, local ) { +export default function addElementAttributes ( generator, block, state, node, local ) { node.attributes.forEach( attribute => { const name = attribute.name; if ( attribute.type === 'Attribute' ) { - let metadata = local.namespace ? null : attributeLookup[ name ]; + let metadata = state.namespace ? null : attributeLookup[ name ]; if ( metadata && metadata.appliesTo && !~metadata.appliesTo.indexOf( node.name ) ) metadata = null; let dynamic = false; @@ -32,28 +32,28 @@ export default function addElementAttributes ( generator, block, node, local ) { // attributes without values, e.g.