1
1
import deindent from '../../../../utils/deindent.js' ;
2
2
import flattenReference from '../../../../utils/flattenReference.js' ;
3
3
import getSetter from './binding/getSetter.js' ;
4
+ import getStaticAttributeValue from './binding/getStaticAttributeValue.js' ;
4
5
5
6
export default function createBinding ( generator , node , attribute , current , local ) {
6
- const { name } = flattenReference ( attribute . value ) ;
7
+ const { name, keypath } = flattenReference ( attribute . value ) ;
7
8
const { snippet, contexts, dependencies } = generator . contextualise ( attribute . value ) ;
8
9
9
10
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
14
15
15
16
const handler = current . getUniqueName ( `${ local . name } ChangeHandler` ) ;
16
17
17
- const isMultipleSelect = node . name === 'select' && node . attributes . find ( attr => attr . name . toLowerCase ( ) === 'multiple' ) ; // TODO ensure that this is a static attribute
18
- const value = getBindingValue ( local , node , attribute , isMultipleSelect ) ;
18
+ const isMultipleSelect = node . name === 'select' && node . attributes . find ( attr => attr . name . toLowerCase ( ) === 'multiple' ) ; // TODO use getStaticAttributeValue
19
+ const bindingGroup = attribute . name === 'group' ? getBindingGroup ( generator , current , attribute , keypath ) : null ;
20
+ const value = getBindingValue ( generator , local , node , attribute , isMultipleSelect , bindingGroup ) ;
19
21
const eventName = getBindingEventName ( node ) ;
20
22
21
23
let setter = getSetter ( { current, name, context : '__svelte' , attribute, dependencies, snippet, value } ) ;
22
-
23
- // special case
24
- if ( node . name === 'select' && ! isMultipleSelect ) {
25
- setter = `var selectedOption = ${ local . name } .selectedOptions[0] || ${ local . name } .options[0];\n` + setter ;
26
- }
27
-
28
24
let updateElement ;
29
25
26
+ // <select> special case
30
27
if ( node . name === 'select' ) {
28
+ if ( ! isMultipleSelect ) {
29
+ setter = `var selectedOption = ${ local . name } .selectedOptions[0] || ${ local . name } .options[0];\n` + setter ;
30
+ }
31
+
31
32
const value = generator . current . getUniqueName ( 'value' ) ;
32
33
const i = generator . current . getUniqueName ( 'i' ) ;
33
34
const option = generator . current . getUniqueName ( 'option' ) ;
@@ -49,7 +50,35 @@ export default function createBinding ( generator, node, attribute, current, loc
49
50
${ ifStatement }
50
51
}
51
52
` ;
52
- } else {
53
+ }
54
+
55
+ // <input type='checkbox|radio' bind:group='selected'> special case
56
+ else if ( attribute . name === 'group' ) {
57
+ const type = getStaticAttributeValue ( node , 'type' ) ;
58
+
59
+ if ( type === 'checkbox' ) {
60
+ local . init . addLine (
61
+ `component._bindingGroups[${ bindingGroup } ].push( ${ local . name } );`
62
+ ) ;
63
+
64
+ local . teardown . addBlock (
65
+ `component._bindingGroups[${ bindingGroup } ].splice( component._bindingGroups[${ bindingGroup } ].indexOf( ${ local . name } ), 1 );`
66
+ ) ;
67
+
68
+ updateElement = `${ local . name } .checked = ~${ snippet } .indexOf( ${ local . name } .__value );` ;
69
+ }
70
+
71
+ else if ( type === 'radio' ) {
72
+ throw new Error ( 'TODO' ) ;
73
+ }
74
+
75
+ else {
76
+ throw new Error ( `Unexpected bind:group` ) ; // TODO catch this in validation with a better error
77
+ }
78
+ }
79
+
80
+ // everything else
81
+ else {
53
82
updateElement = `${ local . name } .${ attribute . name } = ${ snippet } ;` ;
54
83
}
55
84
@@ -93,14 +122,34 @@ function getBindingEventName ( node ) {
93
122
return 'change' ;
94
123
}
95
124
96
- function getBindingValue ( local , node , attribute , isMultipleSelect ) {
125
+ function getBindingValue ( generator , local , node , attribute , isMultipleSelect , bindingGroup ) {
126
+ // <select multiple bind:value='selected>
97
127
if ( isMultipleSelect ) {
98
128
return `[].map.call( ${ local . name } .selectedOptions, function ( option ) { return option.__value; })` ;
99
129
}
100
130
131
+ // <select bind:value='selected>
101
132
if ( node . name === 'select' ) {
102
133
return 'selectedOption && selectedOption.__value' ;
103
134
}
104
135
136
+ // <input type='checkbox' bind:group='foo'>
137
+ if ( attribute . name === 'group' ) {
138
+ return `${ generator . helper ( 'getBindingGroupValue' ) } ( component._bindingGroups[${ bindingGroup } ] )` ;
139
+ }
140
+
141
+ // everything else
105
142
return `${ local . name } .${ attribute . name } ` ;
143
+ }
144
+
145
+ function getBindingGroup ( generator , current , attribute , keypath ) {
146
+ // TODO handle contextual bindings — `keypath` should include unique ID of
147
+ // each block that provides context
148
+ let index = generator . bindingGroups . indexOf ( keypath ) ;
149
+ if ( index === - 1 ) {
150
+ index = generator . bindingGroups . length ;
151
+ generator . bindingGroups . push ( keypath ) ;
152
+ }
153
+
154
+ return index ;
106
155
}
0 commit comments