Bug 1079728 - Ensure that the blur message is sent after removing focus. r=yxl

This commit is contained in:
Tim Chien 2014-10-21 06:57:00 -04:00
parent 03cc975d9a
commit be9563ed5b
3 changed files with 168 additions and 23 deletions

View File

@ -216,7 +216,7 @@ let FormAssistant = {
'range'
]),
isKeyboardOpened: false,
isHandlingFocus: false,
selectionStart: -1,
selectionEnd: -1,
textBeforeCursor: "",
@ -304,7 +304,7 @@ let FormAssistant = {
});
});
if (del && element === self.focusedElement) {
self.hideKeyboard();
self.unhandleFocus();
self.selectionStart = -1;
self.selectionEnd = -1;
}
@ -351,7 +351,7 @@ let FormAssistant = {
if (this._editing) {
return;
}
this.sendKeyboardState(this.focusedElement);
this.sendInputState(this.focusedElement);
},
handleEvent: function fa_handleEvent(evt) {
@ -379,13 +379,13 @@ let FormAssistant = {
}
if (isContentEditable(target)) {
this.showKeyboard(this.getTopLevelEditable(target));
this.handleFocus(this.getTopLevelEditable(target));
this.updateSelection();
break;
}
if (this.isFocusableElement(target)) {
this.showKeyboard(target);
this.handleFocus(target);
this.updateSelection();
}
break;
@ -406,14 +406,14 @@ let FormAssistant = {
case "blur":
if (this.focusedElement) {
this.hideKeyboard();
this.unhandleFocus();
this.selectionStart = -1;
this.selectionEnd = -1;
}
break;
case "resize":
if (!this.isKeyboardOpened)
if (!this.isHandlingFocus)
return;
if (this.scrollIntoViewTimeout) {
@ -672,7 +672,7 @@ let FormAssistant = {
},
showKeyboard: function fa_showKeyboard(target) {
handleFocus: function fa_handleFocus(target) {
if (this.focusedElement === target)
return;
@ -682,18 +682,17 @@ let FormAssistant = {
this.setFocusedElement(target);
let count = this._focusCounter;
this.waitForNextTick(function fa_showKeyboardSync() {
this.waitForNextTick(function fa_handleFocusSync() {
if (count !== this._focusCounter) {
return;
}
let kbOpened = this.sendKeyboardState(target);
if (this.isTextInputElement(target))
this.isKeyboardOpened = kbOpened;
let isHandlingFocus = this.sendInputState(target);
this.isHandlingFocus = isHandlingFocus;
}.bind(this));
},
hideKeyboard: function fa_hideKeyboard() {
unhandleFocus: function fa_unhandleFocus() {
this.setFocusedElement(null);
let count = this._focusCounter;
@ -701,13 +700,13 @@ let FormAssistant = {
// Wait for the next tick before unset the focused element and etc.
// If the user move from one input from another,
// the remote process should get one Forms:Input message instead of two.
this.waitForNextTick(function fa_hideKeyboardSync() {
this.waitForNextTick(function fa_unhandleFocusSync() {
if (count !== this._focusCounter ||
!this.isKeyboardOpened) {
!this.isHandlingFocus) {
return;
}
this.isKeyboardOpened = false;
this.isHandlingFocus = false;
sendAsyncMessage("Forms:Input", { "type": "blur" });
}.bind(this));
},
@ -725,12 +724,6 @@ let FormAssistant = {
!this.ignoredInputTypes.has(element.type));
},
isTextInputElement: function fa_isTextInputElement(element) {
return element instanceof HTMLInputElement ||
element instanceof HTMLTextAreaElement ||
isContentEditable(element);
},
getTopLevelEditable: function fa_getTopLevelEditable(element) {
function retrieveTopLevelEditable(element) {
while (element && !isContentEditable(element))
@ -742,7 +735,7 @@ let FormAssistant = {
return retrieveTopLevelEditable(element) || element;
},
sendKeyboardState: function(element) {
sendInputState: function(element) {
// FIXME/bug 729623: work around apparent bug in the IME manager
// in gecko.
let readonly = element.getAttribute("readonly");

View File

@ -24,3 +24,4 @@ support-files =
[test_delete_focused_element.html]
[test_sendkey_cancel.html]
[test_two_inputs.html]
[test_two_selects.html]

View File

@ -0,0 +1,151 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1079728
-->
<head>
<title>Test switching between two inputs</title>
<script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1079728">Mozilla Bug 1079728</a>
<p id="display"></p>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
inputmethod_setup(function() {
runTest();
});
let appFrameScript = function appFrameScript() {
let select1 = content.document.body.firstElementChild;
let select2 = content.document.body.children[1];
let i = 1;
select1.focus();
addMessageListener('test:next', function() {
i++;
switch (i) {
case 2:
select2.focus();
break;
case 3:
select2.blur();
select2.focus();
break;
case 4:
select2.blur();
break;
case 5:
select2.focus();
select2.blur();
select1.focus();
break;
case 6:
select1.blur();
break;
}
});
};
function runTest() {
let im = navigator.mozInputMethod;
let i = 0;
im.oninputcontextchange = function(evt) {
var inputcontext = navigator.mozInputMethod.inputcontext;
i++;
switch (i) {
// focus on the first input receives the first input context.
case 1:
ok(!!inputcontext, 'Receving the first input context');
is(inputcontext.textAfterCursor, 'First');
mm.sendAsyncMessage('test:next');
break;
// focus on the second input (implicitly blur the first input)
// results the second input context.
case 2:
ok(!!inputcontext, 'Receving the second input context');
is(inputcontext.textAfterCursor, 'Second');
mm.sendAsyncMessage('test:next');
break;
// blur and re-focus on the second input results updated
// input context for the second input.
case 3:
ok(!!inputcontext, 'Receving the second input context');
is(inputcontext.textAfterCursor, 'Second');
mm.sendAsyncMessage('test:next');
break;
// blur on the second input results null input context
case 4:
is(inputcontext, null, 'Receving null inputcontext');
mm.sendAsyncMessage('test:next');
break;
// focus and blur on the second input sends no message;
// focus on the first input receives the first input context.
case 5:
ok(!!inputcontext, 'Receving the first input context');
is(inputcontext.textAfterCursor, 'First');
mm.sendAsyncMessage('test:next');
break;
// blur on the first input results null input context
case 6:
is(inputcontext, null, 'Receving null inputcontext');
inputmethod_cleanup();
break;
default:
ok(false, 'Receving extra inputcontextchange calls');
inputmethod_cleanup();
break;
}
};
// Set current page as an input method.
SpecialPowers.wrap(im).setActive(true);
let iframe = document.createElement('iframe');
iframe.src = 'data:text/html,<html><body><select><option>First</option></select><select><option>Second</option></select></html>';
iframe.setAttribute('mozbrowser', true);
document.body.appendChild(iframe);
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
iframe.addEventListener('mozbrowserloadend', function() {
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
});
}
</script>
</pre>
</body>
</html>