зеркало из https://github.com/mozilla/pjs.git
SNAV: snav can move focus out from single-line input fields only if cursor is at one of the widget edges. r=dougt
This commit is contained in:
Родитель
4d66bc6ccb
Коммит
73b187a40e
|
@ -35,7 +35,7 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Import this module through
|
||||
*
|
||||
* Components.utils.import("resource://gre/modules/SpatialNavigation.js");
|
||||
|
@ -58,7 +58,7 @@ var SpatialNavigation = {
|
|||
init: function(browser, callback) {
|
||||
browser.addEventListener("keypress", function (event) { _onInputKeyPress(event, callback) }, true);
|
||||
},
|
||||
|
||||
|
||||
uninit: function() {
|
||||
}
|
||||
};
|
||||
|
@ -119,34 +119,62 @@ function _onInputKeyPress (event, callback) {
|
|||
if (!PrefObserver['xulContentEnabled'] && doc instanceof Ci.nsIDOMXULDocument)
|
||||
return ;
|
||||
|
||||
// check to see if we are in a textarea or text input element, and if so,
|
||||
// Check to see if we are in a textarea or text input element, and if so,
|
||||
// ensure that we let the arrow keys work properly.
|
||||
if (target instanceof Ci.nsIDOMHTMLHtmlElement) {
|
||||
_focusNextUsingCmdDispatcher(key, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((target instanceof Ci.nsIDOMHTMLInputElement && (target.type == "text" || target.type == "password")) ||
|
||||
target instanceof Ci.nsIDOMHTMLTextAreaElement ) {
|
||||
|
||||
// if there is any selection at all, just ignore
|
||||
if (target.selectionEnd - target.selectionStart > 0)
|
||||
return;
|
||||
|
||||
// if there is no text, there is nothing special to do.
|
||||
if (target.textLength > 0) {
|
||||
if (key == PrefObserver['keyCodeRight'] ||
|
||||
key == PrefObserver['keyCodeDown'] ) {
|
||||
// we are moving forward into the document
|
||||
if (target.textLength != target.selectionEnd)
|
||||
// If it is a single-line input fields ...
|
||||
if (target instanceof Ci.nsIDOMHTMLInputElement &&
|
||||
(target.type == "text" || target.type == "password")) {
|
||||
|
||||
// Up/Down should not care and just move. However, Right/Left
|
||||
// should check the following before move.
|
||||
if (key != PrefObserver['keyCodeUp'] &&
|
||||
key != PrefObserver['keyCodeDown']) {
|
||||
|
||||
// If there is any selection at all, then do not move.
|
||||
if (target.selectionEnd - target.selectionStart > 0)
|
||||
return;
|
||||
|
||||
// If there is text, check if it is okay to move.
|
||||
if (target.textLength > 0) {
|
||||
// Cursor not at the beginning.
|
||||
if (key == PrefObserver['keyCodeLeft'] &&
|
||||
target.selectionStart != 0)
|
||||
return;
|
||||
|
||||
// Cursor not at the end.
|
||||
if (key == PrefObserver['keyCodeRight'] &&
|
||||
target.textLength != target.selectionEnd)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we are at the start of the text, okay to move
|
||||
}
|
||||
}
|
||||
// If it is a multi-line input field ...
|
||||
else if (target instanceof Ci.nsIDOMHTMLTextAreaElement) {
|
||||
|
||||
// If there is any selection at all, again just ignore
|
||||
if (target.selectionEnd - target.selectionStart > 0)
|
||||
return;
|
||||
|
||||
// If there is text, there check if it is okay to move.
|
||||
if (target.textLength > 0) {
|
||||
if (key == PrefObserver['keyCodeUp'] ||
|
||||
key == PrefObserver['keyCodeLeft']) {
|
||||
// Cursor not at the beginning.
|
||||
if (target.selectionStart != 0)
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (key == PrefObserver['keyCodeDown'] ||
|
||||
key == PrefObserver['keyCodeRight'])
|
||||
// Cursor not at the end.
|
||||
if (target.selectionEnd != target.textLength)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,7 +201,7 @@ function _onInputKeyPress (event, callback) {
|
|||
return Ci.nsIDOMNodeFilter.FILTER_SKIP;
|
||||
return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
|
||||
}
|
||||
|
||||
|
||||
if ((node instanceof Ci.nsIDOMHTMLButtonElement ||
|
||||
node instanceof Ci.nsIDOMHTMLInputElement ||
|
||||
node instanceof Ci.nsIDOMHTMLLinkElement ||
|
||||
|
@ -182,7 +210,7 @@ function _onInputKeyPress (event, callback) {
|
|||
node instanceof Ci.nsIDOMHTMLTextAreaElement) &&
|
||||
node.disabled == false)
|
||||
return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
|
||||
|
||||
|
||||
return Ci.nsIDOMNodeFilter.FILTER_SKIP;
|
||||
}
|
||||
|
||||
|
@ -193,7 +221,7 @@ function _onInputKeyPress (event, callback) {
|
|||
|
||||
var treeWalker = doc.createTreeWalker(doc, Ci.nsIDOMNodeFilter.SHOW_ELEMENT, snavfilter, false);
|
||||
var nextNode;
|
||||
|
||||
|
||||
while ((nextNode = treeWalker.nextNode())) {
|
||||
|
||||
if (nextNode == target)
|
||||
|
@ -208,13 +236,13 @@ function _onInputKeyPress (event, callback) {
|
|||
var distance = _spatialDistance(key, focusedRect, nextRect);
|
||||
|
||||
//dump("looking at: " + nextNode + " " + distance);
|
||||
|
||||
|
||||
if (distance <= distanceToBestElement && distance > 0) {
|
||||
distanceToBestElement = distance;
|
||||
bestElementToFocus = nextNode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (bestElementToFocus != null) {
|
||||
//dump("focusing element " + bestElementToFocus.nodeName + " " + bestElementToFocus) + "id=" + bestElementToFocus.getAttribute("id");
|
||||
|
||||
|
@ -230,7 +258,7 @@ function _onInputKeyPress (event, callback) {
|
|||
|
||||
if (callback != undefined)
|
||||
callback(bestElementToFocus);
|
||||
|
||||
|
||||
} else {
|
||||
// couldn't find anything. just advance and hope.
|
||||
_focusNextUsingCmdDispatcher(key, callback);
|
||||
|
@ -278,7 +306,7 @@ function _isRectInDirection(key, focusedRect, anotherRect)
|
|||
function _inflateRect(rect, value)
|
||||
{
|
||||
var newRect = new Object();
|
||||
|
||||
|
||||
newRect.left = rect.left - value;
|
||||
newRect.top = rect.top - value;
|
||||
newRect.right = rect.right + value;
|
||||
|
@ -310,7 +338,7 @@ function _spatialDistance(key, a, b)
|
|||
// |---|
|
||||
// |---|
|
||||
//
|
||||
|
||||
|
||||
if (a.top > b.bottom) {
|
||||
// the b rect is above a.
|
||||
mx = a.left;
|
||||
|
@ -323,7 +351,7 @@ function _spatialDistance(key, a, b)
|
|||
mx = a.left;
|
||||
my = a.bottom;
|
||||
nx = b.right;
|
||||
ny = b.top;
|
||||
ny = b.top;
|
||||
}
|
||||
else {
|
||||
mx = a.left;
|
||||
|
@ -342,7 +370,7 @@ function _spatialDistance(key, a, b)
|
|||
// |---|
|
||||
// |---|
|
||||
//
|
||||
|
||||
|
||||
if (a.top > b.bottom) {
|
||||
// the b rect is above a.
|
||||
mx = a.right;
|
||||
|
@ -355,7 +383,7 @@ function _spatialDistance(key, a, b)
|
|||
mx = a.right;
|
||||
my = a.bottom;
|
||||
nx = b.left;
|
||||
ny = b.top;
|
||||
ny = b.top;
|
||||
} else {
|
||||
mx = a.right;
|
||||
my = 0;
|
||||
|
@ -370,7 +398,7 @@ function _spatialDistance(key, a, b)
|
|||
// |---|
|
||||
// |---|
|
||||
//
|
||||
|
||||
|
||||
if (a.left > b.right) {
|
||||
// the b rect is to the left of a.
|
||||
mx = a.left;
|
||||
|
@ -382,7 +410,7 @@ function _spatialDistance(key, a, b)
|
|||
mx = a.right;
|
||||
my = a.top;
|
||||
nx = b.left;
|
||||
ny = b.bottom;
|
||||
ny = b.bottom;
|
||||
} else {
|
||||
// both b and a share some common x's.
|
||||
mx = 0;
|
||||
|
@ -398,7 +426,7 @@ function _spatialDistance(key, a, b)
|
|||
// |---| |---| |---|
|
||||
// |---| |---| |---|
|
||||
//
|
||||
|
||||
|
||||
if (a.left > b.right) {
|
||||
// the b rect is to the left of a.
|
||||
mx = a.left;
|
||||
|
@ -410,7 +438,7 @@ function _spatialDistance(key, a, b)
|
|||
mx = a.right;
|
||||
my = a.bottom;
|
||||
nx = b.left;
|
||||
ny = b.top;
|
||||
ny = b.top;
|
||||
} else {
|
||||
// both b and a share some common x's.
|
||||
mx = 0;
|
||||
|
@ -419,7 +447,7 @@ function _spatialDistance(key, a, b)
|
|||
ny = b.top;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var scopedRect = _inflateRect(a, gRectFudge);
|
||||
|
||||
if (key == PrefObserver['keyCodeLeft'] ||
|
||||
|
@ -434,13 +462,13 @@ function _spatialDistance(key, a, b)
|
|||
scopedRect.bottom = Infinity;
|
||||
inlineNavigation = _containsRect(scopedRect, b);
|
||||
}
|
||||
|
||||
|
||||
var d = Math.pow((mx-nx), 2) + Math.pow((my-ny), 2);
|
||||
|
||||
|
||||
// prefer elements directly aligned with the focused element
|
||||
if (inlineNavigation)
|
||||
d /= gDirectionalBias;
|
||||
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,11 +50,10 @@ MOCHI_TESTS = chrome/test_snav.xul \
|
|||
chrome/test_snav_selects.xul \
|
||||
chrome/test_snav_prefDisabled.xul \
|
||||
chrome/test_snav_prefKeyCode.xul \
|
||||
chrome/test_snav_textFields.xul \
|
||||
chrome/SpatialNavUtils.js \
|
||||
$(NULL)
|
||||
|
||||
# bug 447671 chrome/test_snav_textFields.xul \
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
libs:: $(MOCHI_TESTS) $(MOCHI_CONTENT)
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
https://bugzilla.mozilla.org/show_bug.cgi?id=436084
|
||||
-->
|
||||
|
||||
<window title="Mozilla Bug 288254"
|
||||
<window title="Mozilla Bug 436084"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="onLoad();">
|
||||
|
||||
<script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script type="text/javascript" src="SpatialNavUtils.js"></script>
|
||||
|
||||
<body id="some-content" xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
@ -27,7 +27,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=436084
|
|||
</p>
|
||||
|
||||
<p>
|
||||
<textarea id="textarea" name="textarea" cols="30" rows="3" wrap="hard">The Book of Mozilla</textarea>
|
||||
<textarea id="textarea" name="textarea" cols="30" rows="3" wrap="hard">Firefox</textarea>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
@ -36,75 +36,56 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=436084
|
|||
|
||||
</body>
|
||||
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
<![CDATA[
|
||||
Components.utils.import("resource://gre/modules/SpatialNavigation.js");
|
||||
|
||||
var moveTable = [
|
||||
["DOWN", "textinput"],
|
||||
["DOWN", "textinput"],
|
||||
["DOWN", "textarea"],
|
||||
["DOWN", "textarea"],
|
||||
["DOWN", "end"],
|
||||
["UP", "textarea"],
|
||||
["UP", "textarea"],
|
||||
["UP", "textinput"],
|
||||
["UP", "textinput"],
|
||||
["UP", "start"],
|
||||
["DOWN", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
|
||||
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textinput"],
|
||||
["RIGHT", "textarea"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["LEFT", "textinput"],
|
||||
["DOWN", "textarea"],
|
||||
["LEFT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "textarea"],
|
||||
["RIGHT", "end"],
|
||||
["UP", "textarea"],
|
||||
["LEFT", "textarea"],
|
||||
["LEFT", "textarea"],
|
||||
["LEFT", "textarea"],
|
||||
["LEFT", "textarea"],
|
||||
["LEFT", "textarea"],
|
||||
["LEFT", "textarea"],
|
||||
["DOWN", "textarea"],
|
||||
["DOWN", "end"],
|
||||
["DONE", "DONE"],
|
||||
];
|
||||
|
||||
|
@ -121,7 +102,7 @@ function onLoad()
|
|||
// starting the test itself.
|
||||
var x = document.getElementById("some-content");
|
||||
SpatialNavigation.init(x);
|
||||
|
||||
|
||||
// get to a known place.
|
||||
document.getElementById("start").focus();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче