4 <title>Test for resizers of some 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"/>
10 background-color: green;
16 <div id=
"content" contenteditable
style=
"width: 200px; height: 200px;"></div>
17 <div id=
"clickaway" style=
"width: 10px; height: 10px"></div>
18 <img src=
"green.png"><!-- for ensuring to load the image at first test of <img> case -->
20 <script type=
"application/javascript">
23 SimpleTest.waitForExplicitFinish();
24 SimpleTest.waitForFocus(async () =
> {
25 document.execCommand(
"enableObjectResizing", false, true);
26 ok(document.queryCommandState(
"enableObjectResizing"),
27 "Object resizer should be enabled by the call of execCommand");
28 // Disable inline-table-editing UI for this test.
29 document.execCommand(
"enableInlineTableEditing", false, false);
31 let outOfEditor = document.getElementById(
"clickaway");
33 function cancel(e) { e.stopPropagation(); }
34 let content = document.getElementById(
"content");
35 content.addEventListener(
"mousedown", cancel);
36 content.addEventListener(
"mousemove", cancel);
37 content.addEventListener(
"mouseup", cancel);
39 async function waitForSelectionChange() {
40 return new Promise(resolve =
> {
41 document.addEventListener(
"selectionchange", () =
> {
47 async function doTest(aDescription, aPreserveRatio, aInnerHTML) {
48 let description = aDescription;
49 if (document.queryCommandState(
"enableAbsolutePositionEditing")) {
50 description +=
" (absolute position editor is enabled)";
53 content.innerHTML = aInnerHTML;
54 let target = document.getElementById(
"target");
57 * This function is a generic resizer test.
58 * We have
8 resizers that we'd like to test, and each can be moved in
8 different directions.
59 * In specifying baseX, W can be considered to be the width of the image, and for baseY, H
60 * can be considered to be the height of the image. deltaX and deltaY are regular pixel values
61 * which can be positive or negative.
62 * TODO: Should test canceling
"beforeinput" events case.
66 async function testResizer(baseX, baseY, deltaX, deltaY, expectedDeltaX, expectedDeltaY) {
67 ok(true, description +
"testResizer(" + [baseX, baseY, deltaX, deltaY, expectedDeltaX, expectedDeltaY].join(
", ") +
")");
69 // Reset the dimensions of the target.
70 target.style.width =
"150px";
71 target.style.height =
"150px";
72 let rect = target.getBoundingClientRect();
73 is(rect.width,
150, description +
"Sanity check the width");
74 is(rect.height,
150, description +
"Sanity check the height");
76 // Click on the target to show the resizers
77 ok(true,
"waiting selectionchange to select the target element");
78 let promiseSelectionChangeEvent = waitForSelectionChange();
79 synthesizeMouseAtCenter(target, {});
80 await promiseSelectionChangeEvent;
82 // Determine which resizer we're dealing with.
83 let basePosX = rect.width * baseX;
84 let basePosY = rect.height * baseY;
86 let inputEventExpected = true;
87 function onInput(aEvent) {
88 if (!inputEventExpected) {
89 ok(false, `
"${aEvent.type}" event shouldn't be fired after stopping resizing`);
92 ok(aEvent instanceof InputEvent,
93 `
"${aEvent.type}" event should be dispatched with InputEvent interface`);
94 is(aEvent.cancelable, false,
95 `
"${aEvent.type}" event should be never cancelable`);
96 is(aEvent.bubbles, true,
97 `
"${aEvent.type}" event should always bubble`);
98 is(aEvent.inputType,
"",
99 `inputType of
"${aEvent.type}" event should be empty string when an element is resized`);
100 is(aEvent.data, null,
101 `data of
"${aEvent.type}" event should be null ${aDescription}`);
102 is(aEvent.dataTransfer, null,
103 `data of
"${aEvent.type}" event should be null ${aDescription}`);
104 let targetRanges = aEvent.getTargetRanges();
105 if (aEvent.type ===
"beforeinput") {
106 let selection = document.getSelection();
107 is(targetRanges.length, selection.rangeCount,
108 `getTargetRanges() of
"beforeinput" event for position changing of absolute position should return selection ranges ${aDescription}`);
109 if (targetRanges.length === selection.rangeCount) {
110 for (let i =
0; i < selection.rangeCount; i++) {
111 let range = selection.getRangeAt(i);
112 is(targetRanges[i].startContainer, range.startContainer,
113 `startContainer of getTargetRanges()[${i}] of
"beforeinput" event for position changing of absolute position does not match ${aDescription}`);
114 is(targetRanges[i].startOffset, range.startOffset,
115 `startOffset of getTargetRanges()[${i}] of
"beforeinput" event for position changing of absolute position does not match ${aDescription}`);
116 is(targetRanges[i].endContainer, range.endContainer,
117 `endContainer of getTargetRanges()[${i}] of
"beforeinput" event for position changing of absolute position does not match ${aDescription}`);
118 is(targetRanges[i].endOffset, range.endOffset,
119 `endOffset of getTargetRanges()[${i}] of
"beforeinput" event for position changing of absolute position does not match ${aDescription}`);
123 is(targetRanges.length,
0,
124 `getTargetRanges() of
"${aEvent.type}" event for position changing of absolute position should return empty array ${aDescription}`);
128 content.addEventListener(
"beforeinput", onInput);
129 content.addEventListener(
"input", onInput);
131 // Click on the correct resizer
132 synthesizeMouse(target, basePosX, basePosY, {type:
"mousedown"});
133 // Drag it delta pixels to the right and bottom (or maybe left and top!)
134 synthesizeMouse(target, basePosX + deltaX, basePosY + deltaY, {type:
"mousemove"});
135 // Release the mouse button
136 synthesizeMouse(target, basePosX + deltaX, basePosY + deltaY, {type:
"mouseup"});
138 inputEventExpected = false;
140 // Move the mouse delta more pixels to the same direction to make sure that the
141 // resize operation has stopped.
142 synthesizeMouse(target, basePosX + deltaX *
2, basePosY + deltaY *
2, {type:
"mousemove"});
144 // Click outside of the editor to hide the resizers
145 ok(true,
"waiting selectionchange to select outside the target element");
146 let promiseSelectionExitEvent = waitForSelectionChange();
147 synthesizeMouseAtCenter(outOfEditor, {});
148 await promiseSelectionExitEvent;
150 // Get the new dimensions for the target
151 // XXX I don't know why we need
2px margin to check this on Android.
152 // Fortunately, this test checks whether objects are resizable
153 // actually. So, bigger difference is okay.
154 let newRect = target.getBoundingClientRect();
155 isfuzzy(newRect.width, rect.width + expectedDeltaX,
2, description +
"The width should be increased by " + expectedDeltaX +
" pixels");
156 isfuzzy(newRect.height, rect.height + expectedDeltaY,
2, description +
"The height should be increased by " + expectedDeltaY +
"pixels");
158 content.removeEventListener(
"beforeinput", onInput);
159 content.removeEventListener(
"input", onInput);
162 // Account for changes in the resizing behavior when we're trying to preserve
163 // the aspect ration of image.
164 // ignoredGrowth means we don't change the size of a dimension because otherwise
165 // the aspect ratio would change undesirably.
166 // needlessGrowth means that we change the size of a dimension perpendecular to
167 // the mouse movement axis in order to preserve the aspect ratio.
168 // reversedGrowth means that we change the size of a dimension in the opposite
169 // direction to the mouse movement in order to maintain the aspect ratio.
170 const ignoredGrowth = aPreserveRatio ?
0 :
1;
171 const needlessGrowth = aPreserveRatio ?
1 :
0;
172 const reversedGrowth = aPreserveRatio ? -
1 :
1;
174 /* eslint-disable no-multi-spaces */
177 await testResizer(W /
2,
0, -
10, -
10,
0,
10);
178 await testResizer(W /
2,
0, -
10,
0,
0,
0);
179 await testResizer(W /
2,
0, -
10,
10,
0, -
10);
180 await testResizer(W /
2,
0,
0, -
10,
0,
10);
181 await testResizer(W /
2,
0,
0,
0,
0,
0);
182 await testResizer(W /
2,
0,
0,
10,
0, -
10);
183 await testResizer(W /
2,
0,
10, -
10,
0,
10);
184 await testResizer(W /
2,
0,
10,
0,
0,
0);
185 await testResizer(W /
2,
0,
10,
10,
0, -
10);
188 await testResizer( W,
0, -
10, -
10, -
10 * reversedGrowth,
10);
189 await testResizer( W,
0, -
10,
0, -
10 * ignoredGrowth,
0);
190 await testResizer( W,
0, -
10,
10, -
10, -
10);
191 await testResizer( W,
0,
0, -
10,
10 * needlessGrowth,
10);
192 await testResizer( W,
0,
0,
0,
0,
0);
193 await testResizer( W,
0,
0,
10,
0, -
10 * ignoredGrowth);
194 await testResizer( W,
0,
10, -
10,
10,
10);
195 await testResizer( W,
0,
10,
0,
10,
10 * needlessGrowth);
196 await testResizer( W,
0,
10,
10,
10, -
10 * reversedGrowth);
199 await testResizer( W, H /
2, -
10, -
10, -
10,
0);
200 await testResizer( W, H /
2, -
10,
0, -
10,
0);
201 await testResizer( W, H /
2, -
10,
10, -
10,
0);
202 await testResizer( W, H /
2,
0, -
10,
0,
0);
203 await testResizer( W, H /
2,
0,
0,
0,
0);
204 await testResizer( W, H /
2,
0,
10,
0,
0);
205 await testResizer( W, H /
2,
10, -
10,
10,
0);
206 await testResizer( W, H /
2,
10,
0,
10,
0);
207 await testResizer( W, H /
2,
10,
10,
10,
0);
209 // bottom right resizer
210 await testResizer( W, H, -
10, -
10, -
10, -
10);
211 await testResizer( W, H, -
10,
0, -
10 * ignoredGrowth,
0);
212 await testResizer( W, H, -
10,
10, -
10 * reversedGrowth,
10);
213 await testResizer( W, H,
0, -
10,
0, -
10 * ignoredGrowth);
214 await testResizer( W, H,
0,
0,
0,
0);
215 await testResizer( W, H,
0,
10,
10 * needlessGrowth,
10);
216 await testResizer( W, H,
10, -
10,
10, -
10 * reversedGrowth);
217 await testResizer( W, H,
10,
0,
10,
10 * needlessGrowth);
218 await testResizer( W, H,
10,
10,
10,
10);
221 await testResizer(W /
2, H, -
10, -
10,
0, -
10);
222 await testResizer(W /
2, H, -
10,
0,
0,
0);
223 await testResizer(W /
2, H, -
10,
10,
0,
10);
224 await testResizer(W /
2, H,
0, -
10,
0, -
10);
225 await testResizer(W /
2, H,
0,
0,
0,
0);
226 await testResizer(W /
2, H,
0,
10,
0,
10);
227 await testResizer(W /
2, H,
10, -
10,
0, -
10);
228 await testResizer(W /
2, H,
10,
0,
0,
0);
229 await testResizer(W /
2, H,
10,
10,
0,
10);
231 // bottom left resizer
232 await testResizer(
0, H, -
10, -
10,
10, -
10 * reversedGrowth);
233 await testResizer(
0, H, -
10,
0,
10,
10 * needlessGrowth);
234 await testResizer(
0, H, -
10,
10,
10,
10);
235 await testResizer(
0, H,
0, -
10,
0, -
10 * ignoredGrowth);
236 await testResizer(
0, H,
0,
0,
0,
0);
237 await testResizer(
0, H,
0,
10,
10 * needlessGrowth,
10);
238 await testResizer(
0, H,
10, -
10, -
10, -
10);
239 await testResizer(
0, H,
10,
0, -
10 * ignoredGrowth,
0);
240 await testResizer(
0, H,
10,
10, -
10 * reversedGrowth,
10);
243 await testResizer(
0, H /
2, -
10, -
10,
10,
0);
244 await testResizer(
0, H /
2, -
10,
0,
10,
0);
245 await testResizer(
0, H /
2, -
10,
10,
10,
0);
246 await testResizer(
0, H /
2,
0, -
10,
0,
0);
247 await testResizer(
0, H /
2,
0,
0,
0,
0);
248 await testResizer(
0, H /
2,
0,
10,
0,
0);
249 await testResizer(
0, H /
2,
10, -
10, -
10,
0);
250 await testResizer(
0, H /
2,
10,
0, -
10,
0);
251 await testResizer(
0, H /
2,
10,
10, -
10,
0);
254 await testResizer(
0,
0, -
10, -
10,
10,
10);
255 await testResizer(
0,
0, -
10,
0,
10,
10 * needlessGrowth);
256 await testResizer(
0,
0, -
10,
10,
10, -
10 * reversedGrowth);
257 await testResizer(
0,
0,
0, -
10,
10 * needlessGrowth,
10);
258 await testResizer(
0,
0,
0,
0,
0,
0);
259 await testResizer(
0,
0,
0,
10,
0, -
10 * ignoredGrowth);
260 await testResizer(
0,
0,
10, -
10, -
10 * reversedGrowth,
10);
261 await testResizer(
0,
0,
10,
0, -
10 * ignoredGrowth,
0);
262 await testResizer(
0,
0,
10,
10, -
10, -
10);
264 /* eslint-enable no-multi-spaces */
268 { description:
"Resizers for <img>",
269 innerHTML:
"<img id=\"target\
" src=\"green.png\
">",
270 mayPreserveRatio: true,
271 isAbsolutePosition: false,
273 { description:
"Resizers for <table>",
274 innerHTML:
"<table id=\"target\
" border><tr><td>cell</td><td>cell</td></tr></table>",
275 mayPreserveRatio: false,
276 isAbsolutePosition: false,
278 { description:
"Resizers for absolute positioned <div>",
279 innerHTML:
"<div id=\"target\
" style=\"position: absolute; top:
50px; left:
50px;\
">positioned</div>",
280 mayPreserveRatio: false,
281 isAbsolutePosition: true,
285 // Resizers for absolute positioned element and table element are available
286 // only when enableAbsolutePositionEditing or enableInlineTableEditing is
287 // enabled for each. So, let's enable them during testing resizers for
288 // absolute positioned elements or table elements.
289 for (const kTest of kTests) {
290 document.execCommand(
"enableAbsolutePositionEditing", false, kTest.isAbsolutePosition);
291 await doTest(kTest.description, kTest.mayPreserveRatio, kTest.innerHTML);
293 content.innerHTML =
"";