Merge pull request #1348 from tschaub/beforechange

Add `ol.ObjectEvent` for changes to `ol.Object` properties.  Previously, `ol.Object` dispatched instances of `goog.events.Event` with type `change`.  Now `ol.ObjectEvent` instances will be dispatched on property changes.  The events include a `getKey` method to get the name of the property being changed.  The `beforepropertychange` type event is fired before a property value changes, and the `propertychange` type event fires after the property value changes.
This commit is contained in:
Tim Schaub
2013-12-13 07:28:36 -08:00
9 changed files with 334 additions and 34 deletions

View File

@@ -10,6 +10,7 @@ goog.require('ol.Collection');
goog.require('ol.CollectionEvent');
goog.require('ol.CollectionEventType');
goog.require('ol.Object');
goog.require('ol.ObjectEventType');
goog.require('ol.layer.Base');
goog.require('ol.source.State');
@@ -104,7 +105,8 @@ ol.layer.Group.prototype.handleLayersChanged_ = function(event) {
for (i = 0, ii = layersArray.length; i < ii; i++) {
layer = layersArray[i];
this.listenerKeys_[goog.getUid(layer).toString()] =
goog.events.listen(layer, goog.events.EventType.CHANGE,
goog.events.listen(layer,
[ol.ObjectEventType.PROPERTYCHANGE, goog.events.EventType.CHANGE],
this.handleLayerChange_, false, this);
}
}
@@ -120,8 +122,8 @@ ol.layer.Group.prototype.handleLayersChanged_ = function(event) {
ol.layer.Group.prototype.handleLayersAdd_ = function(collectionEvent) {
var layer = /** @type {ol.layer.Base} */ (collectionEvent.getElement());
this.listenerKeys_[goog.getUid(layer).toString()] = goog.events.listen(
layer, goog.events.EventType.CHANGE, this.handleLayerChange_, false,
this);
layer, [ol.ObjectEventType.PROPERTYCHANGE, goog.events.EventType.CHANGE],
this.handleLayerChange_, false, this);
this.dispatchChangeEvent();
};

View File

@@ -39,6 +39,7 @@ goog.require('ol.MapBrowserEventHandler');
goog.require('ol.MapEvent');
goog.require('ol.MapEventType');
goog.require('ol.Object');
goog.require('ol.ObjectEvent');
goog.require('ol.ObjectEventType');
goog.require('ol.Pixel');
goog.require('ol.PostRenderFunction');
@@ -208,9 +209,9 @@ ol.Map = function(options) {
/**
* @private
* @type {goog.events.Key}
* @type {Array.<goog.events.Key>}
*/
this.layerGroupPropertyListenerKey_ = null;
this.layerGroupPropertyListenerKeys_ = null;
/**
* @private
@@ -888,7 +889,7 @@ ol.Map.prototype.handleViewChanged_ = function() {
var view = this.getView();
if (goog.isDefAndNotNull(view)) {
this.viewPropertyListenerKey_ = goog.events.listen(
view, ol.ObjectEventType.CHANGE,
view, ol.ObjectEventType.PROPERTYCHANGE,
this.handleViewPropertyChanged_, false, this);
}
this.render();
@@ -899,7 +900,18 @@ ol.Map.prototype.handleViewChanged_ = function() {
* @param {goog.events.Event} event Event.
* @private
*/
ol.Map.prototype.handleLayerGroupMemberChanged_ = function(event) {
goog.asserts.assertInstanceof(event, goog.events.Event);
this.render();
};
/**
* @param {ol.ObjectEvent} event Event.
* @private
*/
ol.Map.prototype.handleLayerGroupPropertyChanged_ = function(event) {
goog.asserts.assertInstanceof(event, ol.ObjectEvent);
this.render();
};
@@ -908,15 +920,23 @@ ol.Map.prototype.handleLayerGroupPropertyChanged_ = function(event) {
* @private
*/
ol.Map.prototype.handleLayerGroupChanged_ = function() {
if (!goog.isNull(this.layerGroupPropertyListenerKey_)) {
goog.events.unlistenByKey(this.layerGroupPropertyListenerKey_);
this.layerGroupPropertyListenerKey_ = null;
if (!goog.isNull(this.layerGroupPropertyListenerKeys_)) {
var length = this.layerGroupPropertyListenerKeys_.length;
for (var i = 0; i < length; ++i) {
goog.events.unlistenByKey(this.layerGroupPropertyListenerKeys_[i]);
}
this.layerGroupPropertyListenerKeys_ = null;
}
var layerGroup = this.getLayerGroup();
if (goog.isDefAndNotNull(layerGroup)) {
this.layerGroupPropertyListenerKey_ = goog.events.listen(
layerGroup, ol.ObjectEventType.CHANGE,
this.handleLayerGroupPropertyChanged_, false, this);
this.layerGroupPropertyListenerKeys_ = [
goog.events.listen(
layerGroup, ol.ObjectEventType.PROPERTYCHANGE,
this.handleLayerGroupPropertyChanged_, false, this),
goog.events.listen(
layerGroup, goog.events.EventType.CHANGE,
this.handleLayerGroupMemberChanged_, false, this)
];
}
this.render();
};

View File

@@ -7,3 +7,6 @@
@exportProperty ol.Object.prototype.setValues
@exportProperty ol.Object.prototype.unbind
@exportProperty ol.Object.prototype.unbindAll
@exportSymbol ol.ObjectEvent
@exportProperty ol.ObjectEvent.prototype.getKey

View File

@@ -6,10 +6,12 @@
*/
goog.provide('ol.Object');
goog.provide('ol.ObjectEvent');
goog.provide('ol.ObjectEventType');
goog.require('goog.array');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.functions');
goog.require('goog.object');
goog.require('ol.Observable');
@@ -19,7 +21,40 @@ goog.require('ol.Observable');
* @enum {string}
*/
ol.ObjectEventType = {
CHANGE: 'change'
BEFOREPROPERTYCHANGE: 'beforepropertychange',
PROPERTYCHANGE: 'propertychange'
};
/**
* Object representing a property change event.
*
* @param {string} type The event type.
* @param {string} key The property name.
* @extends {goog.events.Event}
* @constructor
*/
ol.ObjectEvent = function(type, key) {
goog.base(this, type);
/**
* The name of the property whose value is changing.
* @type {string}
* @private
*/
this.key_ = key;
};
goog.inherits(ol.ObjectEvent, goog.events.Event);
/**
* Get the name of the property associated with this event.
* @return {string} Object property name.
*/
ol.ObjectEvent.prototype.getKey = function() {
return this.key_;
};
@@ -94,6 +129,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);
}
@@ -216,11 +258,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.BEFOREPROPERTYCHANGE,
this.createBeforeChangeListener_(key, targetKey),
undefined, this);
var accessor = new ol.ObjectAccessor(target, targetKey);
var accessors = ol.Object.getAccessors(this);
accessors[key] = accessor;
@@ -229,6 +280,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.getKey() === targetKey) {
this.dispatchEvent(
new ol.ObjectEvent(ol.ObjectEventType.BEFOREPROPERTYCHANGE, key));
}
};
};
/**
* Gets a value.
* @param {string} key Key name.
@@ -331,7 +406,8 @@ ol.Object.prototype.notify = function(key) {
ol.Object.prototype.notifyInternal_ = function(key) {
var eventType = ol.Object.getChangeEventType(key);
this.dispatchEvent(eventType);
this.dispatchEvent(ol.ObjectEventType.CHANGE);
this.dispatchEvent(
new ol.ObjectEvent(ol.ObjectEventType.PROPERTYCHANGE, key));
};
@@ -342,6 +418,8 @@ ol.Object.prototype.notifyInternal_ = function(key) {
* @todo stability experimental
*/
ol.Object.prototype.set = function(key, value) {
this.dispatchEvent(
new ol.ObjectEvent(ol.ObjectEventType.BEFOREPROPERTYCHANGE, key));
var accessors = ol.Object.getAccessors(this);
if (accessors.hasOwnProperty(key)) {
var accessor = accessors[key];
@@ -397,6 +475,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];
}
};