test_abs_positioner_positioning_elements.html (9076B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>Test for positioners of absolute positioned elements</title> 5 <script src="/tests/SimpleTest/SimpleTest.js"></script> 6 <script src="/tests/SimpleTest/EventUtils.js"></script> 7 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> 8 <style> 9 #target { 10 background-color: green; 11 } 12 </style> 13 </head> 14 <body> 15 <p id="display"></p> 16 <div id="content" contenteditable style="height: 200px; width: 200px;"></div> 17 <div id="clickaway" style="position: absolute; top: 250px; width: 10px; height: 10px; z-index: 100;"></div> 18 <img src="green.png"><!-- for ensuring to load the image at first test of <img> case --> 19 <pre id="test"> 20 <script type="application/javascript"> 21 "use strict"; 22 23 SimpleTest.waitForExplicitFinish(); 24 SimpleTest.waitForFocus(async function() { 25 document.execCommand("enableAbsolutePositionEditing", false, true); 26 ok(document.queryCommandState("enableAbsolutePositionEditing"), 27 "Absolute positioned element editor should be enabled by the call of execCommand"); 28 29 let outOfEditor = document.getElementById("clickaway"); 30 31 function cancel(e) { e.stopPropagation(); } 32 let content = document.getElementById("content"); 33 content.addEventListener("mousedown", cancel); 34 content.addEventListener("mousemove", cancel); 35 content.addEventListener("mouseup", cancel); 36 37 async function waitForSelectionChange() { 38 return new Promise(resolve => { 39 document.addEventListener("selectionchange", () => { 40 resolve(); 41 }, {once: true}); 42 }); 43 } 44 45 async function doTest(aDescription, aInnerHTML) { 46 content.innerHTML = aInnerHTML; 47 let description = aDescription + ": "; 48 let target = document.getElementById("target"); 49 target.style.position = "absolute"; 50 51 async function testPositioner(aDeltaX, aDeltaY) { 52 ok(true, description + "testPositioner(" + [aDeltaX, aDeltaY].join(", ") + ")"); 53 54 // Reset the position of the target. 55 target.style.top = "50px"; 56 target.style.left = "50px"; 57 58 // Click on the target to show the positioner. 59 let promiseSelectionChangeEvent = waitForSelectionChange(); 60 synthesizeMouseAtCenter(target, {}); 61 await promiseSelectionChangeEvent; 62 63 let rect = target.getBoundingClientRect(); 64 65 ok(target.hasAttribute("_moz_abspos"), 66 description + "While enableAbsolutePositionEditing is enabled, the positioner should appear"); 67 68 // left is abs positioned element's left + margin-left + border-left-width + 12. 69 // XXX Perhaps, we need to add border-left-width here if you add new test to have thick border. 70 const kPositionerX = 18; 71 // top is abs positioned element's top + margin-top + border-top-width - 14. 72 // XXX Perhaps, we need to add border-top-width here if you add new test to have thick border. 73 const kPositionerY = -7; 74 75 let beforeInputEventExpected = true; 76 let beforeInputFired = false; 77 let inputEventExpected = true; 78 let inputFired = false; 79 function onBeforeInput(aEvent) { 80 beforeInputFired = true; 81 aEvent.preventDefault(); // For making sure this preventDefault() call does not cancel the operation. 82 if (!beforeInputEventExpected) { 83 ok(false, '"beforeinput" event should not be fired after stopping resizing'); 84 return; 85 } 86 ok(aEvent instanceof InputEvent, 87 '"beforeinput" event for position changing of absolute position should be dispatched with InputEvent interface'); 88 is(aEvent.cancelable, false, 89 '"beforeinput" event for position changing of absolute position container should not be cancelable'); 90 is(aEvent.bubbles, true, 91 '"beforeinput" event for position changing of absolute position should always bubble'); 92 is(aEvent.inputType, "", 93 'inputType of "beforeinput" event for position changing of absolute position should be empty string'); 94 is(aEvent.data, null, 95 'data of "beforeinput" event for position changing of absolute position should be null'); 96 is(aEvent.dataTransfer, null, 97 'dataTransfer of "beforeinput" event for position changing of absolute position should be null'); 98 let targetRanges = aEvent.getTargetRanges(); 99 let selection = document.getSelection(); 100 is(targetRanges.length, selection.rangeCount, 101 'getTargetRanges() of "beforeinput" event for position changing of absolute position should return selection ranges'); 102 if (targetRanges.length === selection.rangeCount) { 103 for (let i = 0; i < selection.rangeCount; i++) { 104 let range = selection.getRangeAt(i); 105 is(targetRanges[i].startContainer, range.startContainer, 106 `startContainer of getTargetRanges()[${i}] of "beforeinput" event for position changing of absolute position does not match`); 107 is(targetRanges[i].startOffset, range.startOffset, 108 `startOffset of getTargetRanges()[${i}] of "beforeinput" event for position changing of absolute position does not match`); 109 is(targetRanges[i].endContainer, range.endContainer, 110 `endContainer of getTargetRanges()[${i}] of "beforeinput" event for position changing of absolute position does not match`); 111 is(targetRanges[i].endOffset, range.endOffset, 112 `endOffset of getTargetRanges()[${i}] of "beforeinput" event for position changing of absolute position does not match`); 113 } 114 } 115 } 116 function onInput(aEvent) { 117 inputFired = true; 118 if (!inputEventExpected) { 119 ok(false, '"input" event should not be fired after stopping resizing'); 120 return; 121 } 122 ok(aEvent instanceof InputEvent, 123 '"input" event for position changing of absolute position container should be dispatched with InputEvent interface'); 124 is(aEvent.cancelable, false, 125 '"input" event for position changing of absolute position container should be never cancelable'); 126 is(aEvent.bubbles, true, 127 '"input" event for position changing of absolute position should always bubble'); 128 is(aEvent.inputType, "", 129 'inputType of "input" event for position changing of absolute position should be empty string'); 130 is(aEvent.data, null, 131 'data of "input" event for position changing of absolute position should be null'); 132 is(aEvent.dataTransfer, null, 133 'dataTransfer of "input" event for position changing of absolute position should be null'); 134 is(aEvent.getTargetRanges().length, 0, 135 'getTargetRanges() of "input" event for position changing of absolute position should return empty array'); 136 } 137 138 content.addEventListener("beforeinput", onBeforeInput); 139 content.addEventListener("input", onInput); 140 141 // Click on the positioner. 142 synthesizeMouse(target, kPositionerX, kPositionerY, {type: "mousedown"}); 143 // Drag it delta pixels. 144 synthesizeMouse(target, kPositionerX + aDeltaX, kPositionerY + aDeltaY, {type: "mousemove"}); 145 // Release the mouse button 146 synthesizeMouse(target, kPositionerX + aDeltaX, kPositionerY + aDeltaY, {type: "mouseup"}); 147 148 ok(beforeInputFired, `${description}"beforeinput" event should be fired by moving absolute position container`); 149 ok(inputFired, `${description}"input" event should be fired by moving absolute position container`); 150 151 beforeInputEventExpected = false; 152 inputEventExpected = false; 153 154 // Move the mouse delta more pixels to the same direction to make sure that the 155 // positioning operation has stopped. 156 synthesizeMouse(target, kPositionerX + aDeltaX * 2, kPositionerY + aDeltaY * 2, {type: "mousemove"}); 157 // Click outside of the image to hide the positioner. 158 synthesizeMouseAtCenter(outOfEditor, {}); 159 160 content.removeEventListener("beforeinput", onBeforeInput); 161 content.removeEventListener("input", onInput); 162 163 // Get the new dimensions for the absolute positioned element. 164 let newRect = target.getBoundingClientRect(); 165 isfuzzy(newRect.x, rect.x + aDeltaX, 1, description + "The left should be increased by " + aDeltaX + " pixels"); 166 isfuzzy(newRect.y, rect.y + aDeltaY, 1, description + "The top should be increased by " + aDeltaY + "pixels"); 167 } 168 169 await testPositioner( 10, 10); 170 await testPositioner( 10, -10); 171 await testPositioner(-10, 10); 172 await testPositioner(-10, -10); 173 } 174 175 const kTests = [ 176 { description: "Positioner for <img>", 177 innerHTML: "<img id=\"target\" src=\"green.png\">", 178 }, 179 { description: "Positioner for <table>", 180 innerHTML: "<table id=\"target\" border><tr><td>cell</td><td>cell</td></tr></table>", 181 }, 182 { description: "Positioner for <div>", 183 innerHTML: "<div id=\"target\">div element</div>", 184 }, 185 ]; 186 187 for (const kTest of kTests) { 188 await doTest(kTest.description, kTest.innerHTML); 189 } 190 content.innerHTML = ""; 191 SimpleTest.finish(); 192 }); 193 </script> 194 </pre> 195 </body> 196 </html>