Permalink
Browse files

ObjectController

  • Loading branch information...
krisselden committed May 22, 2012
1 parent 7905b3f commit 10f7ab46a7cc553d4e120693b2b26acd8be73fa5
@@ -215,6 +215,10 @@ Ember.addBeforeObserver = function(obj, path, target, method) {
// This should only be used by the target of the observer
// while it is setting the observed path.
/** @private */
Ember._suspendBeforeObserver = function(obj, path, target, method, callback) {
return Ember._suspendListener(obj, beforeEvent(path), target, method, callback);
};
Ember._suspendObserver = function(obj, path, target, method, callback) {
return Ember._suspendListener(obj, changeEvent(path), target, method, callback);
};
@@ -437,6 +437,10 @@ Ember.watch = function(obj, keyName) {
if (!watching[keyName]) {
watching[keyName] = 1;
if (isKeyName(keyName)) {
if ('function' === typeof obj.willWatchProperty) {
obj.willWatchProperty(keyName);
}
desc = m.descs[keyName];
desc = desc ? desc.watched : WATCHED_PROPERTY;
if (desc) Ember.defineProperty(obj, keyName, desc);
@@ -463,12 +467,17 @@ Ember.unwatch = function(obj, keyName) {
var watching = meta(obj).watching, desc, descs;
keyName = normalizePath(keyName);
if (watching[keyName] === 1) {
watching[keyName] = 0;
if (isKeyName(keyName)) {
desc = meta(obj).descs[keyName];
desc = desc ? desc.unwatched : SIMPLE_PROPERTY;
if (desc) Ember.defineProperty(obj, keyName, desc);
if ('function' === typeof obj.didUnwatchProperty) {
obj.didUnwatchProperty(keyName);
}
} else {
chainsFor(obj).remove(keyName);
}
@@ -0,0 +1,3 @@
require('ember-runtime/system/object_proxy');
Ember.ObjectController = Ember.ObjectProxy.extend();
@@ -6,6 +6,7 @@
require('ember-runtime/system/application');
require('ember-runtime/system/array_proxy');
require('ember-runtime/system/object_proxy');
require('ember-runtime/system/core_object');
require('ember-runtime/system/each_proxy');
@@ -0,0 +1,111 @@
require('ember-runtime/system/object');
var get = Ember.get,
set = Ember.set,
defineProperty = Ember.defineProperty,
addBeforeObserver = Ember.addBeforeObserver,
addObserver = Ember.addObserver,
removeBeforeObserver = Ember.removeBeforeObserver,
removeObserver = Ember.removeObserver,
suspendBeforeObserver = Ember._suspendBeforeObserver,
suspendObserver = Ember._suspendObserver,
propertyWillChange = Ember.propertyWillChange,
propertyDidChange = Ember.propertyDidChange,
getMeta = Ember.getMeta,
delegateDesc;
function addDelegateObservers(proxy, key) {
var delegateKey = 'content.' + key,
willChangeKey = key + 'WillChange',
didChangeKey = key + 'DidChange';
proxy[willChangeKey] = function () {
propertyWillChange(this, key);
};
proxy[didChangeKey] = function () {
propertyDidChange(this, key);
};
// have to use target=null method=string so if
// willWatchProperty is call with prototype it will still work
addBeforeObserver(proxy, delegateKey, null, willChangeKey);
addObserver(proxy, delegateKey, null, didChangeKey);
}
function removeDelegateObservers(proxy, key) {
var delegateKey = 'content.' + key,
willChangeKey = key + 'WillChange',
didChangeKey = key + 'DidChange';
removeBeforeObserver(proxy, delegateKey, null, willChangeKey);
removeObserver(proxy, delegateKey, null, didChangeKey);
delete proxy[willChangeKey];
delete proxy[didChangeKey];
}
function suspendDelegateObservers(proxy, key, fn) {
var delegateKey = 'content.' + key,
willChangeKey = key + 'WillChange',
didChangeKey = key + 'DidChange';
suspendBeforeObserver(proxy, delegateKey, null, willChangeKey, function () {
suspendObserver(proxy, delegateKey, null, didChangeKey, function () {
fn.call(proxy);
});
});
}
function isDelegateDesc(proxy, key) {
var descs = getMeta(proxy, 'descs');
return descs[key] === delegateDesc;
}
function undefineProperty(proxy, key) {
var descs = getMeta(proxy, 'descs');
descs[key].teardown(proxy, key);
delete descs[key];
delete proxy[key];
}
function delegate(key, value) {
if (arguments.length === 1) {
return this.delegateGet(key);
} else {
// CP set notifies, so if we don't suspend
// will be notified again
suspendDelegateObservers(this, key, function () {
this.delegateSet(key, value);
});
}
}
delegateDesc = Ember.computed(delegate).volatile();
Ember.ObjectProxy = Ember.Object.extend({
content: null,
delegateGet: function (key) {
var content = get(this, 'content');
if (content) {
return get(content, key);
}
},
delegateSet: function (key, value) {
var content = get(this, 'content');
if (content) {
return set(content, key, value);
}
},
willWatchProperty: function (key) {
if (key in this) return;
defineProperty(this, key, delegateDesc);
addDelegateObservers(this, key);
},
didUnwatchProperty: function (key) {
if (isDelegateDesc(this, key)) {
removeDelegateObservers(this, key);
undefineProperty(this, key);
}
},
unknownProperty: function (key) {
return this.delegateGet(key);
},
setUnknownProperty: function (key, value) {
this.delegateSet(key, value);
}
});
@@ -0,0 +1,155 @@
module("Ember.ObjectProxy");
testBoth("should proxy properties to content", function(get, set) {
var content = {firstName: 'Tom', lastName: 'Dale'},
proxy = Ember.ObjectProxy.create();
equal(get(proxy, 'firstName'), undefined);
set(proxy, 'firstName', 'Foo');
equal(get(proxy, 'firstName'), undefined);
set(proxy, 'content', content);
equal(get(proxy, 'firstName'), 'Tom');
equal(get(proxy, 'lastName'), 'Dale');
equal(get(proxy, 'foo'), undefined);
set(proxy, 'lastName', 'Huda');
equal(get(content, 'lastName'), 'Huda');
equal(get(proxy, 'lastName'), 'Huda');
set(proxy, 'content', {firstName: 'Yehuda', lastName: 'Katz'});
equal(get(proxy, 'firstName'), 'Yehuda');
equal(get(proxy, 'lastName'), 'Katz');
});
testBoth("should work with watched properties", function(get, set) {
var content1 = {firstName: 'Tom', lastName: 'Dale'},
content2 = {firstName: 'Yehuda', lastName: 'Katz'},
Proxy,
proxy,
count = 0,
last;
Proxy = Ember.ObjectProxy.extend({
fullName: Ember.computed(function () {
var firstName = this.get('firstName'),
lastName = this.get('lastName');
if (firstName && lastName) {
return firstName + ' ' + lastName;
}
return firstName || lastName;
}).property('firstName', 'lastName')
});
proxy = Proxy.create();
Ember.addObserver(proxy, 'fullName', function () {
last = get(proxy, 'fullName');
count++;
});
// proxy without content returns undefined
equal(get(proxy, 'fullName'), undefined);
// setting content causes all watched properties to change
set(proxy, 'content', content1);
// both dependent keys changed
equal(count, 2);
equal(last, 'Tom Dale');
// setting property in content causes proxy property to change
set(content1, 'lastName', 'Huda');
equal(count, 3);
equal(last, 'Tom Huda');
// replacing content causes all watched properties to change
set(proxy, 'content', content2);
// both dependent keys changed
equal(count, 5);
equal(last, 'Yehuda Katz');
// content1 is no longer watched
ok(!Ember.isWatching(content1, 'firstName'), 'not watching firstName');
ok(!Ember.isWatching(content1, 'lastName'), 'not watching lastName');
// setting property in new content
set(content2, 'firstName', 'Tomhuda');
equal(last, 'Tomhuda Katz');
equal(count, 6);
// setting property in proxy syncs with new content
set(proxy, 'lastName', 'Katzdale');
equal(count, 7);
equal(last, 'Tomhuda Katzdale');
equal(get(content2, 'firstName'), 'Tomhuda');
equal(get(content2, 'lastName'), 'Katzdale');
});
test("setPath and getPath should work", function () {
var content = {foo: {bar: 'baz'}},
proxy = Ember.ObjectProxy.create({content: content}),
count = 0;
proxy.setPath('foo.bar', 'hello');
equal(proxy.getPath('foo.bar'), 'hello');
equal(proxy.getPath('content.foo.bar'), 'hello');
proxy.addObserver('foo.bar', function () {
count++;
});
proxy.setPath('foo.bar', 'bye');
equal(count, 1);
equal(proxy.getPath('foo.bar'), 'bye');
equal(proxy.getPath('content.foo.bar'), 'bye');
});
testBoth("should transition between watched and unwatched strategies", function(get, set) {
var content = {foo: 'foo'},
proxy = Ember.ObjectProxy.create({content: content}),
count = 0;
function observer() {
count++;
}
equal(get(proxy, 'foo'), 'foo');
set(content, 'foo', 'bar');
equal(get(proxy, 'foo'), 'bar');
set(proxy, 'foo', 'foo');
equal(get(content, 'foo'), 'foo');
equal(get(proxy, 'foo'), 'foo');
Ember.addObserver(proxy, 'foo', observer);
equal(count, 0);
equal(get(proxy, 'foo'), 'foo');
set(content, 'foo', 'bar');
equal(count, 1);
equal(get(proxy, 'foo'), 'bar');
set(proxy, 'foo', 'foo');
equal(count, 2);
equal(get(content, 'foo'), 'foo');
equal(get(proxy, 'foo'), 'foo');
Ember.removeObserver(proxy, 'foo', observer);
set(content, 'foo', 'bar');
equal(get(proxy, 'foo'), 'bar');
set(proxy, 'foo', 'foo');
equal(get(content, 'foo'), 'foo');
equal(get(proxy, 'foo'), 'foo');
});

0 comments on commit 10f7ab4

Please sign in to comment.