Skip to content

Commit c095ddd

Browse files
committed
3.5.0
1 parent e36e87d commit c095ddd

File tree

4 files changed

+5933
-0
lines changed

4 files changed

+5933
-0
lines changed

dist/amd/can-view-scope.js

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

0 commit comments

Comments
 (0)