diff --git a/browser/metro/base/content/contenthandlers/SelectionHandler.js b/browser/metro/base/content/contenthandlers/SelectionHandler.js index 5e96ea81fff9..a49bc92843d3 100644 --- a/browser/metro/base/content/contenthandlers/SelectionHandler.js +++ b/browser/metro/base/content/contenthandlers/SelectionHandler.js @@ -429,8 +429,12 @@ var SelectionHandler = { this._clearTimers(); this._cache = null; this._contentWindow = null; + this._targetElement = null; this.selectedText = ""; this._selectionMoveActive = false; + this._contentOffset = null; + this._domWinUtils = null; + this._targetIsEditable = false; }, /* @@ -457,11 +461,11 @@ var SelectionHandler = { // Updates this._cache content selection position data which we send over // to SelectionHelperUI. Note updateUIMarkerRects will fail if there isn't // any selection in the page. This can happen when we start a monocle drag - // but haven't dragged enough to create selection. Just return. + // but haven't dragged enough to create selection. Just return. try { this._updateUIMarkerRects(selection); } catch (ex) { - Util.dumpLn(ex.message); + Util.dumpLn("_updateUIMarkerRects:", ex.message); return; } diff --git a/browser/metro/base/content/helperui/SelectionHelperUI.js b/browser/metro/base/content/helperui/SelectionHelperUI.js index f201a635b550..1e206d6a2581 100644 --- a/browser/metro/base/content/helperui/SelectionHelperUI.js +++ b/browser/metro/base/content/helperui/SelectionHelperUI.js @@ -400,9 +400,7 @@ var SelectionHelperUI = { this._msgTarget = aMsgTarget; // Init our list of available monocle ids - this._selectionMarkIds = ["selectionhandle-mark1", - "selectionhandle-mark2", - "selectionhandle-mark3"]; + this._setupMonocleIdArray(); // Init selection rect info this._activeSelectionRect = Util.getCleanRect(); @@ -461,16 +459,7 @@ var SelectionHelperUI = { window.removeEventListener("MozPrecisePointer", this, true); - if (this.startMark != null) - this.startMark.shutdown(); - if (this.endMark != null) - this.endMark.shutdown(); - if (this._caretMark != null) - this._caretMark.shutdown(); - - this._startMark = null; - this._endMark = null; - this._caretMark = null; + this._shutdownAllMarkers(); this._selectionMarkIds = []; this._msgTarget = null; @@ -541,6 +530,36 @@ var SelectionHelperUI = { }); }, + /* + * _transitionFromSelectionToCaret + * + * Transitions from text selection mode to caret mode. + */ + _transitionFromSelectionToCaret: function _transitionFromSelectionToCaret(aX, aY) { + // clear existing selection and shutdown SelectionHandler + this._sendAsyncMessage("Browser:SelectionClear", { clearFocus: false }); + this._sendAsyncMessage("Browser:SelectionClose"); + + // Reset some of our state + this._selectionHandlerActive = false; + this._activeSelectionRect = null; + + // Reset the monocles + this._shutdownAllMarkers(); + this._setupMonocleIdArray(); + + // Init SelectionHandler and turn on caret selection. Note the focus caret + // will have been removed from the target element due to the shutdown call. + // This won't set the caret position on its own. + this._sendAsyncMessage("Browser:CaretAttach", { + xPos: aX, + yPos: aY + }); + + // Set the caret position + this._setCaretPositionAtPoint(aX, aY); + }, + /* * _setupDebugOptions * @@ -574,8 +593,9 @@ var SelectionHelperUI = { }, /* - * _sendAsyncMessage - helper for sending a message to - * SelectionHandler. + * _sendAsyncMessage + * + * Helper for sending a message to SelectionHandler. */ _sendAsyncMessage: function _sendAsyncMessage(aMsg, aJson) { if (!this._msgTarget) { @@ -608,13 +628,43 @@ var SelectionHelperUI = { this._sendAsyncMessage("Browser:CaretUpdate", json); }, + /* + * _shutdownAllMarkers + * + * Helper for shutting down all markers and + * freeing the objects associated with them. + */ + _shutdownAllMarkers: function _shutdownAllMarkers() { + if (this._startMark) + this._startMark.shutdown(); + if (this._endMark) + this._endMark.shutdown(); + if (this._caretMark) + this._caretMark.shutdown(); + + this._startMark = null; + this._endMark = null; + this._caretMark = null; + }, + + /* + * _setupMonocleIdArray + * + * Helper for initing the array of monocle ids. + */ + _setupMonocleIdArray: function _setupMonocleIdArray() { + this._selectionMarkIds = ["selectionhandle-mark1", + "selectionhandle-mark2", + "selectionhandle-mark3"]; + }, + /* * Event handlers for document events */ /* * _onTap - * + * * Handles taps that move the current caret around in text edits, * clear active selection and focus when neccessary, or change * modes. @@ -660,6 +710,24 @@ var SelectionHelperUI = { return; } + let selectionTap = this._hitTestSelection(aEvent); + + // If the tap is in the selection, just ignore it. We disallow this + // since we always get a single tap before a double, and double tap + // copies selected text. + if (selectionTap) { + aEvent.stopPropagation(); + aEvent.preventDefault(); + return; + } + + // A tap within an editable but outside active selection, clear the + // selection and flip back to caret mode. + if (this.startMark.visible && pointInTargetElement && + this._targetIsEditable) { + this._transitionFromSelectionToCaret(aEvent.clientX, aEvent.clientY); + } + // If we have active selection in anything else don't let the event get // to content. Prevents random taps from killing active selection. aEvent.stopPropagation();