Skip to content

Commit 6963750

Browse files
committed
Restructure streams to be more static
1 parent 8719022 commit 6963750

File tree

28 files changed

+403
-316
lines changed

28 files changed

+403
-316
lines changed

ember-cli-build.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ function babelConfigFor(environment) {
3535

3636
if (isProduction) {
3737
plugins.push(filterImports({
38-
'ember-metal/debug': ['assert', 'debug', 'deprecate', 'info', 'runInDebug', 'warn']
38+
'ember-metal/debug': ['assert', 'debug', 'deprecate', 'info', 'runInDebug', 'warn', 'debugSeal']
3939
}));
4040
}
4141

packages/ember-debug/lib/main.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ setDebugFunction('runInDebug', function runInDebug(func) {
149149
func();
150150
});
151151

152+
setDebugFunction('debugSeal', function debugSeal(obj) {
153+
Object.seal(obj);
154+
});
155+
152156
setDebugFunction('deprecate', _deprecate);
153157
setDebugFunction('warn', _warn);
154158
/**

packages/ember-htmlbars/lib/hooks/bind-local.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
@submodule ember-htmlbars
44
*/
55

6-
import Stream from 'ember-metal/streams/stream';
6+
import { wrap } from 'ember-metal/streams/stream';
77
import ProxyStream from 'ember-metal/streams/proxy-stream';
88

99
export default function bindLocal(env, scope, key, value) {
@@ -14,7 +14,7 @@ export default function bindLocal(env, scope, key, value) {
1414
existing.setSource(value);
1515
}
1616
} else {
17-
let newValue = Stream.wrap(value, ProxyStream, key);
17+
let newValue = wrap(value, ProxyStream, key);
1818
scope.bindLocal(key, newValue);
1919
}
2020
}

packages/ember-htmlbars/lib/hooks/bind-self.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
@submodule ember-htmlbars
44
*/
55

6+
import _Ember from 'ember-metal';
67
import ProxyStream from 'ember-metal/streams/proxy-stream';
78

