// This test is used to check copy and paste in editable areas to ensure that non-text
// types (html and images) are copied to and pasted from the clipboard properly.
var testPage =
  "
" +
  "  
" +
  "  Test Bold After Text
" +
  "";
add_task(async function() {
  let tab = BrowserTestUtils.addTab(gBrowser);
  let browser = gBrowser.getBrowserForTab(tab);
  gBrowser.selectedTab = tab;
  await promiseTabLoadEvent(tab, "data:text/html," + escape(testPage));
  await SimpleTest.promiseFocus(browser);
  function sendKey(key, code) {
    return BrowserTestUtils.synthesizeKey(
      key,
      { code, accelKey: true },
      browser
    );
  }
  // On windows, HTML clipboard includes extra data.
  // The values are from widget/windows/nsDataObj.cpp.
  const htmlPrefix = navigator.platform.includes("Win")
    ? "\n"
    : "";
  const htmlPostfix = navigator.platform.includes("Win")
    ? "\n\n"
    : "";
  await SpecialPowers.spawn(browser, [], () => {
    var doc = content.document;
    var main = doc.getElementById("main");
    main.focus();
    // Select an area of the text.
    let selection = doc.getSelection();
    selection.modify("move", "left", "line");
    selection.modify("move", "right", "character");
    selection.modify("move", "right", "character");
    selection.modify("move", "right", "character");
    selection.modify("extend", "right", "word");
    selection.modify("extend", "right", "word");
  });
  // The data is empty as the selection was copied during the event default phase.
  let copyEventPromise = BrowserTestUtils.waitForContentEvent(
    browser,
    "copy",
    false,
    event => {
      return event.clipboardData.mozItemCount == 0;
    }
  );
  await SpecialPowers.spawn(browser, [], () => {});
  await sendKey("c");
  await copyEventPromise;
  let pastePromise = SpecialPowers.spawn(
    browser,
    [htmlPrefix, htmlPostfix],
    (htmlPrefixChild, htmlPostfixChild) => {
      let selection = content.document.getSelection();
      selection.modify("move", "right", "line");
      return new Promise((resolve, reject) => {
        content.addEventListener(
          "paste",
          event => {
            let clipboardData = event.clipboardData;
            Assert.equal(
              clipboardData.mozItemCount,
              1,
              "One item on clipboard"
            );
            Assert.equal(
              clipboardData.types.length,
              2,
              "Two types on clipboard"
            );
            Assert.equal(
              clipboardData.types[0],
              "text/html",
              "text/html on clipboard"
            );
            Assert.equal(
              clipboardData.types[1],
              "text/plain",
              "text/plain on clipboard"
            );
            Assert.equal(
              clipboardData.getData("text/html"),
              htmlPrefixChild + "t Bold" + htmlPostfixChild,
              "text/html value"
            );
            Assert.equal(
              clipboardData.getData("text/plain"),
              "t Bold",
              "text/plain value"
            );
            resolve();
          },
          { capture: true, once: true }
        );
      });
    }
  );
  await SpecialPowers.spawn(browser, [], () => {});
  await sendKey("v");
  await pastePromise;
  let copyPromise = SpecialPowers.spawn(browser, [], () => {
    var main = content.document.getElementById("main");
    Assert.equal(
      main.innerHTML,
      "Test Bold After Textt Bold",
      "Copy and paste html"
    );
    let selection = content.document.getSelection();
    selection.modify("extend", "left", "word");
    selection.modify("extend", "left", "word");
    selection.modify("extend", "left", "character");
    return new Promise((resolve, reject) => {
      content.addEventListener(
        "cut",
        event => {
          event.clipboardData.setData("text/plain", "Some text");
          event.clipboardData.setData("text/html", "Italic ");
          selection.deleteFromDocument();
          event.preventDefault();
          resolve();
        },
        { capture: true, once: true }
      );
    });
  });
  await SpecialPowers.spawn(browser, [], () => {});
  await sendKey("x");
  await copyPromise;
  pastePromise = SpecialPowers.spawn(
    browser,
    [htmlPrefix, htmlPostfix],
    (htmlPrefixChild, htmlPostfixChild) => {
      let selection = content.document.getSelection();
      selection.modify("move", "left", "line");
      return new Promise((resolve, reject) => {
        content.addEventListener(
          "paste",
          event => {
            let clipboardData = event.clipboardData;
            Assert.equal(
              clipboardData.mozItemCount,
              1,
              "One item on clipboard 2"
            );
            Assert.equal(
              clipboardData.types.length,
              2,
              "Two types on clipboard 2"
            );
            Assert.equal(
              clipboardData.types[0],
              "text/html",
              "text/html on clipboard 2"
            );
            Assert.equal(
              clipboardData.types[1],
              "text/plain",
              "text/plain on clipboard 2"
            );
            Assert.equal(
              clipboardData.getData("text/html"),
              htmlPrefixChild + "Italic " + htmlPostfixChild,
              "text/html value 2"
            );
            Assert.equal(
              clipboardData.getData("text/plain"),
              "Some text",
              "text/plain value 2"
            );
            resolve();
          },
          { capture: true, once: true }
        );
      });
    }
  );
  await SpecialPowers.spawn(browser, [], () => {});
  await sendKey("v");
  await pastePromise;
  await SpecialPowers.spawn(browser, [], () => {
    var main = content.document.getElementById("main");
    Assert.equal(
      main.innerHTML,
      "Italic Test Bold After",
      "Copy and paste html 2"
    );
  });
  // Next, check that the Copy Image command works.
  // The context menu needs to be opened to properly initialize for the copy
  // image command to run.
  let contextMenu = document.getElementById("contentAreaContextMenu");
  let contextMenuShown = promisePopupShown(contextMenu);
  BrowserTestUtils.synthesizeMouseAtCenter(
    "#img",
    { type: "contextmenu", button: 2 },
    gBrowser.selectedBrowser
  );
  await contextMenuShown;
  document.getElementById("context-copyimage-contents").doCommand();
  contextMenu.hidePopup();
  await promisePopupHidden(contextMenu);
  // Focus the content again
  await SimpleTest.promiseFocus(browser);
  pastePromise = SpecialPowers.spawn(
    browser,
    [htmlPrefix, htmlPostfix],
    (htmlPrefixChild, htmlPostfixChild) => {
      var doc = content.document;
      var main = doc.getElementById("main");
      main.focus();
      return new Promise((resolve, reject) => {
        content.addEventListener(
          "paste",
          event => {
            let clipboardData = event.clipboardData;
            // DataTransfer doesn't support the image types yet, so only text/html
            // will be present.
            if (
              clipboardData.getData("text/html") !==
              htmlPrefixChild +
                '
' +
                htmlPostfixChild
            ) {
              reject(
                "Clipboard Data did not contain an image, was " +
                  clipboardData.getData("text/html")
              );
            }
            resolve();
          },
          { capture: true, once: true }
        );
      });
    }
  );
  await SpecialPowers.spawn(browser, [], () => {});
  await sendKey("v");
  await pastePromise;
  // The new content should now include an image.
  await SpecialPowers.spawn(browser, [], () => {
    var main = content.document.getElementById("main");
    Assert.equal(
      main.innerHTML,
      'Italic 
' +
        "Test Bold After",
      "Paste after copy image"
    );
  });
  gBrowser.removeCurrentTab();
});