test_editor.xhtml (8540B)
1 <?xml version="1.0"?> 2 3 <window title="Browser element keyhandling tests" 4 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" 5 onload="test();"> 6 7 <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> 8 <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/> 9 <script src="chrome://mochikit/content/tests/SimpleTest/NativeKeyCodes.js"/> 10 11 <script type="application/javascript"> 12 <![CDATA[ 13 SimpleTest.waitForExplicitFinish(); 14 15 const IS_MAC = navigator.platform.indexOf("Mac") === 0; 16 const VK = {}; 17 const CHARS = {}; 18 19 // Copied values from NativeKeyCodes.js and EventUtils.js 20 if (IS_MAC) { 21 VK.LEFT = MAC_VK_LeftArrow; 22 CHARS.LEFT = "\uF702"; 23 VK.RIGHT = MAC_VK_RightArrow; 24 CHARS.RIGHT = "\uF703"; 25 VK.UP = MAC_VK_UpArrow; 26 CHARS.UP = "\uF700"; 27 VK.DOWN = MAC_VK_DownArrow; 28 CHARS.DOWN = "\uF701"; 29 VK.SPACE = MAC_VK_Space; 30 VK.X = MAC_VK_ANSI_X; 31 VK.V = MAC_VK_ANSI_V; 32 VK.A = MAC_VK_ANSI_A; 33 VK.Z = MAC_VK_ANSI_Z; 34 VK.F = MAC_VK_ANSI_F; 35 VK.O = MAC_VK_ANSI_O; 36 VK.BACKSPACE = MAC_VK_PC_Backspace; 37 CHARS.BACKSPACE = "\u007F"; 38 } else { 39 VK.LEFT = WIN_VK_LEFT; 40 CHARS.LEFT = ""; 41 VK.RIGHT = WIN_VK_RIGHT; 42 CHARS.RIGHT = ""; 43 VK.HOME = WIN_VK_HOME; 44 CHARS.HOME = ""; 45 VK.END = WIN_VK_END; 46 CHARS.END = ""; 47 VK.SPACE = WIN_VK_SPACE; 48 VK.X = WIN_VK_X; 49 VK.V = WIN_VK_V; 50 VK.A = WIN_VK_A; 51 VK.Z = WIN_VK_Z; 52 VK.Y = WIN_VK_Y; 53 VK.F = WIN_VK_F; 54 VK.O = WIN_VK_O; 55 VK.BACKSPACE = WIN_VK_BACK; 56 CHARS.BACKSPACE = ""; 57 } 58 59 function waitForEvent(target, event) { 60 info(`Waiting for ${event} event.`); 61 return new Promise(resolve => { 62 browser.addEventListener(event, resolve, { once: true }); 63 }); 64 } 65 66 function synthesizeKey(keyCode, modifiers, chars) { 67 return new Promise((resolve, reject) => { 68 if (!synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, keyCode, modifiers, chars, chars, resolve)) { 69 reject(); 70 } 71 }); 72 } 73 74 function* nodes(element) { 75 let node = element.firstChild; 76 while (node) { 77 yield node; 78 79 if (node.nodeType === Node.ELEMENT_NODE) { 80 yield* nodes(node); 81 } 82 83 node = node.nextSibling; 84 } 85 } 86 87 async function checkElement(element, start, selectedText, content = "Test text") { 88 selectionPosition = (element, range) => { 89 let pos = 0; 90 for (let node of nodes(element)) { 91 if (node.nodeType === Node.TEXT_NODE) { 92 if (node === range.startContainer) { 93 return pos + range.startOffset; 94 } else { 95 pos += node.nodeValue.length; 96 } 97 } else if (node === range.startContainer) { 98 for (let i = 0; i < range.startOffset; i++) { 99 pos += node.childNodes[i].textContent.length; 100 } 101 102 return pos; 103 } 104 } 105 106 throw new Error("startContainer of range never found."); 107 } 108 109 isReady = () => { 110 let selection = element.contentWindow.getSelection(); 111 let range = selection.getRangeAt(0); 112 let pos = selectionPosition(element.contentDocument.documentElement, range); 113 114 if (start != pos) { 115 return false; 116 } 117 if (selectedText != selection.toString()) { 118 return false; 119 } 120 if (content != element.contentDocument.documentElement.textContent) { 121 return false; 122 } 123 return true; 124 }; 125 126 for (let i = 0; i < 10; i++) { 127 if (isReady()) { 128 return; 129 } 130 131 SimpleTest.requestFlakyTimeout("Polling for changes to apply"); 132 await new Promise(resolve => setTimeout(resolve, 50)); 133 } 134 ok(false, `Timed out waiting for state ${start} "${selectedText}" "${content}"`); 135 let selection = element.contentWindow.getSelection(); 136 let range = selection.getRangeAt(0); 137 info(`${selectionPosition(element.contentDocument.documentElement, range)} "${selection.toString()}" "${element.contentDocument.documentElement.textContent}"`); 138 } 139 140 async function test() { 141 let editor = document.getElementById("editor"); 142 editor.contentDocument.designMode = "on"; 143 editor.contentWindow.focus(); 144 let edit = editor.getEditor(editor.contentWindow); 145 edit.beginningOfDocument(); 146 147 await checkElement(editor, 0, ""); 148 149 info("right"); 150 await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); 151 await checkElement(editor, 1, ""); 152 153 info("shift+right"); 154 await synthesizeKey(VK.RIGHT, { shiftKey: true }, CHARS.RIGHT); 155 await checkElement(editor, 1, "e"); 156 157 info("shift+right"); 158 await synthesizeKey(VK.RIGHT, { shiftKey: true }, CHARS.RIGHT); 159 await checkElement(editor, 1, "es"); 160 161 info("shift+left"); 162 await synthesizeKey(VK.LEFT, { shiftKey: true }, CHARS.LEFT); 163 await checkElement(editor, 1, "e"); 164 165 info("shift+left"); 166 await synthesizeKey(VK.LEFT, { shiftKey: true }, CHARS.LEFT); 167 await checkElement(editor, 1, ""); 168 169 info("shift+left"); 170 await synthesizeKey(VK.LEFT, { shiftKey: true }, CHARS.LEFT); 171 await checkElement(editor, 0, "T"); 172 173 info("shift+right"); 174 await synthesizeKey(VK.RIGHT, { shiftKey: true }, CHARS.RIGHT); 175 await checkElement(editor, 1, ""); 176 177 info("left"); 178 await synthesizeKey(VK.LEFT, {}, CHARS.LEFT); 179 await checkElement(editor, 0, ""); 180 181 if (IS_MAC) { 182 info("down"); 183 await synthesizeKey(VK.DOWN, { shiftKey: true }, CHARS.DOWN); 184 } else { 185 info("end"); 186 await synthesizeKey(VK.END, { shiftKey: true }, CHARS.END); 187 } 188 await checkElement(editor, 0, "Test text"); 189 190 info("cut"); 191 await synthesizeKey(VK.X, { accelKey: true }, "x"); 192 await checkElement(editor, 0, "", ""); 193 let text = SpecialPowers.getClipboardData("text/plain"); 194 is(text, "Test text", "Should have cut to the clipboard"); 195 SpecialPowers.clipboardCopyString("New text"); 196 197 info("paste"); 198 await synthesizeKey(VK.V, { accelKey: true }, "v"); 199 await checkElement(editor, 8, "", "New text"); 200 201 if (IS_MAC) { 202 info("up"); 203 await synthesizeKey(VK.UP, {}, CHARS.UP); 204 } else { 205 info("home"); 206 await synthesizeKey(VK.HOME, {}, CHARS.HOME); 207 } 208 await checkElement(editor, 0, "", "New text"); 209 210 info("select all"); 211 await synthesizeKey(VK.A, { accelKey: true}, "a", "select"); 212 await checkElement(editor, 0, "New text", "New text"); 213 214 info("right"); 215 await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); 216 await checkElement(editor, 8, "", "New text"); 217 218 info("word left"); 219 if (IS_MAC) { 220 await synthesizeKey(VK.LEFT, { altKey: true }, CHARS.LEFT); 221 } else { 222 await synthesizeKey(VK.LEFT, { ctrlKey: true }, CHARS.LEFT); 223 } 224 await checkElement(editor, 4, "", "New text"); 225 226 info("delete word left"); 227 if (IS_MAC) { 228 await synthesizeKey(VK.BACKSPACE, { altKey: true }, CHARS.BACKSPACE); 229 } else { 230 await synthesizeKey(VK.BACKSPACE, { ctrlKey: true }, CHARS.BACKSPACE); 231 } 232 await checkElement(editor, 0, "", "text"); 233 234 info("undo"); 235 await synthesizeKey(VK.Z, { accelKey: true }, "z"); 236 await checkElement(editor, 4, "", "New text"); 237 238 info("redo"); 239 if (IS_MAC) { 240 await synthesizeKey(VK.Z, { accelKey: true, shiftKey: true }, "z"); 241 } else { 242 await synthesizeKey(VK.Y, { accelKey: true }, "y"); 243 } 244 await checkElement(editor, 0, "", "text"); 245 246 info("typing"); 247 await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); 248 await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); 249 await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); 250 await synthesizeKey(VK.RIGHT, {}, CHARS.RIGHT); 251 await synthesizeKey(VK.SPACE, {}, " "); 252 await synthesizeKey(VK.F, {}, "f"); 253 await synthesizeKey(VK.O, {}, "o"); 254 await synthesizeKey(VK.O, {}, "o"); 255 await checkElement(editor, 8, "", "text foo"); 256 257 SimpleTest.finish(); 258 } 259 ]]> 260 </script> 261 262 <body xmlns="http://www.w3.org/1999/xhtml"> 263 <p id="display"></p> 264 <div id="content" style="display:none;"></div> 265 <pre id="test"></pre> 266 </body> 267 <editor id="editor" editortype="text" src="data:text/plain,Test text" style="height: 500px"/> 268 </window>