diff --git a/browser/metro/base/content/contenthandlers/ContextMenuHandler.js b/browser/metro/base/content/contenthandlers/ContextMenuHandler.js index c894aabbc484..af4c42e9474e 100644 --- a/browser/metro/base/content/contenthandlers/ContextMenuHandler.js +++ b/browser/metro/base/content/contenthandlers/ContextMenuHandler.js @@ -165,6 +165,13 @@ var ContextMenuHandler = { } else { Util.dumpLn("error: target element does not support nsIDOMNSEditableElement"); } + } else if (Util.isEditableContent(this._target)) { + try { + this._target.ownerDocument.execCommand("copy", false); + } catch (ex) { + dump("ContextMenuHandler: exception copying from contentEditable: " + + ex.message + "\n"); + } } else { let selectionText = this._previousState.string; diff --git a/browser/metro/base/tests/mochitest/browser_context_menu_tests.js b/browser/metro/base/tests/mochitest/browser_context_menu_tests.js index cbda54fc4615..f59dc1326f28 100644 --- a/browser/metro/base/tests/mochitest/browser_context_menu_tests.js +++ b/browser/metro/base/tests/mochitest/browser_context_menu_tests.js @@ -744,7 +744,7 @@ gTests.push({ // Case #2: Document isn't in design mode and text is selected. tabWindow.getSelection().selectAllChildren(testSpan); - let promise = waitForEvent(tabWindow.document, "popupshown"); + let promise = waitForEvent(document, "popupshown"); sendContextMenuClickToSelection(tabWindow); yield promise; @@ -758,7 +758,7 @@ gTests.push({ tabWindow.document.designMode = "on"; tabWindow.getSelection().removeAllRanges(); - promise = waitForEvent(tabWindow.document, "popupshown"); + promise = waitForEvent(document, "popupshown"); sendContextMenuClickToElement(tabWindow, testSpan); yield promise; @@ -771,7 +771,7 @@ gTests.push({ // Case #4: Document is in design mode and text is selected. tabWindow.getSelection().selectAllChildren(testSpan); - promise = waitForEvent(tabWindow.document, "popupshown"); + promise = waitForEvent(document, "popupshown"); sendContextMenuClickToSelection(tabWindow); yield promise; @@ -787,6 +787,93 @@ gTests.push({ } }); +gTests.push({ + desc: "Bug 961702 - 'Copy' context menu action does not copy rich content " + + "while document in design mode (or inside container that allows to " + + "edit its content)", + run: function test() { + info(chromeRoot + "browser_context_menu_tests_05.html"); + yield addTab(chromeRoot + "browser_context_menu_tests_05.html"); + + purgeEventQueue(); + emptyClipboard(); + ContextUI.dismiss(); + + yield waitForCondition(() => !ContextUI.navbarVisible); + + let tabWindow = Browser.selectedTab.browser.contentWindow; + let testDiv = tabWindow.document.getElementById("div1"); + + // Case #1: Document is in design mode. + tabWindow.document.designMode = "on"; + + let promise = waitForEvent(document, "popupshown"); + sendContextMenuClickToElement(tabWindow, testDiv); + yield promise; + + let selectAllMenuItem = document.getElementById("context-select-all"); + promise = waitForEvent(document, "popuphidden"); + sendNativeTap(selectAllMenuItem); + yield promise; + + promise = waitForEvent(document, "popupshown"); + sendContextMenuClickToSelection(tabWindow); + yield promise; + + let copyMenuItem = document.getElementById("context-copy"); + promise = waitForEvent(document, "popuphidden"); + sendNativeTap(copyMenuItem); + yield promise; + + // The wait is needed to give time to populate the clipboard. + let clipboardContent = ""; + let contentToCopy = tabWindow.document.body.innerHTML; + yield waitForCondition(function () { + clipboardContent = SpecialPowers.getClipboardData("text/html"); + return clipboardContent == contentToCopy; + }); + ok(clipboardContent == contentToCopy, "Rich content copied."); + + // Case #2: Container with editable content. + emptyClipboard(); + tabWindow.document.designMode = "off"; + tabWindow.getSelection().removeAllRanges(); + + promise = waitForEvent(tabWindow.document.body, "focus"); + sendNativeTap(testDiv); + yield promise; + + promise = waitForEvent(document, "popupshown"); + sendContextMenuClickToElement(tabWindow, testDiv); + yield promise; + + selectAllMenuItem = document.getElementById("context-select-all"); + promise = waitForEvent(document, "popuphidden"); + sendNativeTap(selectAllMenuItem); + yield promise; + + promise = waitForEvent(document, "popupshown"); + sendContextMenuClickToSelection(tabWindow); + yield promise; + + copyMenuItem = document.getElementById("context-copy"); + promise = waitForEvent(document, "popuphidden"); + sendNativeTap(copyMenuItem); + yield promise; + + // The wait is needed to give time to populate the clipboard. + clipboardContent = ""; + contentToCopy = testDiv.innerHTML; + yield waitForCondition(function () { + clipboardContent = SpecialPowers.getClipboardData("text/html"); + return clipboardContent == contentToCopy; + }); + ok(clipboardContent == contentToCopy, "Rich content copied."); + + Browser.closeTab(Browser.selectedTab, { forceClose: true }); + } +}); + function test() { setDevPixelEqualToPx(); runTests(); diff --git a/browser/metro/base/tests/mochitest/browser_context_menu_tests_05.html b/browser/metro/base/tests/mochitest/browser_context_menu_tests_05.html new file mode 100644 index 000000000000..140abd794f7e --- /dev/null +++ b/browser/metro/base/tests/mochitest/browser_context_menu_tests_05.html @@ -0,0 +1,15 @@ + + + + + + + Test text +
+ + +
Test content
+
+ + diff --git a/browser/metro/base/tests/mochitest/metro.ini b/browser/metro/base/tests/mochitest/metro.ini index 6709fd8ceed4..67a1eabad293 100644 --- a/browser/metro/base/tests/mochitest/metro.ini +++ b/browser/metro/base/tests/mochitest/metro.ini @@ -4,6 +4,7 @@ support-files = browser_context_menu_tests_02.html browser_context_menu_tests_03.html browser_context_menu_tests_04.html + browser_context_menu_tests_05.html browser_findbar.html browser_form_auto_complete.html browser_form_selects.html