Bug 611440 - Smart abbreviation for URLs in the Web Console; f=mihai.sucan,dolske r=dolske approval2.0=dolske
authorPatrick Walton <pwalton@mozilla.com>
Mon, 24 Jan 2011 12:05:05 -0400
changeset 61176 812710794ca1a65b9f5c5014babc948d32376bbb
parent 61175 e09b598992e8f4495e1bd7d51f8b95d39ee966de
child 61177 9ec42a4717062c495cc70fe6d7b10c23b3d79243
push id18259
push userrcampbell@mozilla.com
push dateMon, 24 Jan 2011 16:06:04 +0000
treeherdermozilla-central@812710794ca1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdolske
bugs611440
milestone2.0b10pre
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 611440 - Smart abbreviation for URLs in the Web Console; f=mihai.sucan,dolske r=dolske approval2.0=dolske
toolkit/components/console/hudservice/HUDService.jsm
toolkit/components/console/hudservice/tests/browser/browser_webconsole_basic_net_logging.js
toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_582201_duplicate_errors.js
toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_593003_iframe_wrong_hud.js
toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_601177_log_levels.js
toolkit/components/console/hudservice/tests/browser/head.js
toolkit/locales/en-US/chrome/global/headsUpDisplay.properties
toolkit/themes/gnomestripe/global/webConsole.css
toolkit/themes/pinstripe/global/webConsole.css
toolkit/themes/winstripe/global/webConsole.css
--- a/toolkit/components/console/hudservice/HUDService.jsm
+++ b/toolkit/components/console/hudservice/HUDService.jsm
@@ -2183,17 +2183,17 @@ HUD_SERVICE.prototype =
             // Copy the request header data.
             aChannel.visitRequestHeaders({
               visitHeader: function(aName, aValue) {
                 httpActivity.request.header[aName] = aValue;
               }
             });
 
             // Store the loggedNode and the httpActivity object for later reuse.
-            let linkNode = loggedNode.querySelector(".webconsole-msg-url");
+            let linkNode = loggedNode.querySelector(".webconsole-msg-link");
 
             httpActivity.messageObject = {
               messageNode: loggedNode,
               linkNode:    linkNode
             };
             self.openRequests[httpActivity.id] = httpActivity;
 
             // Make the network span clickable.
@@ -2231,17 +2231,17 @@ HUD_SERVICE.prototype =
             if (!httpActivity) {
               return;
             }
 
             hudId = httpActivity.hudId;
             let msgObject = httpActivity.messageObject;
 
             let updatePanel = false;
