mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 899753 - Part 1: Add the Table console output r=msucan, past
This commit is contained in:
parent
79fc6c368b
commit
f17f459eeb
@ -10,8 +10,12 @@ const {Cc, Ci, Cu} = require("chrome");
|
||||
loader.lazyImporter(this, "VariablesView", "resource:///modules/devtools/VariablesView.jsm");
|
||||
loader.lazyImporter(this, "escapeHTML", "resource:///modules/devtools/VariablesView.jsm");
|
||||
loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
|
||||
loader.lazyImporter(this, "Task","resource://gre/modules/Task.jsm");
|
||||
loader.lazyImporter(this, "Task", "resource://gre/modules/Task.jsm");
|
||||
loader.lazyImporter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm");
|
||||
loader.lazyImporter(this, "ObjectClient", "resource://gre/modules/devtools/dbg-client.jsm");
|
||||
|
||||
loader.lazyRequireGetter(this, "promise");
|
||||
loader.lazyRequireGetter(this, "TableWidget", "devtools/shared/widgets/TableWidget", true);
|
||||
|
||||
const Heritage = require("sdk/core/heritage");
|
||||
const URI = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
@ -81,6 +85,7 @@ const CONSOLE_API_LEVELS_TO_SEVERITIES = {
|
||||
info: "info",
|
||||
log: "log",
|
||||
trace: "log",
|
||||
table: "log",
|
||||
debug: "log",
|
||||
dir: "log",
|
||||
group: "log",
|
||||
@ -111,6 +116,12 @@ const RE_CLEANUP_STYLES = [
|
||||
/['"(]*(?:chrome|resource|about|app|data|https?|ftp|file):+\/*/gi,
|
||||
];
|
||||
|
||||
// Maximum number of rows to display in console.table().
|
||||
const TABLE_ROW_MAX_ITEMS = 1000;
|
||||
|
||||
// Maximum number of columns to display in console.table().
|
||||
const TABLE_COLUMN_MAX_ITEMS = 10;
|
||||
|
||||
/**
|
||||
* The ConsoleOutput object is used to manage output of messages in the Web
|
||||
* Console.
|
||||
@ -1616,6 +1627,343 @@ Messages.ConsoleTrace.prototype = Heritage.extend(Messages.Simple.prototype,
|
||||
_renderRepeatNode: function() { },
|
||||
}); // Messages.ConsoleTrace.prototype
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
let options = {
|
||||
className: "cm-s-mozilla",
|
||||
timestamp: packet.timeStamp,
|
||||
category: "webdev",
|
||||
severity: CONSOLE_API_LEVELS_TO_SEVERITIES[packet.level],
|
||||
private: packet.private,
|
||||
filterDuplicates: false,
|
||||
location: {
|
||||
url: packet.filename,
|
||||
line: packet.lineNumber,
|
||||
},
|
||||
};
|
||||
|
||||
this._populateTableData = this._populateTableData.bind(this);
|
||||
this._renderTable = this._renderTable.bind(this);
|
||||
Messages.Extended.call(this, [this._renderTable], options);
|
||||
|
||||
this._repeatID.consoleApiLevel = packet.level;
|
||||
this._arguments = packet.arguments;
|
||||
};
|
||||
|
||||
Messages.ConsoleTable.prototype = Heritage.extend(Messages.Extended.prototype,
|
||||
{
|
||||
/**
|
||||
* Holds the arguments the content script passed to the console.table()
|
||||
* method.
|
||||
*
|
||||
* @private
|
||||
* @type array
|
||||
*/
|
||||
_arguments: null,
|
||||
|
||||
/**
|
||||
* Array of objects that holds the data to log in the table.
|
||||
*
|
||||
* @private
|
||||
* @type array
|
||||
*/
|
||||
_data: null,
|
||||
|
||||
/**
|
||||
* Key value pair of the id and display name for the columns in the table.
|
||||
* Refer to the TableWidget API.
|
||||
*
|
||||
* @private
|
||||
* @type object
|
||||
*/
|
||||
_columns: null,
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
let result = Messages.Extended.prototype.init.apply(this, arguments);
|
||||
this._data = [];
|
||||
this._columns = {};
|
||||
|
||||
this._populatePromise = this._populateTableData();
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (columns.class == "Array") {
|
||||
let items = columns.preview.items;
|
||||
|
||||
for (let item of items) {
|
||||
if (typeof item == "string") {
|
||||
this._columns[item] = item;
|
||||
}
|
||||
}
|
||||
} else if (typeof columns == "string" && columns) {
|
||||
this._columns[columns] = columns;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
let deferred = promise.defer();
|
||||
|
||||
if (this._arguments.length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let data = this._arguments[0];
|
||||
if (data.class != "Array" && data.class != "Object" &&
|
||||
data.class != "Map" && data.class != "Set") {
|
||||
return;
|
||||
}
|
||||
|
||||
let hasColumnsArg = false;
|
||||
if (this._arguments.length > 1) {
|
||||
if (data.class == "Object" || data.class == "Array") {
|
||||
this._columns["_index"] = l10n.getStr("table.index");
|
||||
} else {
|
||||
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;
|
||||
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");
|
||||
}
|
||||
|
||||
let property = ownProperties[index].value;
|
||||
let item = { _index: index };
|
||||
|
||||
if (property.class == "Object" || property.class == "Array") {
|
||||
let {preview} = property;
|
||||
let entries = property.class == "Object" ?
|
||||
preview.ownProperties : preview.items;
|
||||
|
||||
for (let key of Object.keys(entries)) {
|
||||
let value = property.class == "Object" ?
|
||||
preview.ownProperties[key].value : preview.items[key];
|
||||
|
||||
item[key] = this._renderValueGrip(value, { concise: true });
|
||||
|
||||
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 });
|
||||
|
||||
if (!hasColumnsArg && !("_value" in this._columns)) {
|
||||
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") {
|
||||
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");
|
||||
}
|
||||
|
||||
let rowCount = 0;
|
||||
for (let index of Object.keys(entries || {})) {
|
||||
let [key, value] = entries[index];
|
||||
let item = {
|
||||
_index: index,
|
||||
_key: this._renderValueGrip(key, { concise: true }),
|
||||
_value: this._renderValueGrip(value, { concise: true })
|
||||
};
|
||||
|
||||
this._data.push(item);
|
||||
|
||||
if (++rowCount == TABLE_ROW_MAX_ITEMS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
} else if (data.class == "Set") {
|
||||
let entries = data.preview.items;
|
||||
|
||||
if (!hasColumnsArg) {
|
||||
this._columns["_index"] = l10n.getStr("table.iterationIndex");
|
||||
this._columns["_value"] = l10n.getStr("table.value");
|
||||
}
|
||||
|
||||
let rowCount = 0;
|
||||
for (let index of Object.keys(entries || {})) {
|
||||
let value = entries[index];
|
||||
let item = {
|
||||
_index : index,
|
||||
_value: this._renderValueGrip(value, { concise: true })
|
||||
};
|
||||
|
||||
this._data.push(item);
|
||||
|
||||
if (++rowCount == TABLE_ROW_MAX_ITEMS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
render: function()
|
||||
{
|
||||
Messages.Extended.prototype.render.apply(this, arguments);
|
||||
this.element.setAttribute("open", true);
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Render the table.
|
||||
*
|
||||
* @private
|
||||
* @return DOMElement
|
||||
*/
|
||||
_renderTable: function()
|
||||
{
|
||||
let cmvar = this.document.createElementNS(XHTML_NS, "span");
|
||||
cmvar.className = "cm-variable";
|
||||
cmvar.textContent = "console";
|
||||
|
||||
let cmprop = this.document.createElementNS(XHTML_NS, "span");
|
||||
cmprop.className = "cm-property";
|
||||
cmprop.textContent = "table";
|
||||
|
||||
let title = this.document.createElementNS(XHTML_NS, "span");
|
||||
title.className = "message-body devtools-monospace";
|
||||
title.appendChild(cmvar);
|
||||
title.appendChild(this.document.createTextNode("."));
|
||||
title.appendChild(cmprop);
|
||||
title.appendChild(this.document.createTextNode("():"));
|
||||
|
||||
let repeatNode = Messages.Simple.prototype._renderRepeatNode.call(this);
|
||||
let location = Messages.Simple.prototype._renderLocation.call(this);
|
||||
if (location) {
|
||||
location.target = "jsdebugger";
|
||||
}
|
||||
|
||||
let body = this.document.createElementNS(XHTML_NS, "span");
|
||||
body.className = "message-flex-body";
|
||||
body.appendChild(title);
|
||||
if (repeatNode) {
|
||||
body.appendChild(repeatNode);
|
||||
}
|
||||
if (location) {
|
||||
body.appendChild(location);
|
||||
}
|
||||
body.appendChild(this.document.createTextNode("\n"));
|
||||
|
||||
let result = this.document.createElementNS(XHTML_NS, "div");
|
||||
result.appendChild(body);
|
||||
|
||||
if (this._populatePromise) {
|
||||
this._populatePromise.then(() => {
|
||||
if (this._data.length > 0) {
|
||||
let widget = new Widgets.Table(this, this._data, this._columns).render();
|
||||
result.appendChild(widget.element);
|
||||
}
|
||||
|
||||
result.scrollIntoView();
|
||||
|
||||
// Release object actors
|
||||
if (Array.isArray(this._arguments)) {
|
||||
for (let arg of this._arguments) {
|
||||
if (WebConsoleUtils.isActorGrip(arg)) {
|
||||
this.output._releaseObject(arg.actor);
|
||||
}
|
||||
}
|
||||
}
|
||||
this._arguments = null;
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
_renderBody: function()
|
||||
{
|
||||
let body = Messages.Simple.prototype._renderBody.apply(this, arguments);
|
||||
body.classList.remove("devtools-monospace", "message-body");
|
||||
return body;
|
||||
},
|
||||
|
||||
// no-op for the message location and .repeats elements.
|
||||
// |this._renderTable| handles customized message output.
|
||||
_renderLocation: function() { },
|
||||
_renderRepeatNode: function() { },
|
||||
}); // Messages.ConsoleTable.prototype
|
||||
|
||||
let Widgets = {};
|
||||
|
||||
/**
|
||||
@ -3012,6 +3360,63 @@ Widgets.Stacktrace.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
|
||||
}); // Widgets.Stacktrace.prototype
|
||||
|
||||
|
||||
/**
|
||||
* The table widget.
|
||||
*
|
||||
* @constructor
|
||||
* @extends Widgets.BaseWidget
|
||||
* @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.BaseWidget.call(this, message);
|
||||
this.data = data;
|
||||
this.columns = columns;
|
||||
};
|
||||
|
||||
Widgets.Table.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
|
||||
{
|
||||
/**
|
||||
* Array of objects that holds the data to output in the table.
|
||||
* @type array
|
||||
*/
|
||||
data: null,
|
||||
|
||||
/**
|
||||
* Object containing the key value pair of the id and display name for
|
||||
* the columns in the table.
|
||||
* @type object
|
||||
*/
|
||||
columns: null,
|
||||
|
||||
render: function() {
|
||||
if (this.element) {
|
||||
return this;
|
||||
}
|
||||
|
||||
let result = this.element = this.document.createElementNS(XHTML_NS, "div");
|
||||
result.className = "consoletable devtools-monospace";
|
||||
|
||||
this.table = new TableWidget(result, {
|
||||
initialColumns: this.columns,
|
||||
uniqueId: "_index",
|
||||
firstColumn: "_index"
|
||||
});
|
||||
|
||||
for (let row of this.data) {
|
||||
this.table.push(row);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}); // Widgets.Table.prototype
|
||||
|
||||
function gSequenceId()
|
||||
{
|
||||
return gSequenceId.n++;
|
||||
|
@ -123,6 +123,7 @@ const LEVELS = {
|
||||
info: SEVERITY_INFO,
|
||||
log: SEVERITY_LOG,
|
||||
trace: SEVERITY_LOG,
|
||||
table: SEVERITY_LOG,
|
||||
debug: SEVERITY_LOG,
|
||||
dir: SEVERITY_LOG,
|
||||
group: SEVERITY_LOG,
|
||||
@ -1212,6 +1213,11 @@ WebConsoleFrame.prototype = {
|
||||
node = msg.init(this.output).render().element;
|
||||
break;
|
||||
}
|
||||
case "table": {
|
||||
let msg = new Messages.ConsoleTable(aMessage);
|
||||
node = msg.init(this.output).render().element;
|
||||
break;
|
||||
}
|
||||
case "trace": {
|
||||
let msg = new Messages.ConsoleTrace(aMessage);
|
||||
node = msg.init(this.output).render().element;
|
||||
|
@ -250,3 +250,10 @@ messageToggleDetails=Show/hide message details.
|
||||
# example: 1 empty slot
|
||||
# example: 5 empty slots
|
||||
emptySlotLabel=#1 empty slot;#1 empty slots
|
||||
|
||||
# LOCALIZATION NOTE (table.index, table.iterationIndex, table.key, table.value):
|
||||
# the column header displayed in the console table widget.
|
||||
table.index=(index)
|
||||
table.iterationIndex=(iteration index)
|
||||
table.key=Key
|
||||
table.value=Values
|
||||
|
@ -63,6 +63,10 @@ a {
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
.message-body-wrapper .table-widget-body {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* The red bubble that shows the number of times a message is repeated */
|
||||
.message-repeats {
|
||||
-moz-user-select: none;
|
||||
@ -223,6 +227,13 @@ a {
|
||||
color: hsl(24,85%,39%);
|
||||
}
|
||||
|
||||
.theme-selected .console-string,
|
||||
.theme-selected .cm-number,
|
||||
.theme-selected .cm-variable,
|
||||
.theme-selected .kind-ArrayLike {
|
||||
color: #f5f7fa !important; /* Selection Text Color */
|
||||
}
|
||||
|
||||
.message[category=network] > .indent {
|
||||
-moz-border-end: solid #000 6px;
|
||||
}
|
||||
@ -429,6 +440,10 @@ a {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.consoletable {
|
||||
margin: 5px 0 0 0;
|
||||
}
|
||||
|
||||
.theme-light .message[severity=error] .stacktrace {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user