Commit 7e943e24 authored by Tim Taubert's avatar Tim Taubert
Browse files

merge m-c to fx-team

parents 5c170e7f 2b290df8
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -1161,17 +1161,17 @@ let ConsoleAPIObserver = {
          WebConsoleUtils.cloneObject(aOriginalMessage.arguments, true);
        break;

      case "log":
      case "info":
      case "warn":
      case "error":
      case "debug":
      case "groupEnd":
        aRemoteMessage.argumentsToString =
          Array.map(aOriginalMessage.arguments || [],
                    this._formatObject.bind(this));
        break;

      case "log":
      case "info":
      case "warn":
      case "error":
      case "debug":
      case "dir": {
        aRemoteMessage.objectsCacheId = Manager.sequenceId;
        aRemoteMessage.argumentsToString = [];
+1 −0
Original line number Diff line number Diff line
@@ -112,6 +112,7 @@ MOCHITEST_BROWSER_FILES = \
	browser_result_format_as_string.js \
	browser_webconsole_bug_737873_mixedcontent.js \
	browser_output_breaks_after_console_dir_uninspectable.js \
	browser_console_log_inspectable_object.js \
	head.js \
	$(NULL)

+57 −0
Original line number Diff line number Diff line
/* vim:set ts=2 sw=2 sts=2 et: */
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

// Test that objects given to console.log() are inspectable.

function test()
{
  waitForExplicitFinish();

  addTab("data:text/html,test for bug 676722 - inspectable objects for window.console");

  gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
    gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
    openConsole(null, performTest);
  }, true);
}

