Add old value to property change events
This commit is contained in:
@@ -55,10 +55,18 @@ oli.DrawEvent.prototype.feature;
|
|||||||
oli.ObjectEvent = function() {};
|
oli.ObjectEvent = function() {};
|
||||||
|
|
||||||
|
|
||||||
/** @type {string} */
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
oli.ObjectEvent.prototype.key;
|
oli.ObjectEvent.prototype.key;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {*}
|
||||||
|
*/
|
||||||
|
oli.ObjectEvent.prototype.oldValue;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @interface
|
* @interface
|
||||||
|
|||||||
105
src/ol/object.js
105
src/ol/object.js
@@ -1,3 +1,6 @@
|
|||||||
|
// FIXME propertychange events include the oldValue so remove the
|
||||||
|
// beforepropertychange event type.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of Google Maps' MVCObject.
|
* An implementation of Google Maps' MVCObject.
|
||||||
* @see https://developers.google.com/maps/articles/mvcfun
|
* @see https://developers.google.com/maps/articles/mvcfun
|
||||||
@@ -41,11 +44,12 @@ ol.ObjectEventType = {
|
|||||||
*
|
*
|
||||||
* @param {string} type The event type.
|
* @param {string} type The event type.
|
||||||
* @param {string} key The property name.
|
* @param {string} key The property name.
|
||||||
|
* @param {*} oldValue The old value for `key`.
|
||||||
* @extends {goog.events.Event}
|
* @extends {goog.events.Event}
|
||||||
* @implements {oli.ObjectEvent}
|
* @implements {oli.ObjectEvent}
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
ol.ObjectEvent = function(type, key) {
|
ol.ObjectEvent = function(type, key, oldValue) {
|
||||||
goog.base(this, type);
|
goog.base(this, type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,6 +59,14 @@ ol.ObjectEvent = function(type, key) {
|
|||||||
*/
|
*/
|
||||||
this.key = key;
|
this.key = key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The old value. To get the new value use `e.target.get(e.key)` where
|
||||||
|
* `e` is the event object.
|
||||||
|
* @type {*}
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
this.oldValue = oldValue;
|
||||||
|
|
||||||
};
|
};
|
||||||
goog.inherits(ol.ObjectEvent, goog.events.Event);
|
goog.inherits(ol.ObjectEvent, goog.events.Event);
|
||||||
|
|
||||||
@@ -109,9 +121,10 @@ ol.ObjectAccessor = function(source, target, sourceKey, targetKey) {
|
|||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
ol.ObjectAccessor.prototype.transform = function(from, to) {
|
ol.ObjectAccessor.prototype.transform = function(from, to) {
|
||||||
|
var oldValue = ol.Object.getKeyValue_(this.source, this.sourceKey);
|
||||||
this.from = from;
|
this.from = from;
|
||||||
this.to = to;
|
this.to = to;
|
||||||
this.source.notify(this.sourceKey);
|
this.source.notify(this.sourceKey, oldValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -268,6 +281,42 @@ ol.Object.getSetterName = function(key) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value for an object and a key. Use the getter (`getX`) if it exists,
|
||||||
|
* otherwise use the generic `get` function.
|
||||||
|
* @param {ol.Object} obj Object.
|
||||||
|
* @param {string} key Key;
|
||||||
|
* @return {*} Value;
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ol.Object.getKeyValue_ = function(obj, key) {
|
||||||
|
var getterName = ol.Object.getGetterName(key);
|
||||||
|
var getter = /** @type {function(): *|undefined} */
|
||||||
|
(goog.object.get(obj, getterName));
|
||||||
|
return goog.isDef(getter) ? getter.call(obj) : obj.get(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value for an object and a key. Use the setter (`setX`) if it exists,
|
||||||
|
* otherwise use the generic `set` function.
|
||||||
|
* @param {ol.Object} obj Object.
|
||||||
|
* @param {string} key Key.
|
||||||
|
* @param {*} value Value.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ol.Object.setKeyValue_ = function(obj, key, value) {
|
||||||
|
var setterName = ol.Object.getSetterName(key);
|
||||||
|
var setter = /** @type {function(*)|undefined} */
|
||||||
|
(goog.object.get(obj, setterName));
|
||||||
|
if (goog.isDef(setter)) {
|
||||||
|
setter.call(obj, value);
|
||||||
|
} else {
|
||||||
|
obj.set(key, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The bindTo method allows you to set up a two-way binding between a
|
* The bindTo method allows you to set up a two-way binding between a
|
||||||
* `source` and `target` object. The method returns an object with a
|
* `source` and `target` object. The method returns an object with a
|
||||||
@@ -306,10 +355,11 @@ ol.Object.prototype.bindTo = function(key, target, opt_targetKey) {
|
|||||||
var eventType = ol.Object.getChangeEventType(targetKey);
|
var eventType = ol.Object.getChangeEventType(targetKey);
|
||||||
this.listeners_[key] = goog.events.listen(target, eventType,
|
this.listeners_[key] = goog.events.listen(target, eventType,
|
||||||
/**
|
/**
|
||||||
|
* @param {ol.ObjectEvent} e Event.
|
||||||
* @this {ol.Object}
|
* @this {ol.Object}
|
||||||
*/
|
*/
|
||||||
function() {
|
function(e) {
|
||||||
this.notify(key);
|
this.notify(key, e.oldValue);
|
||||||
}, undefined, this);
|
}, undefined, this);
|
||||||
|
|
||||||
// listen for beforechange events and relay if key matches
|
// listen for beforechange events and relay if key matches
|
||||||
@@ -320,7 +370,7 @@ ol.Object.prototype.bindTo = function(key, target, opt_targetKey) {
|
|||||||
|
|
||||||
var accessor = new ol.ObjectAccessor(this, target, key, targetKey);
|
var accessor = new ol.ObjectAccessor(this, target, key, targetKey);
|
||||||
this.accessors_[key] = accessor;
|
this.accessors_[key] = accessor;
|
||||||
this.notify(key);
|
this.notify(key, this.values_[key]);
|
||||||
return accessor;
|
return accessor;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -342,8 +392,8 @@ ol.Object.prototype.createBeforeChangeListener_ = function(key, targetKey) {
|
|||||||
*/
|
*/
|
||||||
return function(event) {
|
return function(event) {
|
||||||
if (event.key === targetKey) {
|
if (event.key === targetKey) {
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(new ol.ObjectEvent(
|
||||||
new ol.ObjectEvent(ol.ObjectEventType.BEFOREPROPERTYCHANGE, key));
|
ol.ObjectEventType.BEFOREPROPERTYCHANGE, key, undefined));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -360,16 +410,7 @@ ol.Object.prototype.get = function(key) {
|
|||||||
var accessors = this.accessors_;
|
var accessors = this.accessors_;
|
||||||
if (accessors.hasOwnProperty(key)) {
|
if (accessors.hasOwnProperty(key)) {
|
||||||
var accessor = accessors[key];
|
var accessor = accessors[key];
|
||||||
var target = accessor.target;
|
value = ol.Object.getKeyValue_(accessor.target, accessor.targetKey);
|
||||||
var targetKey = accessor.targetKey;
|
|
||||||
var getterName = ol.Object.getGetterName(targetKey);
|
|
||||||
var getter = /** @type {function(): *|undefined} */
|
|
||||||
(goog.object.get(target, getterName));
|
|
||||||
if (goog.isDef(getter)) {
|
|
||||||
value = getter.call(target);
|
|
||||||
} else {
|
|
||||||
value = target.get(targetKey);
|
|
||||||
}
|
|
||||||
value = accessor.to(value);
|
value = accessor.to(value);
|
||||||
} else if (this.values_.hasOwnProperty(key)) {
|
} else if (this.values_.hasOwnProperty(key)) {
|
||||||
value = this.values_[key];
|
value = this.values_[key];
|
||||||
@@ -430,12 +471,14 @@ ol.Object.prototype.getProperties = function() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} key Key name.
|
* @param {string} key Key name.
|
||||||
|
* @param {*} oldValue Old value.
|
||||||
*/
|
*/
|
||||||
ol.Object.prototype.notify = function(key) {
|
ol.Object.prototype.notify = function(key, oldValue) {
|
||||||
var eventType = ol.Object.getChangeEventType(key);
|
var eventType;
|
||||||
this.dispatchEvent(eventType);
|
eventType = ol.Object.getChangeEventType(key);
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(new ol.ObjectEvent(eventType, key, oldValue));
|
||||||
new ol.ObjectEvent(ol.ObjectEventType.PROPERTYCHANGE, key));
|
eventType = ol.ObjectEventType.PROPERTYCHANGE;
|
||||||
|
this.dispatchEvent(new ol.ObjectEvent(eventType, key, oldValue));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -446,25 +489,17 @@ ol.Object.prototype.notify = function(key) {
|
|||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
ol.Object.prototype.set = function(key, value) {
|
ol.Object.prototype.set = function(key, value) {
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(new ol.ObjectEvent(
|
||||||
new ol.ObjectEvent(ol.ObjectEventType.BEFOREPROPERTYCHANGE, key));
|
ol.ObjectEventType.BEFOREPROPERTYCHANGE, key, undefined));
|
||||||
var accessors = this.accessors_;
|
var accessors = this.accessors_;
|
||||||
if (accessors.hasOwnProperty(key)) {
|
if (accessors.hasOwnProperty(key)) {
|
||||||
var accessor = accessors[key];
|
var accessor = accessors[key];
|
||||||
var target = accessor.target;
|
|
||||||
var targetKey = accessor.targetKey;
|
|
||||||
value = accessor.from(value);
|
value = accessor.from(value);
|
||||||
var setterName = ol.Object.getSetterName(targetKey);
|
ol.Object.setKeyValue_(accessor.target, accessor.targetKey, value);
|
||||||
var setter = /** @type {function(*)|undefined} */
|
|
||||||
(goog.object.get(target, setterName));
|
|
||||||
if (goog.isDef(setter)) {
|
|
||||||
setter.call(target, value);
|
|
||||||
} else {
|
|
||||||
target.set(targetKey, value);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
var oldValue = this.values_[key];
|
||||||
this.values_[key] = value;
|
this.values_[key] = value;
|
||||||
this.notify(key);
|
this.notify(key, oldValue);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -115,22 +115,33 @@ describe('ol.Object', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('dispatches events', function() {
|
it('dispatches events', function() {
|
||||||
o.notify('k');
|
o.notify('k', 1);
|
||||||
expect(listener1).to.be.called();
|
expect(listener1.calledOnce).to.be(true);
|
||||||
|
var args = listener1.firstCall.args;
|
||||||
|
expect(args).to.have.length(1);
|
||||||
|
var event = args[0];
|
||||||
|
expect(event.key).to.be('k');
|
||||||
|
expect(event.oldValue).to.be(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('dispatches generic change events to bound objects', function() {
|
it('dispatches generic change events to bound objects', function() {
|
||||||
o.notify('k');
|
o.notify('k', 1);
|
||||||
expect(listener2.calledOnce).to.be(true);
|
expect(listener2.calledOnce).to.be(true);
|
||||||
var args = listener2.firstCall.args;
|
var args = listener2.firstCall.args;
|
||||||
expect(args).to.have.length(1);
|
expect(args).to.have.length(1);
|
||||||
var event = args[0];
|
var event = args[0];
|
||||||
expect(event.key).to.be('k');
|
expect(event.key).to.be('k');
|
||||||
|
expect(event.oldValue).to.be(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('dispatches events to bound objects', function() {
|
it('dispatches events to bound objects', function() {
|
||||||
o.notify('k');
|
o.notify('k', 1);
|
||||||
expect(listener3).to.be.called();
|
expect(listener3.calledOnce).to.be(true);
|
||||||
|
var args = listener3.firstCall.args;
|
||||||
|
expect(args).to.have.length(1);
|
||||||
|
var event = args[0];
|
||||||
|
expect(event.key).to.be('k');
|
||||||
|
expect(event.oldValue).to.be(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -283,8 +294,12 @@ describe('ol.Object', function() {
|
|||||||
|
|
||||||
describe('bindTo after set', function() {
|
describe('bindTo after set', function() {
|
||||||
|
|
||||||
it('gets expected value', function() {
|
beforeEach(function() {
|
||||||
o.set('k', 1);
|
o.set('k', 1);
|
||||||
|
o2.set('k', 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('gets expected value', function() {
|
||||||
o2.bindTo('k', o);
|
o2.bindTo('k', o);
|
||||||
expect(o.get('k')).to.eql(1);
|
expect(o.get('k')).to.eql(1);
|
||||||
expect(o2.get('k')).to.eql(1);
|
expect(o2.get('k')).to.eql(1);
|
||||||
@@ -292,6 +307,31 @@ describe('ol.Object', function() {
|
|||||||
expect(o.getKeys()).to.eql(['k']);
|
expect(o.getKeys()).to.eql(['k']);
|
||||||
expect(o2.getKeys()).to.eql(['k']);
|
expect(o2.getKeys()).to.eql(['k']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('dispatches a change: event', function() {
|
||||||
|
var listener = sinon.spy();
|
||||||
|
o2.on('change:k', listener);
|
||||||
|
o2.bindTo('k', o);
|
||||||
|
expect(listener.calledOnce).to.be(true);
|
||||||
|
var call = listener.firstCall;
|
||||||
|
expect(call.args).to.have.length(1);
|
||||||
|
expect(call.args[0].key).to.be('k');
|
||||||
|
expect(call.args[0].oldValue).to.be(0);
|
||||||
|
expect(o2.get('k')).to.be(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('dispatches a propertychange event', function() {
|
||||||
|
var listener = sinon.spy();
|
||||||
|
o2.on('propertychange', listener);
|
||||||
|
o2.bindTo('k', o);
|
||||||
|
expect(listener.calledOnce).to.be(true);
|
||||||
|
var call = listener.firstCall;
|
||||||
|
expect(call.args).to.have.length(1);
|
||||||
|
expect(call.args[0].key).to.be('k');
|
||||||
|
expect(call.args[0].oldValue).to.be(0);
|
||||||
|
expect(o2.get('k')).to.be(1);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('bindTo before set', function() {
|
describe('bindTo before set', function() {
|
||||||
@@ -643,8 +683,17 @@ describe('ol.Object', function() {
|
|||||||
}, function(v) {
|
}, function(v) {
|
||||||
return v / 2;
|
return v / 2;
|
||||||
});
|
});
|
||||||
expect(sourceSpy.callCount).to.be(2);
|
var call, args;
|
||||||
expect(targetSpy.callCount).to.be(0);
|
expect(sourceSpy.calledTwice).to.be(true);
|
||||||
|
call = sourceSpy.firstCall;
|
||||||
|
expect(call.args).to.have.length(1);
|
||||||
|
expect(call.args[0].key).to.be('x');
|
||||||
|
expect(call.args[0].oldValue).to.be(1);
|
||||||
|
call = sourceSpy.secondCall;
|
||||||
|
expect(call.args).to.have.length(1);
|
||||||
|
expect(call.args[0].key).to.be('x');
|
||||||
|
expect(call.args[0].oldValue).to.be(2);
|
||||||
|
expect(targetSpy.called).to.be(false);
|
||||||
expect(source.get('x')).to.be(1);
|
expect(source.get('x')).to.be(1);
|
||||||
expect(target.get('x')).to.be(2);
|
expect(target.get('x')).to.be(2);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user