зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1079728 - Ensure that the blur message is sent after removing focus. r=yxl
This commit is contained in:
Родитель
03cc975d9a
Коммит
be9563ed5b
|
@ -216,7 +216,7 @@ let FormAssistant = {
|
||||||
'range'
|
'range'
|
||||||
]),
|
]),
|
||||||
|
|
||||||
isKeyboardOpened: false,
|
isHandlingFocus: false,
|
||||||
selectionStart: -1,
|
selectionStart: -1,
|
||||||
selectionEnd: -1,
|
selectionEnd: -1,
|
||||||
textBeforeCursor: "",
|
textBeforeCursor: "",
|
||||||
|
@ -304,7 +304,7 @@ let FormAssistant = {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if (del && element === self.focusedElement) {
|
if (del && element === self.focusedElement) {
|
||||||
self.hideKeyboard();
|
self.unhandleFocus();
|
||||||
self.selectionStart = -1;
|
self.selectionStart = -1;
|
||||||
self.selectionEnd = -1;
|
self.selectionEnd = -1;
|
||||||
}
|
}
|
||||||
|
@ -351,7 +351,7 @@ let FormAssistant = {
|
||||||
if (this._editing) {
|
if (this._editing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.sendKeyboardState(this.focusedElement);
|
this.sendInputState(this.focusedElement);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleEvent: function fa_handleEvent(evt) {
|
handleEvent: function fa_handleEvent(evt) {
|
||||||
|
@ -379,13 +379,13 @@ let FormAssistant = {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isContentEditable(target)) {
|
if (isContentEditable(target)) {
|
||||||
this.showKeyboard(this.getTopLevelEditable(target));
|
this.handleFocus(this.getTopLevelEditable(target));
|
||||||
this.updateSelection();
|
this.updateSelection();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isFocusableElement(target)) {
|
if (this.isFocusableElement(target)) {
|
||||||
this.showKeyboard(target);
|
this.handleFocus(target);
|
||||||
this.updateSelection();
|
this.updateSelection();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -406,14 +406,14 @@ let FormAssistant = {
|
||||||
|
|
||||||
case "blur":
|
case "blur":
|
||||||
if (this.focusedElement) {
|
if (this.focusedElement) {
|
||||||
this.hideKeyboard();
|
this.unhandleFocus();
|
||||||
this.selectionStart = -1;
|
this.selectionStart = -1;
|
||||||
this.selectionEnd = -1;
|
this.selectionEnd = -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "resize":
|
case "resize":
|
||||||
if (!this.isKeyboardOpened)
|
if (!this.isHandlingFocus)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (this.scrollIntoViewTimeout) {
|
if (this.scrollIntoViewTimeout) {
|
||||||
|
@ -672,7 +672,7 @@ let FormAssistant = {
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
showKeyboard: function fa_showKeyboard(target) {
|
handleFocus: function fa_handleFocus(target) {
|
||||||
if (this.focusedElement === target)
|
if (this.focusedElement === target)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -682,18 +682,17 @@ let FormAssistant = {
|
||||||
this.setFocusedElement(target);
|
this.setFocusedElement(target);
|
||||||
|
|
||||||
let count = this._focusCounter;
|
let count = this._focusCounter;
|
||||||
this.waitForNextTick(function fa_showKeyboardSync() {
|
this.waitForNextTick(function fa_handleFocusSync() {
|
||||||
if (count !== this._focusCounter) {
|
if (count !== this._focusCounter) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let kbOpened = this.sendKeyboardState(target);
|
let isHandlingFocus = this.sendInputState(target);
|
||||||
if (this.isTextInputElement(target))
|
this.isHandlingFocus = isHandlingFocus;
|
||||||
this.isKeyboardOpened = kbOpened;
|
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
hideKeyboard: function fa_hideKeyboard() {
|
unhandleFocus: function fa_unhandleFocus() {
|
||||||
this.setFocusedElement(null);
|
this.setFocusedElement(null);
|
||||||
|
|
||||||
let count = this._focusCounter;
|
let count = this._focusCounter;
|
||||||
|
@ -701,13 +700,13 @@ let FormAssistant = {
|
||||||
// Wait for the next tick before unset the focused element and etc.
|
// Wait for the next tick before unset the focused element and etc.
|
||||||
// If the user move from one input from another,
|
// If the user move from one input from another,
|
||||||
// the remote process should get one Forms:Input message instead of two.
|
// 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 ||
|
if (count !== this._focusCounter ||
|
||||||
!this.isKeyboardOpened) {
|
!this.isHandlingFocus) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isKeyboardOpened = false;
|
this.isHandlingFocus = false;
|
||||||
sendAsyncMessage("Forms:Input", { "type": "blur" });
|
sendAsyncMessage("Forms:Input", { "type": "blur" });
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
|
@ -725,12 +724,6 @@ let FormAssistant = {
|
||||||
!this.ignoredInputTypes.has(element.type));
|
!this.ignoredInputTypes.has(element.type));
|
||||||
},
|
},
|
||||||
|
|
||||||
isTextInputElement: function fa_isTextInputElement(element) {
|
|
||||||
return element instanceof HTMLInputElement ||
|
|
||||||
element instanceof HTMLTextAreaElement ||
|
|
||||||
isContentEditable(element);
|
|
||||||
},
|
|
||||||
|
|
||||||
getTopLevelEditable: function fa_getTopLevelEditable(element) {
|
getTopLevelEditable: function fa_getTopLevelEditable(element) {
|
||||||
function retrieveTopLevelEditable(element) {
|
function retrieveTopLevelEditable(element) {
|
||||||
while (element && !isContentEditable(element))
|
while (element && !isContentEditable(element))
|
||||||
|
@ -742,7 +735,7 @@ let FormAssistant = {
|
||||||
return retrieveTopLevelEditable(element) || element;
|
return retrieveTopLevelEditable(element) || element;
|
||||||
},
|
},
|
||||||
|
|
||||||
sendKeyboardState: function(element) {
|
sendInputState: function(element) {
|
||||||
// FIXME/bug 729623: work around apparent bug in the IME manager
|
// FIXME/bug 729623: work around apparent bug in the IME manager
|
||||||
// in gecko.
|
// in gecko.
|
||||||
let readonly = element.getAttribute("readonly");
|
let readonly = element.getAttribute("readonly");
|
||||||
|
|
|
@ -24,3 +24,4 @@ support-files =
|
||||||
[test_delete_focused_element.html]
|
[test_delete_focused_element.html]
|
||||||
[test_sendkey_cancel.html]
|
[test_sendkey_cancel.html]
|
||||||
[test_two_inputs.html]
|
[test_two_inputs.html]
|
||||||
|
[test_two_selects.html]
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче