test_nsIEditor_insertNode.html (6852B)
1 <!doctype> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>nsIEditor.insertNode</title> 6 <script src="/tests/SimpleTest/SimpleTest.js"></script> 7 <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> 8 <script> 9 "use strict"; 10 11 function stringifyInputEvent(aEvent) { 12 if (!aEvent) { 13 return "null"; 14 } 15 return `${aEvent.type}: { inputType=${aEvent.inputType} }`; 16 } 17 18 function getRangeDescription(range) { 19 function getNodeDescription(node) { 20 if (!node) { 21 return "null"; 22 } 23 switch (node.nodeType) { 24 case Node.TEXT_NODE: 25 return `${node.nodeName} "${node.data}"`; 26 case Node.ELEMENT_NODE: 27 return `<${node.nodeName.toLowerCase()}>`; 28 default: 29 return `${node.nodeName}`; 30 } 31 } 32 if (range === null) { 33 return "null"; 34 } 35 if (range === undefined) { 36 return "undefined"; 37 } 38 return range.startContainer == range.endContainer && 39 range.startOffset == range.endOffset 40 ? `(${getNodeDescription(range.startContainer)}, ${range.startOffset})` 41 : `(${getNodeDescription(range.startContainer)}, ${ 42 range.startOffset 43 }) - (${getNodeDescription(range.endContainer)}, ${range.endOffset})`; 44 } 45 46 SimpleTest.waitForExplicitFinish(); 47 SimpleTest.waitForFocus(() => { 48 const editingHost = document.querySelector("div[contenteditable]"); 49 const editor = 50 SpecialPowers.wrap(window).docShell.editingSession.getEditorForWindow(window); 51 52 editingHost.focus(); 53 54 let events = []; 55 editingHost.addEventListener("input", event => events.push(event)); 56 57 (function test_insert_text_to_start() { 58 editor.insertNode(document.createTextNode("abc"), editingHost, 0); 59 is( 60 editingHost.innerHTML, 61 "abc<br>", 62 "test_insert_text_to_start: insertNode() should insert new text node at start of the container" 63 ); 64 is( 65 events.length, 66 1, 67 "test_insert_text_to_start: Only one input event should be fired when insertNode() inserts a text node" 68 ); 69 is( 70 stringifyInputEvent(events[0]), 71 stringifyInputEvent({ type: "input", inputType: "" }), 72 "test_insert_text_to_start: input event should be fired when inserting a node" 73 ); 74 is( 75 getRangeDescription(getSelection().getRangeAt(0)), 76 getRangeDescription({ 77 startContainer: editingHost, 78 startOffset: 1, 79 endContainer: editingHost, 80 endOffset: 1, 81 }), 82 "test_insert_text_to_start: insertNode() should collapse selection after the inserted text node" 83 ); 84 })(); 85 86 (function test_insert_span_to_big_index() { 87 events = []; 88 editingHost.innerHTML = "abc"; 89 const span = document.createElement("span"); 90 span.textContent = "def"; 91 editor.insertNode(span, editingHost, 1000); 92 is( 93 editingHost.innerHTML, 94 "abc<span>def</span>", 95 "test_insert_span_to_big_index: insertNode() with big index should insert new node at end of the container" 96 ); 97 is( 98 events.length, 99 1, 100 "test_insert_span_to_big_index: Only one input event should be fired when insertNode() inserts a node" 101 ); 102 is( 103 stringifyInputEvent(events[0]), 104 stringifyInputEvent({ type: "input", inputType: "" }), 105 "test_insert_span_to_big_index: input event should be fired when inserting a node" 106 ); 107 is( 108 getRangeDescription(getSelection().getRangeAt(0)), 109 getRangeDescription({ 110 startContainer: editingHost, 111 startOffset: 2, 112 endContainer: editingHost, 113 endOffset: 2, 114 }), 115 "test_insert_span_to_big_index: insertNode() should collapse selection after the inserted node" 116 ); 117 })(); 118 119 (function test_preserve_selection() { 120 events = []; 121 editingHost.innerHTML = "abc"; 122 const span = document.createElement("span"); 123 span.textContent = "def"; 124 getSelection().collapse(editingHost, 0); 125 editor.insertNode(span, editingHost, 1, true); 126 is( 127 editingHost.innerHTML, 128 "abc<span>def</span>", 129 "test_preserve_selection: insertNode() should insert new node at end of the container" 130 ); 131 is( 132 events.length, 133 1, 134 "test_preserve_selection: Only one input event should be fired when insertNode() inserts a node" 135 ); 136 is( 137 stringifyInputEvent(events[0]), 138 stringifyInputEvent({ type: "input", inputType: "" }), 139 "test_preserve_selection: input event should be fired when inserting a node" 140 ); 141 is( 142 getRangeDescription(getSelection().getRangeAt(0)), 143 getRangeDescription({ 144 startContainer: editingHost, 145 startOffset: 0, 146 endContainer: editingHost, 147 endOffset: 0, 148 }), 149 "test_preserve_selection: insertNode() should not collapse selection after the inserted node" 150 ); 151 })(); 152 153 (function test_not_preserve_selection_nested_by_beforeinput() { 154 editingHost.innerHTML = "abc"; 155 const span1 = document.createElement("span"); 156 span1.textContent = "def"; 157 const span2 = document.createElement("span"); 158 span2.textContent = "ghi"; 159 getSelection().collapse(editingHost, 0); 160 editingHost.addEventListener("beforeinput", () => { 161 editor.insertNode(span1, editingHost, 1); 162 }, {once: true}); 163 editor.insertNode(span2, editingHost, 2, true); 164 is( 165 editingHost.innerHTML, 166 "abc<span>def</span><span>ghi</span>", 167 "test_not_preserve_selection_nested_by_beforeinput: both insertNode() should work" 168 ); 169 is( 170 getRangeDescription(getSelection().getRangeAt(0)), 171 getRangeDescription({ 172 startContainer: editingHost, 173 startOffset: 2, 174 endContainer: editingHost, 175 endOffset: 2, 176 }), 177 "test_not_preserve_selection_nested_by_beforeinput: only insertNode() called in beforeinput listener should update selection" 178 ); 179 })(); 180 181 (function test_not_preserve_selection_nested_by_input() { 182 editingHost.innerHTML = "abc"; 183 const span1 = document.createElement("span"); 184 span1.textContent = "def"; 185 const span2 = document.createElement("span"); 186 span2.textContent = "ghi"; 187 getSelection().collapse(editingHost, 0); 188 editingHost.addEventListener("input", () => { 189 editor.insertNode(span2, editingHost, 2); 190 }, {once: true}); 191 editor.insertNode(span1, editingHost, 1, true); 192 is( 193 editingHost.innerHTML, 194 "abc<span>def</span><span>ghi</span>", 195 "test_not_preserve_selection_nested_by_input: both insertNode() should work" 196 ); 197 is( 198 getRangeDescription(getSelection().getRangeAt(0)), 199 getRangeDescription({ 200 startContainer: editingHost, 201 startOffset: 3, 202 endContainer: editingHost, 203 endOffset: 3, 204 }), 205 "test_not_preserve_selection_nested_by_input: only insertNode() called in input listener should update selection" 206 ); 207 })(); 208 209 SimpleTest.finish(); 210 }); 211 </script> 212 </head> 213 <body><div contenteditable><br></div></body> 214 </html>