@@ -2,6 +2,7 @@ import { Interpreter, ClassInterpreter } from './generators/interpreter'
2
2
import { Lexer } from './generators/lexer'
3
3
import { Events } from './entity/events'
4
4
import { Attributes } from './entity/attributes'
5
+ import { State } from './state'
5
6
6
7
export default class Entity {
7
8
constructor ( el ) {
@@ -12,8 +13,11 @@ export default class Entity {
12
13
13
14
this . events = new Events ( this )
14
15
this . attributes = new Attributes ( this )
16
+ MiniJS . state . addEntity ( this )
15
17
16
18
if ( MiniJS . debug ) this . element . dataset . entityId = this . id
19
+
20
+ this . attributes . evaluateParent ( )
17
21
}
18
22
19
23
setAsParent ( ) {
@@ -25,6 +29,10 @@ export default class Entity {
25
29
return ! ! this . uuid
26
30
}
27
31
32
+ isExists ( ) {
33
+ return document . documentElement . contains ( this . element )
34
+ }
35
+
28
36
getVariables ( ) {
29
37
this . _getVariablesFromAttributes ( )
30
38
this . _getVariablesFromEvents ( )
@@ -86,44 +94,60 @@ export default class Entity {
86
94
87
95
_initVariables ( ) {
88
96
this . variables = [ ...new Set ( this . variables ) ]
89
- MiniJS . variables = [ ...new Set ( MiniJS . variables . concat ( this . variables ) ) ]
90
97
91
98
this . variables . forEach ( ( variable ) => {
92
- if ( variable . startsWith ( 'el.' ) ) {
99
+ if ( State . isElState ( variable ) ) {
93
100
this . setAsParent ( )
94
101
95
- if ( ! this . parent ) this . parent = this . getParent ( )
102
+ if ( window [ this . id ] == null ) {
103
+ window [ this . id ] = MiniJS . state . create ( { } , this . id )
104
+ }
96
105
97
- const varName = variable . replace ( 'el.' , '' )
106
+ MiniJS . state . addVariable ( this . id , this . id )
98
107
99
- if ( ! window [ this . uuid ] ) window [ this . uuid ] = { }
108
+ if ( variable !== 'el' ) {
109
+ const [ _ , varName ] = variable . split ( '.' )
110
+ MiniJS . state . addEntityVariable ( this . id , varName , this . id )
111
+ }
112
+ } else if ( State . isParentState ( variable ) ) {
113
+ if ( ! this . parent ) this . parent = this . getParent ( )
100
114
101
- // ! FIXME: Any changes to el.varName isn't being watched
102
- window [ this . uuid ] [ varName ] = MiniJS . tryFromLocal (
103
- variable . replace ( 'el.' , this . uuid + '.' )
104
- )
115
+ if ( window [ this . parent . id ] == null ) {
116
+ window [ this . parent . id ] = MiniJS . state . create ( { } , this . parent . id )
117
+ }
118
+
119
+ MiniJS . state . addVariable ( this . parent . id , this . id )
105
120
106
- if ( ! this . variables . includes ( this . uuid ) ) this . variables . push ( this . uuid )
121
+ if ( variable !== 'parent' ) {
122
+ const [ _ , varName ] = variable . split ( '.' )
123
+ MiniJS . state . addEntityVariable ( this . parent . id , varName , this . id )
124
+ }
107
125
} else if ( typeof window [ variable ] === 'function' ) {
108
126
this . variables . splice ( this . variables . indexOf ( variable ) , 1 )
109
- MiniJS . variables . splice ( MiniJS . variables . indexOf ( variable ) , 1 )
110
127
} else {
111
- window [ variable ] = variable . startsWith ( '$' )
112
- ? MiniJS . tryFromLocal ( variable )
113
- : window [ variable ]
128
+ const [ identifier ] = variable . split ( '.' )
129
+
130
+ window [ identifier ] = variable . startsWith ( '$' )
131
+ ? MiniJS . tryFromLocal ( identifier )
132
+ : window [ identifier ]
133
+
134
+ MiniJS . state . addVariable ( identifier , this . id )
114
135
}
115
136
} )
116
137
}
117
138
118
139
async _interpret ( expr , options = { } ) {
119
140
const Engine = options . isClass ? ClassInterpreter : Interpreter
120
141
const engine = new Engine ( expr , options )
121
- const ids = { $ : 'document.querySelector' }
142
+ const ids = {
143
+ $ : 'document.querySelector' ,
144
+ el : `proxyWindow['${ this . id } ']` ,
145
+ }
122
146
123
- if ( this . parent ?. uuid ) ids . el = `proxyWindow['${ this . parent . uuid } ']`
147
+ if ( this . parent ) ids . parent = `proxyWindow['${ this . parent . id } ']`
124
148
125
149
this . variables . forEach ( ( variable ) => {
126
- if ( variable . startsWith ( 'el.' ) || variable === 'el' ) return
150
+ if ( State . isElState ( variable ) || State . isParentState ( variable ) ) return
127
151
128
152
ids [ variable ] = `proxyWindow-${ variable } `
129
153
} )
@@ -133,8 +157,6 @@ export default class Entity {
133
157
return await engine . interpret ( this )
134
158
}
135
159
136
- /* Note: I don't this getParent() is needed,
137
- since el. variables should use the current element's uuid instead. */
138
160
getParent ( ) {
139
161
if ( this . isParent ( ) ) {
140
162
return this
@@ -145,24 +167,20 @@ export default class Entity {
145
167
currentElement = parentNode
146
168
parentNode = currentElement . parentNode
147
169
}
148
- const entity = MiniJS . elements . find (
149
- ( e ) => e . uuid == parentNode . dataset . uuid
150
- )
170
+ const entities = Array . from ( MiniJS . state . entities . values ( ) )
171
+ const entity = entities . find ( ( e ) => e . uuid == parentNode . dataset . uuid )
151
172
return entity
152
173
}
153
174
}
154
175
155
176
generateEntityUUID ( ) {
156
- // Suggestion: we can use crypto.randomUUID(). Tho crypto only works in secure contexts
157
177
return 'Entity' + Date . now ( ) + Math . floor ( Math . random ( ) * 10000 )
158
178
}
159
179
160
180
async init ( ) {
161
181
this . getVariables ( )
162
182
this . events . apply ( )
163
183
await this . attributes . evaluate ( )
164
-
165
- MiniJS . elements . push ( this )
166
184
}
167
185
168
186
initChildren ( ) {
@@ -183,47 +201,31 @@ export default class Entity {
183
201
184
202
dispose ( ) {
185
203
const elements = [ this . element , ...this . element . querySelectorAll ( '*' ) ]
204
+ const entities = Array . from ( MiniJS . state . entities . values ( ) )
186
205
const variables = [ ]
187
206
188
207
// Remove event bindings
189
208
for ( const element of elements ) {
190
209
if ( element . nodeType !== 1 ) continue
191
210
192
- const entity = MiniJS . elements . find (
193
- ( entity ) => entity . element === element
194
- )
211
+ const entity = MiniJS . state . getEntityByElement ( element , entities )
212
+
195
213
if ( ! entity ) continue
196
214
197
215
variables . push ( ...entity . variables )
198
216
entity . events . dispose ( )
217
+ MiniJS . state . removeEntity ( entity )
199
218
}
200
219
201
- // Remove disposed elements
202
- MiniJS . elements = MiniJS . elements . filter (
203
- ( entity ) => ! elements . includes ( entity . element )
204
- )
205
-
206
220
// Clean up unused variables
207
- const usedVariables = MiniJS . elements . reduce (
208
- ( acc , entity ) => acc . concat ( entity . variables ) ,
209
- [ ]
210
- )
221
+ const usedVariables = entities
222
+ . filter ( ( entity ) => ! elements . includes ( entity . element ) )
223
+ . reduce ( ( acc , entity ) => acc . concat ( entity . variables ) , [ ] )
211
224
212
225
const unusedVariables = variables . filter (
213
226
( variable ) => ! usedVariables . includes ( variable )
214
227
)
215
228
216
- MiniJS . variables = MiniJS . variables . filter (
217
- ( variable ) => ! unusedVariables . includes ( variable )
218
- )
219
-
220
- unusedVariables . forEach ( ( variable ) => {
221
- if ( variable . startsWith ( 'el.' ) ) {
222
- const varName = variable . replace ( 'el.' , '' )
223
- if ( window [ this . uuid ] ?. [ varName ] ) delete window [ this . uuid ]
224
- } else {
225
- delete window [ variable ]
226
- }
227
- } )
229
+ MiniJS . state . disposeVariables ( this . id , unusedVariables )
228
230
}
229
231
}
0 commit comments