--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/backspacetest.html Tue Jun 07 12:31:18 2011 -0600
@@ -0,0 +1,34 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Backspace tests</title>
+<link rel=stylesheet href=tests.css>
+<p>Legend: {[ are the selection anchor, }] are the selection focus, {}
+represent an element boundary point, [] represent a text node boundary point.
+Syntax and some of the tests taken from <a
+href=http://www.browserscope.org/richtext2/test>Browserscope</a>. data-start
+and data-end attributes also represent element boundary points, with the node
+being the element with the attribute and the offset given as the attribute
+value, for cases where HTML parsing doesn't allow text nodes. Currently we
+don't really pay attention to reversed selections at all, so they might get
+displayed as forwards or such.
+
+<p><input type=button value="Clear cached results" onclick="clearCachedResults()">
+
+<div id=tests>
+ <input type=button value="Run tests" onclick="runTests()">
+ <table border=1><tr><th>Input<th>Spec<th>Browser<th>Same</table>
+ <p><label>New test input: <input></label> <input type=button value="Add test" onclick="addTest()">
+</div>
+
+<div id=overlay>Tap backspace repeatedly until this annoying message
+disappears! (But not too quickly. And don't hit any other keys or click with
+the mouse anywhere, it will mess it up.<span id=testcount> <span></span>
+test(s) remain.</span>)</div>
+
+<script src=implementation.js></script>
+<script src=tests.js></script>
+<script>
+var command = "delete";
+var keyname = "backspace";
+</script>
+<script src=manualtest.js></script>
--- a/linebreaktest.html Tue Jun 07 12:01:33 2011 -0600
+++ b/linebreaktest.html Tue Jun 07 12:31:18 2011 -0600
@@ -1,24 +1,7 @@
<!doctype html>
-<!-- This is going to be merged into autoimplementation.html at some point. -->
<meta charset=utf-8>
<title>Line-breaking tests</title>
<link rel=stylesheet href=tests.css>
-<style>
-#overlay {
- display: none;
- position: fixed;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- color: red;
- background: yellow;
- font-size: 4em;
- font-weight: bold;
- text-align: center;
- padding: 2em;
-}
-</style>
<p>Legend: {[ are the selection anchor, }] are the selection focus, {}
represent an element boundary point, [] represent a text node boundary point.
Syntax and some of the tests taken from <a
@@ -39,150 +22,13 @@
<div id=overlay>Tap enter repeatedly until this annoying message
disappears! (But not too quickly. And don't hit any other keys or click with
-the mouse anywhere, it will mess it up.)</div>
+the mouse anywhere, it will mess it up.<span id=testcount> <span></span> test(s)
+remain.</span>)</div>
<script src=implementation.js></script>
<script src=tests.js></script>
<script>
-var tests = tests.insertparagraph;
-
-var testsRunning = false;
-
-function clearCachedResults() {
- for (var key in localStorage) {
- if (/^linebreaktest-/.test(key)) {
- localStorage.removeItem(key);
- }
- }
-}
-
-function runTests() {
- testsRunning = true;
- var runTestsButton = document.querySelector("#tests input[type=button]");
- runTestsButton.parentNode.removeChild(runTestsButton);
-
- var addTestButton = document.querySelector("#tests input[type=button]");
- var input = document.querySelector("#tests label input");
- // This code actually focuses and clicks everything because for some
- // reason, anything else doesn't work in IE9 . . .
- input.value = tests[0];
- input.focus();
- addTestButton.click();
-}
-
-function addTest() {
- var tr = doSetup("#tests table", 0);
- var input = document.querySelector("#tests label input");
- var test = input.value;
- doInputCell(tr, test);
- doSpecCell(tr, test, "insertparagraph", false);
- if (localStorage.getItem("linebreaktest-" + test) !== null) {
- // Yay, I get to cheat
- var browserCell = document.createElement("td");
- tr.appendChild(browserCell);
- browserCell.innerHTML = localStorage["linebreaktest-" + test];
- doSameCell(tr);
- runNextTest(test);
- } else {
- doBrowserCell(tr, test, function() {
- doSameCell(tr);
- runNextTest(test);
- });
- }
-}
-
-function runNextTest(test) {
- doTearDown();
- var input = document.querySelector("#tests label input");
- if (!testsRunning) {
- document.getElementById("overlay").style.display = "none";
- return;
- }
- var idx = tests.indexOf(test);
- if (idx != tests.lastIndexOf(test)) {
- // Cheap and effective error reporting
- document.body.textContent = "Duplicate test: " + test;
- }
- if (idx + 1 >= tests.length) {
- document.getElementById("overlay").style.display = "none";
- testsRunning = false;
- input.value = "";
- return;
- }
- input.value = tests[idx + 1];
- input.focus();
- addTest();
-}
-
-function doBrowserCell(tr, test, callback) {
- var browserCell = document.createElement("td");
- tr.appendChild(browserCell);
-
- try {
- var points = setupCell(browserCell, test);
-
- var testDiv = browserCell.firstChild;
- // Work around weird Firefox bug:
- // https://bugzilla.mozilla.org/show_bug.cgi?id=649138
- document.body.appendChild(testDiv);
- testDiv.onkeyup = function() {
- continueBrowserCell(test, testDiv, browserCell);
- callback();
- };
- testDiv.contentEditable = "true";
- testDiv.spellcheck = false;
- document.getElementById("overlay").style.display = "block";
- testDiv.focus();
- setSelection(points[0], points[1], points[2], points[3]);
- } catch (e) {
- browserCellException(e, testDiv, browserCell);
- callback();
- }
-}
-
-function continueBrowserCell(test, testDiv, browserCell) {
- try {
- testDiv.contentEditable = "inherit";
- testDiv.removeAttribute("spellcheck");
- var compareDiv1 = testDiv.cloneNode(true);
-
- if (getSelection().rangeCount) {
- addBrackets(getSelection().getRangeAt(0));
- }
- browserCell.insertBefore(testDiv, browserCell.firstChild);
-
- if (!browserCell.childNodes.length == 2) {
- throw "The cell didn't have two children. Did something spill outside the test div?";
- }
-
- compareDiv1.normalize();
- // Sigh, Gecko is crazy
- var treeWalker = document.createTreeWalker(compareDiv1, NodeFilter.SHOW_ELEMENT, null, null);
- while (treeWalker.nextNode()) {
- var remove = [].filter.call(treeWalker.currentNode.attributes, function(attrib) {
- return /^_moz_/.test(attrib.name) || attrib.value == "_moz";
- });
- for (var i = 0; i < remove.length; i++) {
- treeWalker.currentNode.removeAttribute(remove[i].name);
- }
- }
- var compareDiv2 = compareDiv1.cloneNode(false);
- compareDiv2.innerHTML = compareDiv1.innerHTML;
- if (!compareDiv1.isEqualNode(compareDiv2)
- && compareDiv1.innerHTML != compareDiv2.innerHTML) {
- throw "DOM does not round-trip through serialization! "
- + compareDiv1.innerHTML + " vs. " + compareDiv2.innerHTML;
- }
- if (!compareDiv1.isEqualNode(compareDiv2)) {
- throw "DOM does not round-trip through serialization (although innerHTML is the same)! "
- + testDiv.innerHTML;
- }
-
- browserCell.lastChild.textContent = browserCell.firstChild.innerHTML;
- } catch (e) {
- browserCellException(e, testDiv, browserCell);
- }
-
- localStorage["linebreaktest-" + test] = browserCell.innerHTML;
-}
+var command = "insertparagraph";
+var keyname = "linebreak";
</script>
+<script src=manualtest.js></script>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/manualtest.js Tue Jun 07 12:31:18 2011 -0600
@@ -0,0 +1,148 @@
+var tests = tests[command];
+
+var testsRunning = false;
+
+function clearCachedResults() {
+ for (var key in localStorage) {
+ if (RegExp("^" + keyname + "test-").test(key)) {
+ localStorage.removeItem(key);
+ }
+ }
+}
+
+function runTests() {
+ testsRunning = true;
+ var runTestsButton = document.querySelector("#tests input[type=button]");
+ runTestsButton.parentNode.removeChild(runTestsButton);
+
+ var addTestButton = document.querySelector("#tests input[type=button]");
+ var input = document.querySelector("#tests label input");
+ // This code actually focuses and clicks everything because for some
+ // reason, anything else doesn't work in IE9 . . .
+ input.value = tests[0];
+ input.focus();
+ addTestButton.click();
+}
+
+function addTest() {
+ var tr = doSetup("#tests table", 0);
+ var input = document.querySelector("#tests label input");
+ var test = input.value;
+ doInputCell(tr, test);
+ doSpecCell(tr, test, command, false);
+ if (localStorage.getItem(keyname + "test-" + test) !== null) {
+ // Yay, I get to cheat
+ var browserCell = document.createElement("td");
+ tr.appendChild(browserCell);
+ browserCell.innerHTML = localStorage[keyname + "test-" + test];
+ doSameCell(tr);
+ runNextTest(test);
+ } else {
+ doBrowserCell(tr, test, function() {
+ doSameCell(tr);
+ runNextTest(test);
+ });
+ }
+}
+
+function runNextTest(test) {
+ doTearDown();
+ var input = document.querySelector("#tests label input");
+ if (!testsRunning) {
+ document.getElementById("overlay").style.display = "none";
+ return;
+ }
+ var idx = tests.indexOf(test);
+ if (idx != tests.lastIndexOf(test)) {
+ // Cheap and effective error reporting
+ document.body.textContent = "Duplicate test: " + test;
+ }
+ if (idx + 1 >= tests.length) {
+ document.getElementById("overlay").style.display = "none";
+ testsRunning = false;
+ input.value = "";
+ return;
+ }
+ input.value = tests[idx + 1];
+ input.focus();
+ addTest();
+}
+
+function doBrowserCell(tr, test, callback) {
+ var browserCell = document.createElement("td");
+ tr.appendChild(browserCell);
+
+ try {
+ var points = setupCell(browserCell, test);
+
+ var testDiv = browserCell.firstChild;
+ // Work around weird Firefox bug:
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=649138
+ document.body.appendChild(testDiv);
+ testDiv.onkeyup = function() {
+ continueBrowserCell(test, testDiv, browserCell);
+ callback();
+ };
+ testDiv.contentEditable = "true";
+ testDiv.spellcheck = false;
+ var idx = tests.indexOf(test);
+ if (idx == -1) {
+ document.getElementById("testcount").style.display = "none";
+ } else {
+ document.getElementById("testcount").style.display = "";
+ document.querySelector("#testcount > span").textContent = tests.length - idx;
+ }
+ document.getElementById("overlay").style.display = "block";
+ testDiv.focus();
+ setSelection(points[0], points[1], points[2], points[3]);
+ } catch (e) {
+ browserCellException(e, testDiv, browserCell);
+ callback();
+ }
+}
+
+function continueBrowserCell(test, testDiv, browserCell) {
+ try {
+ testDiv.contentEditable = "inherit";
+ testDiv.removeAttribute("spellcheck");
+ var compareDiv1 = testDiv.cloneNode(true);
+
+ if (getSelection().rangeCount) {
+ addBrackets(getSelection().getRangeAt(0));
+ }
+ browserCell.insertBefore(testDiv, browserCell.firstChild);
+
+ if (!browserCell.childNodes.length == 2) {
+ throw "The cell didn't have two children. Did something spill outside the test div?";
+ }
+
+ compareDiv1.normalize();
+ // Sigh, Gecko is crazy
+ var treeWalker = document.createTreeWalker(compareDiv1, NodeFilter.SHOW_ELEMENT, null, null);
+ while (treeWalker.nextNode()) {
+ var remove = [].filter.call(treeWalker.currentNode.attributes, function(attrib) {
+ return /^_moz_/.test(attrib.name) || attrib.value == "_moz";
+ });
+ for (var i = 0; i < remove.length; i++) {
+ treeWalker.currentNode.removeAttribute(remove[i].name);
+ }
+ }
+ var compareDiv2 = compareDiv1.cloneNode(false);
+ compareDiv2.innerHTML = compareDiv1.innerHTML;
+ if (!compareDiv1.isEqualNode(compareDiv2)
+ && compareDiv1.innerHTML != compareDiv2.innerHTML) {
+ throw "DOM does not round-trip through serialization! "
+ + compareDiv1.innerHTML + " vs. " + compareDiv2.innerHTML;
+ }
+ if (!compareDiv1.isEqualNode(compareDiv2)) {
+ throw "DOM does not round-trip through serialization (although innerHTML is the same)! "
+ + testDiv.innerHTML;
+ }
+
+ browserCell.lastChild.textContent = browserCell.firstChild.innerHTML;
+ } catch (e) {
+ browserCellException(e, testDiv, browserCell);
+ }
+
+ localStorage[keyname + "test-" + test] = browserCell.innerHTML;
+}
--- a/tests.css Tue Jun 07 12:01:33 2011 -0600
+++ b/tests.css Tue Jun 07 12:31:18 2011 -0600
@@ -62,6 +62,21 @@
background: white;
border-bottom: 2px solid gray;
}
-/* For testing */
+/* For easy visibility of nesting */
ol ol { list-style-type: lower-alpha }
ol ol ol { list-style-type: lower-roman }
+/* For manual tests */
+#overlay {
+ display: none;
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ color: red;
+ background: yellow;
+ font-size: 4em;
+ font-weight: bold;
+ text-align: center;
+ padding: 2em;
+}