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:
@@ -141,10 +141,16 @@ ol.MapBrowserEventHandler = function(map) {
|
||||
this.mousedownListenerKey_ = null;
|
||||
|
||||
/**
|
||||
* @type {Array.<number>}
|
||||
* @type {goog.events.Key}
|
||||
* @private
|
||||
*/
|
||||
this.touchListenerKeys_ = null;
|
||||
this.pointerdownListenerKey_ = null;
|
||||
|
||||
/**
|
||||
* @type {goog.events.Key}
|
||||
* @private
|
||||
*/
|
||||
this.touchstartListenerKey_ = null;
|
||||
|
||||
/**
|
||||
* @type {goog.events.BrowserEvent}
|
||||
@@ -158,21 +164,13 @@ ol.MapBrowserEventHandler = function(map) {
|
||||
goog.events.EventType.MOUSEDOWN,
|
||||
this.handleMouseDown_, false, this);
|
||||
|
||||
// touch events
|
||||
this.touchListenerKeys_ = [
|
||||
goog.events.listen(element, [
|
||||
this.pointerdownListenerKey_ = goog.events.listen(element,
|
||||
goog.events.EventType.MSPOINTERDOWN,
|
||||
this.handlePointerDown_, false, this);
|
||||
|
||||
this.touchstartListenerKey_ = goog.events.listen(element,
|
||||
goog.events.EventType.TOUCHSTART,
|
||||
goog.events.EventType.MSPOINTERDOWN
|
||||
], 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)
|
||||
];
|
||||
this.handleTouchStart_, false, this);
|
||||
|
||||
};
|
||||
goog.inherits(ol.MapBrowserEventHandler, goog.events.EventTarget);
|
||||
@@ -227,6 +225,17 @@ ol.MapBrowserEventHandler.prototype.handleMouseUp_ = function(browserEvent) {
|
||||
* @private
|
||||
*/
|
||||
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(
|
||||
ol.MapBrowserEvent.EventType.DOWN, this.map_, browserEvent);
|
||||
this.dispatchEvent(newEvent);
|
||||
@@ -265,21 +274,49 @@ ol.MapBrowserEventHandler.prototype.handleMouseMove_ = function(browserEvent) {
|
||||
* @param {goog.events.BrowserEvent} browserEvent Browser event.
|
||||
* @private
|
||||
*/
|
||||
ol.MapBrowserEventHandler.prototype.handleTouchStart_ = function(browserEvent) {
|
||||
ol.MapBrowserEventHandler.prototype.handlePointerDown_ =
|
||||
function(browserEvent) {
|
||||
if (!goog.isNull(this.mousedownListenerKey_)) {
|
||||
// pointer device detected - unregister the mousedown and touchstart
|
||||
// listeners
|
||||
goog.events.unlistenByKey(this.mousedownListenerKey_);
|
||||
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(
|
||||
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.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.
|
||||
* @private
|
||||
*/
|
||||
ol.MapBrowserEventHandler.prototype.handleTouchMove_ = function(browserEvent) {
|
||||
if (this.down_) {
|
||||
// 'touchmove' events are dispatched only when this.down_ is set
|
||||
// (set after a touch start) to prevent unwanted events when the
|
||||
// mouse hover the page. This only happens with the IE pointer
|
||||
// event system.
|
||||
this.dragged_ = true;
|
||||
var newEvent = new ol.MapBrowserEvent(
|
||||
ol.MapBrowserEvent.EventType.TOUCHMOVE, this.map_, browserEvent);
|
||||
this.dispatchEvent(newEvent);
|
||||
ol.MapBrowserEventHandler.prototype.handlePointerUp_ = function(browserEvent) {
|
||||
var newEvent = new ol.MapBrowserEvent(
|
||||
ol.MapBrowserEvent.EventType.TOUCHEND, this.map_, browserEvent);
|
||||
this.dispatchEvent(newEvent);
|
||||
goog.array.forEach(this.dragListenerKeys_, goog.events.unlistenByKey);
|
||||
if (!this.dragged_) {
|
||||
goog.asserts.assert(!goog.isNull(this.down_));
|
||||
this.emulateClick_(this.down_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* @private
|
||||
@@ -309,6 +390,7 @@ ol.MapBrowserEventHandler.prototype.handleTouchEnd_ = function(browserEvent) {
|
||||
var newEvent = new ol.MapBrowserEvent(
|
||||
ol.MapBrowserEvent.EventType.TOUCHEND, this.map_, browserEvent);
|
||||
this.dispatchEvent(newEvent);
|
||||
goog.array.forEach(this.dragListenerKeys_, goog.events.unlistenByKey);
|
||||
if (!this.dragged_) {
|
||||
goog.asserts.assert(!goog.isNull(this.down_));
|
||||
this.emulateClick_(this.down_);
|
||||
@@ -324,14 +406,18 @@ ol.MapBrowserEventHandler.prototype.disposeInternal = function() {
|
||||
goog.events.unlistenByKey(this.mousedownListenerKey_);
|
||||
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_)) {
|
||||
goog.array.forEach(this.dragListenerKeys_, goog.events.unlistenByKey);
|
||||
this.dragListenerKeys_ = null;
|
||||
}
|
||||
if (!goog.isNull(this.touchListenerKeys_)) {
|
||||
goog.array.forEach(this.touchListenerKeys_, goog.events.unlistenByKey);
|
||||
this.touchListenerKeys_ = null;
|
||||
}
|
||||
goog.base(this, 'disposeInternal');
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user