--- a/devtools/client/webconsole/console-output.js
+++ b/devtools/client/webconsole/console-output.js
@@ -1,29 +1,28 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
"use strict";
-const {Ci, Cu} = require("chrome");
+const {Ci} = require("chrome");
loader.lazyImporter(this, "VariablesView", "resource://devtools/client/shared/widgets/VariablesView.jsm");
loader.lazyImporter(this, "escapeHTML", "resource://devtools/client/shared/widgets/VariablesView.jsm");
loader.lazyRequireGetter(this, "promise");
loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
loader.lazyRequireGetter(this, "TableWidget", "devtools/client/shared/widgets/TableWidget", true);
loader.lazyRequireGetter(this, "ObjectClient", "devtools/shared/client/main", true);
const { extend } = require("sdk/core/heritage");
const XHTML_NS = "http://www.w3.org/1999/xhtml";
-const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const WebConsoleUtils = require("devtools/client/webconsole/utils").Utils;
const { getSourceNames } = require("devtools/client/shared/source-utils");
const {Task} = require("devtools/shared/task");
const l10n = require("devtools/client/webconsole/webconsole-l10n");
const nodeConstants = require("devtools/shared/dom-node-constants");
const {PluralForm} = require("devtools/shared/plural-form");
@@ -113,17 +112,21 @@ const CONSOLE_API_LEVELS_TO_SEVERITIES =
// Array of known message source URLs we need to hide from output.
const IGNORED_SOURCE_URLS = ["debugger eval code"];
// The maximum length of strings to be displayed by the Web Console.
const MAX_LONG_STRING_LENGTH = 200000;
// Regular expression that matches the allowed CSS property names when using
// the `window.console` API.
-const RE_ALLOWED_STYLES = /^(?:-moz-)?(?:background|border|box|clear|color|cursor|display|float|font|line|margin|padding|text|transition|outline|white-space|word|writing|(?:min-|max-)?width|(?:min-|max-)?height)/;
+const RE_ALLOWED_STYLES = new RegExp(["^(?:-moz-)?(?:background|border|box|clear|" +
+ "color|cursor|display|float|font|line|margin|" +
+ "padding|text|transition|outline|white-space|" +
+ "word|writing|(?:min-|max-)?width|" +
+ "(?:min-|max-)?height)"]);
// Regular expressions to search and replace with 'notallowed' in the styles
// given to the `window.console` API methods.
const RE_CLEANUP_STYLES = [
// url(), -moz-element()
/\b(?:url|(?:-moz-)?element)[\s('"]+/gi,
// various URL protocols
@@ -145,18 +148,17 @@ const TABLE_COLUMN_MAX_ITEMS = 10;
* The console output owner. This usually the WebConsoleFrame instance.
* Any other object can be used, as long as it has the following
* properties and methods:
* - window
* - document
* - outputMessage(category, methodOrNode[, methodArguments])
* TODO: this is needed temporarily, until bug 778766 is fixed.
*/
-function ConsoleOutput(owner)
-{
+function ConsoleOutput(owner) {
this.owner = owner;
this._onFlushOutputMessage = this._onFlushOutputMessage.bind(this);
}
ConsoleOutput.prototype = {
_dummyElement: null,
/**
@@ -201,30 +203,28 @@ ConsoleOutput.prototype = {
/**
* Release an actor.
*
* @private
* @param string actorId
* The actor ID you want to release.
*/
- _releaseObject: function (actorId)
- {
+ _releaseObject: function (actorId) {
this.owner._releaseObject(actorId);
},
/**
* Add a message to output.
*
* @param object ...args
* Any number of Message objects.
* @return this
*/
- addMessage: function (...args)
- {
+ addMessage: function (...args) {
for (let msg of args) {
msg.init(this);
this.owner.outputMessage(msg._categoryCompat, this._onFlushOutputMessage,
[msg]);
}
return this;
},
@@ -237,33 +237,31 @@ ConsoleOutput.prototype = {
* TODO: remove this method once bug 778766 is fixed.
*
* @private
* @param object message
* The message object to render.
* @return DOMElement
* The message DOM element that can be added to the console output.
*/
- _onFlushOutputMessage: function (message)
- {
+ _onFlushOutputMessage: function (message) {
return message.render().element;
},
/**
* Get an array of selected messages. This list is based on the text selection
* start and end points.
*
* @param number [limit]
* Optional limit of selected messages you want. If no value is given,
* all of the selected messages are returned.
* @return array
* Array of DOM elements for each message that is currently selected.
*/
- getSelectedMessages: function (limit)
- {
+ getSelectedMessages: function (limit) {
let selection = this.window.getSelection();
if (selection.isCollapsed) {
return [];
}
if (selection.containsNode(this.element, true)) {
return Array.slice(this.element.children);
}
@@ -298,81 +296,75 @@ ConsoleOutput.prototype = {
/**
* Find the DOM element of a message for any given descendant.
*
* @param DOMElement elem
* The element to start the search from.
* @return DOMElement|null
* The DOM element of the message, if any.
*/
- getMessageForElement: function (elem)
- {
+ getMessageForElement: function (elem) {
while (elem && elem.parentNode) {
if (elem.classList && elem.classList.contains("message")) {
return elem;
}
elem = elem.parentNode;
}
return null;
},
/**
* Select all messages.
*/
- selectAllMessages: function ()
- {
+ selectAllMessages: function () {
let selection = this.window.getSelection();
selection.removeAllRanges();
let range = this.document.createRange();
range.selectNodeContents(this.element);
selection.addRange(range);
},
/**
* Add a message to the selection.
*
* @param DOMElement elem
* The message element to select.
*/
- selectMessage: function (elem)
- {
+ selectMessage: function (elem) {
let selection = this.window.getSelection();
selection.removeAllRanges();
let range = this.document.createRange();
range.selectNodeContents(elem);
selection.addRange(range);
},
/**
* Open an URL in a new tab.
* @see WebConsole.openLink() in hudservice.js
*/
- openLink: function ()
- {
+ openLink: function () {
this.owner.owner.openLink.apply(this.owner.owner, arguments);
},
openLocationInDebugger: function ({url, line}) {
return this.owner.owner.viewSourceInDebugger(url, line);
},
/**
* Open the variables view to inspect an object actor.
* @see JSTerm.openVariablesView() in webconsole.js
*/
- openVariablesView: function ()
- {
+ openVariablesView: function () {
this.owner.jsterm.openVariablesView.apply(this.owner.jsterm, arguments);
},
/**
* Destroy this ConsoleOutput instance.
*/
- destroy: function ()
- {
+ destroy: function () {
this._dummyElement = null;
this.owner = null;
},
}; // ConsoleOutput.prototype
/**
* Message objects container.
* @type object
@@ -380,18 +372,17 @@ ConsoleOutput.prototype = {
var Messages = {};
/**
* The BaseMessage object is used for all types of messages. Every kind of
* message should use this object as its base.
*
* @constructor
*/
-Messages.BaseMessage = function ()
-{
+Messages.BaseMessage = function () {
this.widgets = new Set();
this._onClickAnchor = this._onClickAnchor.bind(this);
this._repeatID = { uid: gSequenceId() };
this.textContent = "";
};
Messages.BaseMessage.prototype = {
/**
@@ -466,58 +457,54 @@ Messages.BaseMessage.prototype = {
* Initialize the message.
*
* @param object output
* The ConsoleOutput owner.
* @param object [parent=null]
* Optional: a different message object that owns this instance.
* @return this
*/
- init: function (output, parent = null)
- {
+ init: function (output, parent = null) {
this.output = output;
this.parent = parent;
return this;
},
/**
* Non-unique ID for this message object used for tracking duplicate messages.
* Different message kinds can identify themselves based their own criteria.
*
* @return string
*/
- getRepeatID: function ()
- {
+ getRepeatID: function () {
return JSON.stringify(this._repeatID);
},
/**
* Render the message. After this method is invoked the |element| property
* will point to the DOM element of this message.
* @return this
*/
- render: function ()
- {
+ render: function () {
if (!this.element) {
this.element = this._renderCompat();
}
return this;
},
/**
* Prepare the message container for the Web Console, such that it is
* compatible with the current implementation.
* TODO: remove this once bug 778766 is fixed.
*
* @private
* @return Element
* The DOM element that wraps the message.
*/
- _renderCompat: function ()
- {
+ _renderCompat: function () {
let doc = this.output.document;
let container = doc.createElementNS(XHTML_NS, "div");
container.id = "console-msg-" + gSequenceId();
container.className = "message";
if (this.category == "input") {
// Assistive technology tools shouldn't echo input to the user,
// as the user knows what they've just typed.
container.setAttribute("aria-live", "off");
@@ -539,41 +526,38 @@ Messages.BaseMessage.prototype = {
*
* @private
* @param Element element
* The DOM element to which you want to add a click event handler.
* @param function [callback=this._onClickAnchor]
* Optional click event handler. The default event handler is
* |this._onClickAnchor|.
*/
- _addLinkCallback: function (element, callback = this._onClickAnchor)
- {
+ _addLinkCallback: function (element, callback = this._onClickAnchor) {
// This is going into the WebConsoleFrame object instance that owns
// the ConsoleOutput object. The WebConsoleFrame owner is the WebConsole
// object instance from hudservice.js.
// TODO: move _addMessageLinkCallback() into ConsoleOutput once bug 778766
// is fixed.
this.output.owner._addMessageLinkCallback(element, callback);
},
/**
* The default |click| event handler for links in the output. This function
* opens the anchor's link in a new tab.
*
* @private
* @param Event event
* The DOM event that invoked this function.
*/
- _onClickAnchor: function (event)
- {
+ _onClickAnchor: function (event) {
this.output.openLink(event.target.href);
},
- destroy: function ()
- {
+ destroy: function () {
// Destroy all widgets that have registered themselves in this.widgets
for (let widget of this.widgets) {
widget.destroy();
}
this.widgets.clear();
}
};
@@ -816,18 +800,17 @@ Messages.Simple.prototype = extend(Messa
},
get _filterKeyCompat() {
return this._categoryCompat !== null && this._severityCompat !== null ?
COMPAT.PREFERENCE_KEYS[this._categoryCompat][this._severityCompat] :
null;
},
- init: function ()
- {
+ init: function () {
Messages.BaseMessage.prototype.init.apply(this, arguments);
this._groupDepthCompat = this.output.owner.groupDepth;
this._initRepeatID();
return this;
},
/**
* Tells if the message can be expanded/collapsed.
@@ -838,18 +821,17 @@ Messages.Simple.prototype = extend(Messa
/**
* Getter that tells if this message is collapsed - no details are shown.
* @type boolean
*/
get collapsed() {
return this.collapsible && this.element && !this.element.hasAttribute("open");
},
- _initRepeatID: function ()
- {
+ _initRepeatID: function () {
if (!this._filterDuplicates) {
return;
}
// Add the properties we care about for identifying duplicate messages.
let rid = this._repeatID;
delete rid.uid;
@@ -860,29 +842,27 @@ Messages.Simple.prototype = extend(Messa
rid.location = this.location;
rid.link = this._link;
rid.linkCallback = this._linkCallback + "";
rid.className = this._className;
rid.groupDepth = this._groupDepthCompat;
rid.textContent = "";
},
- getRepeatID: function ()
- {
+ getRepeatID: function () {
// No point in returning a string that includes other properties when there
// is a unique ID.
if (this._repeatID.uid) {
return JSON.stringify({ uid: this._repeatID.uid });
}
return JSON.stringify(this._repeatID);
},
- render: function ()
- {
+ render: function () {
if (this.element) {
return this;
}
let timestamp = new Widgets.MessageTimestamp(this, this.timestamp).render();
let icon = this.document.createElementNS(XHTML_NS, "span");
icon.className = "icon";
@@ -946,18 +926,17 @@ Messages.Simple.prototype = extend(Messa
return this;
},
/**
* Render the message body DOM element.
* @private
* @return Element
*/
- _renderBody: function ()
- {
+ _renderBody: function () {
let bodyWrapper = this.document.createElementNS(XHTML_NS, "span");
bodyWrapper.className = "message-body-wrapper";
let bodyFlex = this.document.createElementNS(XHTML_NS, "span");
bodyFlex.className = "message-flex-body";
bodyWrapper.appendChild(bodyFlex);
let body = this.document.createElementNS(XHTML_NS, "span");
@@ -1009,18 +988,17 @@ Messages.Simple.prototype = extend(Messa
return bodyWrapper;
},
/**
* Render the repeat bubble DOM element part of the message.
* @private
* @return Element
*/
- _renderRepeatNode: function ()
- {
+ _renderRepeatNode: function () {
if (!this._filterDuplicates) {
return null;
}
let repeatNode = this.document.createElementNS(XHTML_NS, "span");
repeatNode.setAttribute("value", "1");
repeatNode.className = "message-repeats";
repeatNode.textContent = 1;
@@ -1028,18 +1006,17 @@ Messages.Simple.prototype = extend(Messa
return repeatNode;
},
/**
* Render the message source location DOM element.
* @private
* @return Element
*/
- _renderLocation: function ()
- {
+ _renderLocation: function () {
if (!this.location) {
return null;
}
let {url, line, column} = this.location;
if (IGNORED_SOURCE_URLS.indexOf(url) != -1) {
return null;
}
@@ -1053,55 +1030,51 @@ Messages.Simple.prototype = extend(Messa
* The click event handler for the message expander arrow element. This method
* toggles the display of message details.
*
* @private
* @param nsIDOMEvent ev
* The DOM event object.
* @see this.toggleDetails()
*/
- _onClickCollapsible: function (ev)
- {
+ _onClickCollapsible: function (ev) {
ev.preventDefault();
this.toggleDetails();
},
/**
* Expand/collapse message details.
*/
- toggleDetails: function ()
- {
+ toggleDetails: function () {
let twisty = this.element.querySelector(".theme-twisty");
if (this.element.hasAttribute("open")) {
this.element.removeAttribute("open");
twisty.removeAttribute("open");
} else {
this.element.setAttribute("open", true);
twisty.setAttribute("open", true);
}
},
}); // Messages.Simple.prototype
-
/**
* The Extended message.
*
* @constructor
* @extends Messages.Simple
* @param array messagePieces
* The message to display given as an array of elements. Each array
* element can be a DOM node, function, ObjectActor, LongString or
* a string.
* @param object [options]
* Options for rendering this message:
* - quoteStrings: boolean that tells if you want strings to be wrapped
* in quotes or not.
*/
-Messages.Extended = function (messagePieces, options = {})
-{
+Messages.Extended = function (messagePieces, options = {}) {
Messages.Simple.call(this, null, options);
this._messagePieces = messagePieces;
if ("quoteStrings" in options) {
this._quoteStrings = options.quoteStrings;
}
@@ -1120,32 +1093,30 @@ Messages.Extended.prototype = extend(Mes
/**
* Boolean that tells if the strings displayed in this message are wrapped.
* @private
* @type boolean
*/
_quoteStrings: true,
- getRepeatID: function ()
- {
+ getRepeatID: function () {
if (this._repeatID.uid) {
return JSON.stringify({ uid: this._repeatID.uid });
}
// Sets are not stringified correctly. Temporarily switching to an array.
let actors = this._repeatID.actors;
this._repeatID.actors = [...actors];
let result = JSON.stringify(this._repeatID);
this._repeatID.actors = actors;
return result;
},
- render: function ()
- {
+ render: function () {
let result = this.document.createDocumentFragment();
for (let i = 0; i < this._messagePieces.length; i++) {
let separator = i > 0 ? this._renderBodyPieceSeparator() : null;
if (separator) {
result.appendChild(separator);
}
@@ -1159,29 +1130,30 @@ Messages.Extended.prototype = extend(Mes
},
/**
* Render the separator between the pieces of the message.
*
* @private
* @return Element
*/
- _renderBodyPieceSeparator: function () { return null; },
+ _renderBodyPieceSeparator: function () {
+ return null;
+ },
/**
* Render one piece/element of the message array.
*
* @private
* @param mixed piece
* Message element to display - this can be a LongString, ObjectActor,
* DOM node or a function to invoke.
* @return Element
*/
- _renderBodyPiece: function (piece, options = {})
- {
+ _renderBodyPiece: function (piece, options = {}) {
if (piece instanceof Ci.nsIDOMNode) {
return piece;
}
if (typeof piece == "function") {
return piece(this);
}
return this._renderValueGrip(piece, options);
@@ -1202,18 +1174,17 @@ Messages.Extended.prototype = extend(Mes
* grip. This is typically set to true when the object needs to be
* displayed in an array preview, or as a property value in object
* previews, etc.
* - shorten - boolean that tells the renderer to display a truncated
* grip.
* @return DOMElement
* The DOM element that displays the given grip.
*/
- _renderValueGrip: function (grip, options = {})
- {
+ _renderValueGrip: function (grip, options = {}) {
let isPrimitive = VariablesView.isPrimitive({ value: grip });
let isActorGrip = WebConsoleUtils.isActorGrip(grip);
let noStringQuotes = !this._quoteStrings;
if ("noStringQuotes" in options) {
noStringQuotes = options.noStringQuotes;
}
if (isActorGrip) {
@@ -1230,17 +1201,17 @@ Messages.Extended.prototype = extend(Mes
let unshortenedGrip = grip;
if (options.shorten) {
grip = this.shortenValueGrip(grip);
}
let result = this.document.createElementNS(XHTML_NS, "span");
if (isPrimitive) {
- if (Widgets.URLString.prototype.containsURL.call(Widgets.URLString.prototype, grip)) {
+ if (Widgets.URLString.prototype.containsURL(grip)) {
let widget = new Widgets.URLString(this, grip, unshortenedGrip).render();
return widget.element;
}
let className = this.getClassNameForValueGrip(grip);
if (className) {
result.className = className;
}
@@ -1261,18 +1232,17 @@ Messages.Extended.prototype = extend(Mes
*
* @param object grip
* Value grip from the server.
* @return object
* Possible values of object:
* - A shortened string, if original grip was of string type.
* - The unmodified input grip, if it wasn't of string type.
*/
- shortenValueGrip: function (grip)
- {
+ shortenValueGrip: function (grip) {
let shortVal = grip;
if (typeof (grip) == "string") {
shortVal = grip.replace(/(\r\n|\n|\r)/gm, " ");
if (shortVal.length > MAX_STRING_GRIP_LENGTH) {
shortVal = shortVal.substring(0, MAX_STRING_GRIP_LENGTH - 1) + ELLIPSIS;
}
}
@@ -1282,18 +1252,17 @@ Messages.Extended.prototype = extend(Mes
/**
* Get a CodeMirror-compatible class name for a given value grip.
*
* @param object grip
* Value grip from the server.
* @return string
* The class name for the grip.
*/
- getClassNameForValueGrip: function (grip)
- {
+ getClassNameForValueGrip: function (grip) {
let map = {
"number": "cm-number",
"longstring": "console-string",
"string": "console-string",
"regexp": "cm-string-2",
"boolean": "cm-atom",
"-infinity": "cm-atom",
"infinity": "cm-atom",
@@ -1320,52 +1289,48 @@ Messages.Extended.prototype = extend(Mes
* @param object objectActor
* The ObjectActor to display.
* @param object options
* Options to use for displaying the ObjectActor.
* @see this._renderValueGrip for the available options.
* @return DOMElement
* The DOM element that displays the object actor.
*/
- _renderObjectActor: function (objectActor, options = {})
- {
- let widget = Widgets.ObjectRenderers.byClass[objectActor.class];
+ _renderObjectActor: function (objectActor, options = {}) {
+ let Widget = Widgets.ObjectRenderers.byClass[objectActor.class];
let { preview } = objectActor;
- if ((!widget || (widget.canRender && !widget.canRender(objectActor)))
+ if ((!Widget || (Widget.canRender && !Widget.canRender(objectActor)))
&& preview
&& preview.kind) {
- widget = Widgets.ObjectRenderers.byKind[preview.kind];
+ Widget = Widgets.ObjectRenderers.byKind[preview.kind];
}
- if (!widget || (widget.canRender && !widget.canRender(objectActor))) {
- widget = Widgets.JSObject;
+ if (!Widget || (Widget.canRender && !Widget.canRender(objectActor))) {
+ Widget = Widgets.JSObject;
}
- let instance = new widget(this, objectActor, options).render();
+ let instance = new Widget(this, objectActor, options).render();
return instance.element;
},
}); // Messages.Extended.prototype
-
-
/**
* The JavaScriptEvalOutput message.
*
* @constructor
* @extends Messages.Extended
* @param object evalResponse
* The evaluation response packet received from the server.
* @param string [errorMessage]
* Optional error message to display.
* @param string [errorDocLink]
* Optional error doc URL to link to.
*/
-Messages.JavaScriptEvalOutput = function (evalResponse, errorMessage, errorDocLink)
-{
+Messages.JavaScriptEvalOutput = function (evalResponse, errorMessage, errorDocLink) {
let severity = "log", msg, quoteStrings = true;
// Store also the response packet from the back end. It might
// be useful to extensions customizing the console output.
this.response = evalResponse;
if (typeof (errorMessage) !== "undefined") {
severity = "error";
@@ -1396,18 +1361,17 @@ Messages.JavaScriptEvalOutput.prototype
/**
* The ConsoleGeneric message is used for console API calls.
*
* @constructor
* @extends Messages.Extended
* @param object packet
* The Console API call packet received from the server.
*/
-Messages.ConsoleGeneric = function (packet)
-{
+Messages.ConsoleGeneric = function (packet) {
let options = {
className: "cm-s-mozilla",
timestamp: packet.timeStamp,
category: packet.category || "webdev",
severity: CONSOLE_API_LEVELS_TO_SEVERITIES[packet.level],
prefix: packet.prefix,
private: packet.private,
filterDuplicates: true,
@@ -1436,36 +1400,33 @@ Messages.ConsoleGeneric = function (pack
this._repeatID.styles = packet.styles;
this.stack = this._repeatID.stacktrace = packet.stacktrace;
this._styles = packet.styles || [];
};
Messages.ConsoleGeneric.prototype = extend(Messages.Extended.prototype, {
_styles: null,
- _renderBodyPieceSeparator: function ()
- {
+ _renderBodyPieceSeparator: function () {
return this.document.createTextNode(" ");
},
- render: function ()
- {
+ render: function () {
let result = this.document.createDocumentFragment();
this._renderBodyPieces(result);
this._message = result;
this._stacktrace = null;
Messages.Simple.prototype.render.call(this);
return this;
},
- _renderBodyPieces: function (container)
- {
+ _renderBodyPieces: function (container) {
let lastStyle = null;
let stylePieces = this._styles.length > 0 ? this._styles.length : 1;
for (let i = 0; i < this._messagePieces.length; i++) {
// Pieces with an associated style definition come from "%c" formatting.
// For body pieces beyond that, add a separator before each one.
if (i >= stylePieces) {
container.appendChild(this._renderBodyPieceSeparator());
@@ -1480,18 +1441,17 @@ Messages.ConsoleGeneric.prototype = exte
container.appendChild(this._renderBodyPiece(piece, lastStyle));
}
this._messagePieces = null;
this._styles = null;
},
- _renderBodyPiece: function (piece, style)
- {
+ _renderBodyPiece: function (piece, style) {
// Skip quotes for top-level strings.
let options = { noStringQuotes: true };
let elem = Messages.Extended.prototype._renderBodyPiece.call(this, piece, options);
let result = elem;
if (style) {
if (elem.nodeType == nodeConstants.ELEMENT_NODE) {
elem.style = style;
@@ -1514,18 +1474,17 @@ Messages.ConsoleGeneric.prototype = exte
* - only some of the properties are allowed, based on a whitelist. See
* RE_ALLOWED_STYLES.
*
* @param string style
* The style string to cleanup.
* @return string
* The style value after cleanup.
*/
- cleanupStyle: function (style)
- {
+ cleanupStyle: function (style) {
for (let r of RE_CLEANUP_STYLES) {
style = style.replace(r, "notallowed");
}
let dummy = this.output._dummyElement;
if (!dummy) {
dummy = this.output._dummyElement =
this.document.createElementNS(XHTML_NS, "div");
@@ -1555,18 +1514,17 @@ Messages.ConsoleGeneric.prototype = exte
/**
* The ConsoleTrace message is used for console.trace() calls.
*
* @constructor
* @extends Messages.Simple
* @param object packet
* The Console API call packet received from the server.
*/
-Messages.ConsoleTrace = function (packet)
-{
+Messages.ConsoleTrace = function (packet) {
let options = {
className: "cm-s-mozilla",
timestamp: packet.timeStamp,
category: packet.category || "webdev",
severity: CONSOLE_API_LEVELS_TO_SEVERITIES[packet.level],
private: packet.private,
filterDuplicates: true,
location: {
@@ -1596,18 +1554,17 @@ Messages.ConsoleTrace.prototype = extend
* method. This array is cleared when the message is initialized, and
* associated actors are released.
*
* @private
* @type array
*/
_arguments: null,
- init: function ()
- {
+ init: function () {
let result = Messages.Simple.prototype.init.apply(this, arguments);
// We ignore console.trace() arguments. Release object actors.
if (Array.isArray(this._arguments)) {
for (let arg of this._arguments) {
if (WebConsoleUtils.isActorGrip(arg)) {
this.output._releaseObject(arg.actor);
}
@@ -1662,18 +1619,17 @@ Messages.ConsoleTrace.prototype = extend
/**
* The ConsoleTable message is used for console.table() calls.
*
* @constructor
* @extends Messages.Extended
* @param object packet
* The Console API call packet received from the server.
*/
-Messages.ConsoleTable = function (packet)
-{
+Messages.ConsoleTable = function (packet) {
let options = {
className: "cm-s-mozilla",
timestamp: packet.timeStamp,
category: packet.category || "webdev",
severity: CONSOLE_API_LEVELS_TO_SEVERITIES[packet.level],
private: packet.private,
filterDuplicates: false,
location: {
@@ -1721,18 +1677,17 @@ Messages.ConsoleTable.prototype = extend
* A promise that resolves when the table data is ready or null if invalid
* arguments are provided.
*
* @private
* @type promise|null
*/
_populatePromise: null,
- init: function ()
- {
+ init: function () {
let result = Messages.Extended.prototype.init.apply(this, arguments);
this._data = [];
this._columns = {};
this._populatePromise = this._populateTableData();
return result;
},
@@ -1741,18 +1696,17 @@ Messages.ConsoleTable.prototype = extend
* Sets the key value pair of the id and display name for the columns in the
* table.
*
* @private
* @param array|string columns
* Either a string or array containing the names for the columns in
* the output table.
*/
- _setColumns: function (columns)
- {
+ _setColumns: function (columns) {
if (columns.class == "Array") {
let items = columns.preview.items;
for (let item of items) {
if (typeof item == "string") {
this._columns[item] = item;
}
}
@@ -1764,67 +1718,66 @@ Messages.ConsoleTable.prototype = extend
/**
* Retrieves the table data and columns from the arguments received from the
* server.
*
* @return Promise|null
* Returns a promise that resolves when the table data is ready or
* null if the arguments are invalid.
*/
- _populateTableData: function ()
- {
+ _populateTableData: function () {
let deferred = promise.defer();
if (this._arguments.length <= 0) {
- return;
+ return deferred.reject();
}
let data = this._arguments[0];
if (data.class != "Array" && data.class != "Object" &&
data.class != "Map" && data.class != "Set" &&
data.class != "WeakMap" && data.class != "WeakSet") {
- return;
+ return deferred.reject();
}
let hasColumnsArg = false;
if (this._arguments.length > 1) {
if (data.class == "Object" || data.class == "Array") {
- this._columns["_index"] = l10n.getStr("table.index");
+ this._columns._index = l10n.getStr("table.index");
} else {
- this._columns["_index"] = l10n.getStr("table.iterationIndex");
+ this._columns._index = l10n.getStr("table.iterationIndex");
}
this._setColumns(this._arguments[1]);
hasColumnsArg = true;
}
if (data.class == "Object" || data.class == "Array") {
// Get the object properties, and parse the key and value properties into
// the table data and columns.
this.client = new ObjectClient(this.output.owner.jsterm.hud.proxy.client,
data);
- this.client.getPrototypeAndProperties(aResponse => {
- let {ownProperties} = aResponse;
+ this.client.getPrototypeAndProperties(response => {
+ let {ownProperties} = response;
let rowCount = 0;
let columnCount = 0;
for (let index of Object.keys(ownProperties || {})) {
// Avoid outputting the length property if the data argument provided
// is an array
if (data.class == "Array" && index == "length") {
continue;
}
if (!hasColumnsArg) {
- this._columns["_index"] = l10n.getStr("table.index");
+ this._columns._index = l10n.getStr("table.index");
}
if (data.class == "Array") {
- if (index == parseInt(index)) {
- index = parseInt(index);
+ if (index == parseInt(index, 10)) {
+ index = parseInt(index, 10);
}
}
let property = ownProperties[index].value;
let item = { _index: index };
if (property.class == "Object" || property.class == "Array") {
let {preview} = property;
@@ -1839,39 +1792,39 @@ Messages.ConsoleTable.prototype = extend
if (!hasColumnsArg && !(key in this._columns) &&
(++columnCount <= TABLE_COLUMN_MAX_ITEMS)) {
this._columns[key] = key;
}
}
} else {
// Display the value for any non-object data input.
- item["_value"] = this._renderValueGrip(property, { concise: true });
+ item._value = this._renderValueGrip(property, { concise: true });
if (!hasColumnsArg && !("_value" in this._columns)) {
- this._columns["_value"] = l10n.getStr("table.value");
+ this._columns._value = l10n.getStr("table.value");
}
}
this._data.push(item);
if (++rowCount == TABLE_ROW_MAX_ITEMS) {
break;
}
}
deferred.resolve();
});
} else if (data.class == "Map" || data.class == "WeakMap") {
let entries = data.preview.entries;
if (!hasColumnsArg) {
- this._columns["_index"] = l10n.getStr("table.iterationIndex");
- this._columns["_key"] = l10n.getStr("table.key");
- this._columns["_value"] = l10n.getStr("table.value");
+ this._columns._index = l10n.getStr("table.iterationIndex");
+ this._columns._key = l10n.getStr("table.key");
+ this._columns._value = l10n.getStr("table.value");
}
let rowCount = 0;
for (let [key, value] of entries) {
let item = {
_index: rowCount,
_key: this._renderValueGrip(key, { concise: true }),
_value: this._renderValueGrip(value, { concise: true })
@@ -1884,42 +1837,41 @@ Messages.ConsoleTable.prototype = extend
}
}
deferred.resolve();
} else if (data.class == "Set" || data.class == "WeakSet") {
let entries = data.preview.items;
if (!hasColumnsArg) {
- this._columns["_index"] = l10n.getStr("table.iterationIndex");
- this._columns["_value"] = l10n.getStr("table.value");
+ this._columns._index = l10n.getStr("table.iterationIndex");
+ this._columns._value = l10n.getStr("table.value");
}
let rowCount = 0;
for (let entry of entries) {
let item = {
- _index : rowCount,
+ _index: rowCount,
_value: this._renderValueGrip(entry, { concise: true })
};
this._data.push(item);
if (++rowCount == TABLE_ROW_MAX_ITEMS) {
break;
}
}
deferred.resolve();
}
return deferred.promise;
},
- render: function ()
- {
+ render: function () {
this._attachment = this._renderTable();
Messages.Extended.prototype.render.apply(this, arguments);
this.element.setAttribute("open", true);
return this;
},
_renderMessage: function () {
let cmvar = this.document.createElementNS(XHTML_NS, "span");
@@ -1978,18 +1930,17 @@ var Widgets = {};
/**
* The base widget class.
*
* @constructor
* @param object message
* The owning message.
*/
-Widgets.BaseWidget = function (message)
-{
+Widgets.BaseWidget = function (message) {
this.message = message;
};
Widgets.BaseWidget.prototype = {
/**
* The owning message object.
* @type object
*/
@@ -2052,18 +2003,17 @@ Widgets.BaseWidget.prototype = {
* of the new DOM element. Otherwise, the value becomes the
* .textContent of the new DOM element.
* @param string [textContent]
* If this argument is provided the value is used as the textContent of
* the new DOM element.
* @return DOMElement
* The new DOM element.
*/
- el: function (tagNameIdAndClasses)
- {
+ el: function (tagNameIdAndClasses) {
let attrs, text;
if (typeof arguments[1] == "object") {
attrs = arguments[1];
text = arguments[2];
} else {
text = arguments[1];
}
@@ -2094,72 +2044,67 @@ Widgets.BaseWidget.prototype = {
* The timestamp widget.
*
* @constructor
* @param object message
* The owning message.
* @param number timestamp
* The UNIX timestamp to display.
*/
-Widgets.MessageTimestamp = function (message, timestamp)
-{
+Widgets.MessageTimestamp = function (message, timestamp) {
Widgets.BaseWidget.call(this, message);
this.timestamp = timestamp;
};
Widgets.MessageTimestamp.prototype = extend(Widgets.BaseWidget.prototype, {
/**
* The UNIX timestamp.
* @type number
*/
timestamp: 0,
- render: function ()
- {
+ render: function () {
if (this.element) {
return this;
}
this.element = this.document.createElementNS(XHTML_NS, "span");
this.element.className = "timestamp devtools-monospace";
this.element.textContent = l10n.timestampString(this.timestamp) + " ";
return this;
},
}); // Widgets.MessageTimestamp.prototype
-
/**
* The URLString widget, for rendering strings where at least one token is a
* URL.
*
* @constructor
* @param object message
* The owning message.
* @param string str
* The string, which contains at least one valid URL.
* @param string unshortenedStr
* The unshortened form of the string, if it was shortened.
*/
-Widgets.URLString = function (message, str, unshortenedStr)
-{
+Widgets.URLString = function (message, str, unshortenedStr) {
Widgets.BaseWidget.call(this, message);
this.str = str;
this.unshortenedStr = unshortenedStr;
};
Widgets.URLString.prototype = extend(Widgets.BaseWidget.prototype, {
/**
* The string to format, which contains at least one valid URL.
* @type string
*/
str: "",
- render: function ()
- {
+ render: function () {
if (this.element) {
return this;
}
// The rendered URLString will be a <span> containing a number of text
// <spans> for non-URL tokens and <a>'s for URL tokens.
this.element = this.el("span", {
class: "console-string"
@@ -2183,32 +2128,32 @@ Widgets.URLString.prototype = extend(Wid
}
this.element.appendChild(this._renderText(this.str.slice(textStart, tokenStart)));
textStart = tokenStart + token.length;
this.element.appendChild(this._renderURL(token, unshortenedToken));
}
}
// Clean up any non-URL text at the end of the source string.
- this.element.appendChild(this._renderText(this.str.slice(textStart, this.str.length)));
+ const rendered = this._renderText(this.str.slice(textStart, this.str.length));
+ this.element.appendChild(rendered);
this.element.appendChild(this._renderText("\""));
return this;
},
/**
* Determines whether a grip is a string containing a URL.
*
* @param string grip
* The grip, which may contain a URL.
* @return boolean
* Whether the grip is a string containing a URL.
*/
- containsURL: function (grip)
- {
+ containsURL: function (grip) {
if (typeof grip != "string") {
return false;
}
let tokens = grip.split(/\s+/);
return tokens.some(this._isURL);
},
@@ -2237,18 +2182,17 @@ Widgets.URLString.prototype = extend(Wid
*
* @param string url
* The string to be rendered as a url.
* @param string fullUrl
* The unshortened form of the URL, if it was shortened.
* @return DOMElement
* An element containing the rendered string.
*/
- _renderURL: function (url, fullUrl)
- {
+ _renderURL: function (url, fullUrl) {
let unshortened = fullUrl || url;
let result = this.el("a", {
class: "url",
title: unshortened,
href: unshortened,
draggable: false
}, url);
this.message._addLinkCallback(result);
@@ -2268,76 +2212,70 @@ Widgets.URLString.prototype = extend(Wid
* The owning message.
* @param object objectActor
* The ObjectActor to display.
* @param object [options]
* Options for displaying the given ObjectActor. See
* Messages.Extended.prototype._renderValueGrip for the available
* options.
*/
-Widgets.JSObject = function (message, objectActor, options = {})
-{
+Widgets.JSObject = function (message, objectActor, options = {}) {
Widgets.BaseWidget.call(this, message);
this.objectActor = objectActor;
this.options = options;
this._onClick = this._onClick.bind(this);
};
Widgets.JSObject.prototype = extend(Widgets.BaseWidget.prototype, {
/**
* The ObjectActor displayed by the widget.
* @type object
*/
objectActor: null,
- render: function ()
- {
+ render: function () {
if (!this.element) {
this._render();
}
return this;
},
- _render: function ()
- {
+ _render: function () {
let str = VariablesView.getString(this.objectActor, this.options);
let className = this.message.getClassNameForValueGrip(this.objectActor);
if (!className && this.objectActor.class == "Object") {
className = "cm-variable";
}
this.element = this._anchor(str, { className: className });
},
/**
* Render a concise representation of an object.
*/
- _renderConciseObject: function ()
- {
+ _renderConciseObject: function () {
this.element = this._anchor(this.objectActor.class,
{ className: "cm-variable" });
},
/**
* Render the `<class> { ` prefix of an object.
*/
- _renderObjectPrefix: function ()
- {
+ _renderObjectPrefix: function () {
let { kind } = this.objectActor.preview;
this.element = this.el("span.kind-" + kind);
this._anchor(this.objectActor.class, { className: "cm-variable" });
this._text(" { ");
},
/**
* Render the ` }` suffix of an object.
*/
- _renderObjectSuffix: function ()
- {
+ _renderObjectSuffix: function () {
this._text(" }");
},
/**
* Render an object property.
*
* @param String key
* The property name.
@@ -2347,57 +2285,63 @@ Widgets.JSObject.prototype = extend(Widg
* The container node to render to.
* @param Boolean needsComma
* True if there was another property before this one and we need to
* separate them with a comma.
* @param Boolean valueIsText
* Add the value as is, don't treat it as a grip and pass it to
* `_renderValueGrip`.
*/
- _renderObjectProperty: function (key, value, container, needsComma, valueIsText = false)
- {
+ _renderObjectProperty: function (
+ key,
+ value,
+ container,
+ needsComma,
+ valueIsText = false
+ ) {
if (needsComma) {
this._text(", ");
}
container.appendChild(this.el("span.cm-property", key));
this._text(": ");
if (valueIsText) {
this._text(value);
} else {
- let valueElem = this.message._renderValueGrip(value, { concise: true, shorten: true });
+ let valueElem = this.message._renderValueGrip(value, {
+ concise: true,
+ shorten: true
+ });
container.appendChild(valueElem);
}
},
/**
* Render this object's properties.
*
* @param nsIDOMNode container
* The container node to render to.
* @param Boolean needsComma
* True if there was another property before this one and we need to
* separate them with a comma.
*/
- _renderObjectProperties: function (container, needsComma)
- {
+ _renderObjectProperties: function (container, needsComma) {
let { preview } = this.objectActor;
let { ownProperties, safeGetterValues } = preview;
let shown = 0;
let getValue = desc => {
if (desc.get) {
return "Getter";
} else if (desc.set) {
return "Setter";
- } else {
- return desc.value;
}
+ return desc.value;
};
for (let key of Object.keys(ownProperties || {})) {
this._renderObjectProperty(key, getValue(ownProperties[key]), container,
shown > 0 || needsComma,
ownProperties[key].get || ownProperties[key].set);
shown++;
}
@@ -2435,18 +2379,17 @@ Widgets.JSObject.prototype = extend(Widg
* on the anchor open the link in a new tab.
* - appendTo (DOMElement): append the element to the given DOM
* element. If not provided, the anchor is appended to |this.element|
* if it is available. If |appendTo| is provided and if it is a falsy
* value, the anchor is not appended to any element.
* @return DOMElement
* The DOM element of the new anchor.
*/
- _anchor: function (text, options = {})
- {
+ _anchor: function (text, options = {}) {
if (!options.onClick) {
// If the anchor has an URL, open it in a new tab. If not, show the
// current object actor.
options.onClick = options.href ? this._onClickAnchor : this._onClick;
}
options.onContextMenu = options.onContextMenu || this._onContextMenu;
@@ -2464,27 +2407,25 @@ Widgets.JSObject.prototype = extend(Widg
options.appendTo.appendChild(anchor);
} else if (!("appendTo" in options) && this.element) {
this.element.appendChild(anchor);
}
return anchor;
},
- openObjectInVariablesView: function ()
- {
+ openObjectInVariablesView: function () {
this.output.openVariablesView({
label: VariablesView.getString(this.objectActor, { concise: true }),
objectActor: this.objectActor,
autofocus: true,
});
},
- storeObjectInWindow: function ()
- {
+ storeObjectInWindow: function () {
let evalString = `{ let i = 0;
while (this.hasOwnProperty("temp" + i) && i < 1000) {
i++;
}
this["temp" + i] = _self;
"temp" + i;
}`;
let options = {
@@ -2496,18 +2437,17 @@ Widgets.JSObject.prototype = extend(Widg
this.output.owner.jsterm.setInputValue(res.result);
});
},
/**
* The click event handler for objects shown inline.
* @private
*/
- _onClick: function ()
- {
+ _onClick: function () {
this.openObjectInVariablesView();
},
_onContextMenu: function (ev) {
// TODO offer a nice API for the context menu.
// Probably worth to take a look at Firebug's way
// https://github.com/firebug/firebug/blob/master/extension/content/firebug/chrome/menu.js
let doc = ev.target.ownerDocument;
@@ -2543,18 +2483,17 @@ Widgets.JSObject.prototype = extend(Widg
*
* @private
* @param string str
* String to add.
* @param DOMElement [target = this.element]
* Optional DOM element to append the string to. The default is
* this.element.
*/
- _text: function (str, target = this.element)
- {
+ _text: function (str, target = this.element) {
target.appendChild(this.document.createTextNode(str));
},
}); // Widgets.JSObject.prototype
Widgets.ObjectRenderers = {};
Widgets.ObjectRenderers.byKind = {};
Widgets.ObjectRenderers.byClass = {};
@@ -2579,18 +2518,17 @@ Widgets.ObjectRenderers.byClass = {};
* - initialize (function, optional): the constructor of the renderer
* widget. This function is invoked with the following arguments: the
* owner message object instance, the object actor grip to display, and
* an options object. See Messages.Extended.prototype._renderValueGrip()
* for details about the options object.
* - render (function, required): the method that displays the given
* object actor.
*/
-Widgets.ObjectRenderers.add = function (obj)
-{
+Widgets.ObjectRenderers.add = function (obj) {
let extendObj = obj.extends || Widgets.JSObject;
let constructor = function () {
if (obj.initialize) {
obj.initialize.apply(this, arguments);
} else {
extendObj.apply(this, arguments);
}
@@ -2616,25 +2554,23 @@ Widgets.ObjectRenderers.add = function (
} else if (obj.byKind) {
Widgets.ObjectRenderers.byKind[obj.byKind] = constructor;
} else {
throw new Error("You are adding an object renderer without any byClass or " +
"byKind property.");
}
};
-
/**
* The widget used for displaying Date objects.
*/
Widgets.ObjectRenderers.add({
byClass: "Date",
- render: function ()
- {
+ render: function () {
let {preview} = this.objectActor;
this.element = this.el("span.class-" + this.objectActor.class);
let anchorText = this.objectActor.class;
let anchorClass = "cm-variable";
if (preview && "timestamp" in preview && typeof preview.timestamp != "number") {
anchorText = new Date(preview.timestamp).toString(); // invalid date
anchorClass = "";
@@ -2654,27 +2590,24 @@ Widgets.ObjectRenderers.add({
});
/**
* The widget used for displaying Function objects.
*/
Widgets.ObjectRenderers.add({
byClass: "Function",
- render: function ()
- {
+ render: function () {
let grip = this.objectActor;
this.element = this.el("span.class-" + this.objectActor.class);
// TODO: Bug 948484 - support arrow functions and ES6 generators
let name = grip.userDisplayName || grip.displayName || grip.name || "";
name = VariablesView.getString(name, { noStringQuotes: true });
- let str = this.options.concise ? name || "function " : "function " + name;
-
if (this.options.concise) {
this._anchor(name || "function", {
className: name ? "cm-variable" : "cm-keyword",
});
if (!name) {
this._text(" ");
}
} else if (name) {
@@ -2702,31 +2635,29 @@ Widgets.ObjectRenderers.add({
this._text(")");
},
_onClick: function () {
let location = this.objectActor.location;
if (location && IGNORED_SOURCE_URLS.indexOf(location.url) === -1) {
this.output.openLocationInDebugger(location);
- }
- else {
+ } else {
this.openObjectInVariablesView();
}
}
}); // Widgets.ObjectRenderers.byClass.Function
/**
* The widget used for displaying ArrayLike objects.
*/
Widgets.ObjectRenderers.add({
byKind: "ArrayLike",
- render: function ()
- {
+ render: function () {
let {preview} = this.objectActor;
let {items} = preview;
this.element = this.el("span.kind-" + preview.kind);
this._anchor(this.objectActor.class, { className: "cm-variable" });
if (!items || this.options.concise) {
this._text("[");
@@ -2740,18 +2671,17 @@ Widgets.ObjectRenderers.add({
let isFirst = true;
let emptySlots = 0;
// A helper that renders a comma between items if isFirst == false.
let renderSeparator = () => !isFirst && this._text(", ");
for (let item of items) {
if (item === null) {
emptySlots++;
- }
- else {
+ } else {
renderSeparator();
isFirst = false;
if (emptySlots) {
this._renderEmptySlots(emptySlots);
emptySlots = 0;
}
@@ -2770,37 +2700,38 @@ Widgets.ObjectRenderers.add({
this._text(", ");
let n = preview.length - shown;
let str = VariablesView.stringifiers._getNMoreString(n);
this._anchor(str);
}
this._text(" ]");
+
+ return this;
},
- _renderEmptySlots: function (aNumSlots, aAppendComma = true) {
+ _renderEmptySlots: function (numSlots, appendComma = true) {
let slotLabel = l10n.getStr("emptySlotLabel");
- let slotText = PluralForm.get(aNumSlots, slotLabel);
- this._text("<" + slotText.replace("#1", aNumSlots) + ">");
- if (aAppendComma) {
+ let slotText = PluralForm.get(numSlots, slotLabel);
+ this._text("<" + slotText.replace("#1", numSlots) + ">");
+ if (appendComma) {
this._text(", ");
}
},
}); // Widgets.ObjectRenderers.byKind.ArrayLike
/**
* The widget used for displaying MapLike objects.
*/
Widgets.ObjectRenderers.add({
byKind: "MapLike",
- render: function ()
- {
+ render: function () {
let {preview} = this.objectActor;
let {entries} = preview;
let container = this.element = this.el("span.kind-" + preview.kind);
this._anchor(this.objectActor.class, { className: "cm-variable" });
if (!entries || this.options.concise) {
if (typeof preview.size == "number") {
@@ -2853,24 +2784,22 @@ Widgets.ObjectRenderers.add({
}); // Widgets.ObjectRenderers.byKind.MapLike
/**
* The widget used for displaying objects with a URL.
*/
Widgets.ObjectRenderers.add({
byKind: "ObjectWithURL",
- render: function ()
- {
+ render: function () {
this.element = this._renderElement(this.objectActor,
this.objectActor.preview.url);
},
- _renderElement: function (objectActor, url)
- {
+ _renderElement: function (objectActor, url) {
let container = this.el("span.kind-" + objectActor.preview.kind);
this._anchor(objectActor.class, {
className: "cm-variable",
appendTo: container,
});
if (!VariablesView.isFalsy({ value: url })) {
@@ -2884,18 +2813,17 @@ Widgets.ObjectRenderers.add({
}); // Widgets.ObjectRenderers.byKind.ObjectWithURL
/**
* The widget used for displaying objects with a string next to them.
*/
Widgets.ObjectRenderers.add({
byKind: "ObjectWithText",
- render: function ()
- {
+ render: function () {
let {preview} = this.objectActor;
this.element = this.el("span.kind-" + preview.kind);
this._anchor(this.objectActor.class, { className: "cm-variable" });
if (!this.options.concise) {
this._text(" ");
this.element.appendChild(this.el("span.theme-fg-color6",
@@ -2905,18 +2833,17 @@ Widgets.ObjectRenderers.add({
});
/**
* The widget used for displaying DOM event previews.
*/
Widgets.ObjectRenderers.add({
byKind: "DOMEvent",
- render: function ()
- {
+ render: function () {
let {preview} = this.objectActor;
let container = this.element = this.el("span.kind-" + preview.kind);
this._anchor(preview.type || this.objectActor.class,
{ className: "cm-variable" });
if (this.options.concise) {
@@ -2987,24 +2914,24 @@ Widgets.ObjectRenderers.add({
case nodeConstants.DOCUMENT_FRAGMENT_NODE:
case nodeConstants.ELEMENT_NODE:
return true;
default:
return false;
}
},
- render: function ()
- {
- switch (this.objectActor.preview.nodeType) {
+ render: function () {
+ const {preview} = this.objectActor;
+
+ switch (preview.nodeType) {
case nodeConstants.DOCUMENT_NODE:
this._renderDocumentNode();
break;
case nodeConstants.ATTRIBUTE_NODE: {
- let {preview} = this.objectActor;
this.element = this.el("span.attributeNode.kind-" + preview.kind);
let attr = this._renderAttributeNode(preview.nodeName, preview.value, true);
this.element.appendChild(attr);
break;
}
case nodeConstants.TEXT_NODE:
this._renderTextNode();
break;
@@ -3017,69 +2944,64 @@ Widgets.ObjectRenderers.add({
case nodeConstants.ELEMENT_NODE:
this._renderElementNode();
break;
default:
throw new Error("Unsupported nodeType: " + preview.nodeType);
}
},
- _renderDocumentNode: function ()
- {
+ _renderDocumentNode: function () {
let fn =
Widgets.ObjectRenderers.byKind.ObjectWithURL.prototype._renderElement;
this.element = fn.call(this, this.objectActor,
this.objectActor.preview.location);
this.element.classList.add("documentNode");
},
- _renderAttributeNode: function (nodeName, nodeValue, addLink)
- {
+ _renderAttributeNode: function (nodeName, nodeValue, addLink) {
let value = VariablesView.getString(nodeValue, { noStringQuotes: true });
let fragment = this.document.createDocumentFragment();
if (addLink) {
this._anchor(nodeName, { className: "cm-attribute", appendTo: fragment });
} else {
fragment.appendChild(this.el("span.cm-attribute", nodeName));
}
this._text("=\"", fragment);
fragment.appendChild(this.el("span.theme-fg-color6", escapeHTML(value)));
this._text("\"", fragment);
return fragment;
},
- _renderTextNode: function ()
- {
+ _renderTextNode: function () {
let {preview} = this.objectActor;
this.element = this.el("span.textNode.kind-" + preview.kind);
this._anchor(preview.nodeName, { className: "cm-variable" });
this._text(" ");
let text = VariablesView.getString(preview.textContent);
this.element.appendChild(this.el("span.console-string", text));
},
- _renderCommentNode: function ()
- {
+ _renderCommentNode: function () {
let {preview} = this.objectActor;
let comment = "<!-- " + VariablesView.getString(preview.textContent, {
noStringQuotes: true,
}) + " -->";
this.element = this._anchor(comment, {
className: "kind-" + preview.kind + " commentNode cm-comment",
});
},
- _renderDocumentFragmentNode: function ()
- {
+ _renderDocumentFragmentNode: function () {
let {preview} = this.objectActor;
let {childNodes} = preview;
let container = this.element = this.el("span.documentFragmentNode.kind-" +
preview.kind);
this._anchor(this.objectActor.class, { className: "cm-variable" });
if (!childNodes || this.options.concise) {
@@ -3108,38 +3030,38 @@ Widgets.ObjectRenderers.add({
let n = preview.childNodesLength - shown;
let str = VariablesView.stringifiers._getNMoreString(n);
this._anchor(str);
}
this._text(" ]");
},
- _renderElementNode: function ()
- {
- let doc = this.document;
+ _renderElementNode: function () {
let {attributes, nodeName} = this.objectActor.preview;
- this.element = this.el("span." + "kind-" + this.objectActor.preview.kind + ".elementNode");
+ this.element = this.el("span." + "kind-" + this.objectActor.preview.kind +
+ ".elementNode");
this._text("<");
let openTag = this.el("span.cm-tag");
this.element.appendChild(openTag);
let tagName = this._anchor(nodeName, {
className: "cm-tag",
appendTo: openTag
});
if (this.options.concise) {
if (attributes.id) {
tagName.appendChild(this.el("span.cm-attribute", "#" + attributes.id));
}
if (attributes.class) {
- tagName.appendChild(this.el("span.cm-attribute", "." + attributes.class.split(/\s+/g).join(".")));
+ const joinedClasses = "." + attributes.class.split(/\s+/g).join(".");
+ tagName.appendChild(this.el("span.cm-attribute", joinedClasses));
}
} else {
for (let name of Object.keys(attributes)) {
let attr = this._renderAttributeNode(" " + name, attributes[name]);
this.element.appendChild(attr);
}
}
@@ -3157,18 +3079,17 @@ Widgets.ObjectRenderers.add({
* will attach mouseover/out event listeners to do so, and the inspector icon
* to open the node in the inspector.
* @return a promise that resolves when the node has been linked to the
* inspector, or rejects if it wasn't (either if no toolbox could be found to
* access the inspector, or if the node isn't present in the inspector, i.e.
* if the node is in a DocumentFragment or not part of the tree, or not of
* type nodeConstants.ELEMENT_NODE).
*/
- linkToInspector: Task.async(function* ()
- {
+ linkToInspector: Task.async(function* () {
if (this._linkedToInspector) {
return;
}
// Checking the node type
if (this.objectActor.preview.nodeType !== nodeConstants.ELEMENT_NODE) {
throw new Error("The object cannot be linked to the inspector as it " +
"isn't an element node");
@@ -3179,17 +3100,18 @@ Widgets.ObjectRenderers.add({
this.toolbox = gDevTools.getToolbox(target);
if (!this.toolbox) {
// In cases like the browser console, there is no toolbox.
return;
}
// Checking that the inspector supports the node
yield this.toolbox.initInspector();
- this._nodeFront = yield this.toolbox.walker.getNodeActorFromObjectActor(this.objectActor.actor);
+ this._nodeFront = yield this.toolbox.walker.getNodeActorFromObjectActor(
+ this.objectActor.actor);
if (!this._nodeFront) {
throw new Error("The object cannot be linked to the inspector, the " +
"corresponding nodeFront could not be found");
}
// At this stage, the message may have been cleared already
if (!this.document) {
throw new Error("The object cannot be linked to the inspector, the " +
@@ -3214,68 +3136,66 @@ Widgets.ObjectRenderers.add({
this._openInspectorNode.title = l10n.getStr("openNodeInInspector");
}),
/**
* Highlight the DOMNode corresponding to the ObjectActor in the page.
* @return a promise that resolves when the node has been highlighted, or
* rejects if the node cannot be highlighted (detached from the DOM)
*/
- highlightDomNode: Task.async(function* ()
- {
+ highlightDomNode: Task.async(function* () {
yield this.linkToInspector();
let isAttached = yield this.toolbox.walker.isInDOMTree(this._nodeFront);
if (isAttached) {
yield this.toolbox.highlighterUtils.highlightNodeFront(this._nodeFront);
} else {
- throw null;
+ throw new Error("Node is not attached.");
}
}),
/**
* Unhighlight a previously highlit node
* @see highlightDomNode
* @return a promise that resolves when the highlighter has been hidden
*/
- unhighlightDomNode: function ()
- {
+ unhighlightDomNode: function () {
return this.linkToInspector().then(() => {
return this.toolbox.highlighterUtils.unhighlight();
}).then(null, e => console.error(e));
},
/**
* Open the DOMNode corresponding to the ObjectActor in the inspector panel
* @return a promise that resolves when the inspector has been switched to
* and the node has been selected, or rejects if the node cannot be selected
* (detached from the DOM). Note that in any case, the inspector panel will
* be switched to.
*/
- openNodeInInspector: Task.async(function* ()
- {
+ openNodeInInspector: Task.async(function* () {
yield this.linkToInspector();
yield this.toolbox.selectTool("inspector");
let isAttached = yield this.toolbox.walker.isInDOMTree(this._nodeFront);
if (isAttached) {
let onReady = promise.defer();
this.toolbox.inspector.once("inspector-updated", onReady.resolve);
yield this.toolbox.selection.setNodeFront(this._nodeFront, "console");
yield onReady.promise;
} else {
- throw null;
+ throw new Error("Node is not attached.");
}
}),
- destroy: function ()
- {
+ destroy: function () {
if (this.toolbox && this._nodeFront) {
this.element.removeEventListener("mouseover", this.highlightDomNode);
this.element.removeEventListener("mouseout", this.unhighlightDomNode);
- this._openInspectorNode.removeEventListener("mousedown", this.openNodeInInspector, true);
+ this._openInspectorNode.removeEventListener("mousedown",
+ this.openNodeInInspector,
+ true);
if (this._linkedToInspector) {
this.unhighlightDomNode().then(() => {
this.toolbox = null;
this._nodeFront = null;
});
} else {
this.toolbox = null;
@@ -3286,18 +3206,17 @@ Widgets.ObjectRenderers.add({
}); // Widgets.ObjectRenderers.byKind.DOMNode
/**
* The widget user for displaying Promise objects.
*/
Widgets.ObjectRenderers.add({
byClass: "Promise",
- render: function ()
- {
+ render: function () {
let { ownProperties, safeGetterValues } = this.objectActor.preview || {};
if ((!ownProperties && !safeGetterValues) || this.options.concise) {
this._renderConciseObject();
return;
}
this._renderObjectPrefix();
let container = this.element;
@@ -3370,18 +3289,17 @@ Widgets.ObjectRenderers.add({
});
/**
* The widget used for displaying generic JS object previews.
*/
Widgets.ObjectRenderers.add({
byKind: "Object",
- render: function ()
- {
+ render: function () {
let { ownProperties, safeGetterValues } = this.objectActor.preview || {};
if ((!ownProperties && !safeGetterValues) || this.options.concise) {
this._renderConciseObject();
return;
}
this._renderObjectPrefix();
this._renderObjectProperties(this.element, false);
@@ -3395,36 +3313,34 @@ Widgets.ObjectRenderers.add({
* @constructor
* @param object message
* The owning message.
* @param object longStringActor
* The LongStringActor to display.
* @param object options
* Options, such as noStringQuotes
*/
-Widgets.LongString = function (message, longStringActor, options)
-{
+Widgets.LongString = function (message, longStringActor, options) {
Widgets.BaseWidget.call(this, message);
this.longStringActor = longStringActor;
this.noStringQuotes = (options && "noStringQuotes" in options) ?
options.noStringQuotes : !this.message._quoteStrings;
this._onClick = this._onClick.bind(this);
this._onSubstring = this._onSubstring.bind(this);
};
Widgets.LongString.prototype = extend(Widgets.BaseWidget.prototype, {
/**
* The LongStringActor displayed by the widget.
* @type object
*/
longStringActor: null,
- render: function ()
- {
+ render: function () {
if (this.element) {
return this;
}
let result = this.element = this.document.createElementNS(XHTML_NS, "span");
result.className = "longString console-string";
this._renderString(this.longStringActor.initial);
result.appendChild(this._renderEllipsis());
@@ -3433,64 +3349,60 @@ Widgets.LongString.prototype = extend(Wi
},
/**
* Render the long string in the widget element.
* @private
* @param string str
* The string to display.
*/
- _renderString: function (str)
- {
+ _renderString: function (str) {
this.element.textContent = VariablesView.getString(str, {
noStringQuotes: this.noStringQuotes,
noEllipsis: true,
});
},
/**
* Render the anchor ellipsis that allows the user to expand the long string.
*
* @private
* @return Element
*/
- _renderEllipsis: function ()
- {
+ _renderEllipsis: function () {
let ellipsis = this.document.createElementNS(XHTML_NS, "a");
ellipsis.className = "longStringEllipsis";
ellipsis.textContent = l10n.getStr("longStringEllipsis");
ellipsis.href = "#";
ellipsis.draggable = false;
this.message._addLinkCallback(ellipsis, this._onClick);
return ellipsis;
},
/**
* The click event handler for the ellipsis shown after the short string. This
* function expands the element to show the full string.
* @private
*/
- _onClick: function ()
- {
+ _onClick: function () {
let longString = this.output.webConsoleClient.longString(this.longStringActor);
let toIndex = Math.min(longString.length, MAX_LONG_STRING_LENGTH);
longString.substring(longString.initial.length, toIndex, this._onSubstring);
},
/**
* The longString substring response callback.
*
* @private
* @param object response
* Response packet.
*/
- _onSubstring: function (response)
- {
+ _onSubstring: function (response) {
if (response.error) {
console.error("LongString substring failure: " + response.error);
return;
}
this.element.lastChild.remove();
this.element.classList.remove("longString");
@@ -3507,27 +3419,25 @@ Widgets.LongString.prototype = extend(Wi
this._logWarningAboutStringTooLong();
}
},
/**
* Inform user that the string he tries to view is too long.
* @private
*/
- _logWarningAboutStringTooLong: function ()
- {
+ _logWarningAboutStringTooLong: function () {
let msg = new Messages.Simple(l10n.getStr("longStringTooLong"), {
category: "output",
severity: "warning",
});
this.output.addMessage(msg);
},
}); // Widgets.LongString.prototype
-
/**
* The stacktrace widget.
*
* @constructor
* @extends Widgets.BaseWidget
* @param object message
* The owning message.
* @param array stacktrace
@@ -3576,18 +3486,17 @@ Widgets.Stacktrace.prototype = extend(Wi
* @param object message
* The owning message.
* @param array data
* Array of objects that holds the data to log in the table.
* @param object columns
* Object containing the key value pair of the id and display name for
* the columns in the table.
*/
-Widgets.Table = function (message, data, columns)
-{
+Widgets.Table = function (message, data, columns) {
Widgets.BaseWidget.call(this, message);
this.data = data;
this.columns = columns;
};
Widgets.Table.prototype = extend(Widgets.BaseWidget.prototype, {
/**
* Array of objects that holds the data to output in the table.
@@ -3620,17 +3529,16 @@ Widgets.Table.prototype = extend(Widgets
for (let row of this.data) {
this.table.push(row);
}
return this;
}
}); // Widgets.Table.prototype
-function gSequenceId()
-{
+function gSequenceId() {
return gSequenceId.n++;
}
gSequenceId.n = 0;
exports.ConsoleOutput = ConsoleOutput;
exports.Messages = Messages;
exports.Widgets = Widgets;