DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (4a45ed98fb43)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
<!DOCTYPE html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1473515
-->
<html>
<head>
  <title>Test for Bug 1473515</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" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1473515">Mozilla Bug 1473515</a>
<p id="display"></p>
<div id="content" style="display: none;">

</div>

<input id="input">
<textarea id="textarea"></textarea>

<pre id="test">

<script class="testbody" type="application/javascript">
"use strict";

SimpleTest.waitForExplicitFinish();
SimpleTest.expectAssertions(0, 1);  // In a11y module
SimpleTest.waitForFocus(async () => {
  await SpecialPowers.pushPrefEnv({
    set: [["dom.input_events.beforeinput.enabled", true]],
  });

  let editableElements = [
    document.getElementById("input"),
    document.getElementById("textarea"),
  ];
  for (let editableElement of editableElements) {
    function checkInputEvent(aEvent, aInputType, aData, aDescription) {
      ok(aEvent instanceof InputEvent,
         `"${aEvent.type}" event should be dispatched with InputEvent interface ${aDescription}`);
      is(aEvent.cancelable, aEvent.type === "beforeinput",
         `"${aEvent.type}" event should ${aEvent.type === "beforeinput" ? "be" : "be never"} cancelable ${aDescription}`);
      is(aEvent.bubbles, true,
         `"${aEvent.type}" event should always bubble ${aDescription}`);
      is(aEvent.inputType, aInputType,
         `inputType of "${aEvent.type}" event should be "${aInputType}" ${aDescription}`);
      is(aEvent.data, aData,
         `data of "${aEvent.type}" event should be ${aData} ${aDescription}`);
      is(aEvent.dataTransfer, null,
         `dataTransfer of "${aEvent.type}" should be null ${aDescription}`);
      is(aEvent.getTargetRanges().length, 0,
         `getTargetRanges() of "${aEvent.type}" should return empty array ${aDescription}`);
    }

    let beforeInputEvents = [];
    let inputEvents = [];
    function onBeforeInput(aEvent) {
      beforeInputEvents.push(aEvent);
    }
    function onInput(aEvent) {
      inputEvents.push(aEvent);
    }
    editableElement.addEventListener("beforeinput", onBeforeInput);
    editableElement.addEventListener("input", onInput);

    editableElement.focus();

    beforeInputEvents = [];
    inputEvents = [];
    synthesizeKey("a");
    is(beforeInputEvents.length, 1,
       `Only one "beforeinput" event should be fired when inserting "a" with key on <${editableElement.tagName.toLowerCase()}> element`);
    checkInputEvent(beforeInputEvents[0], "insertText", "a", `when inserting "a" with key on <${editableElement.tagName.toLowerCase()}> element`);
    is(inputEvents.length, 1,
       `Only one "input" event should be fired when inserting "a" with key on <${editableElement.tagName.toLowerCase()}> element`);
    checkInputEvent(inputEvents[0], "insertText", "a", `when inserting "a" with key on <${editableElement.tagName.toLowerCase()}> element`);

    beforeInputEvents = [];
    inputEvents = [];
    synthesizeKey("c");
    is(beforeInputEvents.length, 1,
       `Only one "beforeinput" event should be fired when inserting "c" with key on <${editableElement.tagName.toLowerCase()}> element`);
    checkInputEvent(beforeInputEvents[0], "insertText", "c", `when inserting "c" with key on <${editableElement.tagName.toLowerCase()}> element`);
    is(inputEvents.length, 1,
       `Only one "input" event should be fired when inserting "c" with key on <${editableElement.tagName.toLowerCase()}> element`);
    checkInputEvent(inputEvents[0], "insertText", "c", `when inserting "c" with key on <${editableElement.tagName.toLowerCase()}> element`);

    beforeInputEvents = [];
    inputEvents = [];
    synthesizeKey("KEY_ArrowLeft");
    is(beforeInputEvents.length, 0,
       `No "beforeinput" event should be fired when pressing "ArrowLeft" key on <${editableElement.tagName.toLowerCase()}> element`);
    is(inputEvents.length, 0,
       `No "input" event should be fired when pressing "ArrowLeft" key on <${editableElement.tagName.toLowerCase()}> element`);

    beforeInputEvents = [];
    inputEvents = [];
    synthesizeKey("b");
    is(beforeInputEvents.length, 1,
       `Only one "beforeinput" event should be fired when inserting "b" with key on <${editableElement.tagName.toLowerCase()}> element`);
    checkInputEvent(beforeInputEvents[0], "insertText", "b", `when inserting "b" with key on <${editableElement.tagName.toLowerCase()}> element`);
    is(inputEvents.length, 1,
       `Only one "input" event should be fired when inserting "b" with key on <${editableElement.tagName.toLowerCase()}> element`);
    checkInputEvent(inputEvents[0], "insertText", "b", `when inserting "b" with key on <${editableElement.tagName.toLowerCase()}> element`);

    let editor = SpecialPowers.wrap(editableElement).editor;
    let transactionManager = editor.transactionManager;
    is(transactionManager.numberOfUndoItems, 2,
       editableElement.tagName + ": Initially, there should be 2 undo items");
    // Defined as TextControlElement::DEFAULT_UNDO_CAP
    is(transactionManager.maxTransactionCount, 1000,
       editableElement.tagName + ": Initially, transaction manager should be able to have 1,000 undo items");

    beforeInputEvents = [];
    inputEvents = [];
    editableElement.value = "def";
    is(beforeInputEvents.length, 0,
       `No "beforeinput" event should be fired when setting value of <${editableElement.tagName.toLowerCase()}> element`);
    is(inputEvents.length, 0,
       `No "input" event should be fired when setting value of <${editableElement.tagName.toLowerCase()}> element`);

    is(transactionManager.numberOfUndoItems, 0,
       editableElement.tagName + ": After setting value, all undo items must be deleted");
    is(transactionManager.maxTransactionCount, 1000,
       editableElement.tagName + ": After setting value, maximum transaction count should be restored to the previous value");

    beforeInputEvents = [];
    inputEvents = [];
    synthesizeKey("a");
    is(beforeInputEvents.length, 1,
       `Only one "beforeinput" event should be fired when inserting "a" with key again on <${editableElement.tagName.toLowerCase()}> element`);
    checkInputEvent(beforeInputEvents[0], "insertText", "a", `when inserting "a" with key again on <${editableElement.tagName.toLowerCase()}> element`);
    is(inputEvents.length, 1,
       `Only one "input" event should be fired when inserting "a" with key again on <${editableElement.tagName.toLowerCase()}> element`);
    checkInputEvent(inputEvents[0], "insertText", "a", `when inserting "a" with key again on <${editableElement.tagName.toLowerCase()}> element`);

    beforeInputEvents = [];
    inputEvents = [];
    synthesizeKey("z", { accelKey: true });
    is(editableElement.value, "def",
       editableElement.tagName + ": undo should work after setting value");
    is(beforeInputEvents.length, 1,
       `Only one "beforeinput" event should be fired when undoing on <${editableElement.tagName.toLowerCase()}> element`);
    checkInputEvent(beforeInputEvents[0], "historyUndo", null, `when undoing on <${editableElement.tagName.toLowerCase()}> element`);
    is(inputEvents.length, 1,
       `Only one "input" event should be fired when undoing on <${editableElement.tagName.toLowerCase()}> element`);
    checkInputEvent(inputEvents[0], "historyUndo", null, `when undoing on <${editableElement.tagName.toLowerCase()}> element`);

    // Disable undo/redo.
    editor.enableUndo(0);
    is(transactionManager.maxTransactionCount, 0,
       editableElement.tagName + ": Transaction manager should not be able to have undo items");
    editableElement.value = "hij";
    is(transactionManager.maxTransactionCount, 0,
       editableElement.tagName + ": Transaction manager should not be able to have undo items after setting value");

    editableElement.removeEventListener("beforeinput", onBeforeInput);
    editableElement.removeEventListener("input", onInput);
  }
  SimpleTest.finish();
});
</script>
</pre>
</body>
</html>