Bug 1162360 - Dispatches focus and blur message synchronously, r=yxl

This commit is contained in:
Tim Chien 2015-05-21 20:13:00 +02:00
Родитель da2704a55c
Коммит 7a032efd9b
7 изменённых файлов: 151 добавлений и 143 удалений

Просмотреть файл

@ -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;