Bug 1005870 - Adding a copy() command to the console. r=robcee
☠☠ backed out by 7963ca1203e3 ☠ ☠
authorDavid Rajchenbach-Teller <dteller@mozilla.com>
Fri, 04 Jul 2014 08:10:00 +0200
changeset 192602 161b47c4a8adca4040222460eb01b8a020ce1932
parent 192601 be0ae5640b90141caaf4c09053c33d49ac351f0d
child 192603 3271ce25db004f93597060325e34a2f7001fc682
push id27091
push userkwierso@gmail.com
push dateMon, 07 Jul 2014 21:11:34 +0000
treeherdermozilla-central@f14b47c39013 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrobcee
bugs1005870
milestone33.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 1005870 - Adding a copy() command to the console. r=robcee
browser/devtools/webconsole/test/browser.ini
browser/devtools/webconsole/test/browser_console_copy_command.js
browser/devtools/webconsole/webconsole.js
toolkit/devtools/webconsole/utils.js
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -122,16 +122,17 @@ support-files =
 [browser_bug_869003_inspect_cross_domain_object.js]
 [browser_bug_871156_ctrlw_close_tab.js]
 [browser_cached_messages.js]
 [browser_console.js]
 [browser_console_addonsdk_loader_exception.js]
 [browser_console_clear_on_reload.js]
 [browser_console_click_focus.js]
 [browser_console_consolejsm_output.js]
+[browser_console_copy_command.js]
 [browser_console_dead_objects.js]
 [browser_console_error_source_click.js]
 [browser_console_filters.js]
 [browser_console_iframe_messages.js]
 [browser_console_keyboard_accessibility.js]
 [browser_console_log_inspectable_object.js]
 [browser_console_native_getters.js]
 [browser_console_navigation_marker.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_console_copy_command.js
@@ -0,0 +1,93 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Tests that the $0 console helper works as intended.
+
+let gWebConsole, gJSTerm;
+
+let TEXT =  "Lorem ipsum dolor sit amet, consectetur adipisicing " +
+    "elit, sed do eiusmod tempor incididunt ut labore et dolore magna " +
+    "aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco " +
+    "laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure " +
+    "dolor in reprehenderit in voluptate velit esse cillum dolore eu " +
+    "fugiat nulla pariatur. Excepteur sint occaecat cupidatat non " +
+    "proident, sunt in culpa qui officia deserunt mollit anim id est laborum." +
+    new Date();
+
+let ID = "select-me";
+
+add_task(function* init() {
+  let deferredFocus = Promise.defer();
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
+    gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
+    waitForFocus(deferredFocus.resolve, content);
+  }, true);
+
+  content.location = "data:text/html;charset=utf-8,test for copy helper in web console";
+
+  yield deferredFocus.promise;
+
+  let doc = content.document;
+  let div = doc.createElement("div");
+  let h1 = doc.createElement("h1");
+  let p1 = doc.createElement("p");
+  let p2 = doc.createElement("p");
+  let div2 = doc.createElement("div");
+  let p3 = doc.createElement("p");
+  doc.title = "Testing copy command";
+  h1.textContent = "Testing copy command";
+  p1.textContent = "This is some example text";
+  p2.textContent = TEXT;
+  p2.id = "" + ID;
+  div.appendChild(h1);
+  div.appendChild(p1);
+  div.appendChild(p2);
+  div2.appendChild(p3);
+  doc.body.appendChild(div);
+  doc.body.appendChild(div2);
+
+  let deferredConsole = Promise.defer();
+  openConsole(gBrowser.selectedTab, deferredConsole.resolve);
+
+  gWebConsole = yield deferredConsole.promise;
+  gJSTerm = gWebConsole.jsterm;
+});
+
+add_task(function* test_copy() {
+  let RANDOM = Math.random();
+  let string = "Text: " + RANDOM;
+  let obj = {a: 1, b: "foo", c: RANDOM};
+
+  let samples = [[RANDOM, RANDOM],
+                 [JSON.stringify(string), string],
+                 [obj.toSource(),  JSON.stringify(obj, null, "  ")],
+                 ["$('#" + ID + "')", content.document.getElementById(ID).outerHTML]
+                ];
+  for (let [source, reference] of samples) {
+    let deferredResult = Promise.defer();
+
+    SimpleTest.waitForClipboard(
+      "" + reference,
+      () => {
+        let command = "copy(" + source + ")";
+        info("Attempting to copy: " + source);
+        info("Executing command: " + command);
+        gJSTerm.execute(command, msg => {
+          is(msg, undefined, "Command success: " + command);
+        });
+      },
+      deferredResult.resolve,
+      deferredResult.reject);
+
+    yield deferredResult.promise;
+  }
+});
+
+add_task(function* cleanup() {
+  gBrowser.removeTab(gBrowser.selectedTab);
+  finishTest();
+});
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -3198,16 +3198,19 @@ JSTerm.prototype = {
           }
           catch (ex) {
             errorMessage = helperResult.message;
           }
           break;
         case "help":
           this.hud.owner.openLink(HELP_URL);
           break;
+        case "copyValueToClipboard":
+          clipboardHelper.copyString(helperResult.value);
+          break;
       }
     }
 
     // Hide undefined results coming from JSTerm helper functions.
     if (!errorMessage && result && typeof result == "object" &&
         result.type == "undefined" &&
         helperResult && !helperHasRawOutput) {
       aCallback && aCallback();
--- a/toolkit/devtools/webconsole/utils.js
+++ b/toolkit/devtools/webconsole/utils.js
@@ -1758,16 +1758,43 @@ function JSTermHelpers(aOwner)
   {
     aOwner.helperResult = { rawOutput: true };
     // Waiving Xrays here allows us to see a closer representation of the
     // underlying object. This may execute arbitrary content code, but that
     // code will run with content privileges, and the result will be rendered
     // inert by coercing it to a String.
     return String(Cu.waiveXrays(aValue));
   };
+
+  /**
+   * Copy the String representation of a value to the clipboard.
+   *
+   * @param any aValue
+   *        A value you want to copy as a string.
+   * @return void
+   */
+  aOwner.sandbox.copy = function JSTH_copy(aValue)
+  {
+    let payload;
+    try {
+      if (aValue instanceof Ci.nsIDOMElement) {
+        payload = aValue.outerHTML;
+      } else if (typeof aValue == "string") {
+        payload = aValue;
+      } else {
+        payload = JSON.stringify(aValue, null, "  ");
+      }
+    } catch (ex) {
+      payload = "/* " + ex  + " */";
+    }
+    aOwner.helperResult = {
+      type: "copyValueToClipboard",
+      value: payload,
+    };
+  };
 }
 exports.JSTermHelpers = JSTermHelpers;
 
 
 /**
  * A ReflowObserver that listens for reflow events from the page.
  * Implements nsIReflowObserver.
  *