@ -1,9 +1,10 @@
import deindent from '../../../../utils/deindent.js' ;
import flattenReference from '../../../../utils/flattenReference.js' ;
import getSetter from './binding/getSetter.js' ;
import getStaticAttributeValue from './binding/getStaticAttributeValue.js' ;
export default function createBinding ( generator , node , attribute , current , local ) {
const { name } = flattenReference ( attribute . value ) ;
const { name , keypath } = flattenReference ( attribute . value ) ;
const { snippet , contexts , dependencies } = generator . contextualise ( attribute . value ) ;
if ( dependencies . length > 1 ) throw new Error ( 'An unexpected situation arose. Please raise an issue at https://github.com/sveltejs/svelte/issues — thanks!' ) ;
@ -14,20 +15,20 @@ export default function createBinding ( generator, node, attribute, current, loc
const handler = current . getUniqueName ( ` ${ local . name } ChangeHandler ` ) ;
const isMultipleSelect = node . name === 'select' && node . attributes . find ( attr => attr . name . toLowerCase ( ) === 'multiple' ) ; // TODO ensure that this is a static attribute
const value = getBindingValue ( local , node , attribute , isMultipleSelect ) ;
const isMultipleSelect = node . name === 'select' && node . attributes . find ( attr => attr . name . toLowerCase ( ) === 'multiple' ) ; // TODO use getStaticAttributeValue
const bindingGroup = attribute . name === 'group' ? getBindingGroup ( generator , current , attribute , keypath ) : null ;
const value = getBindingValue ( generator , local , node , attribute , isMultipleSelect , bindingGroup ) ;
const eventName = getBindingEventName ( node ) ;
let setter = getSetter ( { current , name , context : '__svelte' , attribute , dependencies , snippet , value } ) ;
// special case
if ( node . name === 'select' && ! isMultipleSelect ) {
setter = ` var selectedOption = ${ local . name } .selectedOptions[0] || ${ local . name } .options[0]; \n ` + setter ;
}
let updateElement ;
// <select> special case
if ( node . name === 'select' ) {
if ( ! isMultipleSelect ) {
setter = ` var selectedOption = ${ local . name } .selectedOptions[0] || ${ local . name } .options[0]; \n ` + setter ;
}
const value = generator . current . getUniqueName ( 'value' ) ;
const i = generator . current . getUniqueName ( 'i' ) ;
const option = generator . current . getUniqueName ( 'option' ) ;
@ -49,7 +50,35 @@ export default function createBinding ( generator, node, attribute, current, loc
$ { ifStatement }
}
` ;
} else {
}
// <input type='checkbox|radio' bind:group='selected'> special case
else if ( attribute . name === 'group' ) {
const type = getStaticAttributeValue ( node , 'type' ) ;
if ( type === 'checkbox' ) {
local . init . addLine (
` component._bindingGroups[ ${ bindingGroup } ].push( ${ local . name } ); `
) ;
local . teardown . addBlock (
` component._bindingGroups[ ${ bindingGroup } ].splice( component._bindingGroups[ ${ bindingGroup } ].indexOf( ${ local . name } ), 1 ); `
) ;
updateElement = ` ${ local . name } .checked = ~ ${ snippet } .indexOf( ${ local . name } .__value ); ` ;
}
else if ( type === 'radio' ) {
throw new Error ( 'TODO' ) ;
}
else {
throw new Error ( ` Unexpected bind:group ` ) ; // TODO catch this in validation with a better error
}
}
// everything else
else {
updateElement = ` ${ local . name } . ${ attribute . name } = ${ snippet } ; ` ;
}
@ -93,14 +122,34 @@ function getBindingEventName ( node ) {
return 'change' ;
}
function getBindingValue ( local , node , attribute , isMultipleSelect ) {
function getBindingValue ( generator , local , node , attribute , isMultipleSelect , bindingGroup ) {
// <select multiple bind:value='selected>
if ( isMultipleSelect ) {
return ` [].map.call( ${ local . name } .selectedOptions, function ( option ) { return option.__value; }) ` ;
}
// <select bind:value='selected>
if ( node . name === 'select' ) {
return 'selectedOption && selectedOption.__value' ;
}
// <input type='checkbox' bind:group='foo'>
if ( attribute . name === 'group' ) {
return ` ${ generator . helper ( 'getBindingGroupValue' ) } ( component._bindingGroups[ ${ bindingGroup } ] ) ` ;
}
// everything else
return ` ${ local . name } . ${ attribute . name } ` ;
}
function getBindingGroup ( generator , current , attribute , keypath ) {
// TODO handle contextual bindings — `keypath` should include unique ID of
// each block that provides context
let index = generator . bindingGroups . indexOf ( keypath ) ;
if ( index === - 1 ) {
index = generator . bindingGroups . length ;
generator . bindingGroups . push ( keypath ) ;
}
return index ;
}