const fm = SpecialPowers.Services.focus;
// XXX using selCon for checking the visibility of the caret, however,
// selCon is shared in document, cannot get the element of owner of the
// caret from javascript?
const selCon = SpecialPowers.wrap(window).docShell.
QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor).
getInterface(SpecialPowers.Ci.nsISelectionDisplay).
QueryInterface(SpecialPowers.Ci.nsISelectionController);
(function test_initial_state_on_load() {
is(
getSelection().rangeCount,
0, "There should be no selection range at start"
);
ok(!selCon.caretVisible, "The caret should not be visible in the document");
// Move focus to <input type="text"> in the primary editor
primaryEditor.querySelector("input[type=text]").focus();
is(
SpecialPowers.unwrap(fm.focusedElement),
primaryEditor.querySelector("input[type=text]"), ' in the primary editor should get focus'
);
todo_is(
getSelection().rangeCount,
0, 'There should be no selection range after calling focus() of in the primary editor'
);
ok(
selCon.caretVisible, 'The caret should not be visible in the in the primary editor'
);
})();
// Move focus to the editor
(function test_move_focus_from_child_input_to_parent_editor() {
primaryEditor.focus();
is(
SpecialPowers.unwrap(fm.focusedElement),
primaryEditor,
`The editor should steal focus from <input type="text"> in the primary editor with calling its focus() (got ${
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
}`
);
is(
getSelection().rangeCount,
1, "There should be one range after focus() of the editor is called"
);
const range = getSelection().getRangeAt(0);
ok(
range.collapsed, "The selection range should be collapsed (immediately after calling focus() of the editor)"
);
is(
range.startContainer,
primaryEditor.firstChild,
`The selection range should be in the first text node of the editor (immediately after calling focus() of the editor, got ${
getNodeDescription(range.startContainer)
})`
);
ok(
selCon.caretVisible, "The caret should be visible in the primary editor (immediately after calling focus() of the editor)"
);
})();
// Move focus to other editor
(function test_move_focus_from_editor_to_the_other_editor() {
otherEditor.focus();
is(
SpecialPowers.unwrap(fm.focusedElement),
otherEditor,
`The other editor should steal focus from the editor (got ${
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
}`
);
is(
getSelection().rangeCount,
1, "There should be one range after focus() of the other editor is called"
);
const range = getSelection().getRangeAt(0);
ok(
range.collapsed, "The selection range should be collapsed (immediately after calling focus() of the other editor)"
);
is(
range.startContainer,
otherEditor.firstChild,
`The selection range should be in the first text node of the editor (immediately after calling focus() of the other editor, got ${
getNodeDescription(range.startContainer)
})`
);
ok(
selCon.caretVisible, "The caret should be visible in the primary editor (immediately after calling focus() of the other editor)"
);
})();
// Move focus to <input type="text"> in the primary editor
(function test_move_focus_from_the_other_editor_to_input_in_the_editor() {
primaryEditor.querySelector("input[type=text]").focus();
is(
SpecialPowers.unwrap(fm.focusedElement),
primaryEditor.querySelector("input[type=text]"),
`<input type="text"> in the primary editor should steal focus from the other editor (got ${
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
}`);
is(
getSelection().rangeCount,
1, 'There should be one range after focus() of the in the primary editor is called'
);
const range = getSelection().getRangeAt(0);
ok(
range.collapsed, 'The selection range should be collapsed (immediately after calling focus() of the in the primary editor)'
);
// XXX maybe, the caret can stay on the other editor if it's better.
is(
range.startContainer,
primaryEditor.firstChild,
`The selection range should be in the first text node of the editor (immediately after calling focus() of the <input type="text"> in the primary editor, got ${
getNodeDescription(range.startContainer)
})`
);
ok(
selCon.caretVisible, 'The caret should be visible in the (immediately after calling focus() of the in the primary editor)'
);
})();
// Move focus to the other editor again
(function test_move_focus_from_the_other_editor_to_the_editor_with_Selection_API() {
otherEditor.focus();
is(
SpecialPowers.unwrap(fm.focusedElement),
otherEditor,
`The other editor should steal focus from the <input type="text"> in the primary editor with its focus() (got ${
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
})`
);
// Set selection to the span element in the primary editor.
getSelection().collapse(spanInEditor.firstChild, 5);
is(
getSelection().rangeCount,
1, "There should be one selection range after collapsing selection into the in the primary editor when the other editor has focus"
);
is(
SpecialPowers.unwrap(fm.focusedElement),
primaryEditor,
`The editor should steal focus from the other editor with Selection API (got ${
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
}`
);
ok(
selCon.caretVisible, "The caret should be visible in the primary editor (immediately after moving focus with Selection API)"
);
})();
// Move focus to the editor
(function test_move_focus() {
primaryEditor.focus();
is(
SpecialPowers.unwrap(fm.focusedElement),
primaryEditor, "The editor should keep having focus (immediately after calling focus() of the editor when it has focus)"
);
is(
getSelection().rangeCount,
1, "There should be one selection range in the primary editor (immediately after calling focus() of the editor when it has focus)"
);
const range = getSelection().getRangeAt(0);
ok(
range.collapsed, "The selection range should be collapsed in the primary editor (immediately after calling focus() of the editor when it has focus)"
);
is(
range.startOffset,
5, "The startOffset of the selection range shouldn't be changed (immediately after calling focus() of the editor when it has focus)"
);
is(
range.startContainer.parentNode,
spanInEditor,
`The startContainer of the selection range shouldn't be changed (immediately after calling focus() of the editor when it has focus, got ${
getNodeDescription(range.startContainer)
})`);
ok(
selCon.caretVisible, "The caret should be visible in the primary editor (immediately after calling focus() of the editor when it has focus)"
);
})();
// Move focus to each focusable element in the primary editor.
function test_move_focus_from_the_editor(aTargetElement, aFocusable, aCaretVisible) {
primaryEditor.focus();
is(
SpecialPowers.unwrap(fm.focusedElement),
primaryEditor,
`The editor should have focus at preparing to move focus to ${
getNodeDescription(aTargetElement)
} (got ${
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
}`);
aTargetElement.focus();
if (aFocusable) {
is(
SpecialPowers.unwrap(fm.focusedElement),
aTargetElement,
`${
getNodeDescription(aTargetElement)
} should get focus with calling its focus() (got ${
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
}`
);
} else {
is(
SpecialPowers.unwrap(fm.focusedElement),
primaryEditor,
`${
getNodeDescription(aTargetElement)
} should not take focus with calling its focus() (got ${
getNodeDescription(SpecialPowers.unwrap(fm.focusedElement))
}`
);
}
is(
selCon.caretVisible,
aCaretVisible,
`The caret ${
aCaretVisible ? "should" : "should not"
} visible after calling focus() of ${
getNodeDescription(aTargetElement)
}`
);
}
test_move_focus_from_the_editor(primaryEditor.querySelector("input[type=text]"), true, true);
test_move_focus_from_the_editor(primaryEditor.querySelector("input[type=text][readonly]"), true, true);
// XXX shouldn't the caret become invisible?
test_move_focus_from_the_editor(primaryEditor.querySelector("input[type=button]"), true, true);
test_move_focus_from_the_editor(primaryEditor.querySelector("button"), true, true);
test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false]"), false, true);
test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > span"), false, true);
test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > input[type=text]"), true, true);
test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > input[type=text][readonly]"), true, true);
test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > input[type=button]"), true, false);
test_move_focus_from_the_editor(primaryEditor.querySelector("div[contenteditable=false] > button"), true, false);
test_move_focus_from_the_editor(spanInEditor, false, true);
test_move_focus_from_the_editor(document.querySelector("input[type=text]"), true, true);
test_move_focus_from_the_editor(document.querySelector("input[type=text][readonly]"), true, true);
test_move_focus_from_the_editor(document.querySelector("input[type=button]"), true, false);
test_move_focus_from_the_editor(document.querySelector("button"), true, false);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.