@@ -7,8 +7,9 @@ import replace_object from '../../../utils/replace_object';
7
7
import Block from '../../Block' ;
8
8
import Renderer from '../../Renderer' ;
9
9
import flatten_reference from '../../../utils/flatten_reference' ;
10
- import EachBlock from '../../../nodes/EachBlock' ;
11
10
import { Node , Identifier } from 'estree' ;
11
+ import add_to_set from '../../../utils/add_to_set' ;
12
+ import mark_each_block_bindings from '../shared/mark_each_block_bindings' ;
12
13
13
14
export default class BindingWrapper {
14
15
node : Binding ;
@@ -42,12 +43,7 @@ export default class BindingWrapper {
42
43
}
43
44
44
45
if ( node . is_contextual ) {
45
- // we need to ensure that the each block creates a context including
46
- // the list and the index, if they're not otherwise referenced
47
- const { name } = get_object ( this . node . expression . node ) ;
48
- const each_block = this . parent . node . scope . get_owner ( name ) ;
49
-
50
- ( each_block as EachBlock ) . has_binding = true ;
46
+ mark_each_block_bindings ( this . parent , this . node ) ;
51
47
}
52
48
53
49
this . object = get_object ( this . node . expression . node ) . name ;
@@ -123,17 +119,31 @@ export default class BindingWrapper {
123
119
switch ( this . node . name ) {
124
120
case 'group' :
125
121
{
126
- const binding_group = get_binding_group ( parent . renderer , this . node . expression . node ) ;
122
+ const { binding_group, is_context , contexts , index } = get_binding_group ( parent . renderer , this . node , block ) ;
127
123
128
124
block . renderer . add_to_context ( `$$binding_groups` ) ;
129
- const reference = block . renderer . reference ( `$$binding_groups` ) ;
125
+
126
+ if ( is_context ) {
127
+ if ( contexts . length > 1 ) {
128
+ let binding_group = x `${ block . renderer . reference ( '$$binding_groups' ) } [${ index } ]` ;
129
+ for ( const name of contexts . slice ( 0 , - 1 ) ) {
130
+ binding_group = x `${ binding_group } [${ block . renderer . reference ( name ) } ]` ;
131
+ block . chunks . init . push (
132
+ b `${ binding_group } = ${ binding_group } || [];`
133
+ ) ;
134
+ }
135
+ }
136
+ block . chunks . init . push (
137
+ b `${ binding_group ( true ) } = [];`
138
+ ) ;
139
+ }
130
140
131
141
block . chunks . hydrate . push (
132
- b `${ reference } [ ${ binding_group } ] .push(${ parent . var } );`
142
+ b `${ binding_group ( true ) } .push(${ parent . var } );`
133
143
) ;
134
144
135
145
block . chunks . destroy . push (
136
- b `${ reference } [ ${ binding_group } ] .splice(${ reference } [ ${ binding_group } ] .indexOf(${ parent . var } ), 1);`
146
+ b `${ binding_group ( true ) } .splice(${ binding_group ( true ) } .indexOf(${ parent . var } ), 1);`
137
147
) ;
138
148
break ;
139
149
}
@@ -245,19 +255,61 @@ function get_dom_updater(
245
255
return b `${ element . var } .${ binding . node . name } = ${ binding . snippet } ;` ;
246
256
}
247
257
248
- function get_binding_group ( renderer : Renderer , value : Node ) {
249
- const { parts } = flatten_reference ( value ) ; // TODO handle cases involving computed member expressions
250
- const keypath = parts . join ( '.' ) ;
258
+ function get_binding_group ( renderer : Renderer , value : Binding , block : Block ) {
259
+ const { parts } = flatten_reference ( value . raw_expression ) ;
260
+ let keypath = parts . join ( '.' ) ;
261
+
262
+ const contexts = [ ] ;
263
+
264
+ for ( const dep of value . expression . contextual_dependencies ) {
265
+ const context = block . bindings . get ( dep ) ;
266
+ let key ;
267
+ let name ;
268
+ if ( context ) {
269
+ key = context . object . name ;
270
+ name = context . property . name ;
271
+ } else {
272
+ key = dep ;
273
+ name = dep ;
274
+ }
275
+ keypath = `${ key } @${ keypath } ` ;
276
+ contexts . push ( name ) ;
277
+ }
278
+
279
+ if ( ! renderer . binding_groups . has ( keypath ) ) {
280
+ const index = renderer . binding_groups . size ;
281
+
282
+ contexts . forEach ( context => {
283
+ renderer . add_to_context ( context , true ) ;
284
+ } ) ;
251
285
252
- // TODO handle contextual bindings — `keypath` should include unique ID of
253
- // each block that provides context
254
- let index = renderer . binding_groups . indexOf ( keypath ) ;
255
- if ( index === - 1 ) {
256
- index = renderer . binding_groups . length ;
257
- renderer . binding_groups . push ( keypath ) ;
286
+ renderer . binding_groups . set ( keypath , {
287
+ binding_group : ( to_reference : boolean = false ) => {
288
+ let binding_group = '$$binding_groups' ;
289
+ let _secondary_indexes = contexts ;
290
+
291
+ if ( to_reference ) {
292
+ binding_group = block . renderer . reference ( binding_group ) ;
293
+ _secondary_indexes = _secondary_indexes . map ( name => block . renderer . reference ( name ) ) ;
294
+ }
295
+
296
+ if ( _secondary_indexes . length > 0 ) {
297
+ let obj = x `${ binding_group } [${ index } ]` ;
298
+ _secondary_indexes . forEach ( secondary_index => {
299
+ obj = x `${ obj } [${ secondary_index } ]` ;
300
+ } ) ;
301
+ return obj ;
302
+ } else {
303
+ return x `${ binding_group } [${ index } ]` ;
304
+ }
305
+ } ,
306
+ is_context : contexts . length > 0 ,
307
+ contexts,
308
+ index,
309
+ } ) ;
258
310
}
259
311
260
- return index ;
312
+ return renderer . binding_groups . get ( keypath ) ;
261
313
}
262
314
263
315
function get_event_handler (
@@ -295,7 +347,7 @@ function get_event_handler(
295
347
}
296
348
}
297
349
298
- const value = get_value_from_dom ( renderer , binding . parent , binding ) ;
350
+ const value = get_value_from_dom ( renderer , binding . parent , binding , block , contextual_dependencies ) ;
299
351
300
352
const mutation = b `
301
353
${ lhs } = ${ value } ;
@@ -313,7 +365,9 @@ function get_event_handler(
313
365
function get_value_from_dom (
314
366
renderer : Renderer ,
315
367
element : ElementWrapper | InlineComponentWrapper ,
316
- binding : BindingWrapper
368
+ binding : BindingWrapper ,
369
+ block : Block ,
370
+ contextual_dependencies : Set < string >
317
371
) {
318
372
const { node } = element ;
319
373
const { name } = binding . node ;
@@ -333,9 +387,10 @@ function get_value_from_dom(
333
387
334
388
// <input type='checkbox' bind:group='foo'>
335
389
if ( name === 'group' ) {
336
- const binding_group = get_binding_group ( renderer , binding . node . expression . node ) ;
337
390
if ( type === 'checkbox' ) {
338
- return x `@get_binding_group_value($$binding_groups[${ binding_group } ], this.__value, this.checked)` ;
391
+ const { binding_group, contexts } = get_binding_group ( renderer , binding . node , block ) ;
392
+ add_to_set ( contextual_dependencies , contexts ) ;
393
+ return x `@get_binding_group_value(${ binding_group ( ) } , this.__value, this.checked)` ;
339
394
}
340
395
341
396
return x `this.__value` ;
0 commit comments