Bug 1731005 - HTMLEditor::GetActiveEditingHost() does not return editing host if selection is collapsed in `<input>` r=m_kato

If we flush pending notifications before calling `execCommand` in
`insert-*-in-void-element.tentative.html`, `HTMLEditor` does not work because
`GetActiveEditingHost()` returns `nullptr`.  This is wrong because `Selection`
cannot cross native anonymous subtree boundaries and the selection collapsed in
`<input>` element is valid.  Therefore, it should not check whether the content
has independent selection or not.

Differential Revision: https://phabricator.services.mozilla.com/D125791
This commit is contained in:
Masayuki Nakano 2021-09-17 00:57:22 +00:00
Родитель fe3e424e83
Коммит f7705eac76
4 изменённых файлов: 97 добавлений и 4 удалений

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

@ -5845,12 +5845,14 @@ Element* HTMLEditor::GetActiveEditingHost(
}
nsIContent* content = focusNode->AsContent();
// If the active content isn't editable, or it has independent selection,
// we're not active.
if (!content->HasFlag(NODE_IS_EDITABLE) ||
content->HasIndependentSelection()) {
// If the active content isn't editable, we're not active.
if (!content->HasFlag(NODE_IS_EDITABLE)) {
return nullptr;
}
// Note that `Selection` shouldn't be in the native anonymous subtree of
// <input>/<textarea>, but can be in them (e.g., collapsed at {<input> - 0}).
// Even in such case, we need to look for an ancestor which does not have
// editable parent.
Element* candidateEditingHost = content->GetEditingHost();
if (!candidateEditingHost) {
return nullptr;

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

@ -2,6 +2,9 @@
[Inserting paragraph when selection is collapsed in <hr> in <div> which is only child]
expected: FAIL
[Inserting paragraph when selection is collapsed in <hr> in <div> which is only child (explicitly flushes maybe pending layout)]
expected: FAIL
[Inserting paragraph when selection is collapsed in <hr> which follows a text node in <div>]
expected: FAIL
@ -11,12 +14,18 @@
[Inserting paragraph when selection is collapsed in <embed> in <h1> which is only child]
expected: FAIL
[Inserting paragraph when selection is collapsed in <embed> in <h1> which is only child (explicitly flushes maybe pending layout)]
expected: FAIL
[Inserting paragraph when selection is collapsed in <embed> which follows a text node in <h1>]
expected: FAIL
[Inserting paragraph when selection is collapsed in <hr> in <h1> which is only child]
expected: FAIL
[Inserting paragraph when selection is collapsed in <hr> in <h1> which is only child (explicitly flushes maybe pending layout)]
expected: FAIL
[Inserting paragraph when selection is collapsed in <hr> which follows a text node in <h1>]
expected: FAIL
@ -26,15 +35,24 @@
[Inserting paragraph when selection is collapsed in <wbr> in <h1> which is only child]
expected: FAIL
[Inserting paragraph when selection is collapsed in <wbr> in <h1> which is only child (explicitly flushes maybe pending layout)]
expected: FAIL
[Inserting paragraph when selection is collapsed in <wbr> which follows a text node in <h1>]
expected: FAIL
[Inserting paragraph when selection is collapsed in <br> in <li> which is only child]
expected: FAIL
[Inserting paragraph when selection is collapsed in <br> in <li> which is only child (explicitly flushes maybe pending layout)]
expected: FAIL
[Inserting paragraph when selection is collapsed in <hr> in <li> which is only child]
expected: FAIL
[Inserting paragraph when selection is collapsed in <hr> in <li> which is only child (explicitly flushes maybe pending layout)]
expected: FAIL
[Inserting paragraph when selection is collapsed in <hr> which follows a text node in <li>]
expected: FAIL

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

@ -89,6 +89,49 @@ for (const container of ["div", "h1", "li"]) {
}
}, `Inserting paragraph when selection is collapsed in <${tag}> in <${container}> which is only child`);
test(() => {
editor.innerHTML = `${openTagOfContainer}<${tag}>${closeTagOfContainer}`;
const element = editor.querySelector(tag);
editor.focus();
const selection = getSelection();
selection.collapse(element, 0);
element.getBoundingClientRect();
document.execCommand("insertParagraph");
if (tag == "br") {
if (!visibleTag && container == "h1") {
assert_in_array(
editor.innerHTML,
`${openTagOfContainer}<br>${closeTagOfContainer}<div><br></div>`,
`The paragraph should be inserted before the <${tag}> element`
);
} else {
assert_in_array(
editor.innerHTML,
`${openTagOfContainer}<br>${closeAndOpenTagsOfSplitPoint}<br>${closeTagOfContainer}`,
`The paragraph should be inserted before the <${tag}> element`
);
}
} else if (!visibleTag && container == "h1") {
assert_in_array(
editor.innerHTML,
[
`${openTagOfContainer}<br>${closeTagOfContainer}<div><${tag}></div>`,
`${openTagOfContainer}<br>${closeTagOfContainer}<div><${tag}><br></div>`,
],
`The paragraph should be inserted before the <${tag}> element`
);
} else {
assert_in_array(
editor.innerHTML,
[
`${openTagOfContainer}<br>${closeAndOpenTagsOfSplitPoint}<${tag}>${closeTagOfContainer}`,
`${openTagOfContainer}<br>${closeAndOpenTagsOfSplitPoint}<${tag}><br>${closeTagOfContainer}`,
],
`The paragraph should be inserted before the <${tag}> element`
);
}
}, `Inserting paragraph when selection is collapsed in <${tag}> in <${container}> which is only child (explicitly flushes maybe pending layout)`);
test(() => {
editor.innerHTML = `${openTagOfContainer}abc<${tag}>${closeTagOfContainer}`;
const element = editor.querySelector(tag);

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

@ -56,6 +56,36 @@ for (const tag of voidElements) {
}
}, `Inserting text when selection is collapsed in <${tag}> which is only child`);
test(() => {
editor.innerHTML = `<div></div>`;
const element = document.createElement(tag);
editor.firstChild.appendChild(element);
editor.focus();
const selection = getSelection();
selection.collapse(element, 0);
element.getBoundingClientRect();
document.execCommand("insertText", false, "abc");
if (tag == "br") {
assert_in_array(
editor.innerHTML,
[
"<div>abc</div>",
"<div>abc<br></div>",
],
`The text should be inserted before the <br> element`
);
} else {
assert_in_array(
editor.innerHTML,
[
`<div>abc<${tag}></div>`,
`<div>abc<${tag}><br></div>`,
],
`The text should be inserted before the <${tag}> element`
);
}
}, `Inserting text when selection is collapsed in <${tag}> which is only child (explicitly flushes maybe pending layout)`);
test(() => {
editor.innerHTML = `<div>abc</div>`;
const element = document.createElement(tag);