152 lines
5.1 KiB
HTML
152 lines
5.1 KiB
HTML
<!doctype html>
|
|
<meta charset=utf-8>
|
|
<title>Deletion tests</title>
|
|
<script src=/resources/testharness.js></script>
|
|
<script src=/resources/testharnessreport.js></script>
|
|
<div contenteditable></div>
|
|
<script>
|
|
var div = document.querySelector("div");
|
|
|
|
// Format: [start html, start pos, expected html, expected pos, command]
|
|
// Positions are a sequence of offsets starting from div, e.g., "1,2,0"
|
|
// translates to node = div.childNodes[1].childNodes[2], offset = 0. For a
|
|
// non-collapsed selection, use a hyphen, like "0,0-1,0". The selections are
|
|
// created with collapse() followed by extend() to allow reverse selections, so
|
|
// order is significant.
|
|
//
|
|
// Expected values can be arrays, in which case any is acceptable.
|
|
var tests = [
|
|
["<p><br></p><p><br></p>", "1,0", "<p><br></p>", "0,0", "delete"],
|
|
["<p><br></p><p><br></p>", "0,0", "<p><br></p>", "0,0", "forwarddelete"],
|
|
|
|
// Range
|
|
["<p><br></p><p><br></p>", "0,0-1,0", "<p><br></p>", "0,0", "delete"],
|
|
["<p><br></p><p><br></p>", "0,0-1,0", "<p><br></p>", "0,0", "forwarddelete"],
|
|
["<p><br></p><p><br></p>", "1,0-0,0", "<p><br></p>", "0,0", "delete"],
|
|
["<p><br></p><p><br></p>", "1,0-0,0", "<p><br></p>", "0,0", "forwarddelete"],
|
|
|
|
// Different start values
|
|
["<p>x<br></p><p><br></p>", "1,0",
|
|
// WebKit/Blink like to get rid of the extra <br>
|
|
["<p>x<br></p>", "<p>x</p>"],
|
|
// The selection should really be collapsed inside the text node, but in the
|
|
// parent is close enough.
|
|
["0,0,1", "0,1"], "delete"],
|
|
["<p><br><br></p><p><br></p>", "1,0", "<p><br><br></p>", "0,1", "delete"],
|
|
["<p><br></p><p><br><br></p>", "1,1",
|
|
"<p><br></p><p><br></p>", "1,0", "delete"],
|
|
["<p><br><br><br></p>", "0,2", "<p><br><br></p>", "0,1", "delete"],
|
|
["<p><br></p><p><br><br><br></p>", "1,2",
|
|
"<p><br></p><p><br><br></p>", "1,1", "delete"],
|
|
["<p><br><br></p><p><br><br></p>", "1,1",
|
|
"<p><br><br></p><p><br></p>", "1,0", "delete"],
|
|
["<p><br></p><br>", "1", "<p><br></p>", "0,0", "delete"],
|
|
|
|
// The trailing \n in these cases is actually significant, because it was
|
|
// necessary to trigger an actual Gecko bug (somehow!).
|
|
// NOTE: It's fine to delete surrounding white-spaces of the deleting block.
|
|
["<p><br></p><p><br></p>\n", "1,0",
|
|
["<p><br></p>\n", "<p><br></p>"], "0,0", "delete"],
|
|
["<p><br></p><p><br></p>\n", "0,0",
|
|
["<p><br></p>\n", "<p><br></p>"], "0,0", "forwarddelete"],
|
|
["\n<p><tt>x</tt></p><p><tt><br></tt></p><p><tt><br></tt></p>\n", "3,0,0",
|
|
["\n<p><tt>x</tt></p><p><tt><br></tt></p>\n", "\n<p><tt>x</tt></p><p><tt><br></tt></p>"], "2,0,0", "delete"],
|
|
];
|
|
|
|
div.focus();
|
|
|
|
for (var i = 0; i < tests.length; i++) {
|
|
test(function() {
|
|
var test = tests[i];
|
|
div.innerHTML = test[0];
|
|
setSelection(test[1]);
|
|
|
|
document.execCommand(test[4], false, "");
|
|
|
|
if (typeof test[2] == "string") {
|
|
assert_equals(div.innerHTML, test[2], "innerHTML");
|
|
} else {
|
|
assert_in_array(div.innerHTML, test[2], "innerHTML");
|
|
}
|
|
|
|
var actualSel = recordSelection();
|
|
var expectedSel = [];
|
|
if (typeof test[3] == "string") {
|
|
test[3] = [test[3]];
|
|
}
|
|
for (var j = 0; j < test[3].length; j++) {
|
|
setSelection(test[3][j]);
|
|
expectedSel.push(recordSelection());
|
|
}
|
|
assertSelectionEquals(actualSel, expectedSel, test[2]);
|
|
}, i + ": " + format_value(tests[i][0]) + " " + tests[i][1] +
|
|
" " + tests[i][4]);
|
|
}
|
|
|
|
function setSelection(selstr) {
|
|
var parts = selstr.split("-");
|
|
var collapsePoint = getPointFromArray(parts[0].split(","));
|
|
getSelection().collapse(collapsePoint[0], collapsePoint[1]);
|
|
|
|
if (parts[1]) {
|
|
var extendPoint = getPointFromArray(parts[1].split(","));
|
|
getSelection().extend(extendPoint[0], extendPoint[1]);
|
|
}
|
|
}
|
|
|
|
function getPointFromArray(offsets) {
|
|
var retNode = div, retOffset;
|
|
var offset;
|
|
while (offset = offsets.shift()) {
|
|
if (!offsets.length) {
|
|
retOffset = offset;
|
|
} else {
|
|
retNode = retNode.childNodes[offset];
|
|
}
|
|
}
|
|
return [retNode, retOffset];
|
|
}
|
|
|
|
function recordSelection() {
|
|
return [getSelection().anchorNode, getSelection().anchorOffset,
|
|
getSelection().focusNode, getSelection().focusOffset];
|
|
}
|
|
|
|
function assertSelectionEquals(actual, expected, html) {
|
|
if (typeof expected == "string") {
|
|
expected = [expected];
|
|
}
|
|
var pass = false;
|
|
for (var i = 0; i < expected.length; i++) {
|
|
if (expected[i][0] === actual[0] &&
|
|
expected[i][1] === actual[1] &&
|
|
expected[i][2] === actual[2] &&
|
|
expected[i][3] === actual[3]) {
|
|
pass = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert_true(pass, "Wrong selection, expected " + formatSel(expected) +
|
|
", got " + formatSel(actual) +
|
|
" (in HTML " + format_value(html) + ")");
|
|
}
|
|
|
|
function formatSel(arr) {
|
|
if (arr.length == 1) {
|
|
arr = arr[0];
|
|
}
|
|
if (Array.isArray(arr[0])) {
|
|
var ret = [];
|
|
for (var i = 0; i < arr.length; i++) {
|
|
ret.push(formatSel(arr[i]));
|
|
}
|
|
return ret.join(" or ");
|
|
}
|
|
if (arr[0] == arr[2] && arr[1] == arr[3]) {
|
|
return "collapsed (" + format_value(arr[0]) + ", " + arr[1] + ")";
|
|
}
|
|
return "(" + format_value(arr[0]) + ", " + arr[1] +
|
|
")-(" + format_value(arr[2]) + ", " + arr[3] + ")";
|
|
}
|
|
</script>
|