Handle beforechange events for bound properties

This commit is contained in:
Tim Schaub
2013-12-09 12:14:07 -07:00
parent 9d3a4e3c6c
commit 153cb307e0
2 changed files with 149 additions and 1 deletions

View File

@@ -118,6 +118,13 @@ ol.Object = function(opt_values) {
*/
this.values_ = {};
/**
* Lookup of beforechange listener keys.
* @type {Object.<string, goog.events.Key>}
* @private
*/
this.beforeChangeListeners_ = {};
if (goog.isDef(opt_values)) {
this.setValues(opt_values);
}
@@ -240,11 +247,20 @@ ol.Object.getSetterName = function(key) {
ol.Object.prototype.bindTo = function(key, target, opt_targetKey) {
var targetKey = opt_targetKey || key;
this.unbind(key);
// listen for change:targetkey events
var eventType = ol.Object.getChangeEventType(targetKey);
var listeners = ol.Object.getListeners(this);
listeners[key] = goog.events.listen(target, eventType, function() {
this.notifyInternal_(key);
}, undefined, this);
// listen for beforechange events and relay if key matches
this.beforeChangeListeners_[key] = goog.events.listen(target,
ol.ObjectEventType.BEFORECHANGE,
this.createBeforeChangeListener_(key, targetKey),
undefined, this);
var accessor = new ol.ObjectAccessor(target, targetKey);
var accessors = ol.Object.getAccessors(this);
accessors[key] = accessor;
@@ -253,6 +269,30 @@ ol.Object.prototype.bindTo = function(key, target, opt_targetKey) {
};
/**
* Create a listener for beforechange events on a target object. This listener
* will relay events on this object if the event key matches the provided target
* key.
* @param {string} key The key on this object whose value will be changing.
* @param {string} targetKey The key on the target object.
* @return {function(this: ol.Object, ol.ObjectEvent)} Listener.
* @private
*/
ol.Object.prototype.createBeforeChangeListener_ = function(key, targetKey) {
/**
* Conditionally relay beforechange events if event key matches target key.
* @param {ol.ObjectEvent} event The beforechange event from the target.
* @this {ol.Object}
*/
return function(event) {
if (event.key === targetKey) {
this.dispatchEvent(
new ol.ObjectEvent(ol.ObjectEventType.BEFORECHANGE, key));
}
};
};
/**
* Gets a value.
* @param {string} key Key name.
@@ -422,6 +462,13 @@ ol.Object.prototype.unbind = function(key) {
delete accessors[key];
this.values_[key] = value;
}
// unregister any beforechange listener
var listenerKey = this.beforeChangeListeners_[key];
if (listenerKey) {
goog.events.unlistenByKey(listenerKey);
delete this.beforeChangeListeners_[key];
}
};

View File

@@ -215,7 +215,7 @@ describe('ol.Object', function() {
o2.set('k', 2);
expect(beforeListener.calledOnce).to.be(true);
var args = listener2.firstCall.args;
var args = beforeListener.firstCall.args;
expect(args).to.have.length(1);
var event = args[0];
expect(event.key).to.be('k');
@@ -223,6 +223,54 @@ describe('ol.Object', function() {
expect(oldValue).to.be(1);
});
it('relays beforechange events from bound objects', function() {
var target = new ol.Object({
foo: 'original value'
});
var object = new ol.Object();
object.bindTo('foo', target);
var oldValue;
var beforeListener = sinon.spy(function(event) {
oldValue = object.get(event.key);
});
object.on('beforechange', beforeListener);
target.set('foo', 'new value');
expect(beforeListener.calledOnce).to.be(true);
var args = beforeListener.firstCall.args;
expect(args).to.have.length(1);
var event = args[0];
expect(event.key).to.be('foo');
expect(oldValue).to.be('original value');
expect(object.get('foo')).to.be('new value');
});
it('relays beforechange events when bound with a new key', function() {
var target = new ol.Object({
foo: 'original value'
});
var object = new ol.Object();
object.bindTo('bar', target, 'foo');
var oldValue;
var beforeListener = sinon.spy(function(event) {
oldValue = object.get(event.key);
});
object.on('beforechange', beforeListener);
target.set('foo', 'new value');
expect(beforeListener.calledOnce).to.be(true);
var args = beforeListener.firstCall.args;
expect(args).to.have.length(1);
var event = args[0];
expect(event.key).to.be('bar');
expect(oldValue).to.be('original value');
expect(object.get('bar')).to.be('new value');
});
});
describe('bind', function() {
@@ -302,6 +350,59 @@ describe('ol.Object', function() {
expect(o.get('k')).to.eql(1);
expect(o2.get('k')).to.eql(2);
});
it('stops relaying beforechange events', function() {
var target = new ol.Object({
foo: 'original value'
});
var object = new ol.Object();
object.bindTo('foo', target);
var listener = sinon.spy();
object.on('beforechange', listener);
target.set('foo', 'new value');
expect(listener.calledOnce).to.be(true);
var call = listener.firstCall;
expect(call.args).to.have.length(1);
expect(call.args[0].key).to.be('foo');
object.unbind('foo');
target.set('foo', 'another new value');
expect(listener.calledOnce).to.be(true);
expect(object.get('foo')).to.be('new value');
});
it('selectively stops relaying beforechange events', function() {
var target = new ol.Object({
foo: 'original foo',
bar: 'original bar'
});
var object = new ol.Object();
object.bindTo('foo', target);
object.bindTo('bar', target);
var listener = sinon.spy();
object.on('beforechange', listener);
target.set('foo', 'new foo');
expect(listener.calledOnce).to.be(true);
target.set('bar', 'new bar');
expect(listener.callCount).to.be(2);
object.unbind('foo');
target.set('foo', 'another new foo');
expect(listener.callCount).to.be(2);
target.set('bar', 'another new bar');
expect(listener.callCount).to.be(3);
var lastCall = listener.getCall(2);
expect(lastCall.args).to.have.length(1);
expect(lastCall.args[0].key).to.be('bar');
});
});
describe('unbindAll', function() {