89
export default function bindSelf(env, scope, _self) {
@@ -12,12 +13,19 @@ export default function bindSelf(env, scope, _self) {
1213
let { controller } = self;
1314
self = self.self;
1415

15-
scope.bindLocal('controller', newStream(controller || self));
16+
if (!!_Ember.ENV._LEGACY_CONTROLLER_SUPPORT) {
17+
scope.bindLocal('controller', newStream(controller || self));
18+
}
1619
}
1720

1821
if (self && self.isView) {
19-
scope.bindLocal('view', newStream(self, 'view'));
20-
scope.bindLocal('controller', newStream(self, '').getKey('controller'));
22+
if (!!_Ember.ENV._LEGACY_VIEW_SUPPORT) {
23+
scope.bindLocal('view', newStream(self, 'view'));
24+
}
25+
26+
if (!!_Ember.ENV._LEGACY_CONTROLLER_SUPPORT) {
27+
scope.bindLocal('controller', newStream(self, '').getKey('controller'));
28+
}
2129

2230
let selfStream = newStream(self, '');
2331

@@ -33,8 +41,10 @@ export default function bindSelf(env, scope, _self) {
3341
let selfStream = newStream(self, '');
3442
scope.bindSelf(selfStream);
3543

36-
if (!scope.hasLocal('controller')) {
37-
scope.bindLocal('controller', selfStream);
44+
if (!!_Ember.ENV.LEGACY_CONTROLLER_SUPPORT) {
45+
if (!scope.hasLocal('controller')) {
46+
scope.bindLocal('controller', selfStream);
47+
}
3848
}
3949
}
4050

packages/ember-htmlbars/lib/hooks/create-fresh-scope.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import ProxyStream from 'ember-metal/streams/proxy-stream';
2+
import EmptyObject from 'ember-metal/empty_object';
23

34
/*
45
Ember's implementation of HTMLBars creates an enriched scope.
@@ -50,13 +51,13 @@ import ProxyStream from 'ember-metal/streams/proxy-stream';
5051

5152
function Scope(parent) {
5253
this._self = null;
53-
this._blocks = {};
54+
this._blocks = null;
5455
this._component = null;
5556
this._view = null;
5657
this._attrs = null;
57-
this._locals = {};
58-
this._localPresent = {};
59-
this.overrideController = false;
58+
this._locals = null;
59+
this._localPresent = null;
60+
this.overrideController = null;
6061
this.parent = parent;
6162
}
6263

@@ -81,14 +82,17 @@ proto.updateSelf = function(self, key) {
8182
};
8283

8384
proto.getBlock = function(name) {
85+
if (!this._blocks) { return this.parent.getBlock(name); }
8486
return this._blocks[name] || this.parent.getBlock(name);
8587
};
8688

8789
proto.hasBlock = function(name) {
90+
if (!this._blocks) { return this.parent.hasBlock(name); }
8891
return !!(this._blocks[name] || this.parent.hasBlock(name));
8992
};
9093

9194
proto.bindBlock = function(name, block) {
95+
if (!this._blocks) { this._blocks = new EmptyObject(); }
9296
this._blocks[name] = block;
9397
};
9498

@@ -117,18 +121,25 @@ proto.bindAttrs = function(attrs) {
117121
};
118122

119123
proto.hasLocal = function(name) {
124+
if (!this._localPresent) { return this.parent.hasLocal(name); }
120125
return this._localPresent[name] || this.parent.hasLocal(name);
121126
};
122127

123128
proto.hasOwnLocal = function(name) {
124-
return this._localPresent[name];
129+
return this._localPresent && this._localPresent[name];
125130
};
126131

127132
proto.getLocal = function(name) {
133+
if (!this._localPresent) { return this.parent.getLocal(name); }
128134
return this._localPresent[name] ? this._locals[name] : this.parent.getLocal(name);
129135
};
130136

131137
proto.bindLocal = function(name, value) {
138+
if (!this._localPresent) {
139+
this._localPresent = new EmptyObject();
140+
this._locals = new EmptyObject();
141+
}
142+
132143
this._localPresent[name] = true;
133144
this._locals[name] = value;
134145
};
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export default function didRenderNode(morph, env) {
2-
env.renderedNodes[morph.guid] = true;
2+
env.renderedNodes.add(morph);
33
}

packages/ember-htmlbars/lib/keywords/get.js

Lines changed: 75 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
*/
55

66
import { assert } from 'ember-metal/debug';
7-
import Stream from 'ember-metal/streams/stream';
7+
import BasicStream from 'ember-metal/streams/stream';
88
import KeyStream from 'ember-metal/streams/key-stream';
99
import { isStream } from 'ember-metal/streams/utils';
10-
import merge from 'ember-metal/merge';
1110
import subscribe from 'ember-htmlbars/utils/subscribe';
1211
import { get } from 'ember-metal/property_get';
1312
import { set } from 'ember-metal/property_set';
@@ -22,17 +21,90 @@ function labelFor(source, key) {
2221
return `(get ${sourceLabel} ${keyLabel})`;
2322
}
2423

24+
let DynamicKeyStream = BasicStream.extend({
25+
init(source, keySource) {
26+
assert('DynamicKeyStream error: source must be a stream', isStream(source)); // TODO: This isn't necessary.
27+
28+
// used to get the original path for debugging and legacy purposes
29+
var label = labelFor(source, keySource);
30+
31+
this.label = label;
32+
this.path = label;
33+
this.sourceDep = this.addMutableDependency(source);
34+
this.keyDep = this.addMutableDependency(keySource);
35+
this.observedObject = null;
36+
this.observedKey = null;
37+
},
38+
39+
key() {
40+
const key = this.keyDep.getValue();
41+
if (typeof key === 'string') {
42+
assert('DynamicKeyStream error: key must not have a \'.\'', key.indexOf('.') === -1);
43+
return key;
44+
}
45+
},
46+
47+
compute() {
48+
var object = this.sourceDep.getValue();
49+
var key = this.key();
50+
if (object && key) {
51+
return get(object, key);
52+
}
53+
},
54+
55+
setValue(value) {
56+
var object = this.sourceDep.getValue();
57+
var key = this.key();
58+
if (object) {
59+
set(object, key, value);
60+
}
61+
},
62+
63+
_super$revalidate: BasicStream.prototype.revalidate,
64+
65+
revalidate(value) {
66+
this._super$revalidate(value);
67+
68+
var object = this.sourceDep.getValue();
69+
var key = this.key();
70+
if (object !== this.observedObject || key !== this.observedKey) {
71+
this._clearObservedObject();
72+
73+
if (object && typeof object === 'object' && key) {
74+
addObserver(object, key, this, this.notify);
75+
this.observedObject = object;
76+
this.observedKey = key;
77+
}
78+
}
79+
},
80+
81+
_clearObservedObject() {
82+
if (this.observedObject) {
83+
removeObserver(this.observedObject, this.observedKey, this, this.notify);
84+
this.observedObject = null;
85+
this.observedKey = null;
86+
}
87+
}
88+
});
89+
2590
const buildStream = function buildStream(params) {
2691
const [objRef, pathRef] = params;
2792

2893
assert('The first argument to {{get}} must be a stream', isStream(objRef));
2994
assert('{{get}} requires at least two arguments', params.length > 1);
3095

31-
const stream = new DynamicKeyStream(objRef, pathRef);
96+
const stream = buildDynamicKeyStream(objRef, pathRef);
3297

3398
return stream;
3499
};
35100

101+
function buildDynamicKeyStream(source, keySource) {
102+
if (!isStream(keySource)) {
103+
return new KeyStream(source, keySource);
104+
} else {
105+
return new DynamicKeyStream(source, keySource);
106+
}
107+
}
36108

37109
/**
38110
Dynamically look up a property on an object. The second argument to `{{get}}`
@@ -97,75 +169,4 @@ var getKeyword = function getKeyword(morph, env, scope, params, hash, template,
97169
return true;
98170
};
99171

100-
var DynamicKeyStream = function DynamicKeyStream(source, keySource) {
101-
if (!isStream(keySource)) {
102-
return new KeyStream(source, keySource);
103-
}
104-
assert('DynamicKeyStream error: source must be a stream', isStream(source)); // TODO: This isn't necessary.
105-
106-
// used to get the original path for debugging and legacy purposes
107-
var label = labelFor(source, keySource);
108-
109-
this.init(label);
110-
this.path = label;
111-
this.sourceDep = this.addMutableDependency(source);
112-
this.keyDep = this.addMutableDependency(keySource);
113-
this.observedObject = null;
114-
this.observedKey = null;
115-
};
116-
117-
DynamicKeyStream.prototype = Object.create(KeyStream.prototype);
118-
119-
merge(DynamicKeyStream.prototype, {
120-
key() {
121-
const key = this.keyDep.getValue();
122-
if (typeof key === 'string') {
123-
assert('DynamicKeyStream error: key must not have a \'.\'', key.indexOf('.') === -1);
124-
return key;
125-
}
126-
},
127-
128-
compute() {
129-
var object = this.sourceDep.getValue();
130-
var key = this.key();
131-
if (object && key) {
132-
return get(object, key);
133-
}
134-
},
135-
136-
setValue(value) {
137-
var object = this.sourceDep.getValue();
138-
var key = this.key();
139-
if (object) {
140-
set(object, key, value);
141-
}
142-
},
143-
144-
_super$revalidate: Stream.prototype.revalidate,
145-
146-
revalidate(value) {
147-
this._super$revalidate(value);
148-
149-
var object = this.sourceDep.getValue();
150-
var key = this.key();
151-
if (object !== this.observedObject || key !== this.observedKey) {
152-
this._clearObservedObject();
153-
154-
if (object && typeof object === 'object' && key) {
155-
addObserver(object, key, this, this.notify);
156-
this.observedObject = object;
157-
this.observedKey = key;
158-
}
159-
}
160-
},
161-
162-
_clearObservedObject() {
163-
if (this.observedObject) {
164-
removeObserver(this.observedObject, this.observedKey, this, this.notify);
165-
this.observedObject = null;
166-
this.observedKey = null;
167-
}
168-
}
169-
});
170-
171172
export default getKeyword;

0 commit comments

Comments
 (0)