// 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 = "<body style='margin: 0'>" + " <img id='img' tabindex='1' src='http://example.org/browser/browser/base/content/test/general/moz.png'>" + " <div id='main' contenteditable='true'>Test <b>Bold</b> After Text</div>" + "</body>"; 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") ? "<html><body>\n<!--StartFragment-->" : ""; const htmlPostfix = navigator.platform.includes("Win") ? "<!--EndFragment-->\n</body>\n</html>" : ""; 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 => { 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 <b>Bold</b>" + 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 <b>Bold</b> After Textt <b>Bold</b>", "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 => { content.addEventListener( "cut", event => { event.clipboardData.setData("text/plain", "Some text"); event.clipboardData.setData("text/html", "<i>Italic</i> "); 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 => { 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 + "<i>Italic</i> " + 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, "<i>Italic</i> Test <b>Bold</b> After<b></b>", "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 + '<img id="img" tabindex="1" src="http://example.org/browser/browser/base/content/test/general/moz.png">' + 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, '<i>Italic</i> <img id="img" tabindex="1" ' + 'src="http://example.org/browser/browser/base/content/test/general/moz.png">' + "Test <b>Bold</b> After<b></b>", "Paste after copy image" ); }); gBrowser.removeCurrentTab(); });