Bug 1005870 - Add a copy() command to the console. r=robcee
☠☠ backed out by 549927402a52 ☠ ☠
authorDavid Rajchenbach-Teller <dteller@mozilla.com>
Thu, 03 Jul 2014 06:40:00 -0400
changeset 213098 f007a1c34042d1c0b14500b25adc5544677c6e54
parent 212957 610cfd0139c1a495613ac7dbe568f73ab33d09fe
child 213099 043995106767e7ebbd03f937289e7fe8096c7c5e
push id3857
push userraliiev@mozilla.com
push dateTue, 02 Sep 2014 16:39:23 +0000
treeherdermozilla-beta@5638b907b505 [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 - Add 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,89 @@
+/* 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;
+  }
+});
+
--- 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.
  *