tor-browser

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

browser_clipboard.js (8634B)


      1 // This test is used to check copy and paste in editable areas to ensure that non-text
      2 // types (html and images) are copied to and pasted from the clipboard properly.
      3 
      4 var testPage =
      5  "<body style='margin: 0'>" +
      6  "  <img id='img' tabindex='1' src='http://example.org/browser/browser/base/content/test/general/moz.png'>" +
      7  "  <div id='main' contenteditable='true'>Test <b>Bold</b> After Text</div>" +
      8  "</body>";
      9 
     10 add_task(async function () {
     11  let tab = BrowserTestUtils.addTab(gBrowser);
     12  let browser = gBrowser.getBrowserForTab(tab);
     13 
     14  gBrowser.selectedTab = tab;
     15 
     16  await BrowserTestUtils.loadURIString({
     17    browser: tab.linkedBrowser,
     18    uriString: "data:text/html," + escape(testPage),
     19  });
     20  await SimpleTest.promiseFocus(browser);
     21 
     22  function sendKey(key, code) {
     23    return BrowserTestUtils.synthesizeKey(
     24      key,
     25      { code, accelKey: true },
     26      browser
     27    );
     28  }
     29 
     30  // On windows, HTML clipboard includes extra data.
     31  // The values are from widget/windows/nsDataObj.cpp.
     32  const htmlPrefix = navigator.platform.includes("Win")
     33    ? "<html><body>\n<!--StartFragment-->"
     34    : "";
     35  const htmlPostfix = navigator.platform.includes("Win")
     36    ? "<!--EndFragment-->\n</body>\n</html>"
     37    : "";
     38 
     39  await SpecialPowers.spawn(browser, [], () => {
     40    var doc = content.document;
     41    var main = doc.getElementById("main");
     42    main.focus();
     43 
     44    // Select an area of the text.
     45    let selection = doc.getSelection();
     46    selection.modify("move", "left", "line");
     47    selection.modify("move", "right", "character");
     48    selection.modify("move", "right", "character");
     49    selection.modify("move", "right", "character");
     50    selection.modify("extend", "right", "word");
     51    selection.modify("extend", "right", "word");
     52  });
     53 
     54  // The data is empty as the selection was copied during the event default phase.
     55  let copyEventPromise = BrowserTestUtils.waitForContentEvent(
     56    browser,
     57    "copy",
     58    false,
     59    event => {
     60      return event.clipboardData.mozItemCount == 0;
     61    }
     62  );
     63  await SpecialPowers.spawn(browser, [], () => {});
     64  await sendKey("c");
     65  await copyEventPromise;
     66 
     67  let pastePromise = SpecialPowers.spawn(
     68    browser,
     69    [htmlPrefix, htmlPostfix],
     70    (htmlPrefixChild, htmlPostfixChild) => {
     71      let selection = content.document.getSelection();
     72      selection.modify("move", "right", "line");
     73 
     74      return new Promise(resolve => {
     75        content.addEventListener(
     76          "paste",
     77          event => {
     78            let clipboardData = event.clipboardData;
     79            Assert.equal(
     80              clipboardData.mozItemCount,
     81              1,
     82              "One item on clipboard"
     83            );
     84            Assert.equal(
     85              clipboardData.types.length,
     86              2,
     87              "Two types on clipboard"
     88            );
     89            Assert.equal(
     90              clipboardData.types[0],
     91              "text/html",
     92              "text/html on clipboard"
     93            );
     94            Assert.equal(
     95              clipboardData.types[1],
     96              "text/plain",
     97              "text/plain on clipboard"
     98            );
     99            Assert.equal(
    100              clipboardData.getData("text/html"),
    101              htmlPrefixChild + "t <b>Bold</b>" + htmlPostfixChild,
    102              "text/html value"
    103            );
    104            Assert.equal(
    105              clipboardData.getData("text/plain"),
    106              "t Bold",
    107              "text/plain value"
    108            );
    109            resolve();
    110          },
    111          { capture: true, once: true }
    112        );
    113      });
    114    }
    115  );
    116 
    117  await SpecialPowers.spawn(browser, [], () => {});
    118 
    119  await sendKey("v");
    120  await pastePromise;
    121 
    122  let copyPromise = SpecialPowers.spawn(browser, [], () => {
    123    var main = content.document.getElementById("main");
    124 
    125    Assert.equal(
    126      main.innerHTML,
    127      "Test <b>Bold</b> After Textt <b>Bold</b>",
    128      "Copy and paste html"
    129    );
    130 
    131    let selection = content.document.getSelection();
    132    selection.modify("extend", "left", "word");
    133    selection.modify("extend", "left", "word");
    134    selection.modify("extend", "left", "character");
    135 
    136    return new Promise(resolve => {
    137      content.addEventListener(
    138        "cut",
    139        event => {
    140          event.clipboardData.setData("text/plain", "Some text");
    141          event.clipboardData.setData("text/html", "<i>Italic</i> ");
    142          selection.deleteFromDocument();
    143          event.preventDefault();
    144          resolve();
    145        },
    146        { capture: true, once: true }
    147      );
    148    });
    149  });
    150 
    151  await SpecialPowers.spawn(browser, [], () => {});
    152 
    153  await sendKey("x");
    154  await copyPromise;
    155 
    156  pastePromise = SpecialPowers.spawn(
    157    browser,
    158    [htmlPrefix, htmlPostfix],
    159    (htmlPrefixChild, htmlPostfixChild) => {
    160      let selection = content.document.getSelection();
    161      selection.modify("move", "left", "line");
    162 
    163      return new Promise(resolve => {
    164        content.addEventListener(
    165          "paste",
    166          event => {
    167            let clipboardData = event.clipboardData;
    168            Assert.equal(
    169              clipboardData.mozItemCount,
    170              1,
    171              "One item on clipboard 2"
    172            );
    173            Assert.equal(
    174              clipboardData.types.length,
    175              2,
    176              "Two types on clipboard 2"
    177            );
    178            Assert.equal(
    179              clipboardData.types[0],
    180              "text/html",
    181              "text/html on clipboard 2"
    182            );
    183            Assert.equal(
    184              clipboardData.types[1],
    185              "text/plain",
    186              "text/plain on clipboard 2"
    187            );
    188            Assert.equal(
    189              clipboardData.getData("text/html"),
    190              htmlPrefixChild + "<i>Italic</i> " + htmlPostfixChild,
    191              "text/html value 2"
    192            );
    193            Assert.equal(
    194              clipboardData.getData("text/plain"),
    195              "Some text",
    196              "text/plain value 2"
    197            );
    198            resolve();
    199          },
    200          { capture: true, once: true }
    201        );
    202      });
    203    }
    204  );
    205 
    206  await SpecialPowers.spawn(browser, [], () => {});
    207 
    208  await sendKey("v");
    209  await pastePromise;
    210 
    211  await SpecialPowers.spawn(browser, [], () => {
    212    var main = content.document.getElementById("main");
    213    Assert.equal(
    214      main.innerHTML,
    215      "<i>Italic</i> Test <b>Bold</b> After<b></b>",
    216      "Copy and paste html 2"
    217    );
    218  });
    219 
    220  // Next, check that the Copy Image command works.
    221 
    222  // The context menu needs to be opened to properly initialize for the copy
    223  // image command to run.
    224  let contextMenu = document.getElementById("contentAreaContextMenu");
    225  let contextMenuShown = promisePopupShown(contextMenu);
    226  BrowserTestUtils.synthesizeMouseAtCenter(
    227    "#img",
    228    { type: "contextmenu", button: 2 },
    229    gBrowser.selectedBrowser
    230  );
    231  await contextMenuShown;
    232 
    233  document.getElementById("context-copyimage-contents").doCommand();
    234 
    235  contextMenu.hidePopup();
    236  await promisePopupHidden(contextMenu);
    237 
    238  // Focus the content again
    239  await SimpleTest.promiseFocus(browser);
    240 
    241  pastePromise = SpecialPowers.spawn(
    242    browser,
    243    [htmlPrefix, htmlPostfix],
    244    (htmlPrefixChild, htmlPostfixChild) => {
    245      var doc = content.document;
    246      var main = doc.getElementById("main");
    247      main.focus();
    248 
    249      return new Promise((resolve, reject) => {
    250        content.addEventListener(
    251          "paste",
    252          event => {
    253            let clipboardData = event.clipboardData;
    254 
    255            // DataTransfer doesn't support the image types yet, so only text/html
    256            // will be present.
    257            if (
    258              clipboardData.getData("text/html") !==
    259              htmlPrefixChild +
    260                '<img id="img" tabindex="1" src="http://example.org/browser/browser/base/content/test/general/moz.png">' +
    261                htmlPostfixChild
    262            ) {
    263              reject(
    264                "Clipboard Data did not contain an image, was " +
    265                  clipboardData.getData("text/html")
    266              );
    267            }
    268            resolve();
    269          },
    270          { capture: true, once: true }
    271        );
    272      });
    273    }
    274  );
    275 
    276  await SpecialPowers.spawn(browser, [], () => {});
    277  await sendKey("v");
    278  await pastePromise;
    279 
    280  // The new content should now include an image.
    281  await SpecialPowers.spawn(browser, [], () => {
    282    var main = content.document.getElementById("main");
    283    Assert.equal(
    284      main.innerHTML,
    285      '<i>Italic</i>&nbsp;<img id="img" tabindex="1" ' +
    286        'src="http://example.org/browser/browser/base/content/test/general/moz.png">' +
    287        "Test <b>Bold</b> After<b></b>",
    288      "Paste after copy image"
    289    );
    290  });
    291 
    292  gBrowser.removeCurrentTab();
    293 });