зеркало из https://github.com/mozilla/gecko-dev.git
Bug 891688 - Fix for caret selection not always appearing in subframes. r=mbrubeck
This commit is contained in:
Родитель
95ba75cb0a
Коммит
6a56aa2f59
|
@ -298,6 +298,8 @@ let Content = {
|
|||
xPos: aEvent.clientX + offsetX,
|
||||
yPos: aEvent.clientY + offsetY
|
||||
});
|
||||
} else {
|
||||
SelectionHandler.closeSelection();
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -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();
|
||||
}
|
Загрузка…
Ссылка в новой задаче