зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1162360 - Dispatches focus and blur message synchronously, r=yxl
This commit is contained in:
Родитель
da2704a55c
Коммит
7a032efd9b
|
@ -18,10 +18,6 @@ XPCOMUtils.defineLazyServiceGetter(Services, "fm",
|
|||
"@mozilla.org/focus-manager;1",
|
||||
"nsIFocusManager");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(Services, "threadManager",
|
||||
"@mozilla.org/thread-manager;1",
|
||||
"nsIThreadManager");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "domWindowUtils", function () {
|
||||
return content.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
|
@ -461,13 +457,6 @@ let FormAssistant = {
|
|||
}
|
||||
},
|
||||
|
||||
waitForNextTick: function(callback) {
|
||||
var tm = Services.threadManager;
|
||||
tm.mainThread.dispatch({
|
||||
run: callback,
|
||||
}, Components.interfaces.nsIThread.DISPATCH_NORMAL);
|
||||
},
|
||||
|
||||
receiveMessage: function fa_receiveMessage(msg) {
|
||||
let target = this.focusedElement;
|
||||
let json = msg.json;
|
||||
|
@ -682,35 +671,13 @@ let FormAssistant = {
|
|||
target = target.parentNode;
|
||||
|
||||
this.setFocusedElement(target);
|
||||
|
||||
let count = this._focusCounter;
|
||||
this.waitForNextTick(function fa_handleFocusSync() {
|
||||
if (count !== this._focusCounter) {
|
||||
return;
|
||||
}
|
||||
|
||||
let isHandlingFocus = this.sendInputState(target);
|
||||
this.isHandlingFocus = isHandlingFocus;
|
||||
}.bind(this));
|
||||
this.isHandlingFocus = this.sendInputState(target);
|
||||
},
|
||||
|
||||
unhandleFocus: function fa_unhandleFocus() {
|
||||
this.setFocusedElement(null);
|
||||
|
||||
let count = this._focusCounter;
|
||||
|
||||
// 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_unhandleFocusSync() {
|
||||
if (count !== this._focusCounter ||
|
||||
!this.isHandlingFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isHandlingFocus = false;
|
||||
sendAsyncMessage("Forms:Input", { "type": "blur" });
|
||||
}.bind(this));
|
||||
this.isHandlingFocus = false;
|
||||
sendAsyncMessage("Forms:Input", { "type": "blur" });
|
||||
},
|
||||
|
||||
isFocusableElement: function fa_isFocusableElement(element) {
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<div id="text" contenteditable>Jan Jongboom</div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
var t = document.querySelector('#text');
|
||||
|
||||
t.focus();
|
||||
var range = document.createRange();
|
||||
range.selectNodeContents(t);
|
||||
range.collapse(false);
|
||||
var selection = window.getSelection();
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -6,7 +6,6 @@ support-files =
|
|||
file_inputmethod.html
|
||||
file_inputmethod_1043828.html
|
||||
file_test_app.html
|
||||
file_test_contenteditable.html
|
||||
file_test_sendkey_cancel.html
|
||||
file_test_sms_app.html
|
||||
file_test_sms_app_1066515.html
|
||||
|
|
|
@ -20,8 +20,20 @@ inputmethod_setup(function() {
|
|||
|
||||
// The frame script running in the file
|
||||
function appFrameScript() {
|
||||
let document = content.document;
|
||||
let window = content.document.defaultView;
|
||||
|
||||
let t = document.getElementById('text');
|
||||
t.focus();
|
||||
|
||||
let range = document.createRange();
|
||||
range.selectNodeContents(t);
|
||||
range.collapse(false);
|
||||
let selection = window.getSelection();
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
|
||||
addMessageListener('test:InputMethod:clear', function() {
|
||||
var t = content.document.getElementById('text');
|
||||
t.innerHTML = '';
|
||||
});
|
||||
}
|
||||
|
@ -34,18 +46,26 @@ function runTest() {
|
|||
|
||||
// Create an app frame to recieve keyboard inputs.
|
||||
let app = document.createElement('iframe');
|
||||
app.src = 'file_test_contenteditable.html';
|
||||
app.src = 'data:text/html,<html><body><div id="text" contenteditable>Jan Jongboom</div></html>';
|
||||
app.setAttribute('mozbrowser', true);
|
||||
document.body.appendChild(app);
|
||||
app.addEventListener('mozbrowserloadend', function() {
|
||||
let mm = SpecialPowers.getBrowserFrameMessageManager(app);
|
||||
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
|
||||
|
||||
im.oninputcontextchange = function() {
|
||||
if (im.inputcontext) {
|
||||
im.oninputcontextchange = null;
|
||||
register();
|
||||
}
|
||||
};
|
||||
|
||||
function register() {
|
||||
im.inputcontext.onselectionchange = function() {
|
||||
im.inputcontext.onselectionchange = null;
|
||||
|
||||
is(im.inputcontext.textBeforeCursor, '', 'textBeforeCursor');
|
||||
is(im.inputcontext.textBeforeCursor, '', 'textAfterCursor');
|
||||
is(im.inputcontext.textAfterCursor, '', 'textAfterCursor');
|
||||
is(im.inputcontext.selectionStart, 0, 'selectionStart');
|
||||
is(im.inputcontext.selectionEnd, 0, 'selectionEnd');
|
||||
|
||||
|
@ -54,20 +74,6 @@ function runTest() {
|
|||
|
||||
mm.sendAsyncMessage('test:InputMethod:clear');
|
||||
}
|
||||
|
||||
if (im.inputcontext) {
|
||||
register();
|
||||
}
|
||||
else {
|
||||
im.oninputcontextchange = function() {
|
||||
if (im.inputcontext) {
|
||||
im.oninputcontextchange = null;
|
||||
register();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mm.loadFrameScript('data:,(' + appFrameScript.toString() + ')();', false);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -25,10 +25,6 @@ let appFrameScript = function appFrameScript() {
|
|||
input.focus();
|
||||
input.value = 'First1';
|
||||
input.blur();
|
||||
|
||||
content.setTimeout(function() {
|
||||
sendAsyncMessage('test:next', {});
|
||||
});
|
||||
};
|
||||
|
||||
function runTest() {
|
||||
|
@ -36,7 +32,32 @@ function runTest() {
|
|||
|
||||
let i = 0;
|
||||
im.oninputcontextchange = function() {
|
||||
ok(false, 'Should not receive any inputcontextchange events.');
|
||||
let inputcontext = im.inputcontext;
|
||||
i++;
|
||||
switch (i) {
|
||||
case 1:
|
||||
ok(!!inputcontext, 'Should receive inputcontext from focus().');
|
||||
is(inputcontext.textAfterCursor, 'First');
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
ok(!!inputcontext, 'Should receive inputcontext from value change.');
|
||||
is(inputcontext.textBeforeCursor, 'First1');
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
ok(!inputcontext, 'Should lost inputcontext from blur().');
|
||||
|
||||
inputmethod_cleanup();
|
||||
break;
|
||||
|
||||
default:
|
||||
ok(false, 'Unknown event count.');
|
||||
|
||||
inputmethod_cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
// Set current page as an input method.
|
||||
|
@ -48,11 +69,6 @@ function runTest() {
|
|||
document.body.appendChild(iframe);
|
||||
|
||||
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
|
||||
mm.addMessageListener('test:next', function() {
|
||||
ok(true, '\\o/');
|
||||
inputmethod_cleanup();
|
||||
});
|
||||
|
||||
iframe.addEventListener('mozbrowserloadend', function() {
|
||||
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
|
||||
});
|
||||
|
|
|
@ -34,12 +34,7 @@ let appFrameScript = function appFrameScript() {
|
|||
switch (i) {
|
||||
case 2:
|
||||
input2.focus();
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
input2.blur();
|
||||
input2.focus();
|
||||
i++; // keep the same count with the parent frame.
|
||||
|
||||
break;
|
||||
|
||||
|
@ -50,23 +45,26 @@ let appFrameScript = function appFrameScript() {
|
|||
|
||||
case 5:
|
||||
input2.focus();
|
||||
input2.blur();
|
||||
|
||||
input1.focus();
|
||||
|
||||
break;
|
||||
|
||||
case 6:
|
||||
content.document.body.removeChild(input1);
|
||||
|
||||
break;
|
||||
|
||||
case 7:
|
||||
input2.focus();
|
||||
input1.focus();
|
||||
i++; // keep the same count with the parent frame.
|
||||
|
||||
break;
|
||||
|
||||
case 8:
|
||||
content.document.body.removeChild(input1);
|
||||
|
||||
break;
|
||||
|
||||
case 9:
|
||||
input2.focus();
|
||||
|
||||
break;
|
||||
|
||||
case 10:
|
||||
content.document.body.removeChild(input2);
|
||||
|
||||
break;
|
||||
|
@ -85,26 +83,21 @@ function runTest() {
|
|||
switch (i) {
|
||||
// focus on the first input receives the first input context.
|
||||
case 1:
|
||||
ok(!!inputcontext, 'Receving the first input context');
|
||||
ok(!!inputcontext, '1) 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.
|
||||
// focus on the second input should implicitly blur the first input
|
||||
case 2:
|
||||
ok(!!inputcontext, 'Receving the second input context');
|
||||
is(inputcontext.textAfterCursor, 'Second');
|
||||
is(inputcontext, null, '2) Receving null inputcontext');
|
||||
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
break;
|
||||
|
||||
// blur and re-focus on the second input results updated
|
||||
// input context for the second input.
|
||||
// ... and results the second input context.
|
||||
case 3:
|
||||
ok(!!inputcontext, 'Receving the second input context');
|
||||
ok(!!inputcontext, '3) Receving the second input context');
|
||||
is(inputcontext.textAfterCursor, 'Second');
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
|
@ -112,38 +105,51 @@ function runTest() {
|
|||
|
||||
// blur on the second input results null input context
|
||||
case 4:
|
||||
is(inputcontext, null, 'Receving null inputcontext');
|
||||
is(inputcontext, null, '4) 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.
|
||||
// focus on the second input receives the second input context.
|
||||
case 5:
|
||||
ok(!!inputcontext, 'Receving the first input context');
|
||||
ok(!!inputcontext, '5) Receving the second input context');
|
||||
is(inputcontext.textAfterCursor, 'Second');
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
break;
|
||||
|
||||
// focus on the second input should implicitly blur the first input
|
||||
case 6:
|
||||
is(inputcontext, null, '6) Receving null inputcontext');
|
||||
|
||||
break;
|
||||
|
||||
// ... and results the second input context.
|
||||
case 7:
|
||||
ok(!!inputcontext, '7) Receving the first input context');
|
||||
is(inputcontext.textAfterCursor, 'First');
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
break;
|
||||
|
||||
// remove on the first focused input results null input context
|
||||
case 6:
|
||||
is(inputcontext, null, 'Receving null inputcontext');
|
||||
case 8:
|
||||
is(inputcontext, null, '8) Receving null inputcontext');
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
break;
|
||||
|
||||
// input context for the second input.
|
||||
case 7:
|
||||
ok(!!inputcontext, 'Receving the second input context');
|
||||
case 9:
|
||||
ok(!!inputcontext, '9) Receving the second input context');
|
||||
is(inputcontext.textAfterCursor, 'Second');
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
break;
|
||||
|
||||
// remove on the second focused input results null input context
|
||||
case 8:
|
||||
is(inputcontext, null, 'Receving null inputcontext');
|
||||
case 10:
|
||||
is(inputcontext, null, '10) Receving null inputcontext');
|
||||
|
||||
inputmethod_cleanup();
|
||||
break;
|
||||
|
|
|
@ -32,12 +32,7 @@ let appFrameScript = function appFrameScript() {
|
|||
switch (i) {
|
||||
case 2:
|
||||
select2.focus();
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
select2.blur();
|
||||
select2.focus();
|
||||
i++; // keep the same count with the parent frame.
|
||||
|
||||
break;
|
||||
|
||||
|
@ -48,14 +43,27 @@ let appFrameScript = function appFrameScript() {
|
|||
|
||||
case 5:
|
||||
select2.focus();
|
||||
select2.blur();
|
||||
|
||||
select1.focus();
|
||||
|
||||
break;
|
||||
|
||||
case 6:
|
||||
select1.blur();
|
||||
select1.focus();
|
||||
i++; // keep the same count with the parent frame.
|
||||
|
||||
break;
|
||||
|
||||
case 8:
|
||||
content.document.body.removeChild(select1);
|
||||
|
||||
break;
|
||||
|
||||
case 9:
|
||||
select2.focus();
|
||||
|
||||
break;
|
||||
|
||||
case 10:
|
||||
content.document.body.removeChild(select2);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -73,26 +81,21 @@ function runTest() {
|
|||
switch (i) {
|
||||
// focus on the first input receives the first input context.
|
||||
case 1:
|
||||
ok(!!inputcontext, 'Receving the first input context');
|
||||
ok(!!inputcontext, '1) 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.
|
||||
// focus on the second input should implicitly blur the first input
|
||||
case 2:
|
||||
ok(!!inputcontext, 'Receving the second input context');
|
||||
is(inputcontext.textAfterCursor, 'Second');
|
||||
is(inputcontext, null, '2) Receving null inputcontext');
|
||||
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
break;
|
||||
|
||||
// blur and re-focus on the second input results updated
|
||||
// input context for the second input.
|
||||
// ... and results the second input context.
|
||||
case 3:
|
||||
ok(!!inputcontext, 'Receving the second input context');
|
||||
ok(!!inputcontext, '3) Receving the second input context');
|
||||
is(inputcontext.textAfterCursor, 'Second');
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
|
@ -100,23 +103,51 @@ function runTest() {
|
|||
|
||||
// blur on the second input results null input context
|
||||
case 4:
|
||||
is(inputcontext, null, 'Receving null inputcontext');
|
||||
is(inputcontext, null, '4) 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.
|
||||
// focus on the second input receives the second input context.
|
||||
case 5:
|
||||
ok(!!inputcontext, 'Receving the first input context');
|
||||
ok(!!inputcontext, '5) Receving the second input context');
|
||||
is(inputcontext.textAfterCursor, 'Second');
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
break;
|
||||
|
||||
// focus on the second input should implicitly blur the first input
|
||||
case 6:
|
||||
is(inputcontext, null, '6) Receving null inputcontext');
|
||||
|
||||
break;
|
||||
|
||||
// ... and results the second input context.
|
||||
case 7:
|
||||
ok(!!inputcontext, '7) 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');
|
||||
// remove on the first focused input results null input context
|
||||
case 8:
|
||||
is(inputcontext, null, '8) Receving null inputcontext');
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
break;
|
||||
|
||||
// input context for the second input.
|
||||
case 9:
|
||||
ok(!!inputcontext, '9) Receving the second input context');
|
||||
is(inputcontext.textAfterCursor, 'Second');
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
break;
|
||||
|
||||
// remove on the second focused input results null input context
|
||||
case 10:
|
||||
is(inputcontext, null, '10) Receving null inputcontext');
|
||||
|
||||
inputmethod_cleanup();
|
||||
break;
|
||||
|
|
Загрузка…
Ссылка в новой задаче