function performTest(hud)
{
  hud.jsterm.clearOutput(true);

  hud.jsterm.execute("myObj = {abba: 'omgBug676722'}");
  hud.jsterm.execute("console.log('fooBug676722', myObj)");
  waitForSuccess({
    name: "eval results are shown",
    validatorFn: function()
    {
      return hud.outputNode.textContent.indexOf("fooBug676722") > -1 &&
             hud.outputNode.querySelector(".hud-clickable");
    },
    successFn: function()
    {
      isnot(hud.outputNode.textContent.indexOf("myObj = {"), -1,
            "myObj = ... is shown");

      let clickable = hud.outputNode.querySelector(".hud-clickable");
      ok(clickable, "the console.log() object .hud-clickable was found");
      isnot(clickable.textContent.indexOf("omgBug676722"), -1,
            "clickable node content is correct");

      document.addEventListener("popupshown", function _onPopupShown(aEvent) {
        document.removeEventListener("popupshown", _onPopupShown);

        isnot(aEvent.target.label.indexOf("omgBug676722"), -1,
           "object inspector opened on click");

        executeSoon(finishTest);
      });

      executeSoon(function() {
        EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow);
      });
    },
    failureFn: finishTest,
  });
}
+145 −13
Original line number Diff line number Diff line
@@ -944,7 +944,12 @@ WebConsoleFrame.prototype = {
      case "warn":
      case "error":
      case "debug":
        body = argsToString.join(" ");
        body = {
          cacheId: aMessage.objectsCacheId,
          remoteObjects: args,
          argsToString: argsToString,
        };
        clipboardText = argsToString.join(" ");
        sourceURL = aMessage.apiMessage.filename;
        sourceLine = aMessage.apiMessage.lineNumber;
        break;
@@ -1068,6 +1073,57 @@ WebConsoleFrame.prototype = {
    return node;
  },

  /**
   * The click event handler for objects shown inline coming from the
   * window.console API.
   *
   * @private
   * @param nsIDOMNode aMessage
   *        The message element this handler corresponds to.
   * @param nsIDOMNode aAnchor
   *        The object inspector anchor element. This is the clickable element
   *        in the console.log message we display.
   * @param array aRemoteObject
   *        The remote object representation.
   */
  _consoleLogClick:
  function WCF__consoleLogClick(aMessage, aAnchor, aRemoteObject)
  {
    if (aAnchor._panelOpen) {
      return;
    }

    let options = {
      title: aAnchor.textContent,
      anchor: aAnchor,

      // Data to inspect.
      data: {
        // This is where the resultObject children are cached.
        rootCacheId: aMessage._evalCacheId,
        remoteObject: aRemoteObject,
        // This is where all objects retrieved by the panel will be cached.
        panelCacheId: "HUDPanel-" + gSequenceId(),
        remoteObjectProvider: this.jsterm.remoteObjectProvider.bind(this.jsterm),
      },
    };

    let propPanel = this.jsterm.openPropertyPanel(options);
    propPanel.panel.setAttribute("hudId", this.hudId);

    let onPopupHide = function JST__evalInspectPopupHide() {
      propPanel.panel.removeEventListener("popuphiding", onPopupHide, false);

      this.jsterm.clearObjectCache(options.data.panelCacheId);

      if (!aMessage.parentNode && aMessage._evalCacheId) {
        this.jsterm.clearObjectCache(aMessage._evalCacheId);
      }
    }.bind(this);

    propPanel.panel.addEventListener("popuphiding", onPopupHide, false);
  },

  /**
   * Reports an error in the page source, either JavaScript or CSS.
   *
@@ -1828,19 +1884,31 @@ WebConsoleFrame.prototype = {
    aClipboardText = aClipboardText ||
                     (aBody + (aSourceURL ? " @ " + aSourceURL : "") +
                              (aSourceLine ? ":" + aSourceLine : ""));
    if (!(aBody instanceof Ci.nsIDOMNode)) {
      aBody = this.document.createTextNode(aLevel == "dir" ?
                                           aBody.resultString : aBody);
    }

    if (!aBody.nodeType) {
      aBody = this.document.createTextNode(aBody.toString());
    // Create the containing node and append all its elements to it.
    let node = this.document.createElementNS(XUL_NS, "richlistitem");

    if (aBody instanceof Ci.nsIDOMNode) {
      bodyNode.appendChild(aBody);
    }
    if (typeof aBody == "string") {
      aBody = this.document.createTextNode(aBody);
    else {
      let str = undefined;
      if (aLevel == "dir") {
        str = aBody.resultString;
      }
      else if (["log", "info", "warn", "error", "debug"].indexOf(aLevel) > -1 &&
               typeof aBody == "object") {
        this._makeConsoleLogMessageBody(node, bodyNode, aBody);
      }
      else {
        str = aBody;
      }

      if (str !== undefined) {
        aBody = this.document.createTextNode(str);
        bodyNode.appendChild(aBody);
      }
    }

    let repeatContainer = this.document.createElementNS(XUL_NS, "hbox");
    repeatContainer.setAttribute("align", "start");
@@ -1863,8 +1931,6 @@ WebConsoleFrame.prototype = {
      locationNode = this.createLocationNode(aSourceURL, aSourceLine);
    }

    // Create the containing node and append all its elements to it.
    let node = this.document.createElementNS(XUL_NS, "richlistitem");
    node.clipboardText = aClipboardText;
    node.classList.add("hud-msg-node");

@@ -1924,6 +1990,58 @@ WebConsoleFrame.prototype = {
    return node;
  },

  /**
   * Make the message body for console.log() calls.
   *
   * @private
   * @param nsIDOMElement aMessage
   *        The message element that holds the output for the given call.
   * @param nsIDOMElement aContainer
   *        The specific element that will hold each part of the console.log
   *        output.
   * @param object aBody
   *        The object given by this.logConsoleAPIMessage(). This object holds
   *        the call information that we need to display.
   */
  _makeConsoleLogMessageBody:
  function WCF__makeConsoleLogMessageBody(aMessage, aContainer, aBody)
  {
    aMessage._evalCacheId = aBody.cacheId;

    Object.defineProperty(aMessage, "_panelOpen", {
      get: function() {
        let nodes = aContainer.querySelectorAll(".hud-clickable");
        return Array.prototype.some.call(nodes, function(aNode) {
          return aNode._panelOpen;
        });
      },
      enumerable: true,
      configurable: false
    });

    aBody.remoteObjects.forEach(function(aItem, aIndex) {
      if (aContainer.firstChild) {
        aContainer.appendChild(this.document.createTextNode(" "));
      }

      let text = aBody.argsToString[aIndex];
      if (!Array.isArray(aItem)) {
        aContainer.appendChild(this.document.createTextNode(text));
        return;
      }

      let elem = this.document.createElement("description");
      elem.classList.add("hud-clickable");
      elem.setAttribute("aria-haspopup", "true");
      elem.appendChild(this.document.createTextNode(text));

      this._addMessageLinkCallback(elem,
        this._consoleLogClick.bind(this, aMessage, elem, aItem));

      aContainer.appendChild(elem);
    }, this);
  },

  /**
   * Creates the XUL label that displays the textual location of an incoming
   * message.
@@ -2031,6 +2149,20 @@ WebConsoleFrame.prototype = {

    linkNode.setAttribute("aria-haspopup", "true");

    this._addMessageLinkCallback(aNode, aCallback);
  },

  /**
   * Add the mouse event handlers needed to make a link.
   *
   * @private
   * @param nsIDOMNode aNode
   *        The node for which you want to add the event handlers.
   * @param function aCallback
   *        The function you want to invoke on click.
   */
  _addMessageLinkCallback: function WCF__addMessageLinkCallback(aNode, aCallback)
  {
    aNode.addEventListener("mousedown", function(aEvent) {
      this._startX = aEvent.clientX;
      this._startY = aEvent.clientY;
+22 −5
Original line number Diff line number Diff line
@@ -335,9 +335,9 @@ ConsoleAPI.prototype = {
  /**
   * Process the console API call arguments in order to perform printf-like
   * string substitution.
   * TODO: object substitution should display an interactive property list (bug
   * 685815) and width and precision qualifiers should be taken into account
   * (bug 685813).
   *
   * TODO: object substitution should take into account width and precision
   * qualifiers (bug 685813).
   *
   * @param mixed aArguments
   *        The arguments given to the console API call.
@@ -346,12 +346,18 @@ ConsoleAPI.prototype = {
    if (aArguments.length < 2 || typeof aArguments[0] != "string") {
      return aArguments;
    }

    let args = Array.prototype.slice.call(aArguments);
    let format = args.shift();
    let splitter = "%" + format.length + Date.now() + "%";
    let objects = [];

    // Format specification regular expression.
    let processed = format.replace(ARGUMENT_PATTERN, function CA_PA_substitute(match, submatch) {
      switch (submatch) {
        case "o":
          objects.push(args.shift());
          return splitter;
        case "s":
          return String(args.shift());
        case "d":
@@ -363,8 +369,19 @@ ConsoleAPI.prototype = {
          return submatch;
      };
    });
    args.unshift(processed);
    return args;

    let result = [];
    let processedArray = processed.split(splitter);
    processedArray.forEach(function(aValue, aIndex) {
      if (aValue !== "") {
        result.push(aValue);
      }
      if (objects[aIndex]) {
        result.push(objects[aIndex]);
      }
    });

    return result.concat(args);
  },

  /**
Loading