summaryrefslogtreecommitdiffstats
path: root/editor/libeditor/tests/test_resizers_resizing_elements.html
diff options
context:
space:
mode:
Diffstat (limited to 'editor/libeditor/tests/test_resizers_resizing_elements.html')
-rw-r--r--editor/libeditor/tests/test_resizers_resizing_elements.html299
1 files changed, 299 insertions, 0 deletions
diff --git a/editor/libeditor/tests/test_resizers_resizing_elements.html b/editor/libeditor/tests/test_resizers_resizing_elements.html
new file mode 100644
index 0000000000..f30b6bb269
--- /dev/null
+++ b/editor/libeditor/tests/test_resizers_resizing_elements.html
@@ -0,0 +1,299 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for resizers of some elements</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <style>
+ #target {
+ background-color: green;
+ }
+ </style>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" contenteditable style="width: 200px; height: 200px;"></div>
+<div id="clickaway" style="width: 10px; height: 10px"></div>
+<img src="green.png"><!-- for ensuring to load the image at first test of <img> case -->
+<pre id="test">
+<script type="application/javascript">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(async () => {
+ document.execCommand("enableObjectResizing", false, true);
+ ok(document.queryCommandState("enableObjectResizing"),
+ "Object resizer should be enabled by the call of execCommand");
+ // Disable inline-table-editing UI for this test.
+ document.execCommand("enableInlineTableEditing", false, false);
+
+ let outOfEditor = document.getElementById("clickaway");
+
+ function cancel(e) { e.stopPropagation(); }
+ let content = document.getElementById("content");
+ content.addEventListener("mousedown", cancel);
+ content.addEventListener("mousemove", cancel);
+ content.addEventListener("mouseup", cancel);
+
+ async function waitForSelectionChange() {
+ return new Promise(resolve => {
+ document.addEventListener("selectionchange", () => {
+ resolve();
+ }, {once: true});
+ });
+ }
+
+ async function doTest(aDescription, aPreserveRatio, aInnerHTML) {
+ let description = aDescription;
+ if (document.queryCommandState("enableAbsolutePositionEditing")) {
+ description += " (absolute position editor is enabled)";
+ }
+ description += ": ";
+ content.innerHTML = aInnerHTML;
+ let target = document.getElementById("target");
+
+ /**
+ * This function is a generic resizer test.
+ * We have 8 resizers that we'd like to test, and each can be moved in 8 different directions.
+ * In specifying baseX, W can be considered to be the width of the image, and for baseY, H
+ * can be considered to be the height of the image. deltaX and deltaY are regular pixel values
+ * which can be positive or negative.
+ * TODO: Should test canceling "beforeinput" events case.
+ */
+ const W = 1;
+ const H = 1;
+ async function testResizer(baseX, baseY, deltaX, deltaY, expectedDeltaX, expectedDeltaY) {
+ ok(true, description + "testResizer(" + [baseX, baseY, deltaX, deltaY, expectedDeltaX, expectedDeltaY].join(", ") + ")");
+
+ // Reset the dimensions of the target.
+ target.style.width = "150px";
+ target.style.height = "150px";
+ let rect = target.getBoundingClientRect();
+ is(rect.width, 150, description + "Sanity check the width");
+ is(rect.height, 150, description + "Sanity check the height");
+
+ // Click on the target to show the resizers
+ ok(true, "waiting selectionchange to select the target element");
+ let promiseSelectionChangeEvent = waitForSelectionChange();
+ synthesizeMouseAtCenter(target, {});
+ await promiseSelectionChangeEvent;
+
+ // Determine which resizer we're dealing with.
+ let basePosX = rect.width * baseX;
+ let basePosY = rect.height * baseY;
+
+ let inputEventExpected = true;
+ function onInput(aEvent) {
+ if (!inputEventExpected) {
+ ok(false, `"${aEvent.type}" event shouldn't be fired after stopping resizing`);
+ return;
+ }
+ ok(aEvent instanceof InputEvent,
+ `"${aEvent.type}" event should be dispatched with InputEvent interface`);
+ is(aEvent.cancelable, false,
+ `"${aEvent.type}" event should be never cancelable`);
+ is(aEvent.bubbles, true,
+ `"${aEvent.type}" event should always bubble`);
+ is(aEvent.inputType, "",
+ `inputType of "${aEvent.type}" event should be empty string when an element is resized`);
+ is(aEvent.data, null,
+ `data of "${aEvent.type}" event should be null ${aDescription}`);
+ is(aEvent.dataTransfer, null,
+ `data of "${aEvent.type}" event should be null ${aDescription}`);
+ let targetRanges = aEvent.getTargetRanges();
+ if (aEvent.type === "beforeinput") {
+ let selection = document.getSelection();
+ is(targetRanges.length, selection.rangeCount,
+ `getTargetRanges() of "beforeinput" event for position changing of absolute position should return selection ranges ${aDescription}`);
+ if (targetRanges.length === selection.rangeCount) {
+ for (let i = 0; i < selection.rangeCount; i++) {
+ let range = selection.getRangeAt(i);
+ is(targetRanges[i].startContainer, range.startContainer,
+ `startContainer of getTargetRanges()[${i}] of "beforeinput" event for position changing of absolute position does not match ${aDescription}`);
+ is(targetRanges[i].startOffset, range.startOffset,
+ `startOffset of getTargetRanges()[${i}] of "beforeinput" event for position changing of absolute position does not match ${aDescription}`);
+ is(targetRanges[i].endContainer, range.endContainer,
+ `endContainer of getTargetRanges()[${i}] of "beforeinput" event for position changing of absolute position does not match ${aDescription}`);
+ is(targetRanges[i].endOffset, range.endOffset,
+ `endOffset of getTargetRanges()[${i}] of "beforeinput" event for position changing of absolute position does not match ${aDescription}`);
+ }
+ }
+ } else {
+ is(targetRanges.length, 0,
+ `getTargetRanges() of "${aEvent.type}" event for position changing of absolute position should return empty array ${aDescription}`);
+ }
+ }
+
+ content.addEventListener("beforeinput", onInput);
+ content.addEventListener("input", onInput);
+
+ // Click on the correct resizer
+ synthesizeMouse(target, basePosX, basePosY, {type: "mousedown"});
+ // Drag it delta pixels to the right and bottom (or maybe left and top!)
+ synthesizeMouse(target, basePosX + deltaX, basePosY + deltaY, {type: "mousemove"});
+ // Release the mouse button
+ synthesizeMouse(target, basePosX + deltaX, basePosY + deltaY, {type: "mouseup"});
+
+ inputEventExpected = false;
+
+ // Move the mouse delta more pixels to the same direction to make sure that the
+ // resize operation has stopped.
+ synthesizeMouse(target, basePosX + deltaX * 2, basePosY + deltaY * 2, {type: "mousemove"});
+
+ // Click outside of the editor to hide the resizers
+ ok(true, "waiting selectionchange to select outside the target element");
+ let promiseSelectionExitEvent = waitForSelectionChange();
+ synthesizeMouseAtCenter(outOfEditor, {});
+ await promiseSelectionExitEvent;
+
+ // Get the new dimensions for the target
+ // XXX I don't know why we need 2px margin to check this on Android.
+ // Fortunately, this test checks whether objects are resizable
+ // actually. So, bigger difference is okay.
+ let newRect = target.getBoundingClientRect();
+ isfuzzy(newRect.width, rect.width + expectedDeltaX, 2, description + "The width should be increased by " + expectedDeltaX + " pixels");
+ isfuzzy(newRect.height, rect.height + expectedDeltaY, 2, description + "The height should be increased by " + expectedDeltaY + "pixels");
+
+ content.removeEventListener("beforeinput", onInput);
+ content.removeEventListener("input", onInput);
+ }
+
+ // Account for changes in the resizing behavior when we're trying to preserve
+ // the aspect ration of image.
+ // ignoredGrowth means we don't change the size of a dimension because otherwise
+ // the aspect ratio would change undesirably.
+ // needlessGrowth means that we change the size of a dimension perpendecular to
+ // the mouse movement axis in order to preserve the aspect ratio.
+ // reversedGrowth means that we change the size of a dimension in the opposite
+ // direction to the mouse movement in order to maintain the aspect ratio.
+ const ignoredGrowth = aPreserveRatio ? 0 : 1;
+ const needlessGrowth = aPreserveRatio ? 1 : 0;
+ const reversedGrowth = aPreserveRatio ? -1 : 1;
+
+ /* eslint-disable no-multi-spaces */
+
+ // top resizer
+ await testResizer(W / 2, 0, -10, -10, 0, 10);
+ await testResizer(W / 2, 0, -10, 0, 0, 0);
+ await testResizer(W / 2, 0, -10, 10, 0, -10);
+ await testResizer(W / 2, 0, 0, -10, 0, 10);
+ await testResizer(W / 2, 0, 0, 0, 0, 0);
+ await testResizer(W / 2, 0, 0, 10, 0, -10);
+ await testResizer(W / 2, 0, 10, -10, 0, 10);
+ await testResizer(W / 2, 0, 10, 0, 0, 0);
+ await testResizer(W / 2, 0, 10, 10, 0, -10);
+
+ // top right resizer
+ await testResizer( W, 0, -10, -10, -10 * reversedGrowth, 10);
+ await testResizer( W, 0, -10, 0, -10 * ignoredGrowth, 0);
+ await testResizer( W, 0, -10, 10, -10, -10);
+ await testResizer( W, 0, 0, -10, 10 * needlessGrowth, 10);
+ await testResizer( W, 0, 0, 0, 0, 0);
+ await testResizer( W, 0, 0, 10, 0, -10 * ignoredGrowth);
+ await testResizer( W, 0, 10, -10, 10, 10);
+ await testResizer( W, 0, 10, 0, 10, 10 * needlessGrowth);
+ await testResizer( W, 0, 10, 10, 10, -10 * reversedGrowth);
+
+ // right resizer
+ await testResizer( W, H / 2, -10, -10, -10, 0);
+ await testResizer( W, H / 2, -10, 0, -10, 0);
+ await testResizer( W, H / 2, -10, 10, -10, 0);
+ await testResizer( W, H / 2, 0, -10, 0, 0);
+ await testResizer( W, H / 2, 0, 0, 0, 0);
+ await testResizer( W, H / 2, 0, 10, 0, 0);
+ await testResizer( W, H / 2, 10, -10, 10, 0);
+ await testResizer( W, H / 2, 10, 0, 10, 0);
+ await testResizer( W, H / 2, 10, 10, 10, 0);
+
+ // bottom right resizer
+ await testResizer( W, H, -10, -10, -10, -10);
+ await testResizer( W, H, -10, 0, -10 * ignoredGrowth, 0);
+ await testResizer( W, H, -10, 10, -10 * reversedGrowth, 10);
+ await testResizer( W, H, 0, -10, 0, -10 * ignoredGrowth);
+ await testResizer( W, H, 0, 0, 0, 0);
+ await testResizer( W, H, 0, 10, 10 * needlessGrowth, 10);
+ await testResizer( W, H, 10, -10, 10, -10 * reversedGrowth);
+ await testResizer( W, H, 10, 0, 10, 10 * needlessGrowth);
+ await testResizer( W, H, 10, 10, 10, 10);
+
+ // bottom resizer
+ await testResizer(W / 2, H, -10, -10, 0, -10);
+ await testResizer(W / 2, H, -10, 0, 0, 0);
+ await testResizer(W / 2, H, -10, 10, 0, 10);
+ await testResizer(W / 2, H, 0, -10, 0, -10);
+ await testResizer(W / 2, H, 0, 0, 0, 0);
+ await testResizer(W / 2, H, 0, 10, 0, 10);
+ await testResizer(W / 2, H, 10, -10, 0, -10);
+ await testResizer(W / 2, H, 10, 0, 0, 0);
+ await testResizer(W / 2, H, 10, 10, 0, 10);
+
+ // bottom left resizer
+ await testResizer( 0, H, -10, -10, 10, -10 * reversedGrowth);
+ await testResizer( 0, H, -10, 0, 10, 10 * needlessGrowth);
+ await testResizer( 0, H, -10, 10, 10, 10);
+ await testResizer( 0, H, 0, -10, 0, -10 * ignoredGrowth);
+ await testResizer( 0, H, 0, 0, 0, 0);
+ await testResizer( 0, H, 0, 10, 10 * needlessGrowth, 10);
+ await testResizer( 0, H, 10, -10, -10, -10);
+ await testResizer( 0, H, 10, 0, -10 * ignoredGrowth, 0);
+ await testResizer( 0, H, 10, 10, -10 * reversedGrowth, 10);
+
+ // left resizer
+ await testResizer( 0, H / 2, -10, -10, 10, 0);
+ await testResizer( 0, H / 2, -10, 0, 10, 0);
+ await testResizer( 0, H / 2, -10, 10, 10, 0);
+ await testResizer( 0, H / 2, 0, -10, 0, 0);
+ await testResizer( 0, H / 2, 0, 0, 0, 0);
+ await testResizer( 0, H / 2, 0, 10, 0, 0);
+ await testResizer( 0, H / 2, 10, -10, -10, 0);
+ await testResizer( 0, H / 2, 10, 0, -10, 0);
+ await testResizer( 0, H / 2, 10, 10, -10, 0);
+
+ // top left resizer
+ await testResizer( 0, 0, -10, -10, 10, 10);
+ await testResizer( 0, 0, -10, 0, 10, 10 * needlessGrowth);
+ await testResizer( 0, 0, -10, 10, 10, -10 * reversedGrowth);
+ await testResizer( 0, 0, 0, -10, 10 * needlessGrowth, 10);
+ await testResizer( 0, 0, 0, 0, 0, 0);
+ await testResizer( 0, 0, 0, 10, 0, -10 * ignoredGrowth);
+ await testResizer( 0, 0, 10, -10, -10 * reversedGrowth, 10);
+ await testResizer( 0, 0, 10, 0, -10 * ignoredGrowth, 0);
+ await testResizer( 0, 0, 10, 10, -10, -10);
+
+ /* eslint-enable no-multi-spaces */
+ }
+
+ const kTests = [
+ { description: "Resizers for <img>",
+ innerHTML: "<img id=\"target\" src=\"green.png\">",
+ mayPreserveRatio: true,
+ isAbsolutePosition: false,
+ },
+ { description: "Resizers for <table>",
+ innerHTML: "<table id=\"target\" border><tr><td>cell</td><td>cell</td></tr></table>",
+ mayPreserveRatio: false,
+ isAbsolutePosition: false,
+ },
+ { description: "Resizers for absolute positioned <div>",
+ innerHTML: "<div id=\"target\" style=\"position: absolute; top: 50px; left: 50px;\">positioned</div>",
+ mayPreserveRatio: false,
+ isAbsolutePosition: true,
+ },
+ ];
+
+ // Resizers for absolute positioned element and table element are available
+ // only when enableAbsolutePositionEditing or enableInlineTableEditing is
+ // enabled for each. So, let's enable them during testing resizers for
+ // absolute positioned elements or table elements.
+ for (const kTest of kTests) {
+ document.execCommand("enableAbsolutePositionEditing", false, kTest.isAbsolutePosition);
+ await doTest(kTest.description, kTest.mayPreserveRatio, kTest.innerHTML);
+ }
+ content.innerHTML = "";
+ SimpleTest.finish();
+});
+</script>
+</pre>
+</body>
+</html>