Bug 950464 - Default to selecting all text in SelectionHandler. r=margaret
authorWes Johnston <wjohnston@mozilla.com>
Tue, 17 Dec 2013 18:18:35 -0800
changeset 160997 336da7d0b51aab4f6374d404a10fb43979266732
parent 160996 fc79fa2fd2e368403ec3bd2a299063324acdfb92
child 160998 b329b704e89a34f13c9ca7b80b6115de896afb80
push id25862
push usercbook@mozilla.com
push dateWed, 18 Dec 2013 11:40:53 +0000
treeherdermozilla-central@60373454fc52 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmargaret
bugs950464
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 950464 - Default to selecting all text in SelectionHandler. r=margaret
mobile/android/chrome/content/SelectionHandler.js
mobile/android/chrome/content/browser.js
--- a/mobile/android/chrome/content/SelectionHandler.js
+++ b/mobile/android/chrome/content/SelectionHandler.js
@@ -7,16 +7,19 @@ var SelectionHandler = {
   HANDLE_TYPE_START: "START",
   HANDLE_TYPE_MIDDLE: "MIDDLE",
   HANDLE_TYPE_END: "END",
 
   TYPE_NONE: 0,
   TYPE_CURSOR: 1,
   TYPE_SELECTION: 2,
 
+  SELECT_ALL: 0,
+  SELECT_AT_POINT: 1,
+
   // Keeps track of data about the dimensions of the selection. Coordinates
   // stored here are relative to the _contentWindow window.
   _cache: null,
   _activeType: 0, // TYPE_NONE
   _ignoreSelectionChanges: false, // True while user drags text selection handles
   _ignoreCompositionChanges: false, // Persist caret during IME composition updates
 
   // The window that holds the selection (can be a sub-frame)
@@ -215,36 +218,41 @@ var SelectionHandler = {
     }
   },
 
   /*
    * Called from browser.js when the user long taps on text or chooses
    * the "Select Word" context menu item. Initializes SelectionHandler,
    * starts a selection, and positions the text selection handles.
    *
-   * @param aX, aY tap location in client coordinates.
+   * @param aOptions list of options describing how to start selection
+   *                 Options include:
+   *                   mode - SELECT_ALL to select everything in the target
+   *                          element, or SELECT_AT_POINT to select a word.
+   *                   x    - The x-coordinate for SELECT_AT_POINT.
+   *                   y    - The y-coordinate for SELECT_AT_POINT.
    */
