OLD | NEW |
(Empty) | |
| 1 <!doctype html> |
| 2 <title>Editing event tests</title> |
| 3 <style>body { font-family: serif }</style> |
| 4 <script src=/resources/testharness.js></script> |
| 5 <script src=/resources/testharnessreport.js></script> |
| 6 <div id=test></div> |
| 7 <div id=log></div> |
| 8 <script> |
| 9 "use strict"; |
| 10 |
| 11 var div = document.querySelector("#test"); |
| 12 add_completion_callback(function() { div.parentNode.removeChild(div) }); |
| 13 |
| 14 function copyEvent(e) { |
| 15 var ret = {}; |
| 16 ret.original = e; |
| 17 ["type", "target", "currentTarget", "eventPhase", "bubbles", "cancelable", |
| 18 "defaultPrevented", "isTrusted", "command", "value"].forEach(function(k) { |
| 19 ret[k] = e[k]; |
| 20 }); |
| 21 return ret; |
| 22 } |
| 23 |
| 24 var tests = [ |
| 25 { |
| 26 name: "Simple editable div", |
| 27 html: "<div contenteditable>foo<b>bar</b>baz</div>", |
| 28 initRange: function(range) { |
| 29 range.setStart(div.querySelector("b").firstChild, 0); |
| 30 range.setEnd(div.querySelector("b"), 1); |
| 31 }, |
| 32 target: function() { return div.firstChild }, |
| 33 command: "bold", |
| 34 value: "", |
| 35 }, |
| 36 { |
| 37 name: "Editable b", |
| 38 html: "foo<b contenteditable>bar</b>baz", |
| 39 initRange: function(range) { |
| 40 range.setStart(div.querySelector("b").firstChild, 0); |
| 41 range.setEnd(div.querySelector("b"), 1); |
| 42 }, |
| 43 target: function() { return div.querySelector("b") }, |
| 44 command: "bold", |
| 45 value: "", |
| 46 }, |
| 47 { |
| 48 name: "No editable content", |
| 49 html: "foo<b>bar</b>baz", |
| 50 initRange: function(range) { |
| 51 range.setStart(div.querySelector("b").firstChild, 0); |
| 52 range.setEnd(div.querySelector("b"), 1); |
| 53 }, |
| 54 target: function() { return null }, |
| 55 command: "bold", |
| 56 value: "", |
| 57 }, |
| 58 { |
| 59 name: "Partially-selected editable content", |
| 60 html: "foo<b contenteditable>bar</b>baz", |
| 61 initRange: function(range) { |
| 62 range.setStart(div.querySelector("b").firstChild, 0); |
| 63 range.setEnd(div, 3); |
| 64 }, |
| 65 target: function() { return null }, |
| 66 command: "bold", |
| 67 value: "", |
| 68 }, |
| 69 { |
| 70 name: "Selection spans two editing hosts", |
| 71 html: "<div contenteditable>foo</div><div contenteditable>bar</div>", |
| 72 initRange: function(range) { |
| 73 range.setStart(div.querySelector("div").firstChild, 2); |
| 74 range.setEnd(div.querySelector("div + div").firstChild, 1); |
| 75 }, |
| 76 target: function() { return null }, |
| 77 command: "bold", |
| 78 value: "", |
| 79 }, |
| 80 { |
| 81 name: "Selection includes two editing hosts", |
| 82 html: "foo<div contenteditable>bar</div>baz<div contenteditable>quz</div
>qoz", |
| 83 initRange: function(range) { |
| 84 range.setStart(div.firstChild, 2); |
| 85 range.setEnd(div.lastChild, 1); |
| 86 }, |
| 87 target: function() { return null }, |
| 88 command: "bold", |
| 89 value: "", |
| 90 }, |
| 91 { |
| 92 name: "Changing selection from handler", |
| 93 html: "<div contenteditable>foo</div><div contenteditable>bar</div>", |
| 94 initRange: function(range) { |
| 95 range.setStart(div.querySelector("div").firstChild, 0); |
| 96 range.setEnd(div.querySelector("div").firstChild, 3); |
| 97 }, |
| 98 target: function() { return div.firstChild }, |
| 99 finalTarget: function() { return div.lastChild }, |
| 100 command: "bold", |
| 101 value: "", |
| 102 }, |
| 103 ]; |
| 104 |
| 105 var commandTests = { |
| 106 backColor: ["green"], |
| 107 createLink: ["http://www.w3.org/community/editing/"], |
| 108 fontName: ["serif", "Helvetica"], |
| 109 fontSize: ["6", "15px"], |
| 110 foreColor: ["green"], |
| 111 hiliteColor: ["green"], |
| 112 italic: [], |
| 113 removeFormat: [], |
| 114 strikeThrough: [], |
| 115 subscript: [], |
| 116 superscript: [], |
| 117 underline: [], |
| 118 unlink: [], |
| 119 delete: [], |
| 120 formatBlock: ["p"], |
| 121 forwardDelete: [], |
| 122 indent: [], |
| 123 insertHorizontalRule: ["id"], |
| 124 insertHTML: ["<b>hi</b>"], |
| 125 insertImage: ["../images/green.png"], |
| 126 insertLineBreak: [], |
| 127 insertOrderedList: [], |
| 128 insertParagraph: [], |
| 129 insertText: ["abc"], |
| 130 insertUnorderedList: [], |
| 131 justifyCenter: [], |
| 132 justifyFull: [], |
| 133 justifyLeft: [], |
| 134 justifyRight: [], |
| 135 outdent: [], |
| 136 redo: [], |
| 137 selectAll: [], |
| 138 styleWithCSS: [], |
| 139 undo: [], |
| 140 useCSS: [], |
| 141 }; |
| 142 |
| 143 Object.keys(commandTests).forEach(function(command) { |
| 144 commandTests[command] = ["", "quasit"].concat(commandTests[command]); |
| 145 commandTests[command].forEach(function(value) { |
| 146 tests.push({ |
| 147 name: "Command " + command + ", value " + format_value(value), |
| 148 html: "<div contenteditable>foo<b>bar</b>baz</div>", |
| 149 initRange: function(range) { |
| 150 range.setStart(div.querySelector("b").firstChild, 0); |
| 151 range.setEnd(div.querySelector("b"), 1); |
| 152 }, |
| 153 target: function() { |
| 154 return ["redo", "selectAll", "styleWithCSS", "undo", "useCSS"] |
| 155 .indexOf(command) == -1 ? div.firstChild : null; |
| 156 }, |
| 157 command: command, |
| 158 value: value, |
| 159 }); |
| 160 }); |
| 161 }); |
| 162 |
| 163 tests.forEach(function(obj) { |
| 164 // Kill all event handlers first |
| 165 var newDiv = div.cloneNode(false); |
| 166 div.parentNode.insertBefore(newDiv, div); |
| 167 div.parentNode.removeChild(div); |
| 168 div = newDiv; |
| 169 |
| 170 div.innerHTML = obj.html; |
| 171 |
| 172 var originalContents = div.cloneNode(true); |
| 173 |
| 174 getSelection().removeAllRanges(); |
| 175 var range = document.createRange(); |
| 176 obj.initRange(range); |
| 177 getSelection().addRange(range); |
| 178 |
| 179 var target = obj.target(); |
| 180 var finalTarget = "finalTarget" in obj ? obj.finalTarget() : target; |
| 181 var command = obj.command; |
| 182 var value = obj.value; |
| 183 |
| 184 var inputEvents = []; |
| 185 div.addEventListener("input", function(e) { inputEvents.push(copyEvent(e)) }
); |
| 186 |
| 187 var exception = null; |
| 188 try { |
| 189 document.execCommand(command, false, value); |
| 190 } catch(e) { |
| 191 exception = e; |
| 192 } |
| 193 |
| 194 test(function() { |
| 195 assert_equals(exception, null, "Unexpected exception"); |
| 196 }, obj.name + ": execCommand() must not throw"); |
| 197 |
| 198 test(function() { |
| 199 assert_equals(inputEvents.length, target ? 1 : 0, |
| 200 "number of input events fired"); |
| 201 if (!target) { |
| 202 assert_true(originalContents.isEqualNode(div), |
| 203 "div contents must not be changed"); |
| 204 return; |
| 205 } |
| 206 var e = inputEvents[0]; |
| 207 assert_equals(e.type, "input", "event.type"); |
| 208 assert_equals(e.target, finalTarget, "event.target"); |
| 209 assert_equals(e.currentTarget, div, "event.currentTarget"); |
| 210 assert_equals(e.eventPhase, Event.BUBBLING_PHASE, "event.eventPhase"); |
| 211 assert_equals(e.bubbles, true, "event.bubbles"); |
| 212 assert_equals(e.cancelable, false, "event.cancelable"); |
| 213 assert_equals(e.defaultPrevented, false, "event.defaultPrevented"); |
| 214 assert_own_property(window, "InputEvent", |
| 215 "window.InputEvent must exist"); |
| 216 assert_equals(Object.getPrototypeOf(e.original), InputEvent.prototype, |
| 217 "event prototype"); |
| 218 assert_equals(e.isTrusted, true, "event.isTrusted"); |
| 219 }, obj.name + ": input event"); |
| 220 }); |
| 221 |
| 222 // Thanks, Gecko. |
| 223 document.body.bgColor = ""; |
| 224 </script> |
OLD | NEW |