-            let data, textNode;
+            let data;
             // Store the time information for this activity subtype.
             httpActivity.timing[transCodes[aActivitySubtype]] = aTimestamp;
 
             switch (aActivitySubtype) {
               case activityDistributor.ACTIVITY_SUBTYPE_REQUEST_BODY_SENT: {
                 if (!self.saveRequestAndResponseBodies) {
                   httpActivity.request.bodyDiscarded = true;
                   break;
@@ -2281,35 +2281,27 @@ HUD_SERVICE.prototype =
                 // Note: The response header is not saved here. Calling the
                 //       aChannel.visitResponseHeaders at this point sometimes
                 //       causes an NS_ERROR_NOT_AVAILABLE exception. Therefore,
                 //       the response header and response body is stored on the
                 //       httpActivity object within the RL_onStopRequest function.
                 httpActivity.response.status =
                   aExtraStringData.split(/\r\n|\n|\r/)[0];
 
-                // Remove the text node from the URL node and add a new one that
-                // contains the response status.
-                textNode = msgObject.linkNode.firstChild;
-                textNode.parentNode.removeChild(textNode);
-
-                data = [ httpActivity.url,
-                         httpActivity.response.status ];
-
-                // Format the pieces of data. The result will be something like
-                // "http://example.com/ [HTTP/1.0 200 OK]".
-                let text = self.getFormatStr("networkUrlWithStatus", data);
-
-                // Replace the displayed text and the clipboard text with the
-                // new data.
-                let chromeDocument = msgObject.messageNode.ownerDocument;
-                msgObject.linkNode.appendChild(
-                  chromeDocument.createTextNode(text));
+                // Add the response status.
+                let linkNode = msgObject.linkNode;
+                let statusNode = linkNode.
+                  querySelector(".webconsole-msg-status");
+                let statusText = "[" + httpActivity.response.status + "]";
+                statusNode.setAttribute("value", statusText);
+
+                let clipboardTextPieces =
+                  [ httpActivity.method, httpActivity.url, statusText ];
                 msgObject.messageNode.clipboardText =
-                  msgObject.messageNode.textContent;
+                  clipboardTextPieces.join(" ");
 
                 let status = parseInt(httpActivity.response.status.
                   replace(/^HTTP\/\d\.\d (\d+).+$/, "$1"));
 
                 if (status >= MIN_HTTP_ERROR_CODE &&
                     status < MAX_HTTP_ERROR_CODE) {
                   ConsoleUtils.setMessageType(msgObject.messageNode,
                                               CATEGORY_NETWORK,
@@ -2320,37 +2312,31 @@ HUD_SERVICE.prototype =
               }
 
               case activityDistributor.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE: {
                 let timing = httpActivity.timing;
                 let requestDuration =
                   Math.round((timing.RESPONSE_COMPLETE -
                                 timing.REQUEST_HEADER) / 1000);
 
-                // Remove the text node from the link node and add a new one
-                // that contains the request duration.
-                textNode = msgObject.linkNode.firstChild;
-                textNode.parentNode.removeChild(textNode);
-
-                data = [ httpActivity.url,
-                         httpActivity.response.status,
-                         requestDuration ];
-
-                // Format the pieces of data. The result will be something like
-                // "http://example.com/ [HTTP/1.0 200 OK 200 ms]".
-                let text = self.getFormatStr("networkUrlWithStatusAndDuration",
-                                             data);
-
-                // Replace the displayed text and the clipboard text with the
-                // new data.
-                let chromeDocument = msgObject.messageNode.ownerDocument;
-                msgObject.linkNode.appendChild(
-                  chromeDocument.createTextNode(text));
+                // Add the request duration.
+                let linkNode = msgObject.linkNode;
+                let statusNode = linkNode.
+                  querySelector(".webconsole-msg-status");
+
+                let statusText = httpActivity.response.status;
+                let timeText = self.getFormatStr("NetworkPanel.durationMS",
+                                                 [ requestDuration ]);
+                let fullStatusText = "[" + statusText + " " + timeText + "]";
+                statusNode.setAttribute("value", fullStatusText);
+
+                let clipboardTextPieces =
+                  [ httpActivity.method, httpActivity.url, fullStatusText ];
                 msgObject.messageNode.clipboardText =
-                  msgObject.messageNode.textContent;
+                  clipboardTextPieces.join(" ");
 
                 delete self.openRequests[item.id];
                 updatePanel = true;
                 break;
               }
             }
 
             if (updatePanel) {
@@ -2447,29 +2433,46 @@ HUD_SERVICE.prototype =
    * @returns void
    */
   logNetActivity: function HS_logNetActivity(aActivityObject)
   {
     let hudId = aActivityObject.hudId;
     let outputNode = this.hudReferences[hudId].outputNode;
 
     let chromeDocument = outputNode.ownerDocument;
-    let msgNode = chromeDocument.createElementNS(HTML_NS, "html:span");
-
-    // Create the method part of the message (e.g. "GET").
-    let method = chromeDocument.createTextNode(aActivityObject.method + " ");
-    msgNode.appendChild(method);
-
-    // Create the clickable URL part of the message.
-    let linkNode = chromeDocument.createElementNS(HTML_NS, "html:span");
-    linkNode.appendChild(chromeDocument.createTextNode(aActivityObject.url));
-    linkNode.classList.add("hud-clickable");
-    linkNode.classList.add("webconsole-msg-url");
+    let msgNode = chromeDocument.createElementNS(XUL_NS, "xul:hbox");
+
+    let methodNode = chromeDocument.createElementNS(XUL_NS, "xul:label");
+    methodNode.setAttribute("value", aActivityObject.method);
+    methodNode.classList.add("webconsole-msg-body-piece");
+    msgNode.appendChild(methodNode);
+
+    let linkNode = chromeDocument.createElementNS(XUL_NS, "xul:hbox");
+    linkNode.setAttribute("flex", "1");
+    linkNode.classList.add("webconsole-msg-body-piece");
+    linkNode.classList.add("webconsole-msg-link");
     msgNode.appendChild(linkNode);
 
+    let urlNode = chromeDocument.createElementNS(XUL_NS, "xul:label");
+    urlNode.setAttribute("crop", "center");
+    urlNode.setAttribute("flex", "1");
+    urlNode.setAttribute("title", aActivityObject.url);
+    urlNode.setAttribute("value", aActivityObject.url);
+    urlNode.classList.add("hud-clickable");
+    urlNode.classList.add("webconsole-msg-body-piece");
+    urlNode.classList.add("webconsole-msg-url");
+    linkNode.appendChild(urlNode);
+
+    let statusNode = chromeDocument.createElementNS(XUL_NS, "xul:label");
+    statusNode.setAttribute("value", "");
+    statusNode.classList.add("hud-clickable");
+    statusNode.classList.add("webconsole-msg-body-piece");
+    statusNode.classList.add("webconsole-msg-status");
+    linkNode.appendChild(statusNode);
+
     let clipboardText = aActivityObject.method + " " + aActivityObject.url;
 
     let messageNode = ConsoleUtils.createMessageNode(chromeDocument,
                                                      CATEGORY_NETWORK,
                                                      SEVERITY_LOG,
                                                      msgNode,
                                                      null,
                                                      null,
--- a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_basic_net_logging.js
+++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_basic_net_logging.js
@@ -55,22 +55,20 @@ function onLoad(aEvent) {
 
   browser.addEventListener("load", testBasicNetLogging, true);
   content.location = TEST_NETWORK_URI;
 }
 
 function testBasicNetLogging(aEvent) {
   browser.removeEventListener(aEvent.type, arguments.callee, true);
 
-  hudBox = HUDService.getHeadsUpDisplay(hudId);
+  outputNode = HUDService.hudReferences[hudId].outputNode;
 
   executeSoon(function() {
-    let text = hudBox.querySelector(".hud-output-node").textContent;
-
-    isnot(text.indexOf("test-network.html"), -1, "found test-network.html");
-    isnot(text.indexOf("testscript.js"), -1, "found testscript.js");
-    isnot(text.indexOf("test-image.png"), -1, "found test-image.png");
-    isnot(text.indexOf("network console"), -1, "found network console");
+    findLogEntry("test-network.html");
+    findLogEntry("testscript.js");
+    findLogEntry("test-image.png");
+    findLogEntry("network console");
 
     finishTest();
   });
 }
 
--- a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_582201_duplicate_errors.js
+++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_582201_duplicate_errors.js
@@ -82,15 +82,14 @@ var consoleObserver = {
       var text = outputNode.textContent;
       var error1pos = text.indexOf("fooDuplicateError1");
       ok(error1pos > -1, "found fooDuplicateError1");
       if (error1pos > -1) {
         ok(text.indexOf("fooDuplicateError1", error1pos + 1) == -1,
           "no duplicate for fooDuplicateError1");
       }
 
-      ok(text.indexOf("test-duplicate-error.html") > -1,
-        "found test-duplicate-error.html");
+      findLogEntry("test-duplicate-error.html");
 
       finishTest();
     });
   }
 };
--- a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_593003_iframe_wrong_hud.js
+++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_593003_iframe_wrong_hud.js
@@ -15,16 +15,17 @@
  * The Original Code is DevTools test code.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2010
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *  Mihai Șucan <mihai.sucan@gmail.com>
+ *  Patrick Walton <pcwalton@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
--- a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_601177_log_levels.js
+++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_601177_log_levels.js
@@ -13,51 +13,45 @@ const TEST_URI = "http://example.com/bro
 let msgs;
 
 function onContentLoaded()
 {
   let hudId = HUDService.getHudIdByWindow(content);
   let HUD = HUDService.hudReferences[hudId];
   msgs = HUD.outputNode.querySelectorAll(".hud-msg-node");
 
-  ok(findEntry("hud-networkinfo", "test-bug-601177-log-levels.html"),
-    "found test-bug-601177-log-levels.html");
+  findEntry(HUD, "hud-networkinfo", "test-bug-601177-log-levels.html",
+            "found test-bug-601177-log-levels.html");
 
-  ok(findEntry("hud-networkinfo", "test-bug-601177-log-levels.js"),
-    "found test-bug-601177-log-levels.js");
+  findEntry(HUD, "hud-networkinfo", "test-bug-601177-log-levels.js",
+            "found test-bug-601177-log-levels.js");
 
-  ok(findEntry("hud-networkinfo", "test-image.png"),
-    "found test-image.png");
+  findEntry(HUD, "hud-networkinfo", "test-image.png", "found test-image.png");
 
-  ok(findEntry("hud-network", "foobar-known-to-fail.png"),
-    "found foobar-known-to-fail.png");
+  findEntry(HUD, "hud-network", "foobar-known-to-fail.png",
+            "found foobar-known-to-fail.png");
 
-  ok(findEntry("hud-exception", "foobarBug601177exception"),
-    "found exception");
+  findEntry(HUD, "hud-exception", "foobarBug601177exception",
+            "found exception");
 
-  ok(findEntry("hud-jswarn", "undefinedPropertyBug601177"),
-    "found strict warning");
+  findEntry(HUD, "hud-jswarn", "undefinedPropertyBug601177",
+            "found strict warning");
 
-  ok(findEntry("hud-jswarn", "foobarBug601177strictError"),
-    "found strict error");
+  findEntry(HUD, "hud-jswarn", "foobarBug601177strictError",
+            "found strict error");
 
   msgs = null;
   Services.prefs.setBoolPref("javascript.options.strict", false);
   finishTest();
 }
 
-function findEntry(aClass, aString)
+function findEntry(aHUD, aClass, aString, aMessage)
 {
-  for (let i = 0, n = msgs.length; i < n; i++) {
-    if (msgs[i].classList.contains(aClass) &&
-        msgs[i].textContent.indexOf(aString) > -1) {
-      return true;
-    }
-  }
-  return false;
+  return testLogEntry(aHUD.outputNode, aString, aMessage, false, false,
+                      aClass);
 }
 
 function test()
 {
   addTab("data:text/html,Web Console test for bug 601177: log levels");
 
   Services.prefs.setBoolPref("javascript.options.strict", true);
 
--- a/toolkit/components/console/hudservice/tests/browser/head.js
+++ b/toolkit/components/console/hudservice/tests/browser/head.js
@@ -90,38 +90,64 @@ function addTab(aURL)
  * @param {string} aMatchString
  *        the string you want to check if it exists in the output node.
  * @param {string} aMsg
  *        the message describing the test
  * @param {boolean} [aOnlyVisible=false]
  *        find only messages that are visible, not hidden by the filter.
  * @param {boolean} [aFailIfFound=false]
  *        fail the test if the string is found in the output node.
+ * @param {string} aClass [optional]
+ *        find only messages with the given CSS class.
  */
 function testLogEntry(aOutputNode, aMatchString, aMsg, aOnlyVisible,
-                      aFailIfFound)
+                      aFailIfFound, aClass)
 {
   let selector = ".hud-msg-node";
   // Skip entries that are hidden by the filter.
   if (aOnlyVisible) {
     selector += ":not(.hud-filtered-by-type)";
   }
+  if (aClass) {
+    selector += "." + aClass;
+  }
 
   let msgs = aOutputNode.querySelectorAll(selector);
   let found = false;
   for (let i = 0, n = msgs.length; i < n; i++) {
     let message = msgs[i].textContent.indexOf(aMatchString);
     if (message > -1) {
       found = true;
       break;
     }
+
+    // Search the labels too.
+    let labels = msgs[i].querySelectorAll("label");
+    for (let j = 0; j < labels.length; j++) {
+      if (labels[j].getAttribute("value").indexOf(aMatchString) > -1) {
+        found = true;
+        break;
+      }
+    }
   }
+
   is(found, !aFailIfFound, aMsg);
 }
 
+/**
+ * A convenience method to call testLogEntry().
+ *
+ * @param string aString
+ *        The string to find.
+ */
+function findLogEntry(aString)
+{
+  testLogEntry(outputNode, aString, "found " + aString);
+}
+
 function openConsole()
 {
   HUDService.activateHUDForContext(tab);
 }
 
 function closeConsole()
 {
   HUDService.deactivateHUDForContext(tab);
--- a/toolkit/locales/en-US/chrome/global/headsUpDisplay.properties
+++ b/toolkit/locales/en-US/chrome/global/headsUpDisplay.properties
@@ -82,37 +82,16 @@ copyCmd.label=Copy
 copyCmd.accesskey=C
 selectAllCmd.label=Select All
 selectAllCmd.accesskey=A
 # LOCALIZATION NOTE (timestampFormat): %1$02S = hours (24-hour clock),
 # %2$02S = minutes, %3$02S = seconds, %4$03S = milliseconds.
 timestampFormat=%02S:%02S:%02S.%03S
 
 helperFuncUnsupportedTypeError=Can't call pprint on this type of object.
-# LOCALIZATION NOTE (networkUrlWithStatus):
-#
-# When the HTTP request is started only the URL of the request is printed to the
-# WebConsole. As the response status of the HTTP request arrives, the URL string
-# is replaced by this string (the response status can look like `HTTP/1.1 200 OK`).
-# The bracket is not closed to mark that this request is not done by now. As the
-# request is finished (the HTTP connection is closed) this string is replaced
-# by `networkUrlWithStatusAndDuration` which has a closing the braket.
-#
-# %1$S = URL of network request
-# %2$S = response status code from the server (e.g. `HTTP/1.1 200 OK`)
-networkUrlWithStatus=%1$S [%2$S
-# LOCALIZATION NOTE (networkUrlWithStatusAndDuration):
-#
-# When the HTTP request is finished (the HTTP connection is closed) this string
-# replaces the former `networkUrlWithStatus` string in the WebConsole.
-#
-# %1$S = URL of network request
-# %2$S = response status code from the server (e.g. `HTTP/1.1 200 OK`)
-# %3$S = duration for the complete network request in milliseconds
-networkUrlWithStatusAndDuration=%1$S [%2$S %3$Sms]
 NetworkPanel.label=Inspect Network Request
 # LOCALIZATION NOTE (NetworkPanel.deltaDurationMS):
 #
 # This string is used to show the duration between two network events (e.g
 # request and respones header or response header and response body).
 NetworkPanel.durationMS=%Sms
 # LOCALIZATION NOTE (NetworkPanel.imageSizeDeltaDurationMS):
 # This string is used to show the duration between the response header and the
--- a/toolkit/themes/gnomestripe/global/webConsole.css
+++ b/toolkit/themes/gnomestripe/global/webConsole.css
@@ -86,16 +86,24 @@
 
 .webconsole-msg-body {
   margin-top: 0;
   margin-bottom: 3px;
   -moz-margin-start: 3px;
   -moz-margin-end: 6px;
 }
 
+.webconsole-msg-body-piece {
+  margin: 0;
+}
+
+.webconsole-msg-url {
+  margin: 0 6px;
+}
+
 .webconsole-location {
   margin-top: 0;
   margin-bottom: 0;
   -moz-margin-start: 0;
   -moz-margin-end: 6px;
   width: 10em;
   text-align: end;
 }
--- a/toolkit/themes/pinstripe/global/webConsole.css
+++ b/toolkit/themes/pinstripe/global/webConsole.css
@@ -89,16 +89,24 @@
 
 .webconsole-msg-body {
   margin-top: 0;
   margin-bottom: 3px;
   -moz-margin-start: 3px;
   -moz-margin-end: 6px;
 }
 
+.webconsole-msg-body-piece {
+  margin: 0;
+}
+
+.webconsole-msg-url {
+  margin: 0 6px;
+}
+
 .webconsole-location {
   margin-top: 0;
   margin-bottom: 0;
   -moz-margin-start: 0;
   -moz-margin-end: 6px;
   width: 10em;
   text-align: end;
 }
--- a/toolkit/themes/winstripe/global/webConsole.css
+++ b/toolkit/themes/winstripe/global/webConsole.css
@@ -85,16 +85,24 @@
 
 .webconsole-msg-body {
   margin-top: 0;
   margin-bottom: 3px;
   -moz-margin-start: 3px;
   -moz-margin-end: 6px;
 }
 
+.webconsole-msg-body-piece {
+  margin: 0;
+}
+
+.webconsole-msg-url {
+  margin: 0 6px;
+}
+
 .webconsole-location {
   margin-top: 0;
   margin-bottom: 0;
   -moz-margin-start: 0;
   -moz-margin-end: 6px;
   width: 10em;
   text-align: end;
 }