2233 lines
75 KiB
HTML
2233 lines
75 KiB
HTML
<!DOCTYPE html>
|
|
<meta charset="utf-8">
|
|
<meta name="timeout" content="long">
|
|
<title>InputEvent.getTargetRanges() at Delete (forward delete)</title>
|
|
<div contenteditable></div>
|
|
<script src="input-events-get-target-ranges.js"></script>
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="/resources/testdriver.js"></script>
|
|
<script src="/resources/testdriver-vendor.js"></script>
|
|
<script src="/resources/testdriver-actions.js"></script>
|
|
<script>
|
|
"use strict";
|
|
|
|
// Simply deletes the next ASCII character of caret position.
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc</p>");
|
|
gSelection.collapse(gEditor.firstChild.firstChild, 2);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>ab</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: gEditor.firstChild.firstChild,
|
|
startOffset: 2,
|
|
endContainer: gEditor.firstChild.firstChild,
|
|
endOffset: 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>ab[]c</p>"');
|
|
|
|
// Simply deletes the next ASCII character of caret position.
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc</p>");
|
|
gSelection.collapse(gEditor.firstChild.firstChild, 1);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>ac</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: gEditor.firstChild.firstChild,
|
|
startOffset: 1,
|
|
endContainer: gEditor.firstChild.firstChild,
|
|
endOffset: 2,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>a[]bc</p>"');
|
|
|
|
// Simply deletes the next ASCII character of caret position.
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc</p>");
|
|
gSelection.collapse(gEditor.firstChild.firstChild, 0);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>bc</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: gEditor.firstChild.firstChild,
|
|
startOffset: 0,
|
|
endContainer: gEditor.firstChild.firstChild,
|
|
endOffset: 1,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>[]abc</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc</p>");
|
|
let abc = gEditor.querySelector("p").firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abc</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: abc,
|
|
endOffset: 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDoNothing();
|
|
}, 'Delete at "<p>abc[]</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc<br></p>");
|
|
let abc = gEditor.querySelector("p").firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abc<br></p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: abc,
|
|
endOffset: 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDoNothing();
|
|
}, 'Delete at "<p>abc[]<br></p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest(`<p><img src="${kImgSrc}"><br></p>`);
|
|
let p = gEditor.querySelector("p");
|
|
gSelection.collapse(p, 1);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
`<p><img src="${kImgSrc}"><br></p>`,
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p,
|
|
startOffset: 1,
|
|
endContainer: p,
|
|
endOffset: 1,
|
|
});
|
|
checkGetTargetRangesOfInputOnDoNothing();
|
|
}, 'Delete at "<p><img>[]<br></p>"');
|
|
|
|
// Should delete the `<span>` element because it becomes empty.
|
|
// However, we need discussion whether the `<span>` element should be
|
|
// contained by a range of `getTargetRanges()`.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>a<span>b</span>c</p>");
|
|
let a = gEditor.querySelector("span").previousSibling;
|
|
gSelection.collapse(a, 1);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>ac</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: a,
|
|
startOffset: 1,
|
|
endContainer: gEditor.firstChild,
|
|
endOffset: 2,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>a[]<span>b</span>c</p>"');
|
|
|
|
// Should delete the `<span>` element because it becomes empty.
|
|
// However, we need discussion whether the `<span>` element should be
|
|
// contained by a range of `getTargetRanges()`.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>a<span>b</span>c</p>");
|
|
let b = gEditor.querySelector("span").firstChild;
|
|
gSelection.collapse(b, 0);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>ac</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: gEditor.firstChild,
|
|
startOffset: 1,
|
|
endContainer: gEditor.firstChild,
|
|
endOffset: 2,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>a<span>[]b</span>c</p>"');
|
|
|
|
// Invisible trailing white-space may be deleted when the last visible
|
|
// character is deleted. If it's deleted, it should be contained by
|
|
// the range of `getTargetRanges()`, but needs discussion.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc </p>");
|
|
gSelection.collapse(gEditor.firstChild.firstChild, 2);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<p>ab</p>",
|
|
"<p>ab </p>",
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: gEditor.firstChild.firstChild,
|
|
startOffset: 2,
|
|
endContainer: gEditor.firstChild.firstChild,
|
|
endOffset: gEditor.firstChild.firstChild.data.length == 2 ? 4 : 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>ab[]c </p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc</p><p>def</p>");
|
|
let p1 = gEditor.firstChild;
|
|
let abc = p1.firstChild;
|
|
let p2 = p1.nextSibling;
|
|
let def = p2.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc[]</p><p>def</p>"');
|
|
|
|
// Invisible trailing white-spaces in current block and invisible leading
|
|
// white-spaces in the following block should be deleted for avoiding they
|
|
// becoming visible when the blocks are joined. Perhaps, they should be
|
|
// contained by the range of `getTargetRanges()`, but needs discussion.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc </p><p> def</p>");
|
|
let p1 = gEditor.firstChild;
|
|
let abc = p1.firstChild;
|
|
let p2 = p1.nextSibling;
|
|
let def = p2.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc[] </p><p> def</p>"');
|
|
|
|
// Invisible trailing white-spaces in current block and invisible leading
|
|
// white-spaces in the following block should be deleted for avoiding they
|
|
// becoming visible when the blocks are joined. Perhaps, they should be
|
|
// contained by the range of `getTargetRanges()`, but needs discussion.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc </p><p> def</p>");
|
|
let p1 = gEditor.firstChild;
|
|
let abc = p1.firstChild;
|
|
let p2 = p1.nextSibling;
|
|
let def = p2.firstChild;
|
|
gSelection.collapse(abc, 4);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc [] </p><p> def</p>"');
|
|
|
|
// Invisible trailing white-spaces in current block and invisible leading
|
|
// white-spaces in the following block should be deleted for avoiding they
|
|
// becoming visible when the blocks are joined. Perhaps, they should be
|
|
// contained by the range of `getTargetRanges()`, but needs discussion.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc </p><p> def</p>");
|
|
let p1 = gEditor.firstChild;
|
|
let abc = p1.firstChild;
|
|
let p2 = p1.nextSibling;
|
|
let def = p2.firstChild;
|
|
gSelection.collapse(abc, 5);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc [] </p><p> def</p>"');
|
|
|
|
// Invisible trailing white-spaces in current block and invisible leading
|
|
// white-spaces in the following block should be deleted for avoiding they
|
|
// becoming visible when the blocks are joined. Perhaps, they should be
|
|
// contained by the range of `getTargetRanges()`, but needs discussion.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc </p><p> def</p>");
|
|
let p1 = gEditor.firstChild;
|
|
let abc = p1.firstChild;
|
|
let p2 = p1.nextSibling;
|
|
let def = p2.firstChild;
|
|
gSelection.collapse(abc, 6);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc []</p><p> def</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc</p><p><b>def</b></p>");
|
|
let abc = gEditor.querySelector("p").firstChild;
|
|
let def = gEditor.querySelector("b").firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abc<b>def</b></p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc[]</p><p><b>def</b></p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<p><b>abc</b></p><p><b>def</b></p>");
|
|
let abc = gEditor.querySelector("p > b").firstChild;
|
|
let def = gEditor.querySelector("P + p > b").firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<p><b>abc</b><b>def</b></p>",
|
|
"<p><b>abcdef</b></p>",
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p><b>abc[]</b></p><p><b>def</b></p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<p><i>abc</i></p><p><b>def</b></p>");
|
|
let abc = gEditor.querySelector("i").firstChild;
|
|
let def = gEditor.querySelector("b").firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p><i>abc</i><b>def</b></p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p><i>abc[]</i></p><p><b>def</b></p>"');
|
|
|
|
// Invisible leading white-spaces in the following block should be deleted
|
|
// for avoiding they becoming visible when the blocks are joined, but
|
|
// preformatted trailing white-spaces in the first block shouldn't be
|
|
// deleted. Perhaps, the invisible white-spaces should be contained by
|
|
// the range of `getTargetRanges()`, but needs discussion.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest("<pre>abc </pre><p> def</p>");
|
|
let pre = gEditor.firstChild;
|
|
let abc = pre.firstChild;
|
|
let p = pre.nextSibling;
|
|
let def = p.firstChild;
|
|
gSelection.collapse(abc, 6);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<pre>abc def</pre>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 6,
|
|
endContainer: def,
|
|
endOffset: 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<pre>abc []</pre><p> def</p>"');
|
|
|
|
// Invisible leading/trailing white-spaces in the following block should be
|
|
// deleted for avoiding they becoming visible when the blocks are joined, but
|
|
// preformatted trailing white-spaces in the first block shouldn't be
|
|
// deleted. Perhaps, the invisible leading white-spaces should be contained
|
|
// by the range of `getTargetRanges()`, but needs discussion.
|
|
// And also not sure whether the trailing white-spaces should be contained
|
|
// by additional range of `getTargetRanges()` or not because of the
|
|
// implementation cost and runtime cost. Needs discuss.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest("<pre>abc </pre><p> def</p>");
|
|
let pre = gEditor.firstChild;
|
|
let abc = pre.firstChild;
|
|
let p = pre.nextSibling;
|
|
let def = p.firstChild;
|
|
gSelection.collapse(abc, 6);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<pre>abc def</pre>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 6,
|
|
endContainer: def,
|
|
endOffset: 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<pre>abc []</pre><p> def </p>"');
|
|
|
|
// Invisible trailing white-spaces in the first block should be deleted
|
|
// when the block is joined with the preformatted following block, but
|
|
// the leading white-spaces in the preformatted block shouldn't be
|
|
// removed. So, in this case, the invisible trailing white-spaces should
|
|
// be in the range of `getTargetRanges()`, but not so for the preformatted
|
|
// visible leading white-spaces. But needs discussion.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc </p><pre> def</pre>");
|
|
let p = gEditor.firstChild;
|
|
let abc = p.firstChild;
|
|
let pre = p.nextSibling;
|
|
let def = pre.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<p>abc def</p>",
|
|
"<p>abc def</p>",
|
|
"<p>abc def</p>",
|
|
"<p>abc def</p>",
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc[] </p><pre> def</pre>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest('<p style="white-space:pre-line">abc\ndef</p>');
|
|
const p = gEditor.firstChild;
|
|
const text = p.firstChild;
|
|
gSelection.collapse(text, "abc".length);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
'<p style="white-space:pre-line">abcdef</p>',
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: text,
|
|
startOffset: "abc".length,
|
|
endContainer: text,
|
|
endOffset: "abc\n".length,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p style="white-space:pre-line">abc[]\\ndef</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest('<p style="white-space:pre-line">abc\n def</p>');
|
|
const p = gEditor.firstChild;
|
|
const text = p.firstChild;
|
|
gSelection.collapse(text, "abc".length);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
'<p style="white-space:pre-line">abcdef</p>',
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: text,
|
|
startOffset: "abc".length,
|
|
endContainer: text,
|
|
endOffset: "abc\n ".length,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p style="white-space:pre-line">abc[]\\n def</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest('<p style="white-space:pre-line">abc \ndef</p>');
|
|
const p = gEditor.firstChild;
|
|
const text = p.firstChild;
|
|
gSelection.collapse(text, "abc".length);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
'<p style="white-space:pre-line">abcdef</p>',
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: text,
|
|
startOffset: "abc".length,
|
|
endContainer: text,
|
|
endOffset: "abc \n ".length,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p style="white-space:pre-line">abc[] \\ndef</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest('<p style="white-space:pre-line">abc \n def</p>');
|
|
const p = gEditor.firstChild;
|
|
const text = p.firstChild;
|
|
gSelection.collapse(text, "abc".length);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
'<p style="white-space:pre-line">abcdef</p>',
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: text,
|
|
startOffset: "abc".length,
|
|
endContainer: text,
|
|
endOffset: "abc \n ".length,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p style="white-space:pre-line">abc[] \\n def</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest('<p style="white-space:pre-line">abc \n \n def</p>');
|
|
const p = gEditor.firstChild;
|
|
const text = p.firstChild;
|
|
gSelection.collapse(text, "abc".length);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
'<p style="white-space:pre-line">abc\n def</p>',
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: text,
|
|
startOffset: "abc".length,
|
|
endContainer: text,
|
|
endOffset: "abc \n \n ".length,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p style="white-space:pre-line">abc[] \\n \\n def</p>"');
|
|
|
|
// Deleting from before invisible trailing `<br>` element of a block
|
|
// should delete the `<br>` element and join the blocks. Therefore,
|
|
// the target range should contain the `<br>` element and block boundaries.
|
|
// But maybe needs discussion.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc<br></p><p>def</p>");
|
|
let p1 = gEditor.firstChild;
|
|
let abc = p1.firstChild;
|
|
let p2 = p1.nextSibling;
|
|
let def = p2.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc[]<br></p><p>def</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest(`<p><img src="${kImgSrc}"><br></p><p>def</p>`);
|
|
let p1 = gEditor.firstChild;
|
|
let img = p1.firstChild;
|
|
let p2 = p1.nextSibling;
|
|
let def = p2.firstChild;
|
|
gSelection.collapse(p1, 1);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(`<p><img src="${kImgSrc}">def</p>`, t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p1,
|
|
startOffset: 1,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, `Delete at "<p><img>{}<br></p><p>def</p>"`);
|
|
|
|
// Deleting from last empty line in the first block should delete the
|
|
// invisible `<br>` element for the last empty line and join the blocks.
|
|
// In this case, the invisible `<br>` element should be contained in the
|
|
// range of `getTargetRanges()`, but needs discussion.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc<br><br></p><p>def</p>");
|
|
let p1 = gEditor.firstChild;
|
|
let abc = p1.firstChild;
|
|
let p2 = p1.nextSibling;
|
|
let def = p2.firstChild;
|
|
gSelection.collapse(p1, 2);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abc<br>def</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p1,
|
|
startOffset: 2,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc<br>{}<br></p><p>def</p>"');
|
|
|
|
// Deleting visible `<br>` element should be contained by a range of
|
|
// `getTargetRanges()`.
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc<br>def</p>");
|
|
let p = gEditor.querySelector("p");
|
|
let abc = p.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p,
|
|
startOffset: 1,
|
|
endContainer: p,
|
|
endOffset: 2,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc[]<br>def</p>"');
|
|
|
|
// Deleting visible `<br>` element following white-space should not include
|
|
// the preceding white-space in the range.
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc <br>def</p>");
|
|
let p = gEditor.querySelector("p");
|
|
let abc = p.firstChild;
|
|
gSelection.collapse(abc, 4);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abc def</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p,
|
|
startOffset: 1,
|
|
endContainer: p,
|
|
endOffset: 2,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc []<br>def</p>"');
|
|
|
|
// Deleting visible `<br>` element followed by white-space should include
|
|
// the following white-space in the range because it shouldn't become
|
|
// visible and should be deleted for avoiding it.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc<br> def</p>");
|
|
let p = gEditor.querySelector("p");
|
|
let abc = p.firstChild;
|
|
let def = gEditor.querySelector("br").nextSibling;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p,
|
|
startOffset: 1,
|
|
endContainer: def,
|
|
endOffset: 1,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc[]<br> def</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest(`<p>abc<img src="${kImgSrc}">def</p>`);
|
|
let p = gEditor.querySelector("p");
|
|
let abc = p.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abcdef</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p,
|
|
startOffset: 1,
|
|
endContainer: p,
|
|
endOffset: 2,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc[]<img>def</p>"');
|
|
|
|
// White-spaces around `<img>` element are visible so that they shouldn't
|
|
// be included into the target ranges.
|
|
promise_test(async (t) => {
|
|
initializeTest(`<p>abc <img src="${kImgSrc}">def</p>`);
|
|
let p = gEditor.querySelector("p");
|
|
let abc = p.firstChild;
|
|
gSelection.collapse(abc, 4);
|
|
await sendDeleteKey();
|
|
// If the browser does not join `Text` nodes around <img>, it's fine to
|
|
// convert the preceding white-space to an NBSP.
|
|
if (
|
|
gEditor.querySelector("p")?.childNodes.length == 2 &&
|
|
gEditor.querySelector("p").childNodes[0].length == "abc ".length
|
|
) {
|
|
checkEditorContentResultAsSubTest([
|
|
"<p>abc def</p>",
|
|
"<p>abc def</p>",
|
|
], t.name);
|
|
} else {
|
|
checkEditorContentResultAsSubTest("<p>abc def</p>", t.name);
|
|
}
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p,
|
|
startOffset: 1,
|
|
endContainer: p,
|
|
endOffset: 2,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc []<img>def</p>"');
|
|
|
|
// White-spaces around `<img>` element are visible so that they shouldn't
|
|
// be included into the target ranges.
|
|
promise_test(async (t) => {
|
|
initializeTest(`<p>abc<img src="${kImgSrc}"> def</p>`);
|
|
let p = gEditor.querySelector("p");
|
|
let abc = p.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
// If the browser does not join `Text` nodes around <img>, it's fine to
|
|
// convert the preceding white-space to an NBSP.
|
|
if (
|
|
gEditor.querySelector("p")?.childNodes.length == 2 &&
|
|
gEditor.querySelector("p").childNodes[0].length == "abc".length
|
|
) {
|
|
checkEditorContentResultAsSubTest([
|
|
"<p>abc def</p>",
|
|
"<p>abc def</p>",
|
|
], t.name);
|
|
} else {
|
|
checkEditorContentResultAsSubTest("<p>abc def</p>", t.name);
|
|
}
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p,
|
|
startOffset: 1,
|
|
endContainer: p,
|
|
endOffset: 2,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc[]<img> def</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest(`<p>abc<img src="${kImgSrc}"><img src="${kImgSrc}">def</p>`);
|
|
let p = gEditor.querySelector("p");
|
|
let abc = p.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
`<p>abc<img src="${kImgSrc}">def</p>`,
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p,
|
|
startOffset: 1,
|
|
endContainer: p,
|
|
endOffset: 2,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc[]<img><img>def</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest(`<p>abc<img src="${kImgSrc}"><img src="${kImgSrc}">def</p>`);
|
|
let p = gEditor.querySelector("p");
|
|
gSelection.collapse(p, 2);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
`<p>abc<img src="${kImgSrc}">def</p>`,
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p,
|
|
startOffset: 2,
|
|
endContainer: p,
|
|
endOffset: 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>abc<img>{}<img>def</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest(`<div>abc<hr>def</div>`);
|
|
let div = gEditor.querySelector("div");
|
|
let abc = div.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<div>abcdef</div>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: div,
|
|
startOffset: 1,
|
|
endContainer: div,
|
|
endOffset: 2,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc[]<hr>def</div>"');
|
|
|
|
// White-spaces around block element are invisible white-spaces so that
|
|
// they should be included into the target ranges to avoid they become
|
|
// visible.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest(`<div>abc <hr>def</div>`);
|
|
let div = gEditor.querySelector("div");
|
|
let abc = div.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<div>abcdef</div>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: div,
|
|
startOffset: 1,
|
|
endContainer: div,
|
|
endOffset: 2,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc[] <hr>def</div>"');
|
|
|
|
// White-spaces around block element are invisible white-spaces so that
|
|
// they should be included into the target ranges to avoid they become
|
|
// visible.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest(`<div>abc<hr> def</div>`);
|
|
let div = gEditor.querySelector("div");
|
|
let abc = div.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<div>abcdef</div>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: div,
|
|
startOffset: 1,
|
|
endContainer: div,
|
|
endOffset: 2,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc[]<hr> def</div>"');
|
|
|
|
// Invisible `<br>` element immediately before `<hr>` element should be
|
|
// delete once, and both of them should be included in the target range.
|
|
promise_test(async (t) => {
|
|
initializeTest(`<div>abc<br><hr>def</div>`);
|
|
let div = gEditor.querySelector("div");
|
|
let abc = div.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<div>abcdef</div>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: div,
|
|
startOffset: 1,
|
|
endContainer: div,
|
|
endOffset: 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc[]<br><hr>def</div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest(`<div><img src="${kImgSrc}"><br><hr>def</div>`);
|
|
let div = gEditor.querySelector("div");
|
|
let img = div.firstChild;
|
|
gSelection.collapse(div, 1);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
`<div><img src="${kImgSrc}">def</div>`,
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: div,
|
|
startOffset: 1,
|
|
endContainer: div,
|
|
endOffset: 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div><img>{}<br><hr>def</div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div>abc<p>def<br>ghi</p></div>");
|
|
let p = gEditor.querySelector("p");
|
|
let def = p.firstChild;
|
|
let abc = gEditor.firstChild.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<div>abcdef<p>ghi</p></div>",
|
|
"<div>abcdef<br><p>ghi</p></div>",
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc[]<p>def<br>ghi</p></div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div>abc<br><p>def<br>ghi</p></div>");
|
|
let div = gEditor.firstChild;
|
|
let p = gEditor.querySelector("p");
|
|
let def = p.firstChild;
|
|
let abc = div.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<div>abcdef<p>ghi</p></div>",
|
|
"<div>abcdef<br><p>ghi</p></div>",
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: div,
|
|
startOffset: 1,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc[]<br><p>def<br>ghi</p></div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest(`<div><img src="${kImgSrc}"><br><p>def<br>ghi</p></div>`);
|
|
let div = gEditor.firstChild;
|
|
let p = gEditor.querySelector("p");
|
|
let def = p.firstChild;
|
|
let abc = div.firstChild;
|
|
gSelection.collapse(div, 1);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
`<div><img src="${kImgSrc}">def<p>ghi</p></div>`,
|
|
`<div><img src="${kImgSrc}">def<br><p>ghi</p></div>`,
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: div,
|
|
startOffset: 1,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div><img>{}<br><p>def<br>ghi</p></div>"');
|
|
|
|
// Joining parent block and child block should remove invisible preceding
|
|
// white-spaces of the child block and invisible leading white-spaces in
|
|
// the child block, and they should be contained in a range of
|
|
// `getTargetRanges()`, but maybe needs discussion.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest("<div>abc <p> def<br>ghi</p></div>");
|
|
let p = gEditor.querySelector("p");
|
|
let def = p.firstChild;
|
|
let abc = gEditor.firstChild.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<div>abcdef<p>ghi</p></div>",
|
|
"<div>abcdef<br><p>ghi</p></div>",
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc[] <p> def<br>ghi</p></div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div>abc<p><b>def</b></p></div>");
|
|
let abc = gEditor.querySelector("div").firstChild;
|
|
let def = gEditor.querySelector("b").firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<div>abc<b>def</b></div>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc[]<p><b>def</b></p></div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div><b>abc</b><p><b>def</b></p></div>");
|
|
let abc = gEditor.querySelector("b").firstChild;
|
|
let def = gEditor.querySelector("p > b").firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<div><b>abc</b><b>def</b></div>",
|
|
"<div><b>abcdef</b></div>",
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div><b>abc[]</b><p><b>def</b></p></div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div><i>abc</i><p><b>def</b></p></div>");
|
|
let abc = gEditor.querySelector("i").firstChild;
|
|
let def = gEditor.querySelector("b").firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<div><i>abc</i><b>def</b></div>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div><i>abc[]</i><p><b>def</b></p></div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div><p>abc</p>def</div>");
|
|
let abc = gEditor.querySelector("p").firstChild;
|
|
let def = gEditor.querySelector("p").nextSibling;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<div><p>abcdef</p></div>",
|
|
"<div><p>abcdef<br></p></div>",
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div><p>abc[]</p>def</div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div><p>abc<br></p>def</div>");
|
|
let p = gEditor.querySelector("p");
|
|
let abc = p.firstChild;
|
|
let def = p.nextSibling;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<div><p>abcdef</p></div>",
|
|
"<div><p>abcdef<br></p></div>",
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p,
|
|
startOffset: 1,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div><p>abc[]<br></p>def</div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest(`<div><p><img src="${kImgSrc}"><br></p>def</div>`);
|
|
let p = gEditor.querySelector("p");
|
|
let abc = p.firstChild;
|
|
let def = p.nextSibling;
|
|
gSelection.collapse(p, 1);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
`<div><p><img src="${kImgSrc}">def</p></div>`,
|
|
`<div><p><img src="${kImgSrc}">def<br></p></div>`,
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p,
|
|
startOffset: 1,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div><p><img>{}<br></p>def</div>"');
|
|
|
|
// Joining child block and parent block should remove invisible trailing
|
|
// white-spaces of the child block and invisible following white-spaces
|
|
// in the parent block, and they should be contained by a range of
|
|
// `getTargetRanges()`, but maybe needs discussion.
|
|
// https://github.com/w3c/input-events/issues/112
|
|
promise_test(async (t) => {
|
|
initializeTest("<div><p>abc </p> def</div>");
|
|
let abc = gEditor.querySelector("p").firstChild;
|
|
let def = gEditor.querySelector("p").nextSibling;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<div><p>abcdef</p></div>",
|
|
"<div><p>abcdef<br></p></div>",
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div><p>abc[] </p> def</div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div><p><b>abc</b></p>def</div>");
|
|
let abc = gEditor.querySelector("b").firstChild;
|
|
let def = gEditor.querySelector("p").nextSibling;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<div><p><b>abc</b>def</p></div>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div><p><b>abc[]</b></p>def</div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div><p><b>abc</b></p><b>def</b></div>");
|
|
let abc = gEditor.querySelector("b").firstChild;
|
|
let def = gEditor.querySelector("div > b").firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<div><p><b>abc</b><b>def</b></p></div>",
|
|
"<div><p><b>abcdef</b></p></div>",
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div><p><b>abc[]</b></p><b>def</b></div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div><p><b>abc</b></p><i>def</i></div>");
|
|
let abc = gEditor.querySelector("b").firstChild;
|
|
let def = gEditor.querySelector("i").firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
"<div><p><b>abc</b><i>def</i></p></div>",
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div><p><b>abc[]</b></p><i>def</i></div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div>abc<ul><li>def</li></ul>ghi</div>");
|
|
let abc = gEditor.querySelector("div").firstChild;
|
|
let def = gEditor.querySelector("li").firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<div>abcdefghi</div>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc[]<ul><li>def</li></ul>ghi</div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div>abc <ul><li> def </li></ul> ghi</div>");
|
|
let abc = gEditor.querySelector("div").firstChild;
|
|
let def = gEditor.querySelector("li").firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<div>abcdefghi</div>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 1,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc[] <ul><li> def </li></ul> ghi</div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div>abc <ul><li> def </li></ul> ghi</div>");
|
|
let abc = gEditor.querySelector("div").firstChild;
|
|
let def = gEditor.querySelector("li").firstChild;
|
|
gSelection.collapse(abc, abc.length);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<div>abcdefghi</div>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 1,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc []<ul><li> def </li></ul> ghi</div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div>abc<ul><li>def</li></ul>ghi</div>");
|
|
let def = gEditor.querySelector("li").firstChild;
|
|
let ghi = gEditor.querySelector("ul").nextSibling;
|
|
gSelection.collapse(def, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
"<div>abc<ul><li>defghi</li></ul></div>",
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: def,
|
|
startOffset: 3,
|
|
endContainer: ghi,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc<ul><li>def[]</li></ul>ghi</div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div>abc <ul><li> def </li></ul> ghi</div>");
|
|
let def = gEditor.querySelector("li").firstChild;
|
|
let ghi = gEditor.querySelector("ul").nextSibling;
|
|
gSelection.collapse(def, 5);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<div>abc <ul><li> defghi</li></ul></div>",
|
|
"<div>abc <ul><li>defghi</li></ul></div>",
|
|
"<div>abc<ul><li>defghi</li></ul></div>",
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: def,
|
|
startOffset: 5,
|
|
endContainer: ghi,
|
|
endOffset: 1,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc <ul><li> def[] </li></ul> ghi</div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div>abc <ul><li> def </li></ul> ghi</div>");
|
|
let def = gEditor.querySelector("li").firstChild;
|
|
let ghi = gEditor.querySelector("ul").nextSibling;
|
|
gSelection.collapse(def, def.length);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<div>abc <ul><li> defghi</li></ul></div>",
|
|
"<div>abc <ul><li>defghi</li></ul></div>",
|
|
"<div>abc<ul><li>defghi</li></ul></div>",
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: def,
|
|
startOffset: 5,
|
|
endContainer: ghi,
|
|
endOffset: 1,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc <ul><li> def []</li></ul> ghi</div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div>abc<ul><li>def</li><li>ghi</li></ul>jkl</div>");
|
|
let abc = gEditor.querySelector("div").firstChild;
|
|
let def = gEditor.querySelector("li").firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
"<div>abcdef<ul><li>ghi</li></ul>jkl</div>",
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: def,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc[]<ul><li>def</li><li>ghi</li></ul>jkl</div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div>abc<ul><li>def</li><li>ghi</li></ul>jkl</div>");
|
|
let def = gEditor.querySelector("li").firstChild;
|
|
let ghi = gEditor.querySelector("li + li").firstChild;
|
|
gSelection.collapse(def, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
"<div>abc<ul><li>defghi</li></ul>jkl</div>",
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: def,
|
|
startOffset: 3,
|
|
endContainer: ghi,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc<ul><li>def[]</li><li>ghi</li></ul>jkl</div>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<div>abc<ul><li>def</li><li>ghi</li></ul>jkl</div>");
|
|
let ghi = gEditor.querySelector("li + li").firstChild;
|
|
let jkl = gEditor.querySelector("ul").nextSibling;
|
|
gSelection.collapse(ghi, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
"<div>abc<ul><li>def</li><li>ghijkl</li></ul></div>",
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: ghi,
|
|
startOffset: 3,
|
|
endContainer: jkl,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<div>abc<ul><li>def</li><li>ghi[]</li></ul>jkl</div>"');
|
|
|
|
// Delete in empty paragraph should remove the empty paragraph. In this
|
|
// case, it should be treated as joining with the previous paragraph.
|
|
// The target range should include the invisible <br> element in the empty
|
|
// paragraph.
|
|
promise_test(async (t) => {
|
|
initializeTest("<p><br></p><p>abc</p>");
|
|
let p1 = gEditor.querySelector("p");
|
|
let p2 = p1.nextSibling;
|
|
let abc = p2.firstChild;
|
|
gSelection.collapse(p1, 0);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abc</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p1,
|
|
startOffset: 0,
|
|
endContainer: abc,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>{}<br></p><p>abc</p>"');
|
|
|
|
// Delete ignore the empty span and the other things must be same as the
|
|
// previous test.
|
|
promise_test(async (t) => {
|
|
initializeTest("<p><span></span><br></p><p>abc</p>");
|
|
let p1 = gEditor.querySelector("p");
|
|
let span = p1.firstChild;
|
|
let p2 = p1.nextSibling;
|
|
let abc = p2.firstChild;
|
|
gSelection.collapse(span, 0);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest("<p>abc</p>", t.name);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p1,
|
|
startOffset: 0,
|
|
endContainer: abc,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p><span>{}</span><br></p><p>abc</p>"');
|
|
|
|
// If invisible white-spaces are removed with same action as above tests,
|
|
// the range should be included in the target ranges.
|
|
promise_test(async (t) => {
|
|
initializeTest("<p><br></p><p> abc</p>");
|
|
let p1 = gEditor.querySelector("p");
|
|
let p2 = p1.nextSibling;
|
|
let abc = p2.firstChild;
|
|
gSelection.collapse(p1, 0);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<p> abc</p>",
|
|
"<p>abc</p>",
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p1,
|
|
startOffset: 0,
|
|
endContainer: abc,
|
|
endOffset: 5 - abc.length,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>{}<br></p><p> abc</p>"');
|
|
|
|
// If the next block begins with non-editable content, target range
|
|
// should be at the non-editable content node.
|
|
promise_test(async (t) => {
|
|
initializeTest("<p><br></p><p><span contenteditable=\"false\">abc</span>def</p>");
|
|
let p1 = gEditor.querySelector("p");
|
|
let p2 = p1.nextSibling;
|
|
let span = gEditor.querySelector("span");
|
|
gSelection.collapse(p1, 0);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
"<p><span contenteditable=\"false\">abc</span>def</p>",
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p1,
|
|
startOffset: 0,
|
|
endContainer: p2,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>{}<br></p><p><span contenteditable="false">abc</span>def</p>"');
|
|
|
|
// If next non-editable paragraph is deleted, target range should end
|
|
// with start of the text node in the last paragraph. Otherwise, ends at
|
|
// the non-editable paragraph.
|
|
promise_test(async (t) => {
|
|
initializeTest("<p><br></p><p contenteditable=\"false\">abc</p><p>def</p>");
|
|
let p1 = gEditor.querySelector("p");
|
|
let p2 = p1.nextSibling;
|
|
let p3 = p2.nextSibling;
|
|
let def = p3.firstChild;
|
|
gSelection.collapse(p3, 0);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<p>def</p>",
|
|
"<p contenteditable=\"false\">abc</p><p>def</p>",
|
|
],
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p1,
|
|
startOffset: 0,
|
|
endContainer: p2.isConnected ? gEditor : p3,
|
|
endOffset: p2.isConnected ? 1 : 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<p>{}<br></p><p contenteditable=\"false\">abc</p><p>def</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>abc<span contenteditable=\"false\">def</span>ghi</p>");
|
|
let p = gEditor.querySelector("p");
|
|
let abc = p.firstChild;
|
|
gSelection.collapse(abc, 3);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<p>abc<span contenteditable=\"false\">def</span>ghi</p>",
|
|
"<p>abcghi</p>",
|
|
"<p>abcghi<br></p>",
|
|
],
|
|
t.name
|
|
);
|
|
if (gEditor.innerHTML === "<p>abc<span contenteditable=\"false\">def</span>ghi</p>") {
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: abc,
|
|
startOffset: 3,
|
|
endContainer: abc,
|
|
endOffset: 3,
|
|
});
|
|
checkGetTargetRangesOfInputOnDoNothing();
|
|
} else {
|
|
// If the non-editable `<span>` is deleted, it should be treated as
|
|
// an atomic node.
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p,
|
|
startOffset: 1,
|
|
endContainer: p,
|
|
endOffset: 2,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}
|
|
}, 'Delete at "<p>abc[]<span contenteditable=\"false\">def</span>ghi</p>"');
|
|
|
|
// If just removes the paragraph, target range should end at the table element.
|
|
promise_test(async (t) => {
|
|
initializeTest("<p><br></p><table><tr><td>cell</td></tr></table>");
|
|
let cell = gEditor.querySelector("td");
|
|
let p = gEditor.querySelector("p");
|
|
gSelection.collapse(p, 0);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<table><tbody><tr><td>cell</td></tr></tbody></table>",
|
|
"<p><br></p><table><tbody><tr><td>cell</td></tr></tbody></table>",
|
|
],
|
|
t.name
|
|
);
|
|
if (p.isConnected) {
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p,
|
|
startOffset: 0,
|
|
endContainer: p,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDoNothing();
|
|
} else {
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p,
|
|
startOffset: 0,
|
|
endContainer: gEditor,
|
|
endOffset: 1,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}
|
|
}, 'Delete at "<p>{}<br></p><table><tr><td>cell</td></tr></table>"');
|
|
|
|
// If table cell won't be joined, target range should be collapsed in the
|
|
// cell.
|
|
promise_test(async (t) => {
|
|
initializeTest("<table><tr><td><br></td><td>cell2</td></tr></table>");
|
|
let cell1 = gEditor.querySelector("td");
|
|
let cell2 = cell1.nextSibling;
|
|
gSelection.collapse(cell1, 0);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
"<table><tbody><tr><td><br></td><td>cell2</td></tr></tbody></table>",
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: cell1,
|
|
startOffset: 0,
|
|
endContainer: cell1,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDoNothing();
|
|
}, 'Delete at "<table><tr><td>{}<br></td><td>cell2</td></tr></table>"');
|
|
|
|
// If table caption won't be deleted, target range should be collapsed in the
|
|
// caption element.
|
|
promise_test(async (t) => {
|
|
initializeTest("<table><caption><br></caption><tr><td>cell</td></tr></table>");
|
|
let caption = gEditor.querySelector("caption");
|
|
gSelection.collapse(caption, 0);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
"<table><caption><br></caption><tbody><tr><td>cell</td></tr></tbody></table>",
|
|
t.name
|
|
);
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: caption,
|
|
startOffset: 0,
|
|
endContainer: caption,
|
|
endOffset: 0,
|
|
});
|
|
checkGetTargetRangesOfInputOnDoNothing();
|
|
}, 'Delete at "<table><caption>{}<br></caption><tr><td>cell</td></tr></table>"');
|
|
|
|
// If a table cell element is selected, only its content should be deleted.
|
|
promise_test(async (t) => {
|
|
initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr></table>");
|
|
let cell1 = gEditor.querySelector("td");
|
|
let tr = cell1.parentNode;
|
|
gSelection.setBaseAndExtent(tr, 0, tr, 1);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<table><tbody><tr><td></td><td>cell2</td></tr></tbody></table>",
|
|
"<table><tbody><tr><td><br></td><td>cell2</td></tr></tbody></table>",
|
|
],
|
|
t.name
|
|
);
|
|
// XXX Perhaps, target range should be selecting only all children of
|
|
// cell1 instead.
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: tr,
|
|
startOffset: 0,
|
|
endContainer: tr,
|
|
endOffset: 1,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<table><tr>{<td>cell1</td>}<td>cell2</td></tr></table>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr></table>");
|
|
let cell2 = gEditor.querySelector("td + td");
|
|
let tr = cell2.parentNode;
|
|
gSelection.setBaseAndExtent(tr, 1, tr, 2);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<table><tbody><tr><td>cell1</td><td></td></tr></tbody></table>",
|
|
"<table><tbody><tr><td>cell1</td><td><br></td></tr></tbody></table>",
|
|
],
|
|
t.name
|
|
);
|
|
// XXX Perhaps, target range should be selecting only all children of
|
|
// cell1 instead.
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: tr,
|
|
startOffset: 1,
|
|
endContainer: tr,
|
|
endOffset: 2,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<table><tr><td>cell1</td>{<td>cell2</td>}</tr></table>"');
|
|
|
|
// If the last table cell element is selected, what browsers should do?
|
|
promise_test(async (t) => {
|
|
initializeTest("<table><tr><td>cell</td></tr></table>");
|
|
let cell = gEditor.querySelector("td");
|
|
let tr = cell.parentNode;
|
|
let table = gEditor.querySelector("table");
|
|
gSelection.setBaseAndExtent(tr, 0, tr, 1);
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<table><tbody><tr><td></td></tr></tbody></table>",
|
|
"<table><tbody><tr><td><br></td></tr></tbody></table>",
|
|
"<br>",
|
|
],
|
|
t.name
|
|
);
|
|
if (gEditor.querySelector("table")) {
|
|
// XXX Perhaps, target range should be selecting only all children of
|
|
// cell1 instead.
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: tr,
|
|
startOffset: 0,
|
|
endContainer: tr,
|
|
endOffset: 1,
|
|
});
|
|
} else {
|
|
// If it causes deleting entire the table, the `<table>` element should
|
|
// be in the target range.
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: gEditor,
|
|
startOffset: 0,
|
|
endContainer: gEditor,
|
|
endOffset: 1,
|
|
});
|
|
}
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<table><tr>{<td>cell</td>}</tr></table>"');
|
|
|
|
// Testing multiple cell selection mode.
|
|
promise_test(async (t) => {
|
|
initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr><tr><td>cell3</td><td>cell4</td></tr></table>");
|
|
let cell1 = gEditor.querySelector("td");
|
|
let cell4 = gEditor.querySelector("tr + tr > td + td");
|
|
let tr1 = cell1.parentNode;
|
|
let tr2 = cell4.parentNode;
|
|
gSelection.removeAllRanges();
|
|
let range = document.createRange();
|
|
range.selectNode(cell1);
|
|
gSelection.addRange(range);
|
|
range = document.createRange();
|
|
range.selectNode(cell4);
|
|
gSelection.addRange(range);
|
|
assert_equals(gSelection.rangeCount, 2, "Should support multiple cell selection");
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<table><tbody><tr><td></td><td>cell2</td></tr><tr><td>cell3</td><td></td></tr></tbody></table>",
|
|
"<table><tbody><tr><td><br></td><td>cell2</td></tr><tr><td>cell3</td><td><br></td></tr></tbody></table>",
|
|
],
|
|
t.name
|
|
);
|
|
// XXX Perhaps, target range should be selecting only all children of
|
|
// cell1 and cell4 instead.
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething([
|
|
{
|
|
startContainer: tr1,
|
|
startOffset: 0,
|
|
endContainer: tr1,
|
|
endOffset: 1,
|
|
},
|
|
{
|
|
startContainer: tr2,
|
|
startOffset: 1,
|
|
endContainer: tr2,
|
|
endOffset: 2,
|
|
},
|
|
]);
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<table><tr>{<td>cell1</td>}<td>cell2</td></tr><tr><td>cell3</td>{<td>cell4</td>}</tr></table>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr><tr><td>cell3</td><td>cell4</td></tr></table>");
|
|
let cell1 = gEditor.querySelector("td");
|
|
let cell3 = gEditor.querySelector("tr + tr > td");
|
|
let tr1 = cell1.parentNode;
|
|
let tr2 = cell3.parentNode;
|
|
gSelection.removeAllRanges();
|
|
let range = document.createRange();
|
|
range.selectNode(cell1);
|
|
gSelection.addRange(range);
|
|
range = document.createRange();
|
|
range.selectNode(cell3);
|
|
gSelection.addRange(range);
|
|
assert_equals(gSelection.rangeCount, 2, "Should support multiple cell selection");
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<table><tbody><tr><td></td><td>cell2</td></tr><tr><td></td><td>cell4</td></tr></tbody></table>",
|
|
"<table><tbody><tr><td><br></td><td>cell2</td></tr><tr><td><br></td><td>cell4</td></tr></tbody></table>",
|
|
"<table><tbody><tr><td>cell2</td></tr><tr><td>cell4</td></tr></tbody></table>",
|
|
],
|
|
t.name
|
|
);
|
|
// XXX Perhaps, target range should be selecting only all children of
|
|
// cell1 and cell3 instead.
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething([
|
|
{
|
|
startContainer: tr1,
|
|
startOffset: 0,
|
|
endContainer: tr1,
|
|
endOffset: 1,
|
|
},
|
|
{
|
|
startContainer: tr2,
|
|
startOffset: 0,
|
|
endContainer: tr2,
|
|
endOffset: 1,
|
|
},
|
|
]);
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<table><tr>{<td>cell1</td>}<td>cell2</td></tr><tr>{<td>cell3</td>}<td>cell4</td></tr></table>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr><tr><td>cell3</td><td>cell4</td></tr></table>");
|
|
let cell1 = gEditor.querySelector("td");
|
|
let cell2 = gEditor.querySelector("td + td");
|
|
let tr1 = cell1.parentNode;
|
|
let tbody = tr1.parentNode;
|
|
gSelection.removeAllRanges();
|
|
let range = document.createRange();
|
|
range.selectNode(cell1);
|
|
gSelection.addRange(range);
|
|
range = document.createRange();
|
|
range.selectNode(cell2);
|
|
gSelection.addRange(range);
|
|
assert_equals(gSelection.rangeCount, 2, "Should support multiple cell selection");
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<table><tbody><tr><td></td><td></td></tr><tr><td>cell3</td><td>cell4</td></tr></tbody></table>",
|
|
"<table><tbody><tr><td><br></td><td><br></td></tr><tr><td>cell3</td><td>cell4</td></tr></tbody></table>",
|
|
"<table><tbody><tr><td>cell3</td><td>cell4</td></tr></tbody></table>",
|
|
],
|
|
t.name
|
|
);
|
|
if (gEditor.querySelector("tr + tr")) {
|
|
// XXX Perhaps, target range should be selecting only all children of
|
|
// cell1 and cell2 instead.
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething([
|
|
{
|
|
startContainer: tr1,
|
|
startOffset: 0,
|
|
endContainer: tr1,
|
|
endOffset: 1,
|
|
},
|
|
{
|
|
startContainer: tr1,
|
|
startOffset: 1,
|
|
endContainer: tr1,
|
|
endOffset: 2,
|
|
},
|
|
]);
|
|
} else {
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: tbody,
|
|
startOffset: 0,
|
|
endContainer: tbody,
|
|
endOffset: 1,
|
|
});
|
|
}
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<table><tr>{<td>cell1</td>}{<td>cell2</td>}</tr><tr><td>cell3</td><td>cell4</td></tr></table>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr><tr><td>cell3</td><td>cell4</td></tr></table>");
|
|
let cell3 = gEditor.querySelector("tr + tr > td");
|
|
let cell4 = gEditor.querySelector("tr + tr > td + td");
|
|
let tr2 = cell3.parentNode;
|
|
gSelection.removeAllRanges();
|
|
let range = document.createRange();
|
|
range.selectNode(cell3);
|
|
gSelection.addRange(range);
|
|
range = document.createRange();
|
|
range.selectNode(cell4);
|
|
gSelection.addRange(range);
|
|
assert_equals(gSelection.rangeCount, 2, "Should support multiple cell selection");
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<table><tbody><tr><td>cell1</td><td>cell2</td></tr><tr><td></td><td></td></tr></tbody></table>",
|
|
"<table><tbody><tr><td>cell1</td><td>cell2</td></tr><tr><td><br></td><td><br></td></tr></tbody></table>",
|
|
"<table><tbody><tr><td>cell1</td><td>cell2</td></tr></tbody></table>",
|
|
],
|
|
t.name
|
|
);
|
|
if (gEditor.querySelector("tr + tr")) {
|
|
// XXX Perhaps, target range should be selecting only all children of
|
|
// cell3 and cell4 instead.
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething([
|
|
{
|
|
startContainer: tr2,
|
|
startOffset: 0,
|
|
endContainer: tr2,
|
|
endOffset: 1,
|
|
},
|
|
{
|
|
startContainer: tr2,
|
|
startOffset: 1,
|
|
endContainer: tr2,
|
|
endOffset: 2,
|
|
},
|
|
]);
|
|
} else {
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: tbody,
|
|
startOffset: 1,
|
|
endContainer: tbody,
|
|
endOffset: 2,
|
|
});
|
|
}
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<table><tr><td>cell1</td><td>cell2</td></tr><tr>{<td>cell3</td>}{<td>cell4</td>}</tr></table>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr><tr><td>cell3</td><td>cell4</td></tr></table>");
|
|
let cell1 = gEditor.querySelector("td");
|
|
let cell2 = gEditor.querySelector("td + td");
|
|
let cell3 = gEditor.querySelector("tr + tr > td");
|
|
let cell4 = gEditor.querySelector("tr + tr > td + td");
|
|
let tr1 = cell1.parentNode;
|
|
let tr2 = cell3.parentNode;
|
|
gSelection.removeAllRanges();
|
|
let range = document.createRange();
|
|
range.selectNode(cell1);
|
|
gSelection.addRange(range);
|
|
range = document.createRange();
|
|
range.selectNode(cell2);
|
|
gSelection.addRange(range);
|
|
range = document.createRange();
|
|
range.selectNode(cell3);
|
|
gSelection.addRange(range);
|
|
range = document.createRange();
|
|
range.selectNode(cell4);
|
|
gSelection.addRange(range);
|
|
assert_equals(gSelection.rangeCount, 4, "Should support multiple cell selection");
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<table><tbody><tr><td></td><td></td></tr><tr><td></td><td></td></tr></tbody></table>",
|
|
"<table><tbody><tr><td><br></td><td><br></td></tr><tr><td><br></td><td><br></td></tr></tbody></table>",
|
|
"<br>",
|
|
],
|
|
t.name
|
|
);
|
|
if (gEditor.querySelector("table")) {
|
|
// XXX Perhaps, target range should be selecting only all children of
|
|
// cell1, cell2, cell3 and cell4 instead.
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething([
|
|
{
|
|
startContainer: tr1,
|
|
startOffset: 0,
|
|
endContainer: tr1,
|
|
endOffset: 1,
|
|
},
|
|
{
|
|
startContainer: tr1,
|
|
startOffset: 1,
|
|
endContainer: tr1,
|
|
endOffset: 2,
|
|
},
|
|
{
|
|
startContainer: tr2,
|
|
startOffset: 0,
|
|
endContainer: tr2,
|
|
endOffset: 1,
|
|
},
|
|
{
|
|
startContainer: tr2,
|
|
startOffset: 1,
|
|
endContainer: tr2,
|
|
endOffset: 2,
|
|
},
|
|
]);
|
|
} else {
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: gEditor,
|
|
startOffset: 0,
|
|
endContainer: gEditor,
|
|
endOffset: 1,
|
|
});
|
|
}
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<table><tr>{<td>cell1</td>}{<td>cell2</td>}</tr><tr>{<td>cell3</td>}{<td>cell4</td>}</tr></table>"');
|
|
|
|
promise_test(async (t) => {
|
|
initializeTest("<table><tr><td>cell1</td><td>cell2</td></tr><tr><td>cell3</td><td>cell4</td></tr></table>");
|
|
let cell1 = gEditor.querySelector("td");
|
|
let cell2 = gEditor.querySelector("td + td");
|
|
let cell4 = gEditor.querySelector("tr + tr > td + td");
|
|
let tr1 = cell1.parentNode;
|
|
let tr2 = cell4.parentNode;
|
|
gSelection.removeAllRanges();
|
|
let range = document.createRange();
|
|
range.selectNode(cell1);
|
|
gSelection.addRange(range);
|
|
range = document.createRange();
|
|
range.setStart(cell2.firstChild, 1);
|
|
range.setEnd(cell2.firstChild, 4);
|
|
gSelection.addRange(range);
|
|
range = document.createRange();
|
|
range.selectNode(cell4);
|
|
gSelection.addRange(range);
|
|
assert_equals(gSelection.rangeCount, 3, "Should support multiple cell selection");
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<table><tbody><tr><td></td><td>cell2</td></tr><tr><td>cell3</td><td></td></tr></tbody></table>",
|
|
"<table><tbody><tr><td><br></td><td>cell2</td></tr><tr><td>cell3</td><td><br></td></tr></tbody></table>",
|
|
"<table><tbody><tr><td></td><td>c2</td></tr><tr><td>cell3</td><td></td></tr></tbody></table>",
|
|
"<table><tbody><tr><td><br></td><td>c2</td></tr><tr><td>cell3</td><td><br></td></tr></tbody></table>",
|
|
],
|
|
t.name
|
|
);
|
|
if (cell2.firstChild.length == "cell2".length) {
|
|
// XXX Perhaps, target range should be selecting only all children of
|
|
// cell1 and cell4 instead.
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething([
|
|
{
|
|
startContainer: tr1,
|
|
startOffset: 0,
|
|
endContainer: tr1,
|
|
endOffset: 1,
|
|
},
|
|
{
|
|
startContainer: tr2,
|
|
startOffset: 1,
|
|
endContainer: tr2,
|
|
endOffset: 2,
|
|
},
|
|
]);
|
|
} else {
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething([
|
|
{
|
|
startContainer: tr1,
|
|
startOffset: 0,
|
|
endContainer: tr1,
|
|
endOffset: 1,
|
|
},
|
|
{
|
|
startContainer: cell2.firstChild,
|
|
startOffset: 1,
|
|
endContainer: cell2.firstChild,
|
|
endOffset: 4,
|
|
},
|
|
{
|
|
startContainer: tr2,
|
|
startOffset: 1,
|
|
endContainer: tr2,
|
|
endOffset: 2,
|
|
},
|
|
]);
|
|
}
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Delete at "<table><tr>{<td>cell1</td>}<td>c[ell]2</td></tr><tr>{<td>cell3</td>}<td>cell4</td></tr></table>"');
|
|
|
|
// If caret is not adjacent of deleting character, browser may not delete the
|
|
// character, but update the caret position for next deletion.
|
|
promise_test(async (t) => {
|
|
initializeTest("<p>helloשלום</p>");
|
|
let text1 = gEditor.querySelector("p").firstChild;
|
|
let text2 = text1.nextSibling;
|
|
gSelection.collapse(text1, 4);
|
|
await sendArrowRightKey();
|
|
await sendDeleteKey();
|
|
checkEditorContentResultAsSubTest(
|
|
[
|
|
"<p>hello\u05E9\u05DC\u05D5\u05DD</p>",
|
|
"<p>hello\u05DC\u05D5\u05DD</p>",
|
|
"<p>hello\u05E9\u05DC\u05D5</p>",
|
|
],
|
|
t.name
|
|
);
|
|
if (gEditor.innerHTML === "<p>hello\u05E9\u05DC\u05D5\u05DD</p>") {
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: text2 ? text2 : text1,
|
|
startOffset: text2 ? 0 : 5,
|
|
endContainer: text2 ? text2 : text1,
|
|
endOffset: text2 ? 0 : 5,
|
|
});
|
|
checkGetTargetRangesOfInputOnDoNothing();
|
|
} else if (gEditor.innerHTML === "<p>hello\u05DC\u05D5\u05DD</p>") {
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: text2 ? text2: text1,
|
|
startOffset: text2 ? 0 : 5,
|
|
endContainer: text2 ? text2 : text1,
|
|
endOffset: text2 ? 1 : 6,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
} else {
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: text2 ? text2: text1,
|
|
startOffset: text2 ? 3 : 8,
|
|
endContainer: text2 ? text2 : text1,
|
|
endOffset: text2 ? 4 : 9,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}
|
|
}, 'Delete at "<p>hello[]שלום</p>"');
|
|
|
|
// The following tests check whether the range returned from
|
|
// `beforeinput[0].getTargetRanges()` is modified or different range is
|
|
// modified instead. I.e., they don't test which type of deletion should
|
|
// occur. Therefore, their result depends on browser's key bindings,
|
|
// system settings and running OS.
|
|
|
|
function getFirstDifferentOffset(currentString, originalString) {
|
|
for (let i = 0; i < currentString.length; i++) {
|
|
if (currentString.charAt(i) !== originalString.charAt(i) &&
|
|
(originalString.charAt(i) !== " " || !currentString.charAt("\u00A0"))) {
|
|
return i;
|
|
}
|
|
}
|
|
return currentString.length;
|
|
}
|
|
|
|
promise_test(async (t) => {
|
|
const kText = "abc def ghi";
|
|
initializeTest(`<p>${kText}</p>`);
|
|
let p = gEditor.querySelector("p");
|
|
gSelection.collapse(p.firstChild, "abc ".length);
|
|
await sendDeleteKey(kShift);
|
|
let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
|
|
let length = kText.length - p.firstChild.data.length;
|
|
checkEditorContentResultAsSubTest(
|
|
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`,
|
|
t.name,
|
|
{ ignoreWhiteSpaceDifference: true }
|
|
);
|
|
if (startOffset === kText.length) {
|
|
checkBeforeinputAndInputEventsOnNOOP();
|
|
return;
|
|
}
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p.firstChild,
|
|
startOffset: startOffset,
|
|
endContainer: p.firstChild,
|
|
endOffset: startOffset + length,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Shift + Delete at "<p>abc []def ghi</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
const kText = "abc def ghi";
|
|
initializeTest(`<p>${kText}</p>`);
|
|
let p = gEditor.querySelector("p");
|
|
gSelection.collapse(p.firstChild, "abc ".length);
|
|
await sendDeleteKey(kControl);
|
|
let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
|
|
let length = kText.length - p.firstChild.data.length;
|
|
checkEditorContentResultAsSubTest(
|
|
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`,
|
|
t.name,
|
|
{ ignoreWhiteSpaceDifference: true }
|
|
);
|
|
if (startOffset === kText.length) {
|
|
checkBeforeinputAndInputEventsOnNOOP();
|
|
return;
|
|
}
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p.firstChild,
|
|
startOffset: startOffset,
|
|
endContainer: p.firstChild,
|
|
endOffset: startOffset + length,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Control + Delete at "<p>abc []def ghi</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
const kText = "abc def ghi";
|
|
initializeTest(`<p>${kText}</p>`);
|
|
let p = gEditor.querySelector("p");
|
|
gSelection.collapse(p.firstChild, "abc ".length);
|
|
await sendDeleteKey(kAlt);
|
|
let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
|
|
let length = kText.length - p.firstChild.data.length;
|
|
checkEditorContentResultAsSubTest(
|
|
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`,
|
|
t.name,
|
|
{ ignoreWhiteSpaceDifference: true }
|
|
);
|
|
if (startOffset === kText.length) {
|
|
checkBeforeinputAndInputEventsOnNOOP();
|
|
return;
|
|
}
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p.firstChild,
|
|
startOffset: startOffset,
|
|
endContainer: p.firstChild,
|
|
endOffset: startOffset + length,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Alt + Delete at "<p>abc []def ghi</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
const kText = "abc def ghi";
|
|
initializeTest(`<p>${kText}</p>`);
|
|
let p = gEditor.querySelector("p");
|
|
gSelection.collapse(p.firstChild, "abc ".length);
|
|
await sendDeleteKey(kMeta);
|
|
let startOffset = getFirstDifferentOffset(p.firstChild.data, kText);
|
|
let length = kText.length - p.firstChild.data.length;
|
|
checkEditorContentResultAsSubTest(
|
|
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length)}</p>`,
|
|
t.name,
|
|
{ ignoreWhiteSpaceDifference: true }
|
|
);
|
|
if (startOffset === kText.length) {
|
|
checkBeforeinputAndInputEventsOnNOOP();
|
|
return;
|
|
}
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p.firstChild,
|
|
startOffset: startOffset,
|
|
endContainer: p.firstChild,
|
|
endOffset: startOffset + length,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Meta + Delete at "<p>abc []def ghi</p>"');
|
|
|
|
promise_test(async (t) => {
|
|
const kText = "abc def";
|
|
initializeTest(`<p>${kText} </p>`);
|
|
let p = gEditor.querySelector("p");
|
|
gSelection.collapse(p.firstChild, "abc ".length);
|
|
await sendDeleteKey(kShift);
|
|
let visibleText = p.firstChild.data.replace(/%s+$/, "");
|
|
let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
|
|
let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
|
|
let length = kText.length + 3 - p.firstChild.data.length;
|
|
// If invisible white-spaces are deleted, they should be contained in the target range.
|
|
checkEditorContentResultAsSubTest(
|
|
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`,
|
|
t.name,
|
|
{ ignoreWhiteSpaceDifference: true }
|
|
);
|
|
if (startOffset === kText.length) {
|
|
checkBeforeinputAndInputEventsOnNOOP();
|
|
return;
|
|
}
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p.firstChild,
|
|
startOffset: startOffset,
|
|
endContainer: p.firstChild,
|
|
endOffset: startOffset + length,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Shift + Delete at "<p>abc []def </p>"');
|
|
|
|
promise_test(async (t) => {
|
|
const kText = "abc def";
|
|
initializeTest(`<p>${kText} </p>`);
|
|
let p = gEditor.querySelector("p");
|
|
gSelection.collapse(p.firstChild, "abc ".length);
|
|
await sendDeleteKey(kControl);
|
|
let visibleText = p.firstChild.data.replace(/%s+$/, "");
|
|
let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
|
|
let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
|
|
let length = kText.length + 3 - p.firstChild.data.length;
|
|
// If invisible white-spaces are deleted, they should be contained in the target range.
|
|
checkEditorContentResultAsSubTest(
|
|
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`,
|
|
t.name,
|
|
{ ignoreWhiteSpaceDifference: true }
|
|
);
|
|
if (startOffset === kText.length) {
|
|
checkBeforeinputAndInputEventsOnNOOP();
|
|
return;
|
|
}
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p.firstChild,
|
|
startOffset: startOffset,
|
|
endContainer: p.firstChild,
|
|
endOffset: startOffset + length,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Control + Delete at "<p>abc []def </p>"');
|
|
|
|
promise_test(async (t) => {
|
|
const kText = "abc def";
|
|
initializeTest(`<p>${kText} </p>`);
|
|
let p = gEditor.querySelector("p");
|
|
gSelection.collapse(p.firstChild, "abc ".length);
|
|
await sendDeleteKey(kAlt);
|
|
let visibleText = p.firstChild.data.replace(/%s+$/, "");
|
|
let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
|
|
let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
|
|
let length = kText.length + 3 - p.firstChild.data.length;
|
|
// If invisible white-spaces are deleted, they should be contained in the target range.
|
|
checkEditorContentResultAsSubTest(
|
|
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`,
|
|
t.name,
|
|
{ ignoreWhiteSpaceDifference: true }
|
|
);
|
|
if (startOffset === kText.length) {
|
|
checkBeforeinputAndInputEventsOnNOOP();
|
|
return;
|
|
}
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p.firstChild,
|
|
startOffset: startOffset,
|
|
endContainer: p.firstChild,
|
|
endOffset: startOffset + length,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Alt + Delete at "<p>abc []def </p>"');
|
|
|
|
promise_test(async (t) => {
|
|
const kText = "abc def";
|
|
initializeTest(`<p>${kText} s</p>`);
|
|
let p = gEditor.querySelector("p");
|
|
gSelection.collapse(p.firstChild, "abc ".length);
|
|
await sendDeleteKey(kMeta);
|
|
let visibleText = p.firstChild.data.replace(/%s+$/, "");
|
|
let invisibleWhiteSpaces = " ".repeat(p.firstChild.data.length - visibleText.length);
|
|
let startOffset = invisibleWhiteSpaces.length + getFirstDifferentOffset(visibleText, kText);
|
|
let length = kText.length + 3 - p.firstChild.data.length;
|
|
// If invisible white-spaces are deleted, they should be contained in the target range.
|
|
checkEditorContentResultAsSubTest(
|
|
`<p>${kText.substr(0, startOffset) + kText.substr(startOffset + length) + invisibleWhiteSpaces}</p>`,
|
|
t.name,
|
|
{ ignoreWhiteSpaceDifference: true }
|
|
);
|
|
if (startOffset === kText.length) {
|
|
checkBeforeinputAndInputEventsOnNOOP();
|
|
return;
|
|
}
|
|
checkGetTargetRangesOfBeforeinputOnDeleteSomething({
|
|
startContainer: p.firstChild,
|
|
startOffset: startOffset,
|
|
endContainer: p.firstChild,
|
|
endOffset: startOffset + length,
|
|
});
|
|
checkGetTargetRangesOfInputOnDeleteSomething();
|
|
}, 'Meta + Delete at "<p>abc []def</p>"');
|
|
|
|
</script>
|