mobile/android/tests/browser/robocop/robocop_input.html
author Sebastian Hengst <archaeopteryx@coole-files.de>
Thu, 29 Jun 2017 01:01:15 +0200
changeset 366665 36ea00c880db9a3a16e5e9e8441bdf87e3012f81
parent 366639 1cd9e27f0fa16bd65edc431ca37bbcd5ad72b3bd
child 367193 003e74a2a953449614ea1355f7f5b9dfdcf1654c
permissions -rw-r--r--
Backed out changeset 1cd9e27f0fa1 (bug 1351608)

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Robocop Input</title>
  </head>
  <body>
    <p>Input: <input id="input" type="text"></p>
    <p>Text area: <textarea id="text-area"></textarea></p>
    <p>Content editable: <div id="content-editable" contentEditable="true"></div></p>
    <p>Design mode: <iframe id="design-mode" src="data:text/html;charset=utf-8,<html><body></body></html>"></iframe></p>
    <p>Resetting input: <input id="resetting-input" type="text"></p>
    <p>Hiding input: <input id="hiding-input" type="text"></p>
    <script type="application/javascript" src="robocop_head.js"></script>
    <script type="application/javascript">
      let input = document.getElementById("input");
      let textArea = document.getElementById("text-area");
      let contentEditable = document.getElementById("content-editable");

      let designMode = document.getElementById("design-mode");
      try {
        designMode.contentDocument.designMode = "on";
      } catch (e) {
        // Setting designMode above sometimes fails, so try again later.
        setTimeout(function() { designMode.contentDocument.designMode = "on" }, 0);
      }

      // Spatial navigation interferes with design-mode key event tests.
      SpecialPowers.setBoolPref("snav.enabled", false);
      // Enable "selectionchange" events for input/textarea.
      SpecialPowers.setBoolPref("dom.select_events.textcontrols.enabled", true);

      // An input that resets the editor on every input by resetting the value property.
      let resetting_input = document.getElementById("resetting-input");
      resetting_input.addEventListener('input', function() {
        this.value = this.value;
      });

      // An input that hides on input.
      let hiding_input = document.getElementById("hiding-input");
      hiding_input.addEventListener('keydown', function(e) {
        if (e.key === "!") { // '!' key event as sent by testInputConnection.java.
          this.value = "";
          this.style.display = "none";
        }
      });

      let getEditor, setValue, setSelection;

      let events_log;
      function log_event(event) {
        switch (event.type) {
          case "compositionstart":
            events_log += "<";
            break;
          case "compositionupdate":
            events_log += "=";
            break;
          case "compositionend":
            events_log += ">";
            break;
          case "selectionchange":
            events_log += "|";
            break;
          default:
            events_log += "?";
            break;
        }
      }

      function get_event_target() {
        var editor = getEditor();
        var parent = SpecialPowers.unwrap(editor.rootElement.parentElement);
        if (parent instanceof HTMLInputElement || parent instanceof HTMLTextAreaElement) {
          // "selectionchange" is only dispatched to the element itself,
          // so use the element as the target instead of using the document.
          return parent;
        }
        return editor.document;
      }

      let test = {
        focus_input: function(value) {
          getEditor = function() {
            return SpecialPowers.wrap(input).QueryInterface(
                SpecialPowers.Ci.nsIDOMNSEditableElement).editor;
          };
          setValue = function(val) {
            input.value = val;
          };
          setSelection = function(pos) {
            input.setSelectionRange(pos, pos);
          };
          setValue(value);
          input.focus();
        },

        focus_text_area: function(value) {
          getEditor = function() {
            return SpecialPowers.wrap(textArea).QueryInterface(
                SpecialPowers.Ci.nsIDOMNSEditableElement).editor;
          };
          setValue = function(val) {
            textArea.value = val;
          };
          setSelection = function(pos) {
            textArea.setSelectionRange(pos, pos);
          };
          setValue(value);
          textArea.focus();
        },

        focus_content_editable: function(value) {
          getEditor = function() {
            return SpecialPowers.wrap(window).QueryInterface(
                SpecialPowers.Ci.nsIInterfaceRequestor).getInterface(
                SpecialPowers.Ci.nsIWebNavigation).QueryInterface(
                SpecialPowers.Ci.nsIDocShell).editor;
          };
          setValue = function(val) {
            contentEditable.innerHTML = val;
          };
          setSelection = function(pos) {
            window.getSelection().collapse(contentEditable.firstChild, pos);
          };
          setValue(value);
          contentEditable.focus();
        },

        focus_design_mode: function(value) {
          getEditor = function() {
            return SpecialPowers.wrap(designMode.contentWindow).QueryInterface(
                SpecialPowers.Ci.nsIInterfaceRequestor).getInterface(
                SpecialPowers.Ci.nsIWebNavigation).QueryInterface(
                SpecialPowers.Ci.nsIDocShell).editor;
          };
          setValue = function(val) {
            designMode.contentDocument.body.innerHTML = val;
          };
          setSelection = function(pos) {
            designMode.contentWindow.getSelection().collapse(
                designMode.contentDocument.body.firstChild, pos);
          };
          setValue(value);
          designMode.contentWindow.focus();
          designMode.contentDocument.body.focus();
        },

        test_reflush_changes: function() {
          do_check_true(getEditor().composing);

          // Ending the composition then setting the input value triggers the bug.
          getEditor().forceCompositionEnd();
          setValue("good"); // Value that testInputConnection.java expects.
          setSelection(4);
        },

        test_set_selection: function() {
          do_check_true(getEditor().composing);

          // Ending the composition then setting the selection triggers the bug.
          getEditor().forceCompositionEnd();
          setSelection(3); // Offsets that testInputConnection.java expects.
        },

        start_events_log: function() {
          // Reset the log
          events_log = "";

          let target = get_event_target();
          target.addEventListener("compositionstart", log_event);
          target.addEventListener("compositionupdate", log_event);
          target.addEventListener("compositionend", log_event);
          target.addEventListener("selectionchange", log_event);
        },

        end_events_log: function() {
          java.asyncCall("setEventsLog", events_log);

          let target = get_event_target();
          target.removeEventListener("compositionstart", log_event);
          target.removeEventListener("compositionupdate", log_event);
          target.removeEventListener("compositionend", log_event);
          target.removeEventListener("selectionchange", log_event);
        },

        test_bug1123514: function() {
          document.activeElement.addEventListener('input', function() {
            // Only works on input and textarea.
            if (this.value === 'b') {
              this.value = 'abc';
            }
          }, {once: true});
        },

        focus_resetting_input: function(val) {
          resetting_input.value = val;
          resetting_input.focus();
        },

        focus_hiding_input: function(val) {
          hiding_input.value = val;
          hiding_input.style.display = "";
          hiding_input.focus();
        },

        finish_test: function() {
          java.disconnect();
        },
      };

      var java = new JavaBridge(test);
    </script>
  </body>
</html>