Map browser event handler refactoring
This commit refactors the code of the map browser event handler. The changes are the following: Previously the `handleTouch*_` listener functions handled both `touch*` and `mspointer*` events. With this commit we use per-event type listeners. This duplicates some code (could be avoidable), but makes it easier to introduce mouse/touch/pointer specific treatments in the future. We now listen to pointermove, pointerup, touchmove and touchend only when needed. In this way we're assured that a `down` event was received (and that `this.down_` is set) when the `up` or `move` listeners are called. This fixes the bug @oterral reported on the mailing list: https://groups.google.com/d/msg/ol3-dev/jR844F7Nlg8/eN9dt4uATK0J. To avoid problems in browsers that trigger different types of events (e.g. both mouse and pointer events) the `down` listeners unregister the other `down` listeners. For example, the `pointerdown` listener unregisters the `mousedown` and `touchstart` listeners, for ever.
This commit is contained in:
+124
-38
@@ -141,10 +141,16 @@ ol.MapBrowserEventHandler = function(map) {
|
|||||||
this.mousedownListenerKey_ = null;
|
this.mousedownListenerKey_ = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Array.<number>}
|
* @type {goog.events.Key}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this.touchListenerKeys_ = null;
|
this.pointerdownListenerKey_ = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {goog.events.Key}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this.touchstartListenerKey_ = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {goog.events.BrowserEvent}
|
* @type {goog.events.BrowserEvent}
|
||||||
@@ -158,21 +164,13 @@ ol.MapBrowserEventHandler = function(map) {
|
|||||||
goog.events.EventType.MOUSEDOWN,
|
goog.events.EventType.MOUSEDOWN,
|
||||||
this.handleMouseDown_, false, this);
|
this.handleMouseDown_, false, this);
|
||||||
|
|
||||||
// touch events
|
this.pointerdownListenerKey_ = goog.events.listen(element,
|
||||||
this.touchListenerKeys_ = [
|
goog.events.EventType.MSPOINTERDOWN,
|
||||||
goog.events.listen(element, [
|
this.handlePointerDown_, false, this);
|
||||||
|
|
||||||
|
this.touchstartListenerKey_ = goog.events.listen(element,
|
||||||
goog.events.EventType.TOUCHSTART,
|
goog.events.EventType.TOUCHSTART,
|
||||||
goog.events.EventType.MSPOINTERDOWN
|
this.handleTouchStart_, false, this);
|
||||||
], this.handleTouchStart_, false, this),
|
|
||||||
goog.events.listen(goog.global.document, [
|
|
||||||
goog.events.EventType.TOUCHMOVE,
|
|
||||||
goog.events.EventType.MSPOINTERMOVE
|
|
||||||
], this.handleTouchMove_, false, this),
|
|
||||||
goog.events.listen(goog.global.document, [
|
|
||||||
goog.events.EventType.TOUCHEND,
|
|
||||||
goog.events.EventType.MSPOINTERUP
|
|
||||||
], this.handleTouchEnd_, false, this)
|
|
||||||
];
|
|
||||||
|
|
||||||
};
|
};
|
||||||
goog.inherits(ol.MapBrowserEventHandler, goog.events.EventTarget);
|
goog.inherits(ol.MapBrowserEventHandler, goog.events.EventTarget);
|
||||||
@@ -227,6 +225,17 @@ ol.MapBrowserEventHandler.prototype.handleMouseUp_ = function(browserEvent) {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
ol.MapBrowserEventHandler.prototype.handleMouseDown_ = function(browserEvent) {
|
ol.MapBrowserEventHandler.prototype.handleMouseDown_ = function(browserEvent) {
|
||||||
|
if (!goog.isNull(this.pointerdownListenerKey_)) {
|
||||||
|
// mouse device detected - unregister the pointerdown and touchstart
|
||||||
|
// listeners
|
||||||
|
goog.events.unlistenByKey(this.pointerdownListenerKey_);
|
||||||
|
this.pointerdownListenerKey_ = null;
|
||||||
|
|
||||||
|
goog.asserts.assert(!goog.isNull(this.touchstartListenerKey_));
|
||||||
|
goog.events.unlistenByKey(this.touchstartListenerKey_);
|
||||||
|
this.touchstartListenerKey_ = null;
|
||||||
|
}
|
||||||
|
|
||||||
var newEvent = new ol.MapBrowserEvent(
|
var newEvent = new ol.MapBrowserEvent(
|
||||||
ol.MapBrowserEvent.EventType.DOWN, this.map_, browserEvent);
|
ol.MapBrowserEvent.EventType.DOWN, this.map_, browserEvent);
|
||||||
this.dispatchEvent(newEvent);
|
this.dispatchEvent(newEvent);
|
||||||
@@ -265,21 +274,49 @@ ol.MapBrowserEventHandler.prototype.handleMouseMove_ = function(browserEvent) {
|
|||||||
* @param {goog.events.BrowserEvent} browserEvent Browser event.
|
* @param {goog.events.BrowserEvent} browserEvent Browser event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
ol.MapBrowserEventHandler.prototype.handleTouchStart_ = function(browserEvent) {
|
ol.MapBrowserEventHandler.prototype.handlePointerDown_ =
|
||||||
|
function(browserEvent) {
|
||||||
if (!goog.isNull(this.mousedownListenerKey_)) {
|
if (!goog.isNull(this.mousedownListenerKey_)) {
|
||||||
|
// pointer device detected - unregister the mousedown and touchstart
|
||||||
|
// listeners
|
||||||
goog.events.unlistenByKey(this.mousedownListenerKey_);
|
goog.events.unlistenByKey(this.mousedownListenerKey_);
|
||||||
this.mousedownListenerKey_ = null;
|
this.mousedownListenerKey_ = null;
|
||||||
|
|
||||||
|
goog.asserts.assert(!goog.isNull(this.touchstartListenerKey_));
|
||||||
|
goog.events.unlistenByKey(this.touchstartListenerKey_);
|
||||||
|
this.touchstartListenerKey_ = null;
|
||||||
}
|
}
|
||||||
// prevent context menu
|
|
||||||
// When the IE pointer events are used, this prevents a
|
|
||||||
// 'mousedown' from being fired after this event for the primary
|
|
||||||
// contact (first finger on the screen or mouse)
|
|
||||||
browserEvent.preventDefault();
|
|
||||||
this.down_ = browserEvent;
|
|
||||||
this.dragged_ = false;
|
|
||||||
var newEvent = new ol.MapBrowserEvent(
|
var newEvent = new ol.MapBrowserEvent(
|
||||||
ol.MapBrowserEvent.EventType.TOUCHSTART, this.map_, browserEvent);
|
ol.MapBrowserEvent.EventType.TOUCHSTART, this.map_, browserEvent);
|
||||||
this.dispatchEvent(newEvent);
|
this.dispatchEvent(newEvent);
|
||||||
|
|
||||||
|
this.down_ = browserEvent;
|
||||||
|
this.dragged_ = false;
|
||||||
|
this.dragListenerKeys_ = [
|
||||||
|
goog.events.listen(goog.global.document,
|
||||||
|
goog.events.EventType.MSPOINTERMOVE,
|
||||||
|
this.handlePointerMove_, false, this),
|
||||||
|
goog.events.listen(goog.global.document, goog.events.EventType.MSPOINTERUP,
|
||||||
|
this.handlePointerUp_, false, this)
|
||||||
|
];
|
||||||
|
|
||||||
|
// FIXME check if/when this is necessary
|
||||||
|
// prevent context menu
|
||||||
|
browserEvent.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {goog.events.BrowserEvent} browserEvent Browser event.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ol.MapBrowserEventHandler.prototype.handlePointerMove_ =
|
||||||
|
function(browserEvent) {
|
||||||
|
this.dragged_ = true;
|
||||||
|
var newEvent = new ol.MapBrowserEvent(
|
||||||
|
ol.MapBrowserEvent.EventType.TOUCHMOVE, this.map_, browserEvent);
|
||||||
|
this.dispatchEvent(newEvent);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -287,20 +324,64 @@ ol.MapBrowserEventHandler.prototype.handleTouchStart_ = function(browserEvent) {
|
|||||||
* @param {goog.events.BrowserEvent} browserEvent Browser event.
|
* @param {goog.events.BrowserEvent} browserEvent Browser event.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
ol.MapBrowserEventHandler.prototype.handleTouchMove_ = function(browserEvent) {
|
ol.MapBrowserEventHandler.prototype.handlePointerUp_ = function(browserEvent) {
|
||||||
if (this.down_) {
|
var newEvent = new ol.MapBrowserEvent(
|
||||||
// 'touchmove' events are dispatched only when this.down_ is set
|
ol.MapBrowserEvent.EventType.TOUCHEND, this.map_, browserEvent);
|
||||||
// (set after a touch start) to prevent unwanted events when the
|
this.dispatchEvent(newEvent);
|
||||||
// mouse hover the page. This only happens with the IE pointer
|
goog.array.forEach(this.dragListenerKeys_, goog.events.unlistenByKey);
|
||||||
// event system.
|
if (!this.dragged_) {
|
||||||
this.dragged_ = true;
|
goog.asserts.assert(!goog.isNull(this.down_));
|
||||||
var newEvent = new ol.MapBrowserEvent(
|
this.emulateClick_(this.down_);
|
||||||
ol.MapBrowserEvent.EventType.TOUCHMOVE, this.map_, browserEvent);
|
|
||||||
this.dispatchEvent(newEvent);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {goog.events.BrowserEvent} browserEvent Browser event.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ol.MapBrowserEventHandler.prototype.handleTouchStart_ = function(browserEvent) {
|
||||||
|
if (!goog.isNull(this.mousedownListenerKey_)) {
|
||||||
|
// touch device detected - unregister the mousedown and pointerdown
|
||||||
|
// listeners
|
||||||
|
goog.events.unlistenByKey(this.mousedownListenerKey_);
|
||||||
|
this.mousedownListenerKey_ = null;
|
||||||
|
|
||||||
|
goog.asserts.assert(!goog.isNull(this.pointerdownListenerKey_));
|
||||||
|
goog.events.unlistenByKey(this.pointerdownListenerKey_);
|
||||||
|
this.pointerdownListenerKey_ = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newEvent = new ol.MapBrowserEvent(
|
||||||
|
ol.MapBrowserEvent.EventType.TOUCHSTART, this.map_, browserEvent);
|
||||||
|
this.dispatchEvent(newEvent);
|
||||||
|
|
||||||
|
this.down_ = browserEvent;
|
||||||
|
this.dragged_ = false;
|
||||||
|
this.dragListenerKeys_ = [
|
||||||
|
goog.events.listen(goog.global.document, goog.events.EventType.TOUCHMOVE,
|
||||||
|
this.handleTouchMove_, false, this),
|
||||||
|
goog.events.listen(goog.global.document, goog.events.EventType.TOUCHEND,
|
||||||
|
this.handleTouchEnd_, false, this)
|
||||||
|
];
|
||||||
|
|
||||||
|
// FIXME check if/when this is necessary
|
||||||
|
browserEvent.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {goog.events.BrowserEvent} browserEvent Browser event.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ol.MapBrowserEventHandler.prototype.handleTouchMove_ = function(browserEvent) {
|
||||||
|
this.dragged_ = true;
|
||||||
|
var newEvent = new ol.MapBrowserEvent(
|
||||||
|
ol.MapBrowserEvent.EventType.TOUCHMOVE, this.map_, browserEvent);
|
||||||
|
this.dispatchEvent(newEvent);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {goog.events.BrowserEvent} browserEvent Browser event.
|
* @param {goog.events.BrowserEvent} browserEvent Browser event.
|
||||||
* @private
|
* @private
|
||||||
@@ -309,6 +390,7 @@ ol.MapBrowserEventHandler.prototype.handleTouchEnd_ = function(browserEvent) {
|
|||||||
var newEvent = new ol.MapBrowserEvent(
|
var newEvent = new ol.MapBrowserEvent(
|
||||||
ol.MapBrowserEvent.EventType.TOUCHEND, this.map_, browserEvent);
|
ol.MapBrowserEvent.EventType.TOUCHEND, this.map_, browserEvent);
|
||||||
this.dispatchEvent(newEvent);
|
this.dispatchEvent(newEvent);
|
||||||
|
goog.array.forEach(this.dragListenerKeys_, goog.events.unlistenByKey);
|
||||||
if (!this.dragged_) {
|
if (!this.dragged_) {
|
||||||
goog.asserts.assert(!goog.isNull(this.down_));
|
goog.asserts.assert(!goog.isNull(this.down_));
|
||||||
this.emulateClick_(this.down_);
|
this.emulateClick_(this.down_);
|
||||||
@@ -324,14 +406,18 @@ ol.MapBrowserEventHandler.prototype.disposeInternal = function() {
|
|||||||
goog.events.unlistenByKey(this.mousedownListenerKey_);
|
goog.events.unlistenByKey(this.mousedownListenerKey_);
|
||||||
this.mousedownListenerKey_ = null;
|
this.mousedownListenerKey_ = null;
|
||||||
}
|
}
|
||||||
|
if (!goog.isNull(this.pointerdownListenerKey_)) {
|
||||||
|
goog.events.unlistenByKey(this.pointerdownListenerKey_);
|
||||||
|
this.pointerdownListenerKey_ = null;
|
||||||
|
}
|
||||||
|
if (!goog.isNull(this.touchstartListenerKey_)) {
|
||||||
|
goog.events.unlistenByKey(this.touchstartListenerKey_);
|
||||||
|
this.touchstartListenerKey_ = null;
|
||||||
|
}
|
||||||
if (!goog.isNull(this.dragListenerKeys_)) {
|
if (!goog.isNull(this.dragListenerKeys_)) {
|
||||||
goog.array.forEach(this.dragListenerKeys_, goog.events.unlistenByKey);
|
goog.array.forEach(this.dragListenerKeys_, goog.events.unlistenByKey);
|
||||||
this.dragListenerKeys_ = null;
|
this.dragListenerKeys_ = null;
|
||||||
}
|
}
|
||||||
if (!goog.isNull(this.touchListenerKeys_)) {
|
|
||||||
goog.array.forEach(this.touchListenerKeys_, goog.events.unlistenByKey);
|
|
||||||
this.touchListenerKeys_ = null;
|
|
||||||
}
|
|
||||||
goog.base(this, 'disposeInternal');
|
goog.base(this, 'disposeInternal');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user