tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_nsIEditorMailSupport_insertAsCitedQuotation.html (13389B)


      1 <!DOCTYPE>
      2 <html>
      3 <head>
      4  <title>Test for nsIEditorMailSupport.insertAsCitedQuotation()</title>
      5  <script src="/tests/SimpleTest/SimpleTest.js"></script>
      6  <link rel="stylesheet" href="/tests/SimpleTest/test.css">
      7 </head>
      8 <body>
      9 <div contenteditable></div>
     10 <script>
     11 "use strict";
     12 
     13 SimpleTest.waitForExplicitFinish();
     14 SimpleTest.waitForFocus(() => {
     15  function testInputEvents() {
     16    const inReadonlyMode = getEditor().flags & SpecialPowers.Ci.nsIEditor.eEditorReadonlyMask;
     17    const editorDescription = `(readonly=${!!inReadonlyMode})`;
     18 
     19    const editor = document.querySelector("div[contenteditable]");
     20    const selection = getSelection();
     21 
     22    let beforeInputEvents = [];
     23    let inputEvents = [];
     24    let selectionRanges = [];
     25    function onBeforeInput(aEvent) {
     26      beforeInputEvents.push(aEvent);
     27      selectionRanges = [];
     28      for (let i = 0; i < selection.rangeCount; i++) {
     29        let range = selection.getRangeAt(i);
     30        selectionRanges.push({startContainer: range.startContainer, startOffset: range.startOffset,
     31                              endContainer: range.endContainer, endOffset: range.endOffset});
     32      }
     33    }
     34    function onInput(aEvent) {
     35      inputEvents.push(aEvent);
     36    }
     37    editor.addEventListener("beforeinput", onBeforeInput);
     38    editor.addEventListener("input", onInput);
     39 
     40    editor.innerHTML = "";
     41    editor.focus();
     42    selection.collapse(editor, 0);
     43 
     44    function checkInputEvent(aEvent, aInputType, aData, aDescription) {
     45      ok(aEvent instanceof InputEvent,
     46        `"${aEvent.type}" event should be dispatched with InputEvent interface ${aDescription}`);
     47      // If it were cancelable whose inputType is empty string, web apps would
     48      // block any Firefox specific modification whose inputType are not declared
     49      // by the spec.
     50      let expectedCancelable = aEvent.type === "beforeinput" && aInputType !== "";
     51      is(aEvent.cancelable, expectedCancelable,
     52        `"${aEvent.type}" event should ${expectedCancelable ? "be" : "be never"} cancelable ${aDescription}`);
     53      is(aEvent.bubbles, true,
     54        `"${aEvent.type}" event should always bubble ${aDescription}`);
     55      is(aEvent.inputType, aInputType,
     56        `inputType of "${aEvent.type}" event should be "${aInputType}" ${aDescription}`);
     57      is(aEvent.data, aData,
     58        `data of "${aEvent.type}" event should be ${aData} ${aDescription}`);
     59      is(aEvent.dataTransfer, null,
     60        `dataTransfer of "${aEvent.type}" event should be null ${aDescription}`);
     61      let targetRanges = aEvent.getTargetRanges();
     62      if (aEvent.type === "beforeinput") {
     63        is(targetRanges.length, selectionRanges.length,
     64          `getTargetRanges() of "beforeinput" event should return selection ranges ${aDescription}`);
     65        if (targetRanges.length === selectionRanges.length) {
     66          for (let i = 0; i < selectionRanges.length; i++) {
     67            is(targetRanges[i].startContainer, selectionRanges[i].startContainer,
     68              `startContainer of getTargetRanges()[${i}] of "beforeinput" event does not match ${aDescription}`);
     69            is(targetRanges[i].startOffset, selectionRanges[i].startOffset,
     70              `startOffset of getTargetRanges()[${i}] of "beforeinput" event does not match ${aDescription}`);
     71            is(targetRanges[i].endContainer, selectionRanges[i].endContainer,
     72              `endContainer of getTargetRanges()[${i}] of "beforeinput" event does not match ${aDescription}`);
     73            is(targetRanges[i].endOffset, selectionRanges[i].endOffset,
     74              `endOffset of getTargetRanges()[${i}] of "beforeinput" event does not match ${aDescription}`);
     75          }
     76        }
     77      } else {
     78        is(targetRanges.length, 0,
     79          `getTargetRanges() of "${aEvent.type}" event should return empty array ${aDescription}`);
     80      }
     81    }
     82 
     83    // Tests when the editor is in plaintext mode.
     84 
     85    getEditor().flags |= SpecialPowers.Ci.nsIEditor.eEditorPlaintextMask;
     86 
     87    beforeInputEvents = [];
     88    inputEvents = [];
     89    getEditorMailSupport().insertAsCitedQuotation("this is quoted text\nAnd here is second line.", "this is cited text", false);
     90 
     91    ok(
     92      selection.isCollapsed,
     93      `Selection should be collapsed after calling nsIEditorMailSupport.insertAsCitedQuotation() of plaintext editor ${editorDescription}`
     94    );
     95    is(
     96      selection.focusNode,
     97      editor,
     98      `focus node of Selection should be a child of the editing host after calling nsIEditorMailSupport.insertAsCitedQuotation() of plaintext editor ${editorDescription}`
     99    );
    100    is(
    101      selection.focusOffset,
    102      1,
    103      `focus offset of Selection should be next to inserted <span> element after calling nsIEditorMailSupport.insertAsCitedQuotation() of plaintext editor ${editorDescription}`
    104    );
    105    is(
    106      editor.innerHTML,
    107      '<span style="white-space: pre-wrap;">&gt; this is quoted text<br>&gt; And here is second line.<br><br></span>',
    108      `The quoted text should be inserted as plaintext into the plaintext editor ${editorDescription}`
    109    );
    110    is(
    111      beforeInputEvents.length,
    112      1,
    113      `One "beforeinput" event should be fired on the editing host after calling nsIEditorMailSupport.insertAsCitedQuotation() of plaintext editor ${editorDescription}`
    114    );
    115    checkInputEvent(
    116      beforeInputEvents[0],
    117      "insertText", "this is quoted text\nAnd here is second line.",
    118      `after calling nsIEditorMailSupport.insertAsCitedQuotation() of plaintext editor ${editorDescription}`
    119    );
    120    is(
    121      inputEvents.length,
    122      1,
    123      `One "input" event should be fired on the editing host after calling nsIEditorMailSupport.insertAsCitedQuotation() of plaintext editor ${editorDescription}`
    124    );
    125    checkInputEvent(
    126      inputEvents[0],
    127      "insertText", "this is quoted text\nAnd here is second line.",
    128      `after calling nsIEditorMailSupport.insertAsCitedQuotation() of plaintext editor ${editorDescription}`
    129    );
    130 
    131    // Tests when the editor is in HTML editor mode.
    132    getEditor().flags &= ~SpecialPowers.Ci.nsIEditor.eEditorPlaintextMask;
    133 
    134    editor.innerHTML = "";
    135 
    136    beforeInputEvents = [];
    137    inputEvents = [];
    138    getEditorMailSupport().insertAsCitedQuotation("this is quoted text<br>", "this is cited text", false);
    139 
    140    ok(
    141      selection.isCollapsed,
    142      `Selection should be collapsed after calling nsIEditorMailSupport.insertAsCitedQuotation() of HTMLEditor editor (inserting as plaintext) ${editorDescription}`
    143    );
    144    is(
    145      selection.focusNode,
    146      editor,
    147      `focus node of Selection should be a child of the editing host after calling nsIEditorMailSupport.insertAsCitedQuotation() of HTMLEditor editor (inserting as plaintext)  ${editorDescription}`
    148    );
    149    is(
    150      selection.focusOffset,
    151      1,
    152      `focus offset of Selection should be next to inserted <span> element after calling nsIEditorMailSupport.insertAsCitedQuotation() of HTMLEditor editor (inserting as plaintext) ${editorDescription}`
    153    );
    154    is(
    155      editor.innerHTML,
    156      '<blockquote type="cite" cite="this is cited text">this is quoted text&lt;br&gt;</blockquote>',
    157      `The quoted text should be inserted as plaintext into the HTML editor ${editorDescription}`
    158    );
    159    is(
    160      beforeInputEvents.length,
    161      1,
    162      `One "beforeinput" event should be fired on the editing host after calling nsIEditorMailSupport.insertAsCitedQuotation() of HTMLEditor editor (inserting as plaintext) ${editorDescription}`
    163    );
    164    checkInputEvent(
    165      beforeInputEvents[0],
    166      "",
    167      null,
    168      `after calling nsIEditorMailSupport.insertAsCitedQuotation() of HTMLEditor editor (inserting as plaintext) ${editorDescription}`
    169    );
    170    is(
    171      inputEvents.length,
    172      1,
    173      `One "input" event should be fired on the editing host after calling nsIEditorMailSupport.insertAsCitedQuotation() of HTMLEditor editor (inserting as plaintext) ${editorDescription}`
    174    );
    175    checkInputEvent(
    176      inputEvents[0],
    177      "",
    178      null,
    179      `after calling nsIEditorMailSupport.insertAsCitedQuotation() of HTMLEditor editor (inserting as plaintext) ${editorDescription}`
    180    );
    181 
    182    editor.innerHTML = "";
    183 
    184    beforeInputEvents = [];
    185    inputEvents = [];
    186    getEditorMailSupport().insertAsCitedQuotation("this is quoted text<br>And here is second line.", "this is cited text", true);
    187 
    188    ok(
    189      selection.isCollapsed,
    190      `Selection should be collapsed after calling nsIEditorMailSupport.insertAsCitedQuotation() of HTMLEditor editor (inserting as HTML source) ${editorDescription}`
    191    );
    192    is(
    193      selection.focusNode,
    194      editor,
    195      `focus node of Selection should be a child of the editing host after calling nsIEditorMailSupport.insertAsCitedQuotation() of HTMLEditor editor (inserting as HTML source) ${editorDescription}`
    196    );
    197    is(
    198      selection.focusOffset,
    199      1,
    200      `focus offset of Selection should be next to inserted <span> element after calling nsIEditorMailSupport.insertAsCitedQuotation() of HTMLEditor editor (inserting as HTML source) ${editorDescription}`
    201    );
    202    is(
    203      editor.innerHTML,
    204      '<blockquote type="cite" cite="this is cited text">this is quoted text<br>And here is second line.</blockquote>',
    205      `The quoted text should be inserted as HTML source into the HTML editor ${editorDescription}`
    206    );
    207    is(
    208      beforeInputEvents.length,
    209      1,
    210      `One "beforeinput" event should be fired on the editing host after calling nsIEditorMailSupport.insertAsCitedQuotation() of HTMLEditor editor (inserting as HTML source) ${editorDescription}`
    211    );
    212    checkInputEvent(
    213      beforeInputEvents[0],
    214      "",
    215      null,
    216      `after calling nsIEditorMailSupport.insertAsCitedQuotation() of HTMLEditor editor (inserting as HTML source) ${editorDescription}`
    217    );
    218    is(
    219      inputEvents.length,
    220      1,
    221      `One "input" event should be fired on the editing host after calling nsIEditorMailSupport.insertAsCitedQuotation() of HTMLEditor editor (inserting as HTML source) ${editorDescription}`
    222    );
    223    checkInputEvent(
    224      inputEvents[0],
    225      "",
    226      null,
    227      `after calling nsIEditorMailSupport.insertAsCitedQuotation() of HTMLEditor editor (inserting as HTML source) ${editorDescription}`
    228    );
    229 
    230    editor.removeEventListener("beforeinput", onBeforeInput);
    231    editor.removeEventListener("input", onInput);
    232  }
    233 
    234  function testStyleOfPlaintextMode() {
    235    const inReadonlyMode = getEditor().flags & SpecialPowers.Ci.nsIEditor.eEditorReadonlyMask;
    236    const editorDescription = `(readonly=${!!inReadonlyMode})`;
    237 
    238    getEditor().flags |= SpecialPowers.Ci.nsIEditor.eEditorPlaintextMask;
    239 
    240    (function testInDiv() {
    241      const editor = document.querySelector("div[contenteditable]");
    242      editor.innerHTML = "";
    243      editor.focus();
    244      getEditorMailSupport().insertAsCitedQuotation(
    245        "this is quoted text.",
    246        "this is cited text",
    247        false
    248      );
    249      is(
    250        editor.firstChild.tagName,
    251        "SPAN",
    252        `testStyleOfPlaintextMode: testInDiv: insertAsCitedQuotation should insert a <span> element ${editorDescription}`
    253      );
    254      const computedSpanStyle = getComputedStyle(editor.firstChild);
    255      is(
    256        computedSpanStyle.display,
    257        "inline",
    258        `testStyleOfPlaintextMode: testInDiv: The inserted <span> element should be "display: inline;" ${editorDescription}`
    259      );
    260      is(
    261        computedSpanStyle.whiteSpace,
    262        "pre-wrap",
    263        `testStyleOfPlaintextMode: testInDiv: The inserted <span> element should be "white-space: pre-wrap;" ${editorDescription}`
    264      );
    265    })();
    266 
    267    try {
    268      document.body.contentEditable = true;
    269      (function testInBody() {
    270        getSelection().collapse(document.body, 0);
    271        getEditorMailSupport().insertAsCitedQuotation(
    272          "this is quoted text.",
    273          "this is cited text",
    274          false
    275        );
    276        is(
    277          document.body.firstChild.tagName,
    278          "SPAN",
    279          `testStyleOfPlaintextMode: testInBody: insertAsCitedQuotation should insert a <span> element in plaintext mode and in a <body> element ${editorDescription}`
    280        );
    281        const computedSpanStyle = getComputedStyle(document.body.firstChild);
    282        is(
    283          computedSpanStyle.display,
    284          "block",
    285          `testStyleOfPlaintextMode: testInBody: The inserted <span> element should be "display: block;" in plaintext mode and in a <body> element ${editorDescription}`
    286        );
    287        is(
    288          computedSpanStyle.whiteSpace,
    289          "pre-wrap",
    290          `testStyleOfPlaintextMode: testInBody: The inserted <span> element should be "white-space: pre-wrap;" in plaintext mode and in a <body> element ${editorDescription}`
    291        );
    292        document.body.firstChild.remove();
    293      })();
    294    } finally {
    295      document.body.contentEditable = false;
    296    }
    297  }
    298 
    299  testInputEvents();
    300  testStyleOfPlaintextMode();
    301 
    302  // Even if the HTMLEditor is readonly, XPCOM API should keep working.
    303  getEditor().flags |= SpecialPowers.Ci.nsIEditor.eEditorReadonlyMask;
    304  testInputEvents();
    305  testStyleOfPlaintextMode();
    306 
    307  SimpleTest.finish();
    308 });
    309 
    310 function getEditor() {
    311  var editingSession = SpecialPowers.wrap(window).docShell.editingSession;
    312  return editingSession.getEditorForWindow(window);
    313 }
    314 
    315 function getEditorMailSupport() {
    316  return getEditor().QueryInterface(SpecialPowers.Ci.nsIEditorMailSupport);
    317 }
    318 
    319 </script>
    320 </body>
    321 
    322 </html>