From b22b13c2f45ccb0e76043d8e3931f64dbd0b316b Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 17 Mar 2017 11:49:52 -0400 Subject: [PATCH] refactoring --- .../visitors/attributes/addElementBinding.js | 81 ++++++++----------- 1 file changed, 33 insertions(+), 48 deletions(-) diff --git a/src/generators/dom/visitors/attributes/addElementBinding.js b/src/generators/dom/visitors/attributes/addElementBinding.js index 93cac65345..5ec144d085 100644 --- a/src/generators/dom/visitors/attributes/addElementBinding.js +++ b/src/generators/dom/visitors/attributes/addElementBinding.js @@ -1,5 +1,4 @@ import deindent from '../../../../utils/deindent.js'; -import isReference from '../../../../utils/isReference.js'; import flattenReference from '../../../../utils/flattenReference.js'; export default function createBinding ( generator, node, attribute, current, local ) { @@ -8,8 +7,6 @@ export default function createBinding ( generator, node, attribute, current, loc if ( dependencies.length > 1 ) throw new Error( 'An unexpected situation arose. Please raise an issue!' ); - const contextual = name in current.contexts; - contexts.forEach( context => { if ( !~local.allUsedContexts.indexOf( context ) ) local.allUsedContexts.push( context ); }); @@ -17,59 +14,20 @@ export default function createBinding ( generator, node, attribute, current, loc const handler = current.getUniqueName( `${local.name}ChangeHandler` ); let setter; - let eventName = 'change'; - if ( node.name === 'input' ) { - const typeAttribute = node.attributes.find( attr => attr.type === 'Attribute' && attr.name === 'type' ); - const type = typeAttribute ? typeAttribute.value[0].data : 'text'; // TODO in validation, should throw if type attribute is not static - - if ( type !== 'checkbox' && type !== 'radio' ) { - eventName = 'input'; - } - } - - else if ( node.name === 'textarea' ) { - eventName = 'input'; - } - const isMultipleSelect = node.name === 'select' && node.attributes.find( attr => attr.name.toLowerCase() === 'multiple' ); // TODO ensure that this is a static attribute - let value; + const value = getBindingValue( local, node, attribute, isMultipleSelect ); + const eventName = getBindingEventName( node ); - if ( node.name === 'select' ) { - if ( isMultipleSelect ) { - value = `[].map.call( ${local.name}.selectedOptions, function ( option ) { return option.__value; })`; - } else { - value = 'selectedOption && selectedOption.__value'; - } - } else { - value = `${local.name}.${attribute.name}`; - } - - if ( contextual ) { + if ( name in current.contexts ) { // find the top-level property that this is a child of - let fragment = current; - let prop = name; - - do { - if ( fragment.expression && fragment.context === prop ) { - if ( !isReference( fragment.expression ) ) { - // TODO this should happen in prior validation step - throw new Error( `${prop} is read-only, it cannot be bound` ); - } - - prop = flattenReference( fragment.expression ).name; - } - } while ( fragment = fragment.parent ); - - generator.expectedProperties[ prop ] = true; + const prop = dependencies[0]; const listName = current.listNames[ name ]; const indexName = current.indexNames[ name ]; - const context = local.isComponent ? `_context` : `__svelte`; - setter = deindent` - var list = this.${context}.${listName}; - var index = this.${context}.${indexName}; + var list = this.__svelte.${listName}; + var index = this.__svelte.${indexName}; list[index]${parts.slice( 1 ).map( part => `.${part}` ).join( '' )} = ${value}; component._set({ ${prop}: component.get( '${prop}' ) }); @@ -145,3 +103,30 @@ export default function createBinding ( generator, node, attribute, current, loc ${generator.helper( 'removeEventListener' )}( ${local.name}, '${eventName}', ${handler} ); ` ); } + +function getBindingEventName ( node ) { + if ( node.name === 'input' ) { + const typeAttribute = node.attributes.find( attr => attr.type === 'Attribute' && attr.name === 'type' ); + const type = typeAttribute ? typeAttribute.value[0].data : 'text'; // TODO in validation, should throw if type attribute is not static + + return type === 'checkbox' || type === 'radio' ? 'change' : 'input'; + } + + if ( node.name === 'textarea' ) { + return 'input'; + } + + return 'change'; +} + +function getBindingValue ( local, node, attribute, isMultipleSelect ) { + if ( isMultipleSelect ) { + return `[].map.call( ${local.name}.selectedOptions, function ( option ) { return option.__value; })`; + } + + if ( node.name === 'select' ) { + return 'selectedOption && selectedOption.__value'; + } + + return `${local.name}.${attribute.name}`; +} \ No newline at end of file