Bug 960203 - Allow text selection handles to crossover in <input> and <textarea> elements. r=mleibovic
authorMax Li <maxli@maxli.ca>
Sat, 25 Jan 2014 16:15:31 -0800
changeset 165631 afed99fd2c9f6ade5ff025723108cf4c2f301172
parent 165630 d3f107710885743fb96afe07b9bf5ab145207c5d
child 165632 ea49291871ef8e22ef8ba632787779c5df834a92
push id4624
push userryanvm@gmail.com
push dateTue, 28 Jan 2014 23:09:06 +0000
treeherderfx-team@ea49291871ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmleibovic
bugs960203
milestone29.0a1
Bug 960203 - Allow text selection handles to crossover in <input> and <textarea> elements. r=mleibovic
mobile/android/chrome/content/SelectionHandler.js
--- a/mobile/android/chrome/content/SelectionHandler.js
+++ b/mobile/android/chrome/content/SelectionHandler.js
@@ -556,16 +556,33 @@ var SelectionHandler = {
     return (this._activeType == this.TYPE_SELECTION);
   },
 
   selectAll: function sh_selectAll(aElement) {
     this.startSelection(aElement, { mode : this.SELECT_ALL });
   },
 
   /*
+   * Helper function for moving the selection inside an editable element.
+   *
+   * @param aAnchorX the stationary handle's x-coordinate in client coordinates
+   * @param aX the moved handle's x-coordinate in client coordinates
+   * @param aCaretPos the current position of the caret
+   */
+  _moveSelectionInEditable: function sh_moveSelectionInEditable(aAnchorX, aX, aCaretPos) {
+    let anchorOffset = aX < aAnchorX ? this._targetElement.selectionEnd
+                                     : this._targetElement.selectionStart;
+    let newOffset = aCaretPos.offset;
+    let [start, end] = anchorOffset <= newOffset ?
+                       [anchorOffset, newOffset] :
+                       [newOffset, anchorOffset];
+    this._targetElement.setSelectionRange(start, end);
+  },
+
+  /*
    * 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
    */
   _moveSelection: function sh_moveSelection(aIsStartHandle, aX, aY) {
     // XXX We should be smarter about the coordinates we pass to caretPositionFromPoint, especially
     // in editable targets. We should factor out the logic that's currently in _sendMouseEvents.
@@ -592,28 +609,28 @@ var SelectionHandler = {
     }
 
     let selection = this._getSelection();
 
     // The handles work the same on both LTR and RTL pages, but the anchor/focus nodes
     // are reversed, so we need to reverse the logic to extend the selection.
     if ((aIsStartHandle && !this._isRTL) || (!aIsStartHandle && this._isRTL)) {
       if (targetIsEditable) {
-        // XXX This will just collapse the selection if the start handle goes past the end handle.
-        this._targetElement.selectionStart = caretPos.offset;
+        let anchorX = this._isRTL ? this._cache.start.x : this._cache.end.x;
+        this._moveSelectionInEditable(anchorX, aX, caretPos);
       } else {
         let focusNode = selection.focusNode;
         let focusOffset = selection.focusOffset;
         selection.collapse(caretPos.offsetNode, caretPos.offset);
         selection.extend(focusNode, focusOffset);
       }
     } else {
       if (targetIsEditable) {
-        // XXX This will just collapse the selection if the end handle goes past the start handle.
-        this._targetElement.selectionEnd = caretPos.offset;
+        let anchorX = this._isRTL ? this._cache.end.x : this._cache.start.x;
+        this._moveSelectionInEditable(anchorX, aX, caretPos);
       } else {
         selection.extend(caretPos.offsetNode, caretPos.offset);
       }
     }
   },
 
   _sendMouseEvents: function sh_sendMouseEvents(aX, aY, useShift) {
     // If we're positioning a cursor in an input field, make sure the handle