-  startSelection: function sh_startSelection(aElement, aX, aY) {
+  startSelection: function sh_startSelection(aElement, aOptions = { mode: SelectionHandler.SELECT_ALL }) {
     // Clear out any existing active selection
     this._closeSelection();
 
     this._initTargetInfo(aElement);
 
     // Clear any existing selection from the document
     this._contentWindow.getSelection().removeAllRanges();
 
-    // If we didn't have any coordinates to associate with this event (for instance, selectAll is chosen from
-    // the actionMode), set them to a point inside the top left corner of the target
-    if (aX == undefined || aY == undefined) {
-      let rect = this._targetElement.getBoundingClientRect();
-      aX = rect.left + 1;
-      aY = rect.top  + 1;
-    }
-
-    if (!this._domWinUtils.selectAtPoint(aX, aY, Ci.nsIDOMWindowUtils.SELECT_WORDNOSPACE)) {
+    if (aOptions.mode == this.SELECT_ALL) {
+      this._getSelectionController().selectAll();
+    } else if (aOptions.mode == this.SELECT_AT_POINT) {
+      if (!this._domWinUtils.selectAtPoint(aOptions.x, aOptions.y, Ci.nsIDOMWindowUtils.SELECT_WORDNOSPACE)) {
+        this._deactivate();
+        return false;
+      }
+    } else {
+      Services.console.logStringMessage("Invalid selection mode " + aOptions.mode);
       this._deactivate();
       return false;
     }
 
     let selection = this._getSelection();
     // If the range didn't have any text, let's bail
     if (!selection || selection.rangeCount == 0 || selection.getRangeAt(0).collapsed) {
       this._deactivate();
@@ -257,46 +265,50 @@ var SelectionHandler = {
 
     // Initialize the cache
     this._cache = { start: {}, end: {}};
     this._updateCacheForSelection();
 
     let scroll = this._getScrollPos();
     // Figure out the distance between the selection and the click
     let positions = this._getHandlePositions(scroll);
-    let clickX = scroll.X + aX;
-    let clickY = scroll.Y + aY;
-    let distance = 0;
 
-    // Check if the click was in the bounding box of the selection handles
-    if (positions[0].left < clickX && clickX < positions[1].left
-        && positions[0].top < clickY && clickY < positions[1].top) {
-      distance = 0;
-    } else {
-      // If it was outside, check the distance to the center of the selection
-      let selectposX = (positions[0].left + positions[1].left) / 2;
-      let selectposY = (positions[0].top + positions[1].top) / 2;
-
-      let dx = Math.abs(selectposX - clickX);
-      let dy = Math.abs(selectposY - clickY);
-      distance = dx + dy;
-    }
-
-    let maxSelectionDistance = Services.prefs.getIntPref("browser.ui.selection.distance");
-    // Do not select text far away from where the user clicked
-    if (distance > maxSelectionDistance) {
-      this._closeSelection();
-      return false;
+    if (aOptions.mode == this.SELECT_AT_POINT && !this.selectionNearClick(scroll.X + aOptions.x,
+                                                                      scroll.Y + aOptions.y,
+                                                                      positions)) {
+        this._closeSelection();
+        return false;
     }
 
     this._positionHandles(positions);
-    this._sendMessage("TextSelection:ShowHandles", [this.HANDLE_TYPE_START, this.HANDLE_TYPE_END], aX, aY);
+    this._sendMessage("TextSelection:ShowHandles", [this.HANDLE_TYPE_START, this.HANDLE_TYPE_END], aOptions.x, aOptions.y);
     return true;
   },
 
+  /* Return true if the current selection (given by aPositions) is near to where the coordinates passed in */
+  _selectionNearClick: function(aX, aY, aPositions) {
+      let distance = 0;
+
+      // Check if the click was in the bounding box of the selection handles
+      if (aPositions[0].left < aX && aX < aPositions[1].left
+          && aPositions[0].top < aY && aY < aPositions[1].top) {
+        distance = 0;
+      } else {
+        // If it was outside, check the distance to the center of the selection
+        let selectposX = (aPositions[0].left + aPositions[1].left) / 2;
+        let selectposY = (aPositions[0].top + aPositions[1].top) / 2;
+
+        let dx = Math.abs(selectposX - aX);
+        let dy = Math.abs(selectposY - aY);
+        distance = dx + dy;
+      }
+
+      let maxSelectionDistance = Services.prefs.getIntPref("browser.ui.selection.distance");
+      return (distance < maxSelectionDistance);
+  },
 
   /* Reads a value from an action. If the action defines the value as a function, will return the result of calling
      the function. Otherwise, will return the value itself. If the value isn't defined for this action, will return a default */
   _getValue: function(obj, name, defaultValue) {
     if (!(name in obj))
       return defaultValue;
 
     if (typeof obj[name] == "function")
@@ -484,24 +496,25 @@ var SelectionHandler = {
                                  QueryInterface(Ci.nsISelectionController);
   },
 
   // Used by the contextmenu "matches" functions in ClipboardHelper
   isSelectionActive: function sh_isSelectionActive() {
     return (this._activeType == this.TYPE_SELECTION);
   },
 
-  selectAll: function sh_selectAll(aElement, aX, aY) {
-    if (this._activeType != this.TYPE_SELECTION)
-      this.startSelection(aElement, aX, aY);
-
-    let selectionController = this._getSelectionController();
-    selectionController.selectAll();
-    this._updateCacheForSelection();
-    this._positionHandles();
+  selectAll: function sh_selectAll(aElement) {
+    if (this._activeType != this.TYPE_SELECTION) {
+      this.startSelection(aElement, { mode : this.SELECT_ALL });
+    } else {
+      let selectionController = this._getSelectionController();
+      selectionController.selectAll();
+      this._updateCacheForSelection();
+      this._positionHandles();
+    }
   },
 
   /*
    * Moves the selection as the user drags a selection handle.
    *
    * @param aIsStartHandle whether the user is moving the start handle (as opposed to the end handle)
    * @param aX, aY selection point in client coordinates
    */
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -2121,17 +2121,21 @@ var NativeWindow = {
                              0, null);
         target.ownerDocument.defaultView.addEventListener("contextmenu", this, false);
         target.dispatchEvent(event);
       } else {
         this._target = null;
         BrowserEventHandler._cancelTapHighlight();
 
         if (SelectionHandler.canSelect(target)) {
-          if (!SelectionHandler.startSelection(target, aX, aY)) {
+          if (!SelectionHandler.startSelection(target, {
+              mode: SelectionHandler.SELECT_AT_POINT,
+              x: aX,
+              y: aY
+            })) {
             SelectionHandler.attachCaret(target);
           }
         }
       }
     },
 
     // Actually shows the native context menu by passing a list of context menu items to
     // show to the Java.
@@ -6222,21 +6226,21 @@ var ClipboardHelper = {
       string = aElement.value.slice(selectionStart, selectionEnd);
       this.clipboardHelper.copyString(string, aElement.ownerDocument);
     } else {
       this.clipboardHelper.copyString(aElement.value, aElement.ownerDocument);
     }
   },
 
   selectWord: function(aElement, aX, aY) {
-    SelectionHandler.startSelection(aElement, aX, aY);
-  },
-
-  selectAll: function(aElement, aX, aY) {
-    SelectionHandler.selectAll(aElement, aX, aY);
+    SelectionHandler.startSelection(aElement, {
+      mode: SelectionHandler.SELECT_AT_POINT,
+      x: aX,
+      y: aY
+    });
   },
 
   searchWith: function(aElement) {
     SelectionHandler.searchSelection(aElement);
   },
 
   share: function() {
     SelectionHandler.shareSelection();