1
+ /*[email protected] #can-view-scope*/
2
+ define ( [
3
+ 'require' ,
4
+ 'exports' ,
5
+ 'module' ,
6
+ 'can-stache-key' ,
7
+ 'can-observation' ,
8
+ './reference-map' ,
9
+ './compute_data' ,
10
+ 'can-util/js/assign' ,
11
+ 'can-util/js/each' ,
12
+ 'can-namespace' ,
13
+ 'can-util/js/dev' ,
14
+ 'can-reflect' ,
15
+ 'can-util/js/log'
16
+ ] , function ( require , exports , module ) {
17
+ var observeReader = require ( 'can-stache-key' ) ;
18
+ var Observation = require ( 'can-observation' ) ;
19
+ var ReferenceMap = require ( './reference-map' ) ;
20
+ var makeComputeData = require ( './compute_data' ) ;
21
+ var assign = require ( 'can-util/js/assign' ) ;
22
+ var each = require ( 'can-util/js/each' ) ;
23
+ var namespace = require ( 'can-namespace' ) ;
24
+ var dev = require ( 'can-util/js/dev' ) ;
25
+ var canReflect = require ( 'can-reflect' ) ;
26
+ var canLog = require ( 'can-util/js/log' ) ;
27
+ function Scope ( context , parent , meta ) {
28
+ this . _context = context ;
29
+ this . _parent = parent ;
30
+ this . _meta = meta || { } ;
31
+ this . __cache = { } ;
32
+ }
33
+ assign ( Scope , {
34
+ read : observeReader . read ,
35
+ Refs : ReferenceMap ,
36
+ refsScope : function ( ) {
37
+ return new Scope ( new this . Refs ( ) ) ;
38
+ } ,
39
+ keyInfo : function ( attr ) {
40
+ var info = { } ;
41
+ info . isDotSlash = attr . substr ( 0 , 2 ) === './' ;
42
+ info . isThisDot = attr . substr ( 0 , 5 ) === 'this.' ;
43
+ info . isThisAt = attr . substr ( 0 , 5 ) === 'this@' ;
44
+ info . isInCurrentContext = info . isDotSlash || info . isThisDot || info . isThisAt ;
45
+ info . isInParentContext = attr . substr ( 0 , 3 ) === '../' ;
46
+ info . isCurrentContext = attr === '.' || attr === 'this' ;
47
+ info . isParentContext = attr === '..' ;
48
+ info . isContextBased = info . isInCurrentContext || info . isInParentContext || info . isCurrentContext || info . isParentContext ;
49
+ return info ;
50
+ }
51
+ } ) ;
52
+ assign ( Scope . prototype , {
53
+ add : function ( context , meta ) {
54
+ if ( context !== this . _context ) {
55
+ return new this . constructor ( context , this , meta ) ;
56
+ } else {
57
+ return this ;
58
+ }
59
+ } ,
60
+ read : function ( attr , options ) {
61
+ if ( attr === '%root' ) {
62
+ return { value : this . getRoot ( ) } ;
63
+ }
64
+ if ( attr === '%scope' ) {
65
+ return { value : this } ;
66
+ }
67
+ var keyInfo = Scope . keyInfo ( attr ) ;
68
+ if ( keyInfo . isContextBased && this . _meta . notContext ) {
69
+ return this . _parent . read ( attr , options ) ;
70
+ }
71
+ var currentScopeOnly ;
72
+ if ( keyInfo . isInCurrentContext ) {
73
+ currentScopeOnly = true ;
74
+ attr = keyInfo . isDotSlash ? attr . substr ( 2 ) : attr . substr ( 5 ) ;
75
+ } else if ( keyInfo . isInParentContext || keyInfo . isParentContext ) {
76
+ var parent = this . _parent ;
77
+ while ( parent . _meta . notContext ) {
78
+ parent = parent . _parent ;
79
+ }
80
+ if ( keyInfo . isParentContext ) {
81
+ return observeReader . read ( parent . _context , [ ] , options ) ;
82
+ }
83
+ return parent . read ( attr . substr ( 3 ) || '.' , options ) ;
84
+ } else if ( keyInfo . isCurrentContext ) {
85
+ return observeReader . read ( this . _context , [ ] , options ) ;
86
+ }
87
+ var keyReads = observeReader . reads ( attr ) ;
88
+ if ( keyReads [ 0 ] . key . charAt ( 0 ) === '*' ) {
89
+ return this . getRefs ( ) . _read ( keyReads , options , true ) ;
90
+ } else {
91
+ return this . _read ( keyReads , options , currentScopeOnly ) ;
92
+ }
93
+ } ,
94
+ _read : function ( keyReads , options , currentScopeOnly ) {
95
+ var currentScope = this , currentContext , undefinedObserves = [ ] , currentObserve , currentReads , setObserveDepth = - 1 , currentSetReads , currentSetObserve , readOptions = assign ( {
96
+ foundObservable : function ( observe , nameIndex ) {
97
+ currentObserve = observe ;
98
+ currentReads = keyReads . slice ( nameIndex ) ;
99
+ } ,
100
+ earlyExit : function ( parentValue , nameIndex ) {
101
+ if ( nameIndex > setObserveDepth || nameIndex === setObserveDepth && ( typeof parentValue === 'object' && keyReads [ nameIndex ] . key in parentValue ) ) {
102
+ currentSetObserve = currentObserve ;
103
+ currentSetReads = currentReads ;
104
+ setObserveDepth = nameIndex ;
105
+ }
106
+ }
107
+ } , options ) ;
108
+ while ( currentScope ) {
109
+ currentContext = currentScope . _context ;
110
+ if ( currentContext !== null && ( typeof currentContext === 'object' || typeof currentContext === 'function' ) ) {
111
+ var getObserves = Observation . trap ( ) ;
112
+ var data = observeReader . read ( currentContext , keyReads , readOptions ) ;
113
+ var observes = getObserves ( ) ;
114
+ if ( data . value !== undefined ) {
115
+ Observation . addAll ( observes ) ;
116
+ return {
117
+ scope : currentScope ,
118
+ rootObserve : currentObserve ,
119
+ value : data . value ,
120
+ reads : currentReads
121
+ } ;
122
+ } else {
123
+ undefinedObserves . push . apply ( undefinedObserves , observes ) ;
124
+ }
125
+ }
126
+ if ( currentScopeOnly ) {
127
+ currentScope = null ;
128
+ } else {
129
+ currentScope = currentScope . _parent ;
130
+ }
131
+ }
132
+ Observation . addAll ( undefinedObserves ) ;
133
+ return {
134
+ setRoot : currentSetObserve ,
135
+ reads : currentSetReads ,
136
+ value : undefined
137
+ } ;
138
+ } ,
139
+ get : function ( key , options ) {
140
+ options = assign ( { isArgument : true } , options ) ;
141
+ var res = this . read ( key , options ) ;
142
+ return res . value ;
143
+ } ,
144
+ peek : Observation . ignore ( function ( key , options ) {
145
+ return this . get ( key , options ) ;
146
+ } ) ,
147
+ peak : Observation . ignore ( function ( key , options ) {
148
+ return this . peek ( key , options ) ;
149
+ } ) ,
150
+ getScope : function ( tester ) {
151
+ var scope = this ;
152
+ while ( scope ) {
153
+ if ( tester ( scope ) ) {
154
+ return scope ;
155
+ }
156
+ scope = scope . _parent ;
157
+ }
158
+ } ,
159
+ getContext : function ( tester ) {
160
+ var res = this . getScope ( tester ) ;
161
+ return res && res . _context ;
162
+ } ,
163
+ getRefs : function ( ) {
164
+ var lastScope ;
165
+ var refScope = this . getScope ( function ( scope ) {
166
+ lastScope = scope ;
167
+ return scope . _context instanceof Scope . Refs ;
168
+ } ) ;
169
+ if ( ! refScope ) {
170
+ lastScope . _parent = Scope . refsScope ( ) ;
171
+ refScope = lastScope . _parent ;
172
+ }
173
+ return refScope ;
174
+ } ,
175
+ getRoot : function ( ) {
176
+ var cur = this , child = this ;
177
+ while ( cur . _parent ) {
178
+ child = cur ;
179
+ cur = cur . _parent ;
180
+ }
181
+ if ( cur . _context instanceof Scope . Refs ) {
182
+ cur = child ;
183
+ }
184
+ return cur . _context ;
185
+ } ,
186
+ set : function ( key , value , options ) {
187
+ options = options || { } ;
188
+ var keyInfo = Scope . keyInfo ( key ) ;
189
+ if ( keyInfo . isCurrentContext ) {
190
+ return canReflect . setValue ( this . _context , value ) ;
191
+ } else if ( keyInfo . isInParentContext || keyInfo . isParentContext ) {
192
+ var parent = this . _parent ;
193
+ while ( parent . _meta . notContext ) {
194
+ parent = parent . _parent ;
195
+ }
196
+ if ( keyInfo . isParentContext ) {
197
+ return canReflect . setValue ( parent . _context , value ) ;
198
+ }
199
+ return parent . set ( key . substr ( 3 ) || '.' , value , options ) ;
200
+ }
201
+ var dotIndex = key . lastIndexOf ( '.' ) , slashIndex = key . lastIndexOf ( '/' ) , contextPath , propName ;
202
+ if ( slashIndex > dotIndex ) {
203
+ contextPath = key . substring ( 0 , slashIndex ) ;
204
+ propName = key . substring ( slashIndex + 1 , key . length ) ;
205
+ } else {
206
+ if ( dotIndex !== - 1 ) {
207
+ contextPath = key . substring ( 0 , dotIndex ) ;
208
+ propName = key . substring ( dotIndex + 1 , key . length ) ;
209
+ } else {
210
+ contextPath = '.' ;
211
+ propName = key ;
212
+ }
213
+ }
214
+ if ( key . charAt ( 0 ) === '*' ) {
215
+ observeReader . write ( this . getRefs ( ) . _context , key , value , options ) ;
216
+ } else {
217
+ var context = this . read ( contextPath , options ) . value ;
218
+ if ( context === undefined ) {
219
+ return ;
220
+ }
221
+ if ( ! canReflect . isObservableLike ( context ) && canReflect . isObservableLike ( context [ propName ] ) ) {
222
+ if ( canReflect . isMapLike ( context [ propName ] ) ) {
223
+ dev . warn ( 'can-view-scope: Merging data into "' + propName + '" because its parent is non-observable' ) ;
224
+ canReflect . updateDeep ( context [ propName ] , value ) ;
225
+ } else if ( canReflect . isValueLike ( context [ propName ] ) ) {
226
+ canReflect . setValue ( context [ propName ] , value ) ;
227
+ } else {
228
+ observeReader . write ( context , propName , value , options ) ;
229
+ }
230
+ } else {
231
+ observeReader . write ( context , propName , value , options ) ;
232
+ }
233
+ }
234
+ } ,
235
+ attr : Observation . ignore ( function ( key , value , options ) {
236
+ canLog . warn ( 'can-view-scope::attr is deprecated, please use peek, get or set' ) ;
237
+ options = assign ( { isArgument : true } , options ) ;
238
+ if ( arguments . length === 2 ) {
239
+ return this . set ( key , value , options ) ;
240
+ } else {
241
+ return this . get ( key , options ) ;
242
+ }
243
+ } ) ,
244
+ computeData : function ( key , options ) {
245
+ return makeComputeData ( this , key , options ) ;
246
+ } ,
247
+ compute : function ( key , options ) {
248
+ return this . computeData ( key , options ) . compute ;
249
+ } ,
250
+ cloneFromRef : function ( ) {
251
+ var contexts = [ ] ;
252
+ var scope = this , context , parent ;
253
+ while ( scope ) {
254
+ context = scope . _context ;
255
+ if ( context instanceof Scope . Refs ) {
256
+ parent = scope . _parent ;
257
+ break ;
258
+ }
259
+ contexts . unshift ( context ) ;
260
+ scope = scope . _parent ;
261
+ }
262
+ if ( parent ) {
263
+ each ( contexts , function ( context ) {
264
+ parent = parent . add ( context ) ;
265
+ } ) ;
266
+ return parent ;
267
+ } else {
268
+ return this ;
269
+ }
270
+ }
271
+ } ) ;
272
+ function Options ( data , parent , meta ) {
273
+ if ( ! data . helpers && ! data . partials && ! data . tags ) {
274
+ data = { helpers : data } ;
275
+ }
276
+ Scope . call ( this , data , parent , meta ) ;
277
+ }
278
+ Options . prototype = new Scope ( ) ;
279
+ Options . prototype . constructor = Options ;
280
+ Scope . Options = Options ;
281
+ namespace . view = namespace . view || { } ;
282
+ module . exports = namespace . view . Scope = Scope ;
283
+ } ) ;
0 commit comments