зеркало из https://github.com/mozilla/pjs.git
Bug 609940 - caret (cursor) can hide underneath the formfill helper [r=mfinkle]
This commit is contained in:
Родитель
6f76879ff8
Коммит
fa24470ee5
|
@ -159,6 +159,7 @@ pref("signon.SignonFileName", "signons.txt");
|
|||
/* form helper */
|
||||
pref("formhelper.enabled", true);
|
||||
pref("formhelper.autozoom", true);
|
||||
pref("formhelper.autozoom.caret", true);
|
||||
pref("formhelper.restore", false);
|
||||
|
||||
/* find helper */
|
||||
|
|
|
@ -247,9 +247,6 @@ var Browser = {
|
|||
this.styles[style] = stylesheet.cssRules[index].style;
|
||||
}
|
||||
|
||||
// Init the cache used in the resize handler
|
||||
window.cachedWidth = window.innerWidth;
|
||||
|
||||
// Saved the scrolls values before the resizing of the window, to restore
|
||||
// the scrollbox position once the resize has finished.
|
||||
// The last parameter of addEventListener is true to be sure we performed
|
||||
|
@ -284,10 +281,10 @@ var Browser = {
|
|||
Browser.styles["window-width"].width = w + "px";
|
||||
Browser.styles["window-height"].height = h + "px";
|
||||
Browser.styles["toolbar-height"].height = toolbarHeight + "px";
|
||||
ViewableAreaObserver.update();
|
||||
|
||||
// Tell the UI to resize the browser controls
|
||||
BrowserUI.sizeControls(w, h);
|
||||
ViewableAreaObserver.update();
|
||||
|
||||
// Restore the previous scroll position
|
||||
let restorePosition = Browser.controlsPosition;
|
||||
|
@ -307,20 +304,6 @@ var Browser = {
|
|||
Browser.tryFloatToolbar(0, 0);
|
||||
}
|
||||
|
||||
let oldWidth = window.cachedWidth || w;
|
||||
window.cachedWidth = w;
|
||||
|
||||
for (let i = Browser.tabs.length - 1; i >= 0; i--) {
|
||||
let tab = Browser.tabs[i];
|
||||
let oldContentWindowWidth = tab.browser.contentWindowWidth;
|
||||
tab.updateViewportSize();
|
||||
|
||||
// If the viewport width is still the same, the page layout has not
|
||||
// changed, so we can keep keep the same content on-screen.
|
||||
if (tab.browser.contentWindowWidth == oldContentWindowWidth)
|
||||
tab.restoreViewportPosition(oldWidth, w);
|
||||
}
|
||||
|
||||
// We want to keep the current focused element into view if possible
|
||||
let currentElement = document.activeElement;
|
||||
let [scrollbox, scrollInterface] = ScrollUtils.getScrollboxFromElement(currentElement);
|
||||
|
@ -1005,7 +988,6 @@ var Browser = {
|
|||
* @return Rect in viewport coordinates, or null
|
||||
*/
|
||||
_getZoomRectForRect: function _getZoomRectForRect(rect, y) {
|
||||
let oldZoomLevel = getBrowser().scale;
|
||||
let zoomLevel = this._getZoomLevelForRect(rect);
|
||||
return this._getZoomRectForPoint(rect.center().x, y, zoomLevel);
|
||||
},
|
||||
|
@ -1208,7 +1190,7 @@ Browser.MainDragger.prototype = {
|
|||
switch (aEvent.type) {
|
||||
case "PanBegin": {
|
||||
let browser = Browser.selectedBrowser;
|
||||
let width = window.innerWidth, height = window.innerHeight;
|
||||
let width = ViewableAreaObserver.width, height = ViewableAreaObserver.height;
|
||||
let contentWidth = browser.contentDocumentWidth * browser.scale;
|
||||
let contentHeight = browser.contentDocumentHeight * browser.scale;
|
||||
|
||||
|
@ -1291,13 +1273,13 @@ Browser.MainDragger.prototype = {
|
|||
_showScrollbars: function _showScrollbars() {
|
||||
let scaleX = this._scrollScales.x, scaleY = this._scrollScales.y;
|
||||
if (scaleX) {
|
||||
this._horizontalScrollbar.width = ViewableAreaObserver.width * scaleX;
|
||||
this._horizontalScrollbar.setAttribute("panning", "true");
|
||||
this._horizontalScrollbar.width = window.innerWidth * scaleX;
|
||||
}
|
||||
|
||||
if (scaleY) {
|
||||
this._verticalScrollbar.height = ViewableAreaObserver.height * scaleY;
|
||||
this._verticalScrollbar.setAttribute("panning", "true");
|
||||
this._verticalScrollbar.height = window.innerHeight * scaleY;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -2474,8 +2456,8 @@ Tab.prototype = {
|
|||
if (!browser)
|
||||
return;
|
||||
|
||||
let screenW = window.innerWidth;
|
||||
let screenH = window.innerHeight;
|
||||
let screenW = ViewableAreaObserver.width;
|
||||
let screenH = ViewableAreaObserver.height;
|
||||
let viewportW, viewportH;
|
||||
|
||||
let metadata = this.metadata;
|
||||
|
@ -2797,22 +2779,46 @@ var ViewableAreaObserver = {
|
|||
},
|
||||
|
||||
get height() {
|
||||
return this._height || window.innerHeight;
|
||||
return (this._height || window.innerHeight) - Elements.contentNavigator.getBoundingClientRect().height;
|
||||
},
|
||||
|
||||
observe: function va_observe(aSubject, aTopic, aData) {
|
||||
let rect = Rect.fromRect(JSON.parse(aData));
|
||||
this._height = rect.bottom - rect.top;
|
||||
this._width = rect.right - rect.left;
|
||||
let height = rect.bottom - rect.top;
|
||||
let width = rect.right - rect.left;
|
||||
if (height == window.innerHeight && width == window.innerWidth) {
|
||||
this._height = null;
|
||||
this._width = null;
|
||||
}
|
||||
else {
|
||||
this._height = height;
|
||||
this._width = width;
|
||||
}
|
||||
this.update();
|
||||
},
|
||||
|
||||
update: function va_update() {
|
||||
let oldHeight = parseInt(Browser.styles["viewable-height"].height);
|
||||
let newHeight = this.height - Elements.contentNavigator.getBoundingClientRect().height;
|
||||
if (newHeight != oldHeight) {
|
||||
let oldWidth = parseInt(Browser.styles["viewable-width"].width);
|
||||
|
||||
let newWidth = this.width;
|
||||
let newHeight = this.height;
|
||||
if (newHeight != oldHeight || newWidth != oldWidth) {
|
||||
Browser.styles["viewable-height"].height = newHeight + "px";
|
||||
Browser.styles["viewable-width"].width = this.width + "px";
|
||||
Browser.styles["viewable-height"].maxHeight = newHeight + "px";
|
||||
|
||||
Browser.styles["viewable-width"].width = newWidth + "px";
|
||||
Browser.styles["viewable-width"].maxWidth = newWidth + "px";
|
||||
|
||||
for (let i = Browser.tabs.length - 1; i >= 0; i--) {
|
||||
let tab = Browser.tabs[i];
|
||||
tab.updateViewportSize();
|
||||
|
||||
// If the viewport width is still the same, the page layout has not
|
||||
// changed, so we can keep keep the same content on-screen.
|
||||
if (tab.browser.contentWindowWidth == oldWidth)
|
||||
tab.restoreViewportPosition(oldWidth, w);
|
||||
}
|
||||
|
||||
// setTimeout(callback, 0) to ensure the resize event handler dispatch is finished
|
||||
setTimeout(function() {
|
||||
|
|
|
@ -859,6 +859,7 @@ var FormHelperUI = {
|
|||
} else if (aElementRect && !Browser.selectedTab.allowZoom && autozoomEnabled) {
|
||||
// Even if zooming is disabled we could need to reposition the view in
|
||||
// order to keep the element on-screen
|
||||
zoomRect = Browser._getZoomRectForPoint(aElementRect.center().x, aElementRect.y, browser.scale);
|
||||
Browser.animatedZoomTo(zoomRect);
|
||||
}
|
||||
|
||||
|
@ -866,7 +867,7 @@ var FormHelperUI = {
|
|||
},
|
||||
|
||||
_ensureCaretVisible: function _ensureCaretVisible(aCaretRect) {
|
||||
if (!aCaretRect)
|
||||
if (!aCaretRect || !Services.prefs.getBoolPref("formhelper.autozoom.caret"))
|
||||
return;
|
||||
|
||||
// the scrollX/scrollY position can change because of the animated zoom so
|
||||
|
@ -884,7 +885,7 @@ var FormHelperUI = {
|
|||
let zoomRect = Rect.fromRect(browser.getBoundingClientRect());
|
||||
|
||||
this._currentCaretRect = aCaretRect;
|
||||
let caretRect = aCaretRect.scale(browser.scale, browser.scale);
|
||||
let caretRect = aCaretRect.clone().scale(browser.scale, browser.scale);
|
||||
|
||||
let scroll = browser.getPosition();
|
||||
zoomRect = new Rect(scroll.x, scroll.y, zoomRect.width, zoomRect.height);
|
||||
|
|
|
@ -95,7 +95,12 @@ FormAssistant.prototype = {
|
|||
if (element) {
|
||||
this._currentIndex = aIndex;
|
||||
gFocusManager.setFocus(element, Ci.nsIFocusManager.FLAG_NOSCROLL);
|
||||
sendAsyncMessage("FormAssist:Show", this._getJSON());
|
||||
|
||||
// To ensure we get the current caret positionning of the focused
|
||||
// element we need to delayed a bit the event
|
||||
this._executeDelayed(function(self) {
|
||||
sendAsyncMessage("FormAssist:Show", self._getJSON());
|
||||
});
|
||||
}
|
||||
return element;
|
||||
},
|
||||
|
@ -473,9 +478,10 @@ FormAssistant.prototype = {
|
|||
/** Caret is used to input text for this element. */
|
||||
_getCaretRect: function _formHelperGetCaretRect() {
|
||||
let element = this.currentElement;
|
||||
let focusedElement = gFocusManager.getFocusedElementForWindow(content, true, {});
|
||||
if ((element instanceof HTMLTextAreaElement ||
|
||||
(element instanceof HTMLInputElement && element.type == "text")) &&
|
||||
gFocusManager.focusedElement == element) {
|
||||
focusedElement == element) {
|
||||
let utils = Util.getWindowUtils(element.ownerDocument.defaultView);
|
||||
let rect = utils.sendQueryContentEvent(utils.QUERY_CARET_RECT, element.selectionEnd, 0, 0, 0);
|
||||
if (rect) {
|
||||
|
|
|
@ -50,7 +50,9 @@ _BROWSER_FILES = \
|
|||
head.js \
|
||||
remote_head.js \
|
||||
remote_forms.js \
|
||||
remote_formsZoom.js \
|
||||
remote_vkb.js \
|
||||
browser_addons.js \
|
||||
browser_awesomescreen.js \
|
||||
browser_blank_01.html \
|
||||
browser_blank_02.html \
|
||||
|
@ -61,9 +63,10 @@ _BROWSER_FILES = \
|
|||
browser_click_content.js \
|
||||
browser_contacts.js \
|
||||
browser_find.js \
|
||||
browser_addons.js \
|
||||
browser_forms.html \
|
||||
browser_forms.js \
|
||||
browser_formsZoom.html \
|
||||
browser_formsZoom.js \
|
||||
browser_mainui.js \
|
||||
browser_navigation.js \
|
||||
browser_preferences_basic.js \
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Browser Zoom Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
|
||||
<textarea id="textarea-1" spellcheck="false" rows="10">textarea 1</textarea><br>
|
||||
<textarea id="textarea-2" spellcheck="false" rows="10">textarea 2</textarea><br>
|
||||
<textarea id="textarea-3" spellcheck="false" rows="10">textarea 3
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
</textarea><br>
|
||||
<textarea id="textarea-4" spellcheck="false" rows="10">textarea 4
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
</textarea>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,216 @@
|
|||
let testURL_01 = chromeRoot + "browser_formsZoom.html";
|
||||
|
||||
let baseURI = "http://mochi.test:8888/browser/mobile/chrome/";
|
||||
let testURL_02 = baseURI + "browser_formsZoom.html";
|
||||
messageManager.loadFrameScript(baseURI + "remote_formsZoom.js", true);
|
||||
|
||||
// A queue to order the tests and a handle for each test
|
||||
var gTests = [];
|
||||
var gCurrentTest = null;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Entry point (must be named "test")
|
||||
function test() {
|
||||
// The "runNextTest" approach is async, so we need to call "waitForExplicitFinish()"
|
||||
// We call "finish()" when the tests are finished
|
||||
waitForExplicitFinish();
|
||||
// Start the tests
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
function waitForPageShow(aPageURL, aCallback) {
|
||||
messageManager.addMessageListener("pageshow", function(aMessage) {
|
||||
if (aMessage.target.currentURI.spec == aPageURL) {
|
||||
messageManager.removeMessageListener("pageshow", arguments.callee);
|
||||
setTimeout(function() { aCallback(); }, 0);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Iterating tests by shifting test out one by one as runNextTest is called.
|
||||
function runNextTest() {
|
||||
// Run the next test until all tests completed
|
||||
if (gTests.length > 0) {
|
||||
gCurrentTest = gTests.shift();
|
||||
info(gCurrentTest.desc);
|
||||
setTimeout(gCurrentTest.run, 0);
|
||||
}
|
||||
else {
|
||||
// Cleanup. All tests are completed at this point
|
||||
try {
|
||||
// Add any cleanup code here
|
||||
}
|
||||
finally {
|
||||
// We must finialize the tests
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function waitForZoom(aCallback) {
|
||||
if (AnimatedZoom.isZooming()) {
|
||||
let self = this;
|
||||
window.addEventListener("AnimatedZoomEnd", function() {
|
||||
window.removeEventListener("AnimatedZoomEnd", arguments.callee, false);
|
||||
setTimeout(aCallback, 0);
|
||||
}, false);
|
||||
}
|
||||
else setTimeout(aCallback, 0);
|
||||
}
|
||||
|
||||
function isElementVisible(aElement) {
|
||||
let elementRect = Rect.fromRect(aElement.rect);
|
||||
let caretRect = Rect.fromRect(aElement.caretRect);
|
||||
|
||||
let browser = getBrowser();
|
||||
let zoomRect = Rect.fromRect(browser.getBoundingClientRect());
|
||||
let scroll = browser.getPosition();
|
||||
let browserRect = new Rect(scroll.x, scroll.y, zoomRect.width, zoomRect.height);
|
||||
|
||||
info("CanZoom: " +Browser.selectedTab.allowZoom);
|
||||
|
||||
info("Browser rect: " + browserRect + " - scale: " + browser.scale);
|
||||
info("Element rect: " + elementRect + " - caret rect: " + caretRect);
|
||||
info("Scale element rect: " + elementRect.clone().scale(browser.scale, browser.scale) + " - scale caretRect: " + caretRect.clone().scale(browser.scale, browser.scale));
|
||||
info("Resulting zoom rect: " + Browser._getZoomRectForPoint(elementRect.center().x, elementRect.y, browser.scale));
|
||||
|
||||
let isCaretSyncEnabled = Services.prefs.getBoolPref("formhelper.autozoom.caret");
|
||||
if (isCaretSyncEnabled) {
|
||||
ok(browserRect.contains(caretRect.clone().scale(browser.scale, browser.scale)), "Caret rect should be completely visible");
|
||||
}
|
||||
else {
|
||||
elementRect = elementRect.clone().scale(browser.scale, browser.scale);
|
||||
let resultRect = browserRect.intersect(elementRect);
|
||||
ok(!resultRect.isEmpty() && elementRect.x > browserRect.x && elementRect.y > browserRect.y, "Element should be partially visible");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Case: Loading a page and Zoom into textarea field with caret sync disabled
|
||||
gTests.push({
|
||||
desc: "Loading a page and Zoom into textarea field with caret sync enabled",
|
||||
elements: ["textarea-1", "textarea-2", "textarea-3", "textarea-4"],
|
||||
_currentTab: null,
|
||||
|
||||
run: function() {
|
||||
Services.prefs.setBoolPref("formhelper.autozoom.caret", false);
|
||||
gCurrentTest._currentTab = BrowserUI.newTab(testURL_01);
|
||||
|
||||
waitForPageShow(testURL_01, function() { gCurrentTest.zoomNext(); });
|
||||
},
|
||||
|
||||
zoomNext: function() {
|
||||
let id = this.elements.shift();
|
||||
if (!id) {
|
||||
BrowserUI.closeTab();
|
||||
runNextTest();
|
||||
return;
|
||||
}
|
||||
|
||||
info("Zooming to " + id);
|
||||
AsyncTests.waitFor("FormAssist:Show", { id: id }, function(json) {
|
||||
waitForZoom(function() {
|
||||
isElementVisible(json.current);
|
||||
gCurrentTest.zoomNext();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Case: Loading a page and Zoom into textarea field with caret sync enabled
|
||||
gTests.push({
|
||||
desc: "Loading a page and Zoom into textarea field with caret sync enabled",
|
||||
elements: ["textarea-1", "textarea-2", "textarea-3", "textarea-4"],
|
||||
_currentTab: null,
|
||||
|
||||
run: function() {
|
||||
Services.prefs.setBoolPref("formhelper.autozoom.caret", true);
|
||||
gCurrentTest._currentTab = BrowserUI.newTab(testURL_01);
|
||||
|
||||
waitForPageShow(testURL_01, function() { gCurrentTest.zoomNext(); });
|
||||
},
|
||||
|
||||
zoomNext: function() {
|
||||
let id = this.elements.shift();
|
||||
if (!id) {
|
||||
BrowserUI.closeTab();
|
||||
runNextTest();
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncTests.waitFor("FormAssist:Show", { id: id }, function(json) {
|
||||
waitForZoom(function() {
|
||||
isElementVisible(json.current);
|
||||
gCurrentTest.zoomNext();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Case: Loading a remote page and Zoom into textarea field with caret sync disabled
|
||||
gTests.push({
|
||||
desc: "Loading a remote page and Zoom into textarea field with caret sync disabled",
|
||||
elements: ["textarea-1", "textarea-2", "textarea-3", "textarea-4"],
|
||||
_currentTab: null,
|
||||
|
||||
run: function() {
|
||||
Services.prefs.setBoolPref("formhelper.autozoom.caret", false);
|
||||
gCurrentTest._currentTab = BrowserUI.newTab(testURL_02);
|
||||
|
||||
waitForPageShow(testURL_02, function() { gCurrentTest.zoomNext(); });
|
||||
},
|
||||
|
||||
zoomNext: function() {
|
||||
let id = this.elements.shift();
|
||||
if (!id) {
|
||||
BrowserUI.closeTab();
|
||||
runNextTest();
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncTests.waitFor("FormAssist:Show", { id: id }, function(json) {
|
||||
waitForZoom(function() {
|
||||
isElementVisible(json.current);
|
||||
gCurrentTest.zoomNext();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Case: Loading a remote page and Zoom into textarea field with caret sync enabled
|
||||
gTests.push({
|
||||
desc: "Loading a remote page and Zoom into textarea field with caret sync enabled",
|
||||
elements: ["textarea-1", "textarea-2"],
|
||||
_currentTab: null,
|
||||
|
||||
run: function() {
|
||||
Services.prefs.setBoolPref("formhelper.autozoom.caret", true);
|
||||
gCurrentTest._currentTab = BrowserUI.newTab(testURL_02);
|
||||
|
||||
waitForPageShow(testURL_02, function() { gCurrentTest.zoomNext(); });
|
||||
},
|
||||
|
||||
zoomNext: function() {
|
||||
let id = this.elements.shift();
|
||||
if (!id) {
|
||||
todo(false, "textarea-3 caret should be synced, but for some reason it is not");
|
||||
todo(false, "textarea-4 caret should be synced, but for some reason it is not");
|
||||
BrowserUI.closeTab();
|
||||
runNextTest();
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncTests.waitFor("FormAssist:Show", { id: id }, function(json) {
|
||||
waitForZoom(function() {
|
||||
isElementVisible(json.current);
|
||||
gCurrentTest.zoomNext();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -72,5 +72,8 @@ let AsyncTests = {
|
|||
};
|
||||
|
||||
let chromeRoot = getRootDirectory(gTestPath);
|
||||
messageManager.loadFrameScript(chromeRoot + "remote_head.js", true);
|
||||
// For some security reasons (which?), loading remote_head using chromeRoot
|
||||
// instead of baseURI make the browser_formsZoom.js test fails.
|
||||
let baseURI = "http://mochi.test:8888/browser/mobile/chrome/";
|
||||
messageManager.loadFrameScript(baseURI + "remote_head.js", true);
|
||||
messageManager.loadFrameScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", true);
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
dump("====================== Content Script Loaded =======================\n");
|
||||
|
||||
let assistant = Content._formAssistant;
|
||||
|
||||
AsyncTests.add("FormAssist:Show", function(aMessage, aJson) {
|
||||
let element = content.document.getElementById(aJson.id);
|
||||
assistant.open(element);
|
||||
});
|
||||
|
Загрузка…
Ссылка в новой задаче