summaryrefslogtreecommitdiffstats
path: root/dom/tests/mochitest/general/frameSelectEvents.html
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/tests/mochitest/general/frameSelectEvents.html485
1 files changed, 485 insertions, 0 deletions
diff --git a/dom/tests/mochitest/general/frameSelectEvents.html b/dom/tests/mochitest/general/frameSelectEvents.html
new file mode 100644
index 0000000000..78805408ef
--- /dev/null
+++ b/dom/tests/mochitest/general/frameSelectEvents.html
@@ -0,0 +1,485 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Testing Selection Events</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ </head>
+
+ <body>
+ <div id="normal">
+ <span id="inner">A bunch of text in a span inside of a div which should be selected</span>
+ </div>
+
+ <div id="ce">
+ This is a random block of text
+ </div>
+
+ <input type="text" id="input" value="XXXXXXXXXXXXXXXXXXX" width="200"> <br>
+
+ <textarea id="textarea" width="200">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</textarea>
+
+ <script>
+ // Call the testing methods from the parent window
+ var is = parent.is;
+ var ok = parent.ok;
+
+ // spin() spins the event loop for two cycles, giving time for
+ // selectionchange events to be fired, and handled by our listeners.
+ function spin() {
+ return new Promise(function(a) {
+ parent.SimpleTest.executeSoon(function() {
+ parent.SimpleTest.executeSoon(a)
+ });
+ });
+ }
+
+ // The main test
+ parent.add_task(async function() {
+ await spin();
+
+ var selectstart = 0;
+ var selectionchange = 0;
+ var inputSelectionchange = 0;
+ var textareaSelectionchange = 0;
+
+ var cancel = false;
+ var selectstartTarget = null;
+
+ async function UpdateSelectEventsOntextControlsPref(aEnabled) {
+ await SpecialPowers.pushPrefEnv({'set': [['dom.select_events.textcontrols.enabled', aEnabled]]});
+ }
+ await UpdateSelectEventsOntextControlsPref(false);
+
+ document.addEventListener('selectstart', function(aEvent) {
+ console.log("originaltarget", aEvent.originalTarget, "new", selectstartTarget);
+ is(aEvent.originalTarget, selectstartTarget,
+ "The original target of selectstart");
+ selectstartTarget = null;
+
+ console.log(selectstart);
+ selectstart++;
+
+ if (cancel) {
+ aEvent.preventDefault();
+ }
+ });
+ document.addEventListener('selectionchange', function(aEvent) {
+ is(aEvent.originalTarget, document,
+ "The original target of selectionchange should be the document");
+ console.log(selectionchange);
+ selectionchange++;
+ });
+
+ function elt(aId) { return document.getElementById(aId); }
+ function reset() {
+ selectstart = 0;
+ selectionchange = 0;
+ inputSelectionchange = 0;
+ textareaSelectionchange = 0;
+ cancel = false;
+ }
+
+ elt("input").addEventListener('selectionchange', function(aEvent) {
+ is (aEvent.originalTarget, elt("input"),
+ "The original target of selectionchange should be the input");
+ console.log(inputSelectionchange);
+ inputSelectionchange++;
+ });
+ elt("textarea").addEventListener('selectionchange', function(aEvent) {
+ is (aEvent.originalTarget, elt("textarea"),
+ "The original target of selectionchange should be the textarea");
+ console.log(textareaSelectionchange);
+ textareaSelectionchange++;
+ });
+ async function mouseAction(aElement, aOffset, aType,
+ aSelStart, aSelChng, aISelChng, aTSelChng,
+ aYOffset)
+ {
+ if (aType == "click") { // You can simulate a click event by sending undefined
+ aType = undefined;
+ }
+ if (!aYOffset) {
+ aYOffset = 10;
+ }
+ synthesizeMouse(aElement, aOffset, aYOffset, { type: aType });
+ await spin();
+
+ is(selectstart, aSelStart,
+ "SelStart Mouse Action (" + aOffset + " - " + aType + ")");
+ is(selectionchange, aSelChng,
+ "SelChng Mouse Action (" + aOffset + " - " + aType + ")");
+ is(inputSelectionchange, aISelChng || 0,
+ "ISelChng Mouse Action (" + aOffset + " - " + aType + ")");
+ is(textareaSelectionchange, aTSelChng || 0,
+ "TSelChng Mouse Action (" + aOffset + " - " + aType + ")");
+ reset();
+ }
+
+ async function keyAction(aKey, aShift, aAccel,
+ aSelStart, aSelChng, aISelChng, aTSelChng)
+ {
+ synthesizeKey(aKey, { shiftKey: aShift, accelKey: aAccel });
+ await spin();
+ is(selectstart, aSelStart,
+ "SelStart Key Action (" + aKey + " - " + aShift + " - " + aAccel + ")");
+ is(selectionchange, aSelChng,
+ "SelChng Key Action (" + aKey + " - " + aShift + " - " + aAccel + ")");
+ is(inputSelectionchange, aISelChng || 0,
+ "ISelChng Key Action (" + aKey + " - " + aShift + " - " + aAccel + ")");
+ is(textareaSelectionchange, aTSelChng || 0,
+ "TSelChng Key Action (" + aKey + " - " + aShift + " - " + aAccel + ")");
+ reset();
+ }
+
+ async function contentEditableAction(aElement, aContentEditable,
+ aSelStart, aSelChng,
+ aISelChng, aTSelChng)
+ {
+ aElement.setAttribute("contenteditable",
+ aContentEditable ? "true" : "false");
+ await spin();
+
+ is(selectstart, aSelStart,
+ "SelStart ContentEditable Action");
+ is(selectionchange, aSelChng,
+ "SelStart ContentEditable Action");
+ is(inputSelectionchange, aISelChng || 0,
+ "SelStart ContentEditable Action");
+ is(textareaSelectionchange, aTSelChng || 0,
+ "SelStart ContentEditable Action");
+ reset();
+ }
+
+ var selection = document.getSelection();
+ function isCollapsed() {
+ is(selection.isCollapsed, true, "Selection is collapsed");
+ }
+ function isNotCollapsed() {
+ is(selection.isCollapsed, false, "Selection is not collapsed");
+ }
+
+ // Make sure setting the element to contentEditable doesn't cause any selectionchange events
+ await contentEditableAction(elt("ce"), true, 0, 0, 0, 0);
+
+ // Make sure setting the element to not be contentEditable doesn't cause any selectionchange events
+ await contentEditableAction(elt("ce"), false, 0, 0, 0, 0);
+
+ // Now make the div contentEditable and proceed with the test
+ await contentEditableAction(elt("ce"), true, 0, 0, 0, 0);
+
+ // Focus the contenteditable text
+ await mouseAction(elt("ce"), 100, "click", 0, 1);
+ isCollapsed();
+
+ // Move the selection to the right, this should only fire selectstart once
+ selectstartTarget = elt("ce").firstChild;
+ await keyAction("VK_RIGHT", true, false, 1, 1);
+ isNotCollapsed();
+ await keyAction("VK_RIGHT", true, false, 0, 1);
+ isNotCollapsed();
+
+ // Move it back so that the selection is empty again
+ await keyAction("VK_LEFT", true, false, 0, 1);
+ isNotCollapsed();
+ await keyAction("VK_LEFT", true, false, 0, 1);
+ isCollapsed();
+
+ // Going from empty to non-empty should fire selectstart again
+ selectstartTarget = elt("ce").firstChild;
+ await keyAction("VK_LEFT", true, false, 1, 1);
+ isNotCollapsed();
+
+ async function mouseMoves(aElement, aTarget) {
+ // Select a region
+ await mouseAction(aElement, 50, "mousedown", 0, 1);
+ isCollapsed();
+
+ selectstartTarget = aTarget;
+ await mouseAction(aElement, 100, "mousemove", 1, 1);
+ isNotCollapsed();
+
+ // Moving it more shouldn't trigger a start (move back to empty)
+ await mouseAction(aElement, 75, "mousemove", 0, 1);
+ isNotCollapsed();
+ await mouseAction(aElement, 50, "mousemove", 0, 1);
+ isCollapsed();
+
+ // Wiggling the mouse a little such that it doesn't select any
+ // characters shouldn't trigger a selection
+ await mouseAction(aElement, 50, "mousemove", 0, 0, 0, 0, 11);
+ isCollapsed();
+
+ // Moving the mouse again from an empty selection should trigger a
+ // selectstart
+ selectstartTarget = aTarget;
+ await mouseAction(aElement, 25, "mousemove", 1, 1);
+ isNotCollapsed();
+
+ // Releasing the mouse shouldn't do anything
+ await mouseAction(aElement, 25, "mouseup", 0, 0);
+ isNotCollapsed();
+
+ // And neither should moving your mouse around when the mouse
+ // button isn't pressed
+ await mouseAction(aElement, 50, "mousemove", 0, 0);
+ isNotCollapsed();
+
+ // Clicking in an random location should move the selection, but not perform a
+ // selectstart
+ await mouseAction(aElement, 50, "click", 0, 1);
+ isCollapsed();
+
+ // Clicking there again should do nothing
+ await mouseAction(aElement, 50, "click", 0, 0);
+ isCollapsed();
+
+ // Selecting a region, and canceling the selectstart should mean that the
+ // selection remains collapsed
+ await mouseAction(aElement, 75, "mousedown", 0, 1);
+ isCollapsed();
+ cancel = true;
+ selectstartTarget = aTarget;
+ await mouseAction(aElement, 100, "mousemove", 1, 1);
+ isCollapsed();
+ await mouseAction(aElement, 100, "mouseup", 0, 0);
+ isCollapsed();
+ }
+
+ // Should work both on normal
+ await mouseMoves(elt("inner"), elt("inner").firstChild);
+ // and contenteditable fields
+ await mouseMoves(elt("ce"), elt("ce").firstChild);
+ // and fields with elements in them
+ await mouseMoves(elt("normal"), elt("inner").firstChild);
+
+ await mouseAction(elt("inner"), 50, "click", 0, 1);
+ isCollapsed();
+
+ reset();
+ // Select all should fire both selectstart and change
+ selectstartTarget = document.body;
+ await keyAction("A", false, true, 1, 1);
+ isNotCollapsed();
+
+ // Clear the selection
+ await mouseAction(elt("inner"), 50, "click", 0, 1);
+ isCollapsed();
+
+ // Even if we already have a selection
+ await mouseAction(elt("inner"), 75, "mousedown", 0, 1);
+ isCollapsed();
+ selectstartTarget = elt("inner").firstChild;
+ await mouseAction(elt("inner"), 100, "mousemove", 1, 1);
+ isNotCollapsed();
+ await mouseAction(elt("inner"), 100, "mouseup", 0, 0);
+ isNotCollapsed();
+
+ selectstartTarget = document.body;
+ await keyAction("A", false, true, 1, 1);
+ isNotCollapsed();
+
+ // Clear the selection
+ await mouseAction(elt("inner"), 50, "click", 0, 1);
+ isCollapsed();
+
+ // Make sure that a synthesized selection change doesn't fire selectstart
+ var s = document.getSelection();
+ s.removeAllRanges();
+ await spin();
+ is(selectstart, 0, "Synthesized range removals shouldn't fire selectstart");
+ is(selectionchange, 1, "Synthesized range removals should change selectionchange");
+ reset();
+ isCollapsed();
+
+ var range = document.createRange();
+ range.selectNode(elt("inner"));
+ s.addRange(range);
+ await spin();
+ is(selectstart, 0, "Synthesized range additions shouldn't fire selectstart");
+ is(selectionchange, 1, "Synthesized range additions should change selectionchange");
+ reset();
+ isNotCollapsed();
+
+ // Change the range, without replacing
+ range.selectNode(elt("ce"));
+ await spin();
+ is(selectstart, 0, "Synthesized range mutations shouldn't fire selectstart");
+ is(selectionchange, 1, "Synthesized range mutations should change selectionchange");
+ reset();
+ isNotCollapsed();
+
+ // Remove the range
+ s.removeAllRanges();
+ await spin();
+ is(selectstart, 0, "Synthesized range removal");
+ is(selectionchange, 1, "Synthesized range removal");
+ reset();
+ isCollapsed();
+
+
+ /*
+ Selection events mouse move on input type=text
+ */
+
+ // Select a region
+
+ // Without the dom.select_events.textcontrols.enabled pref,
+ // pressing the mouse shouldn't do anything.
+ await mouseAction(elt("input"), 50, "mousedown", 0, 1, 0, 0);
+
+ // Releasing the mouse shouldn't do anything
+ await mouseAction(elt("input"), 50, "mouseup", 0, 0, 0, 0);
+
+ await UpdateSelectEventsOntextControlsPref(true);
+
+ await mouseAction(elt("input"), 50, "mousedown", 0, 0, 0, 0);
+
+ selectstartTarget = elt("input");
+ await mouseAction(elt("input"), 100, "mousemove", 1, 0, 1, 0);
+
+ // Moving it more shouldn't trigger a start (move back to empty)
+ await mouseAction(elt("input"), 75, "mousemove", 0, 0, 1, 0);
+ await mouseAction(elt("input"), 50, "mousemove", 0, 0, 1, 0);
+
+ // Wiggling the mouse a little such that it doesn't select any
+ // characters shouldn't trigger a selection
+ await mouseAction(elt("input"), 50, "mousemove", 0, 0, 0, 0, 11);
+
+ // Moving the mouse again from an empty selection should trigger a
+ // selectstart
+ selectstartTarget = elt("input");
+ await mouseAction(elt("input"), 25, "mousemove", 1, 0, 1, 0);
+
+ // Releasing the mouse shouldn't do anything
+ await mouseAction(elt("input"), 25, "mouseup", 0, 0, 0, 0);
+
+ // And neither should moving your mouse around when the mouse
+ // button isn't pressed
+ await mouseAction(elt("input"), 50, "mousemove", 0, 0, 0, 0);
+
+ // Clicking in an random location should move the selection, but
+ // not perform a selectstart
+ await mouseAction(elt("input"), 50, "click", 0, 0, 1, 0);
+
+ // Clicking there again should do nothing
+ await mouseAction(elt("input"), 50, "click", 0, 0, 0, 0);
+
+ // Selecting a region, and canceling the selectstart should mean that the
+ // selection remains collapsed
+ await mouseAction(elt("input"), 75, "mousedown", 0, 0, 1, 0);
+ cancel = true;
+ selectstartTarget = elt("input");
+ await mouseAction(elt("input"), 100, "mousemove", 1, 0, 1, 0);
+ await mouseAction(elt("input"), 100, "mouseup", 0, 0, 0, 0);
+
+
+ await UpdateSelectEventsOntextControlsPref(false);
+
+ // Without the dom.select_events.textcontrols.enabled pref,
+ // pressing the mouse shouldn't do anything.
+ // XXX For some reason we fire 2 selectchange events on the body
+ // when switching from the input to the text area.
+ await mouseAction(elt("textarea"), 50, "mousedown", 0, 2, 0, 0);
+
+ // Releasing the mouse shouldn't do anything
+ await mouseAction(elt("textarea"), 50, "mouseup", 0, 0, 0, 0);
+
+ await UpdateSelectEventsOntextControlsPref(true);
+
+ // Select a region
+ await mouseAction(elt("textarea"), 50, "mousedown", 0, 0, 0, 0);
+
+ selectstartTarget = elt("textarea");
+ await mouseAction(elt("textarea"), 100, "mousemove", 1, 0, 0, 1);
+
+ // Moving it more shouldn't trigger a start (move back to empty)
+ await mouseAction(elt("textarea"), 75, "mousemove", 0, 0, 0, 1);
+ await mouseAction(elt("textarea"), 50, "mousemove", 0, 0, 0, 1);
+
+ // Wiggling the mouse a little such that it doesn't select any
+ // characters shouldn't trigger a selection
+ await mouseAction(elt("textarea"), 50, "mousemove", 0, 0, 0, 0, 11);
+
+ // Moving the mouse again from an empty selection should trigger a
+ // selectstart
+ selectstartTarget = elt("textarea");
+ await mouseAction(elt("textarea"), 25, "mousemove", 1, 0, 0, 1);
+
+ // Releasing the mouse shouldn't do anything
+ await mouseAction(elt("textarea"), 25, "mouseup", 0, 0, 0, 0);
+
+ // And neither should moving your mouse around when the mouse
+ // button isn't pressed
+ await mouseAction(elt("textarea"), 50, "mousemove", 0, 0, 0, 0);
+
+ // Clicking in an random location should move the selection, but not perform a
+ // selectstart
+ await mouseAction(elt("textarea"), 50, "click", 0, 0, 0, 1);
+
+ // Clicking there again should do nothing
+ await mouseAction(elt("textarea"), 50, "click", 0, 0, 0, 0);
+
+ // Selecting a region, and canceling the selectstart should mean that the
+ // selection remains collapsed
+ await mouseAction(elt("textarea"), 75, "mousedown", 0, 0, 0, 1);
+ cancel = true;
+ selectstartTarget = elt("textarea");
+ await mouseAction(elt("textarea"), 100, "mousemove", 1, 0, 0, 1);
+ await mouseAction(elt("textarea"), 100, "mouseup", 0, 0, 0, 0);
+
+ // Marking the input and textarea as display: none and then as visible again
+ // shouldn't trigger any changes, although the nodes will be re-framed
+ elt("input").setAttribute("style", "display: none;");
+ await spin();
+ is(selectstart, 0, "idn - ss 1");
+ is(selectionchange, 0, "idn - sc 1");
+ is(inputSelectionchange, 0, "idn - isc 1");
+ is(textareaSelectionchange, 0, "idn - tsc 1");
+ reset();
+
+ elt("input").setAttribute("style", "");
+ await spin();
+ is(selectstart, 0, "idn - ss 2");
+ is(selectionchange, 0, "idn - sc 2");
+ is(inputSelectionchange, 0, "idn - isc 2");
+ is(textareaSelectionchange, 0, "idn - tsc 2");
+ reset();
+
+ elt("textarea").setAttribute("style", "display: none;");
+ await spin();
+ is(selectstart, 0, "tdn - ss 1");
+ is(selectionchange, 0, "tdn - sc 1");
+ is(inputSelectionchange, 0, "tdn - isc 1");
+ is(textareaSelectionchange, 0, "tdn - tsc 1");
+ reset();
+
+ elt("textarea").setAttribute("style", "");
+ await spin();
+ is(selectstart, 0, "tdn - ss 2");
+ is(selectionchange, 0, "tdn - sc 2");
+ is(inputSelectionchange, 0, "tdn - isc 2");
+ is(textareaSelectionchange, 0, "tdn - tsc 2");
+ reset();
+
+ // When selection is at the end of contentEditable's content,
+ // clearing the content should trigger selection events.
+ var savedContent = elt("ce").innerHTML;
+ document.getSelection().setBaseAndExtent(elt("ce"), 1, elt("ce"), 1);
+ await spin();
+ reset();
+
+ elt("ce").firstChild.remove();
+ await spin();
+ is(selectstart, 0, "clear ce - ss");
+ is(selectionchange, 1, "clear ce - sc");
+ is(inputSelectionchange, 0, "clear ce - isc");
+ is(textareaSelectionchange, 0, "clear ce - tsc");
+
+ elt("ce").innerHTML = savedContent;
+ await spin();
+ reset();
+ });
+ </script>
+ </body>
+</html>