Bug 891688 - Fix for caret selection not always appearing in subframes. r=mbrubeck

This commit is contained in:
Jim Mathies 2013-08-01 07:31:34 -05:00
parent ccbe235452
commit d6773fd8db
6 changed files with 116 additions and 95 deletions

View File

@ -298,6 +298,8 @@ let Content = {
xPos: aEvent.clientX + offsetX,
yPos: aEvent.clientY + offsetY
});
} else {
SelectionHandler.closeSelection();
}
},

View File

@ -225,14 +225,14 @@ var SelectionHandler = {
// This should never happen, but we check to make sure
if (!this._targetIsEditable) {
this._onFail("Unexpected, coordiates didn't find a text input element.");
this._onFail("Coordiates didn't find a text input element.");
return;
}
// Locate and sanity check the caret position
let selection = this._getSelection();
if (!selection || !selection.isCollapsed) {
this._onFail("Unexpected, No selection or selection is not collapsed.");
this._onFail("No selection or selection is not collapsed.");
return;
}
@ -281,7 +281,7 @@ var SelectionHandler = {
if (aClearSelection) {
this._clearSelection();
}
this._closeSelection();
this.closeSelection();
},
/*
@ -307,7 +307,7 @@ var SelectionHandler = {
Util.dumpLn(aDbgMessage);
this.sendAsync("Content:SelectionFail");
this._clearSelection();
this._closeSelection();
this.closeSelection();
},
/*
@ -368,11 +368,11 @@ var SelectionHandler = {
},
/*
* _closeSelection
* closeSelection
*
* Shuts SelectionHandler down.
*/
_closeSelection: function _closeSelection() {
closeSelection: function closeSelection() {
this._clearTimers();
this._cache = null;
this._contentWindow = null;

View File

@ -639,38 +639,6 @@ var SelectionHelperUI = {
});
},
/*
* _transitionFromSelectionToCaret
*
* Transitions from text selection mode to caret mode.
*
* @param aClientX, aClientY - client coordinates of the
* tap that initiates the change.
*/
_transitionFromSelectionToCaret: function _transitionFromSelectionToCaret(aClientX, aClientY) {
// Reset some of our state
this._activeSelectionRect = null;
// Reset the monocles
this._shutdownAllMarkers();
this._setupMonocleIdArray();
// Translate to browser relative client coordinates
let coords =
this._msgTarget.ptClientToBrowser(aClientX, aClientY, true);
// 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: coords.x,
yPos: coords.y
});
// Set the caret position
this._setCaretPositionAtPoint(coords.x, coords.y);
},
/*
* _setupDebugOptions
*
@ -803,68 +771,14 @@ var SelectionHelperUI = {
*/
/*
* _onTap
*
* Handles taps that move the current caret around in text edits,
* clear active selection and focus when neccessary, or change
* modes.
* Future: changing selection modes by tapping on a monocle.
*/
_onTap: function _onTap(aEvent) {
let clientCoords =
this._msgTarget.ptBrowserToClient(aEvent.clientX, aEvent.clientY, true);
// Check for a tap on a monocle
if (this.startMark.hitTest(clientCoords.x, clientCoords.y) ||
this.endMark.hitTest(clientCoords.x, clientCoords.y)) {
aEvent.stopPropagation();
aEvent.preventDefault();
return;
}
// Is the tap point within the bound of the target element? This
// is useful if we are dealing with some sort of input control.
// Not so much if the target is a page or div.
let pointInTargetElement =
Util.pointWithinRect(clientCoords.x, clientCoords.y,
this._targetElementRect);
// If the tap is within an editable element and the caret monocle is
// active, update the caret.
if (this.caretMark.visible && pointInTargetElement) {
// setCaretPositionAtPoint takes browser relative coords.
this._setCaretPositionAtPoint(aEvent.clientX, aEvent.clientY);
return;
}
// if the target is editable, we have selection or a caret, and the
// user clicks off the target clear selection and remove focus from
// the input.
if (this._targetIsEditable && !pointInTargetElement) {
// shutdown but leave focus alone. the event will fall through
// and the dom will update focus for us. If the user tapped on
// another input, we'll get a attachToCaret call soonish on the
// new input.
this.closeEditSession(false);
return;
}
if (this._hitTestSelection(aEvent) && this._targetIsEditable) {
// Attach to the newly placed caret position
_onClick: function(aEvent) {
if (this.layerMode == kChromeLayer && this._targetIsEditable) {
this.attachToCaret(this._msgTarget, aEvent.clientX, aEvent.clientY);
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(clientCoords.x, clientCoords.y);
return;
}
// Close when we get a single tap in content.
this.closeEditSession(false);
},
_onKeypress: function _onKeypress() {
@ -1019,7 +933,7 @@ var SelectionHelperUI = {
}
switch (aEvent.type) {
case "click":
this._onTap(aEvent);
this._onClick(aEvent);
break;
case "touchstart": {

View File

@ -56,6 +56,8 @@ MOCHITEST_METRO_FILES += \
browser_selection_urlbar.js \
browser_selection_contenteditable.js \
browser_selection_contenteditable.html \
browser_selection_caretfocus.js \
browser_selection_caretfocus.html \
$(NULL)
endif

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<input id="Text1" style="width:300px;" value="text input text input text input" type="text">
<input id="Text2" style="width:300px;" value="text input text input text input" type="text">
<input id="Text3" style="width:300px;" value="text input text input text input" type="text">
<iframe id="Text4" frameborder="0" style="overflow: hidden; border: 1px solid lightgray;" height="50" src="./res/textarea01.html" width="300"></iframe>
<textarea id="Text5" style="overflow: hidden;" name="textarea" rows="2" cols="36">text area text area text area text area text area</textarea>
<div id="Text6" style="width:300px; border: 1px solid lightgray;">text div text div text div text div</div>
</body>
</html>

View File

@ -0,0 +1,90 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let gWindow = null;
///////////////////////////////////////////////////
// form input tests
///////////////////////////////////////////////////
function setUpAndTearDown() {
emptyClipboard();
if (gWindow)
clearSelection(gWindow);
yield waitForCondition(function () {
return !SelectionHelperUI.isSelectionUIVisible;
});
InputSourceHelper.isPrecise = false;
InputSourceHelper.fireUpdate();
}
gTests.push({
desc: "normalize browser",
setUp: setUpAndTearDown,
tearDown: setUpAndTearDown,
run: function test() {
info(chromeRoot + "browser_selection_caretfocus.html");
yield addTab(chromeRoot + "browser_selection_caretfocus.html");
yield waitForCondition(function () {
return !StartUI.isStartPageVisible;
});
yield hideContextUI();
gWindow = Browser.selectedTab.browser.contentWindow;
},
});
function tapText(aIndex) {
gWindow = Browser.selectedTab.browser.contentWindow;
let id = "Text" + aIndex;
info("tapping " + id);
let element = gWindow.document.getElementById(id);
if (element.contentDocument) {
element = element.contentDocument.getElementById("textarea");
gWindow = element.ownerDocument.defaultView;
}
sendElementTap(gWindow, element, 100, 10);
return element;
}
gTests.push({
desc: "focus navigation",
setUp: setUpAndTearDown,
tearDown: setUpAndTearDown,
run: function test() {
for (let iteration = 0; iteration < 3; iteration++) {
for (let input = 1; input <= 6; input++) {
let element = tapText(input);
if (input == 6) {
// div
yield waitForCondition(function () {
return !SelectionHelperUI.isActive;
});
} else {
// input
yield SelectionHelperUI.pingSelectionHandler();
yield waitForCondition(function () {
return SelectionHelperUI.isCaretUIVisible;
});
ok(element == gWindow.document.activeElement, "element has focus");
}
}
}
},
});
function test() {
if (!isLandscapeMode()) {
todo(false, "browser_selection_tests need landscape mode to run.");
return;
}
// XXX need this until bugs 886624 and 859742 are fully resolved
setDevPixelEqualToPx();
runTests();
}