diff --git a/toolkit/devtools/touch-events.js b/toolkit/devtools/touch-events.js index 2feaecae8f..90f8c0e02e 100644 --- a/toolkit/devtools/touch-events.js +++ b/toolkit/devtools/touch-events.js @@ -2,22 +2,24 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; -let {CC, Cc, Ci, Cu, Cr} = require('chrome'); +let {Ci, Cu} = require("chrome"); -Cu.import('resource://gre/modules/Services.jsm'); +Cu.import("resource://gre/modules/Services.jsm"); -let handlerCount = 0; - -let orig_w3c_touch_events = Services.prefs.getIntPref('dom.w3c_touch_events.enabled'); +let savedTouchEventsEnabled = + Services.prefs.getIntPref("dom.w3c_touch_events.enabled"); let systemAppOrigin = (function() { let systemOrigin = "_"; try { systemOrigin = Services.io.newURI( - Services.prefs.getCharPref('b2g.system_manifest_url'), null, null) + Services.prefs.getCharPref("b2g.system_manifest_url"), null, null) .prePath; - } catch(e) {} + } catch(e) { + // Fall back to default value + } return systemOrigin; })(); @@ -25,7 +27,7 @@ let trackedWindows = new WeakMap(); // =================== Touch ==================== // Simulate touch events on desktop -function TouchEventHandler (window) { +function TouchEventHandler(window) { // Returns an already instanciated handler for this window let cached = trackedWindows.get(window); if (cached) { @@ -33,27 +35,31 @@ function TouchEventHandler (window) { } let contextMenuTimeout = 0; - - let threshold = 25; try { - threshold = Services.prefs.getIntPref('ui.dragThresholdX'); - } catch(e) {} + threshold = Services.prefs.getIntPref("ui.dragThresholdX"); + } catch(e) { + // Fall back to default value + } let delay = 500; try { - delay = Services.prefs.getIntPref('ui.click_hold_context_menus.delay'); - } catch(e) {} + delay = Services.prefs.getIntPref("ui.click_hold_context_menus.delay"); + } catch(e) { + // Fall back to default value + } - let TouchEventHandler = { + let handler = { enabled: false, - events: ['mousedown', 'mousemove', 'mouseup', 'touchstart', 'touchend'], - start: function teh_start() { - if (this.enabled) + events: ["mousedown", "mousemove", "mouseup", "touchstart", "touchend"], + start() { + if (this.enabled) { return false; + } this.enabled = true; - let isReloadNeeded = Services.prefs.getIntPref('dom.w3c_touch_events.enabled') != 1; - Services.prefs.setIntPref('dom.w3c_touch_events.enabled', 1); + let isReloadNeeded = + Services.prefs.getIntPref("dom.w3c_touch_events.enabled") != 1; + Services.prefs.setIntPref("dom.w3c_touch_events.enabled", 1); this.events.forEach((function(evt) { // Only listen trusted events to prevent messing with // event dispatched manually within content documents @@ -61,16 +67,18 @@ function TouchEventHandler (window) { }).bind(this)); return isReloadNeeded; }, - stop: function teh_stop() { - if (!this.enabled) + stop() { + if (!this.enabled) { return; + } this.enabled = false; - Services.prefs.setIntPref('dom.w3c_touch_events.enabled', orig_w3c_touch_events); + Services.prefs.setIntPref("dom.w3c_touch_events.enabled", + savedTouchEventsEnabled); this.events.forEach((function(evt) { window.removeEventListener(evt, this, true); }).bind(this)); }, - handleEvent: function teh_handleEvent(evt) { + handleEvent(evt) { // The gaia system window use an hybrid system even on the device which is // a mix of mouse/touch events. So let's not cancel *all* mouse events // if it is the current target. @@ -78,16 +86,20 @@ function TouchEventHandler (window) { if (!content) { return; } - let isSystemWindow = content.location.toString().startsWith(systemAppOrigin); + let isSystemWindow = content.location.toString() + .startsWith(systemAppOrigin); // App touchstart & touchend should also be dispatched on the system app // to match on-device behavior. - if (evt.type.startsWith('touch') && !isSystemWindow) { + if (evt.type.startsWith("touch") && !isSystemWindow) { let sysFrame = content.realFrameElement; + if (!sysFrame) { + return; + } let sysDocument = sysFrame.ownerDocument; let sysWindow = sysDocument.defaultView; - let touchEvent = sysDocument.createEvent('touchevent'); + let touchEvent = sysDocument.createEvent("touchevent"); let touch = evt.touches[0] || evt.changedTouches[0]; let point = sysDocument.createTouch(sysWindow, sysFrame, 0, touch.pageX, touch.pageY, @@ -107,18 +119,20 @@ function TouchEventHandler (window) { // Ignore all but real mouse event coming from physical mouse // (especially ignore mouse event being dispatched from a touch event) - if (evt.button || evt.mozInputSource != Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE || evt.isSynthesized) { + if (evt.button || + evt.mozInputSource != Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE || + evt.isSynthesized) { return; } let eventTarget = this.target; - let type = ''; + let type = ""; switch (evt.type) { - case 'mousedown': + case "mousedown": this.target = evt.target; contextMenuTimeout = - this.sendContextMenu(evt.target, evt.pageX, evt.pageY, delay); + this.sendContextMenu(evt.target, evt.pageX, evt.pageY); this.cancelClick = false; this.startX = evt.pageX; @@ -128,12 +142,13 @@ function TouchEventHandler (window) { // won't be dispatched to something else. evt.target.setCapture(false); - type = 'touchstart'; + type = "touchstart"; break; - case 'mousemove': - if (!eventTarget) + case "mousemove": + if (!eventTarget) { return; + } if (!this.cancelClick) { if (Math.abs(this.startX - evt.pageX) > threshold || @@ -143,48 +158,47 @@ function TouchEventHandler (window) { } } - type = 'touchmove'; + type = "touchmove"; break; - case 'mouseup': - if (!eventTarget) + case "mouseup": + if (!eventTarget) { return; + } this.target = null; content.clearTimeout(contextMenuTimeout); - type = 'touchend'; + type = "touchend"; // Only register click listener after mouseup to ensure // catching only real user click. (Especially ignore click // being dispatched on form submit) if (evt.detail == 1) { - window.addEventListener('click', this, true, false); + window.addEventListener("click", this, true, false); } break; - case 'click': + case "click": // Mouse events has been cancelled so dispatch a sequence // of events to where touchend has been fired evt.preventDefault(); evt.stopImmediatePropagation(); - window.removeEventListener('click', this, true, false); + window.removeEventListener("click", this, true, false); - if (this.cancelClick) + if (this.cancelClick) { return; + } - ignoreEvents = true; content.setTimeout(function dispatchMouseEvents(self) { try { - self.fireMouseEvent('mousedown', evt); - self.fireMouseEvent('mousemove', evt); - self.fireMouseEvent('mouseup', evt); + self.fireMouseEvent("mousedown", evt); + self.fireMouseEvent("mousemove", evt); + self.fireMouseEvent("mouseup", evt); } catch(e) { - Cu.reportError('Exception in touch event helper: ' + e); + Cu.reportError("Exception in touch event helper: " + e); } - ignoreEvents = false; - }, 0, this); - + }, 0, this); return; } @@ -198,16 +212,17 @@ function TouchEventHandler (window) { evt.stopImmediatePropagation(); } }, - fireMouseEvent: function teh_fireMouseEvent(type, evt) { + fireMouseEvent(type, evt) { let content = this.getContent(evt.target); - var utils = content.QueryInterface(Ci.nsIInterfaceRequestor) + let utils = content.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils); - utils.sendMouseEvent(type, evt.clientX, evt.clientY, 0, 1, 0, true, 0, Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH); + utils.sendMouseEvent(type, evt.clientX, evt.clientY, 0, 1, 0, true, 0, + Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH); }, - sendContextMenu: function teh_sendContextMenu(target, x, y, delay) { + sendContextMenu(target, x, y) { let doc = target.ownerDocument; - let evt = doc.createEvent('MouseEvent'); - evt.initMouseEvent('contextmenu', true, true, doc.defaultView, + let evt = doc.createEvent("MouseEvent"); + evt.initMouseEvent("contextmenu", true, true, doc.defaultView, 0, x, y, x, y, false, false, false, false, 0, null); @@ -219,38 +234,38 @@ function TouchEventHandler (window) { return timeout; }, - sendTouchEvent: function teh_sendTouchEvent(evt, target, name) { + sendTouchEvent(evt, target, name) { + function clone(obj) { + return Cu.cloneInto(obj, target); + } // When running OOP b2g desktop, we need to send the touch events // using the mozbrowser api on the unwrapped frame. if (target.localName == "iframe" && target.mozbrowser === true) { if (name == "touchstart") { this.touchstartTime = Date.now(); } else if (name == "touchend") { - // If we have a 'fast' tap, don't send a click as both will be turned + // If we have a "fast" tap, don't send a click as both will be turned // into a click and that breaks eg. checkboxes. if (Date.now() - this.touchstartTime < delay) { this.cancelClick = true; } } - function clone(obj) { - return Cu.cloneInto(obj, target); - } - let unwraped = XPCNativeWrapper.unwrap(target); - unwraped.sendTouchEvent(name, clone([0]), // event type, id - clone([evt.clientX]), // x - clone([evt.clientY]), // y - clone([1]), clone([1]), // rx, ry - clone([0]), clone([0]), // rotation, force - 1); // count + let unwrapped = XPCNativeWrapper.unwrap(target); + unwrapped.sendTouchEvent(name, clone([0]), // event type, id + clone([evt.clientX]), // x + clone([evt.clientY]), // y + clone([1]), clone([1]), // rx, ry + clone([0]), clone([0]), // rotation, force + 1); // count return; } let document = target.ownerDocument; let content = this.getContent(target); if (!content) { - return null; + return; } - let touchEvent = document.createEvent('touchevent'); + let touchEvent = document.createEvent("touchevent"); let point = document.createTouch(content, target, 0, evt.pageX, evt.pageY, evt.screenX, evt.screenY, @@ -263,18 +278,17 @@ function TouchEventHandler (window) { false, false, false, false, touches, targetTouches, changedTouches); target.dispatchEvent(touchEvent); - return touchEvent; }, - getContent: function teh_getContent(target) { + getContent(target) { let win = (target && target.ownerDocument) ? target.ownerDocument.defaultView : null; return win; } }; - trackedWindows.set(window, TouchEventHandler); + trackedWindows.set(window, handler); - return TouchEventHandler; + return handler; } exports.TouchEventHandler = TouchEventHandler;