@@ -16,19 +16,29 @@ const type = (value) =>
1616?Type . Dict
1717:Type . Atom ;
1818
19- const slots = ( name , scope , processor = undefined , initial = { } ) =>
20- $ ( `[${ name } ]` , scope ) . reduce ( ( r , n ) => {
19+ const slots = ( name , parent , processor = undefined , initial = { } ) =>
20+ $ ( `[${ name } ]` , parent ) . reduce ( ( r , n ) => {
2121const k = n . getAttribute ( name ) ;
2222// n.removeAttribute(name);
2323if ( r [ k ] === undefined ) {
2424const v = new UISelection ( n ) ;
25+ v . parent = parent ;
2526r [ k ] = processor ?processor ( v , n , k ) :v ;
2627} else {
2728r [ k ] . push ( n ) ;
2829}
2930return r ;
3031} , initial ) ;
3132
33+ class UIEvent {
34+ constructor ( name , data , origin ) {
35+ this . name = name ;
36+ this . data = data ;
37+ this . origin = origin ;
38+ this . current = undefined ;
39+ }
40+ }
41+
3242class AppliedUISelection {
3343constructor ( selection , data ) {
3444this . selection = selection ;
@@ -53,33 +63,117 @@ class UISelection extends Selection {
5363node,
5464} ;
5565} ) ;
56-
57- // Data
66+ // Parent
67+ this . parent = undefined ;
68+ // Data & State
5869this . data = undefined ;
5970this . key = undefined ;
6071this . dataType = Type . Null ;
6172this . rendered = new Map ( ) ;
6273this . condition = undefined ;
63- // Interaction/Behavior
74+ // Interaction/Behavior (passed in cloned)
6475this . behavior = undefined ;
76+ this . subs = undefined ;
6577// TODO: Initial state parsing
6678}
6779
68- clone ( ) {
80+ // TODO: There's a question whether we should have Instance instead
81+ // of clone. We could certainly speed up init.
82+ clone ( parent ) {
6983const res = super . clone ( ) ;
7084res . behavior = this . behavior ; //new Object(res.behavior);
85+ res . subs = this . subs ;
86+ res . parent = parent ;
87+ // We bind the event handlers
88+ for ( const k in res . on ) {
89+ let handlers = res . behavior [ k ] ;
90+ if ( handlers instanceof Function ) {
91+ // TODO: Select the best type of event for the target
92+ handlers = { click :handlers } ;
93+ }
94+ if ( handlers ) {
95+ for ( const event in handlers ) {
96+ const h = handlers [ event ] ;
97+ res . on [ k ] . bind ( event , ( event ) =>
98+ h ( event , res , res . data , res . key ) ,
99+ ) ;
100+ }
101+ }
102+ }
71103return res ;
72104}
73105
74106apply ( data ) {
75107return new AppliedUISelection ( this , data ) ;
76108}
77109
110+ // ========================================================================
111+ // BEHAVIOUR
112+ // ========================================================================
113+
78114does ( behavior ) {
79115this . behavior = Object . assign ( this . behavior ?? { } , behavior ) ;
80116return this ;
81117}
82118
119+ // ========================================================================
120+ // EVENTS
121+ // ========================================================================
122+
123+ send ( event , data ) {
124+ return this . pub ( event , data ) ;
125+ }
126+
127+ pub ( event , data ) {
128+ const res = new UIEvent ( event , data , this ) ;
129+ this . parent ?. onPub ( res ) ;
130+ return res ;
131+ }
132+
133+ sub ( event , handler = undefined ) {
134+ if ( typeof event === "string" ) {
135+ if ( ! handler ) {
136+ return this ;
137+ }
138+ if ( this . subs === undefined ) {
139+ this . subs = new Map ( ) ;
140+ }
141+ if ( this . subs . has ( event ) ) {
142+ this . subs . get ( event ) . push ( handler ) ;
143+ } else {
144+ this . subs . set ( event , [ handler ] ) ;
145+ }
146+ } else {
147+ for ( const k in event ) {
148+ this . sub ( k , event [ k ] ) ;
149+ }
150+ }
151+ return this ;
152+ }
153+
154+ onPub ( event ) {
155+ event . current = this ;
156+ let propagate = true ;
157+ console . log ( "GOT" , event ) ;
158+ if ( this . subs ) {
159+ const hl = this . subs . get ( event . name ) ;
160+ if ( hl ) {
161+ for ( const h of hl ) {
162+ // We do an early exit when `false` is returned,
163+ // Or stop propagation on `null`
164+ const c = h ( event , this , this . data , this . key ) ;
165+ if ( c === false ) {
166+ return event ;
167+ } else if ( c === null ) {
168+ propagate = false ;
169+ }
170+ }
171+ }
172+ }
173+ propagate && this . parent ?. onPub ( event ) ;
174+ return event ;
175+ }
176+
83177// ========================================================================
84178// DATA
85179// ========================================================================
@@ -100,21 +194,10 @@ class UISelection extends Selection {
100194
101195// --
102196// Creates, updates or removes a selection based on the argument
103- doCreate ( data , key = this . key ) {
197+ doCreate ( data , key = this . key , parent = undefined ) {
104198// Create a new instance of the selection
105- const ui = this . clone ( ) ;
106- // We bind the event handlers
107- for ( const k in this . on ) {
108- const handlers = this . behavior [ k ] ;
109- if ( handlers ) {
110- for ( const event in handlers ) {
111- const h = handlers [ event ] ;
112- ui . on [ k ] . bind ( event , ( event ) => {
113- return h . apply ( ui . data ?? data , [ event , ui , key ] ) ;
114- } ) ;
115- }
116- }
117- }
199+ const ui = this . clone ( parent ) ;
200+
118201ui . attr ( "data-xxx" , "POUET" ) ;
119202ui . set ( data , key ) ;
120203return ui ;
@@ -213,7 +296,7 @@ class UISelection extends Selection {
213296if ( r ) {
214297r . doUpdate ( data ) ;
215298} else {
216- r = ui . doCreate ( data ) ;
299+ r = ui . doCreate ( data , null , this ) ;
217300this . append ( r ) ;
218301this . rendered . set ( null , r ) ;
219302}
@@ -226,19 +309,18 @@ class UISelection extends Selection {
226309this . rendered . get ( i ) . doUpdate ( data [ i ] , i ) ;
227310}
228311for ( let i = n ; i < data . length ; i ++ ) {
229- const r = ui . doCreate ( data [ i ] , i ) ;
312+ const r = ui . doCreate ( data [ i ] , i , this ) ;
230313this . append ( r ) ;
231314this . rendered . set ( i , r ) ;
232315}
233316for ( let i = n ; i < this . data . length ; i ++ ) {
234- console . log ( "XXX REMOVE ITEM" , i ) ;
235317this . rendered . get ( i ) . doRemove ( ) ;
236318this . rendered . delete ( i ) ;
237319}
238320} else {
239321this . doClear ( ) ;
240322for ( let i = 0 ; i < data . length ; i ++ ) {
241- const r = ui . doCreate ( data [ i ] , i ) ;
323+ const r = ui . doCreate ( data [ i ] , i , this ) ;
242324this . append ( r ) ;
243325this . rendered . set ( i , r ) ;
244326}
@@ -248,7 +330,7 @@ class UISelection extends Selection {
248330if ( this . dataType === data_type ) {
249331for ( const k in data ) {
250332if ( this . data [ k ] === undefined ) {
251- const r = ui . doCreate ( data [ k ] , k ) ;
333+ const r = ui . doCreate ( data [ k ] , k , this ) ;
252334this . append ( r ) ;
253335this . rendered . set ( k , r ) ;
254336} else {
@@ -264,7 +346,7 @@ class UISelection extends Selection {
264346} else {
265347this . doClear ( ) ;
266348for ( const k in data ) {
267- const r = ui . doCreate ( data [ k ] , k ) ;
349+ const r = ui . doCreate ( data [ k ] , k , this ) ;
268350this . append ( r ) ;
269351this . rendered . set ( k , r ) ;
270352}