Bug 961702 - "Copy" context menu action doesn't copy rich content while document in design mode (or inside container that allows to edit its content). r=sfoster
authorAleh Zasypkin <aleh.zasypkin@gmail.com>
Tue, 21 Jan 2014 20:04:04 +0100
changeset 164798 3ea5b5cc5817d00bcf3b69c141315426e4f119d5
parent 164797 530cd49cb5d8c5cbc3dfd272d70d0b2943c8684e
child 164799 d86f25820d53af93aa01866aeb60ab4cbc49d3cd
push id38817
push usercbook@mozilla.com
push dateThu, 23 Jan 2014 10:29:13 +0000
treeherdermozilla-inbound@7fdda1995af8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfoster
bugs961702
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 961702 - "Copy" context menu action doesn't copy rich content while document in design mode (or inside container that allows to edit its content). r=sfoster
browser/metro/base/content/contenthandlers/ContextMenuHandler.js
browser/metro/base/tests/mochitest/browser_context_menu_tests.js
browser/metro/base/tests/mochitest/browser_context_menu_tests_05.html
browser/metro/base/tests/mochitest/metro.ini
--- a/browser/metro/base/content/contenthandlers/ContextMenuHandler.js
+++ b/browser/metro/base/content/contenthandlers/ContextMenuHandler.js
@@ -160,16 +160,23 @@ var ContextMenuHandler = {
   _onCopy: function _onCopy() {
     if (Util.isTextInput(this._target)) {
       let edit = this._target.QueryInterface(Ci.nsIDOMNSEditableElement);
       if (edit) {
         edit.editor.copy();
       } 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;
 
       Cc["@mozilla.org/widget/clipboardhelper;1"]
         .getService(Ci.nsIClipboardHelper).copyString(selectionText);
     }
     this.reset();
   },
--- a/browser/metro/base/tests/mochitest/browser_context_menu_tests.js
+++ b/browser/metro/base/tests/mochitest/browser_context_menu_tests.js
@@ -739,55 +739,142 @@ gTests.push({
     ok(ContextUI.tabbarVisible, "Tabbar is visible on context menu action.");
 
     ContextUI.dismiss();
     yield waitForCondition(() => !ContextUI.navbarVisible);
 
     // 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;
 
     checkContextUIMenuItemVisibility(["context-copy", "context-search"]);
 
     promise = waitForEvent(document, "popuphidden");
     ContextMenuUI.hide();
     yield promise;
 
     // Case #3: Document is in design mode and nothing is selected.
     tabWindow.document.designMode = "on";
     tabWindow.getSelection().removeAllRanges();
 
-    promise = waitForEvent(tabWindow.document, "popupshown");
+    promise = waitForEvent(document, "popupshown");
     sendContextMenuClickToElement(tabWindow, testSpan);
     yield promise;
 
     checkContextUIMenuItemVisibility(["context-select-all", "context-select"]);
 
     promise = waitForEvent(document, "popuphidden");
     ContextMenuUI.hide();
     yield promise;
 
     // 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;
 
     checkContextUIMenuItemVisibility(["context-cut", "context-copy",
                                       "context-select-all", "context-select",
                                       "context-search"]);
 
     promise = waitForEvent(document, "popuphidden");
     ContextMenuUI.hide();
     yield promise;
 
     Browser.closeTab(Browser.selectedTab, { forceClose: true });
   }
 });
 
+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();
 }
copy from browser/metro/base/tests/mochitest/browser_context_menu_tests_04.html
copy to browser/metro/base/tests/mochitest/browser_context_menu_tests_05.html
--- a/browser/metro/base/tests/mochitest/browser_context_menu_tests_04.html
+++ b/browser/metro/base/tests/mochitest/browser_context_menu_tests_05.html
@@ -1,15 +1,15 @@
 <!DOCTYPE html>
 <html>
   <head>
     <style>
     </style>
   </head>
 <body style="padding: 10px; margin: 10px;">
-  <div style="margin: 0; padding: 200px 0;">
-    <span id="text1">hello, I'm sorry but I <a id="text1-link" href="#test">must be going</a>.</span>
-  </div>
-  <div style="margin: 0; padding: 200px 0;">
-    <span id="text2"><a id="text2-link" href="#test">hello, I'm sorry but</a> I must be going.</span>
+  <span id="text1">Test text</span>
+  <div contenteditable="true" id="div1" style="border: 2px solid blue; width: 200px; height: 200px;">
+    <table>
+      <tr><td>Test content</td></tr>
+    </table>
   </div>
 </body>
-</html>
\ No newline at end of file
+</html>
--- a/browser/metro/base/tests/mochitest/metro.ini
+++ b/browser/metro/base/tests/mochitest/metro.ini
@@ -1,14 +1,15 @@
 [DEFAULT]
 support-files =
   browser_context_menu_tests_01.html
   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
   browser_link_click.html
   browser_onscreen_keyboard.html
   browser_progress_indicator.xul
   browser_selection_basic.html
   browser_selection_caretfocus.html