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 (c68fe15a81fc)

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
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1315065
-->
<head>
  <meta charset="utf-8">
  <title>Test for Bug 1315065</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=1315065">Mozilla Bug 1315065</a>
<div contenteditable><p>abc<br></p></div>
<script type="application/javascript">
/** Test for Bug 1315065 **/
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(() => {
  var editor = document.getElementsByTagName("div")[0];
  function initForBackspace(aSelectionCollapsedTo /* = 0 ~ 3 */) {
    editor.innerHTML = "<p id='p'>abc<br></p>";
    var p = document.getElementById("p");
    // FYI: We cannot inserting empty text nodes as expected with
    //      Node.appendChild() nor Node.insertBefore(). Therefore, let's use
    //      Range.insertNode() like actual web apps.
    var selection = window.getSelection();
    selection.collapse(p, 1);
    var range = selection.getRangeAt(0);
    var emptyTextNode3 = document.createTextNode("");
    range.insertNode(emptyTextNode3);
    var emptyTextNode2 = document.createTextNode("");
    range.insertNode(emptyTextNode2);
    var emptyTextNode1 = document.createTextNode("");
    range.insertNode(emptyTextNode1);
    is(p.childNodes.length, 5, "Failed to initialize the editor");
    is(p.childNodes.item(1), emptyTextNode1, "1st text node should be emptyTextNode1");
    is(p.childNodes.item(2), emptyTextNode2, "2nd text node should be emptyTextNode2");
    is(p.childNodes.item(3), emptyTextNode3, "3rd text node should be emptyTextNode3");
    switch (aSelectionCollapsedTo) {
      case 0:
        selection.collapse(p.firstChild, 3); // next to 'c'
        break;
      case 1:
        selection.collapse(emptyTextNode1, 0);
        break;
      case 2:
        selection.collapse(emptyTextNode2, 0);
        break;
      case 3:
        selection.collapse(emptyTextNode3, 0);
        break;
      default:
        ok(false, "aSelectionCollapsedTo is illegal value");
    }
  }

  for (let i = 0; i < 4; i++) {
    const kDescription = i == 0 ? "Backspace from immediately after the last character" :
                                  "Backspace from " + i + "th empty text node";
    editor.focus();
    initForBackspace(i);
    synthesizeKey("KEY_Backspace");
    let p = document.getElementById("p");
    ok(p, kDescription + ": <p> element shouldn't be removed by Backspace key press");
    is(p.tagName.toLowerCase(), "p", kDescription + ": <p> element shouldn't be removed by Backspace key press");
    // When Backspace key is pressed even in empty text nodes, Gecko should not remove empty text nodes for now
    // because we should keep our traditional behavior (same as Edge) for backward compatibility as far as possible.
    // In this case, Chromium removes all empty text nodes, but Edge doesn't remove any empty text nodes.
    is(p.childNodes.length, 5, kDescription + ": <p> should have 5 children after pressing Backspace key");
    is(p.childNodes.item(0).textContent, "ab", kDescription + ": 'c' should be removed by pressing Backspace key");
    is(p.childNodes.item(1).textContent, "", kDescription + ": 1st empty text node should not be removed by pressing Backspace key");
    is(p.childNodes.item(2).textContent, "", kDescription + ": 2nd empty text node should not be removed by pressing Backspace key");
    is(p.childNodes.item(3).textContent, "", kDescription + ": 3rd empty text node should not be removed by pressing Backspace key");
    editor.blur();
  }

  function initForDelete(aSelectionCollapsedTo /* = 0 ~ 3 */) {
    editor.innerHTML = "<p id='p'>abc<br></p>";
    var p = document.getElementById("p");
    // FYI: We cannot inserting empty text nodes as expected with
    //      Node.appendChild() nor Node.insertBefore(). Therefore, let's use
    //      Range.insertNode() like actual web apps.
    var selection = window.getSelection();
    selection.collapse(p, 0);
    var range = selection.getRangeAt(0);
    var emptyTextNode1 = document.createTextNode("");
    range.insertNode(emptyTextNode1);
    var emptyTextNode2 = document.createTextNode("");
    range.insertNode(emptyTextNode2);
    var emptyTextNode3 = document.createTextNode("");
    range.insertNode(emptyTextNode3);
    is(p.childNodes.length, 5, "Failed to initialize the editor");
    is(p.childNodes.item(0), emptyTextNode3, "1st text node should be emptyTextNode3");
    is(p.childNodes.item(1), emptyTextNode2, "2nd text node should be emptyTextNode2");
    is(p.childNodes.item(2), emptyTextNode1, "3rd text node should be emptyTextNode1");
    switch (aSelectionCollapsedTo) {
      case 0:
        selection.collapse(p.childNodes.item(3), 0); // next to 'a'
        break;
      case 1:
        selection.collapse(emptyTextNode1, 0);
        break;
      case 2:
        selection.collapse(emptyTextNode2, 0);
        break;
      case 3:
        selection.collapse(emptyTextNode3, 0);
        break;
      default:
        ok(false, "aSelectionCollapsedTo is illegal value");
    }
  }

  for (let i = 0; i < 4; i++) {
    const kDescription = i == 0 ? "Delete from immediately before the first character" :
                                  "Delete from " + i + "th empty text node";
    editor.focus();
    initForDelete(i);
    synthesizeKey("KEY_Delete");
    var p = document.getElementById("p");
    ok(p, kDescription + ": <p> element shouldn't be removed by Delete key press");
    is(p.tagName.toLowerCase(), "p", kDescription + ": <p> element shouldn't be removed by Delete key press");
    if (i == 0) {
      // If Delete key is pressed in non-empty text node, only the text node should be modified.
      // This is same behavior as Chromium, but different from Edge.  Edge removes all empty text nodes in this case.
      is(p.childNodes.length, 5, kDescription + ": <p> should have only 2 children after pressing Delete key (empty text nodes should be removed");
      is(p.childNodes.item(0).textContent, "", kDescription + ": 1st empty text node should not be removed by pressing Delete key");
      is(p.childNodes.item(1).textContent, "", kDescription + ": 2nd empty text node should not be removed by pressing Delete key");
      is(p.childNodes.item(2).textContent, "", kDescription + ": 3rd empty text node should not be removed by pressing Delete key");
      is(p.childNodes.item(3).textContent, "bc", kDescription + ": 'a' should be removed by pressing Delete key");
    } else {
      // If Delete key is pressed in an empty text node, it and following empty text nodes should be removed and the non-empty text node should be modified.
      // This is same behavior as Chromium, but different from Edge.  Edge removes all empty text nodes in this case.
      var expectedEmptyTextNodes = 3 - i;
      is(p.childNodes.length, expectedEmptyTextNodes + 2, kDescription + ": <p> should have only " + i + " children after pressing Delete key (" + i + " empty text nodes should be removed");
      is(p.childNodes.item(expectedEmptyTextNodes).textContent, "bc", kDescription + ": empty text nodes and 'a' should be removed by pressing Delete key");
    }
    editor.blur();
  }
  SimpleTest.finish();
});
</script>
</body>
</html>