Skip to content
This repository has been archived by the owner on May 12, 2020. It is now read-only.

Commit

Permalink
Only process each mouse up & down event once at either canvas or window
Browse files Browse the repository at this point in the history
Internet explorer will only trigger mouse events at the window level. If
the handler is bound to both window and canvas however, the event will
be processed twice in every other browser.

A solution to this is to track manually (without affecting the bubble or
other features on the event) that an event has been processed, and don't
process it a second time.
  • Loading branch information
peitschie committed Nov 20, 2013
1 parent 3e4c944 commit 1b72f4c
Showing 1 changed file with 65 additions and 11 deletions.
76 changes: 65 additions & 11 deletions webodf/lib/gui/EventManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,42 @@ gui.EventManager = function EventManager(odtDocument) {
"beforepaste": true
},
// Events that should be bound to the global window rather than the canvas element
bindToWindow = {
// Capture selections that start outside the canvas element and end within the canvas element
"mousedown": true,
// Capture selections that start inside the canvas element and end outside of the element or even window
"mouseup": true
bindToWindow;

/**
* Ensures events that may bubble through multiple sources are only handled once.
* @constructor
*/
function EventDelegate() {
var self = this,
recentEvents = [];

/**
* @type {!Array.<!function(!Event)>}
*/
this.handlers = [];

/**
* @type {!boolean}
*/
this.isSubscribed = false;

/**
* @param {!Event} e
*/
this.handleEvent = function(e) {
if (recentEvents.indexOf(e) === -1) {
recentEvents.push(e); // Track this event as already processed by these handlers
self.handlers.forEach(function(handler) {
// Yes yes... this is not a spec-compliant event processor... sorry!
handler(e);
});
// Reset the processed events list after this tick is complete. The event won't be
// processed by any other sources after this
runtime.setTimeout(function() { recentEvents.splice(recentEvents.indexOf(e), 1); }, 0);
}
};
}

/**
* @param {!Window} window
Expand Down Expand Up @@ -147,21 +177,35 @@ gui.EventManager = function EventManager(odtDocument) {
* @param {function(!Event)|function()} handler
*/
this.subscribe = function(eventName, handler) {
if (bindToWindow[eventName] && window) {
listenEvent(window, eventName, handler);
var delegate = window && bindToWindow[eventName];
if (delegate) {
delegate.handlers.push(handler);
if (!delegate.isSubscribed) {
delegate.isSubscribed = true;
// Internet explorer will only supply mouse up & down on the window object
// For other browser though, listening to both will cause two events to be processed
listenEvent(/**@type {!Window}*/(window), eventName, delegate.handleEvent);
listenEvent(canvasElement, eventName, delegate.handleEvent);
}
} else {
listenEvent(canvasElement, eventName, handler);
}
listenEvent(canvasElement, eventName, handler);
};

/**
* @param {!string} eventName
* @param {function(!Event)|function()} handler
*/
this.unsubscribe = function(eventName, handler) {
if (bindToWindow[eventName] && window) {
removeEvent(window, eventName, handler);
var delegate = window && bindToWindow[eventName],
handlerIndex = delegate && delegate.handlers.indexOf(handler);
if (delegate) {
if (handlerIndex !== -1) {
delegate.handlers.splice(handlerIndex, 1);
}
} else {
removeEvent(canvasElement, eventName, handler);
}
removeEvent(canvasElement, eventName, handler);
};

/**
Expand Down Expand Up @@ -209,4 +253,14 @@ gui.EventManager = function EventManager(odtDocument) {
}
}
};

function init() {
bindToWindow = {
// Capture selections that start outside the canvas element and end within the canvas element
"mousedown": new EventDelegate(),
// Capture selections that start inside the canvas element and end outside of the element or even window
"mouseup": new EventDelegate()
};
}
init();
};

0 comments on commit 1b72f4c

Please sign in to comment.