summaryrefslogtreecommitdiffstats
path: root/devtools/client/webconsole/new-console-output/components/console-table.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/webconsole/new-console-output/components/console-table.js')
-rw-r--r--devtools/client/webconsole/new-console-output/components/console-table.js202
1 files changed, 202 insertions, 0 deletions
diff --git a/devtools/client/webconsole/new-console-output/components/console-table.js b/devtools/client/webconsole/new-console-output/components/console-table.js
new file mode 100644
index 000000000..bf8fdcbd8
--- /dev/null
+++ b/devtools/client/webconsole/new-console-output/components/console-table.js
@@ -0,0 +1,202 @@
+/* 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 {
+ createClass,
+ createFactory,
+ DOM: dom,
+ PropTypes
+} = require("devtools/client/shared/vendor/react");
+const { ObjectClient } = require("devtools/shared/client/main");
+const actions = require("devtools/client/webconsole/new-console-output/actions/messages");
+const {l10n} = require("devtools/client/webconsole/new-console-output/utils/messages");
+const GripMessageBody = createFactory(require("devtools/client/webconsole/new-console-output/components/grip-message-body"));
+
+const TABLE_ROW_MAX_ITEMS = 1000;
+const TABLE_COLUMN_MAX_ITEMS = 10;
+
+const ConsoleTable = createClass({
+
+ displayName: "ConsoleTable",
+
+ propTypes: {
+ dispatch: PropTypes.func.isRequired,
+ parameters: PropTypes.array.isRequired,
+ serviceContainer: PropTypes.shape({
+ hudProxyClient: PropTypes.object.isRequired,
+ }),
+ id: PropTypes.string.isRequired,
+ },
+
+ componentWillMount: function () {
+ const {id, dispatch, serviceContainer, parameters} = this.props;
+
+ if (!Array.isArray(parameters) || parameters.length === 0) {
+ return;
+ }
+
+ const client = new ObjectClient(serviceContainer.hudProxyClient, parameters[0]);
+ let dataType = getParametersDataType(parameters);
+
+ // Get all the object properties.
+ dispatch(actions.messageTableDataGet(id, client, dataType));
+ },
+
+ getHeaders: function (columns) {
+ let headerItems = [];
+ columns.forEach((value, key) => headerItems.push(dom.th({}, value)));
+ return headerItems;
+ },
+
+ getRows: function (columns, items) {
+ return items.map(item => {
+ let cells = [];
+ columns.forEach((value, key) => {
+ cells.push(
+ dom.td(
+ {},
+ GripMessageBody({
+ grip: item[key]
+ })
+ )
+ );
+ });
+ return dom.tr({}, cells);
+ });
+ },
+
+ render: function () {
+ const {parameters, tableData} = this.props;
+ const headersGrip = parameters[1];
+ const headers = headersGrip && headersGrip.preview ? headersGrip.preview.items : null;
+
+ // if tableData is nullable, we don't show anything.
+ if (!tableData) {
+ return null;
+ }
+
+ const {columns, items} = getTableItems(
+ tableData,
+ getParametersDataType(parameters),
+ headers
+ );
+
+ return (
+ dom.table({className: "new-consoletable devtools-monospace"},
+ dom.thead({}, this.getHeaders(columns)),
+ dom.tbody({}, this.getRows(columns, items))
+ )
+ );
+ }
+});
+
+function getParametersDataType(parameters = null) {
+ if (!Array.isArray(parameters) || parameters.length === 0) {
+ return null;
+ }
+ return parameters[0].class;
+}
+
+function getTableItems(data = {}, type, headers = null) {
+ const INDEX_NAME = "_index";
+ const VALUE_NAME = "_value";
+ const namedIndexes = {
+ [INDEX_NAME]: (
+ ["Object", "Array"].includes(type) ?
+ l10n.getStr("table.index") : l10n.getStr("table.iterationIndex")
+ ),
+ [VALUE_NAME]: l10n.getStr("table.value"),
+ key: l10n.getStr("table.key")
+ };
+
+ let columns = new Map();
+ let items = [];
+
+ let addItem = function (item) {
+ items.push(item);
+ Object.keys(item).forEach(key => addColumn(key));
+ };
+
+ let addColumn = function (columnIndex) {
+ let columnExists = columns.has(columnIndex);
+ let hasMaxColumns = columns.size == TABLE_COLUMN_MAX_ITEMS;
+ let hasCustomHeaders = Array.isArray(headers);
+
+ if (
+ !columnExists &&
+ !hasMaxColumns && (
+ !hasCustomHeaders ||
+ headers.includes(columnIndex) ||
+ columnIndex === INDEX_NAME
+ )
+ ) {
+ columns.set(columnIndex, namedIndexes[columnIndex] || columnIndex);
+ }
+ };
+
+ for (let index of Object.keys(data)) {
+ if (type !== "Object" && index == parseInt(index, 10)) {
+ index = parseInt(index, 10);
+ }
+
+ let item = {
+ [INDEX_NAME]: index
+ };
+
+ let property = data[index].value;
+
+ if (property.preview) {
+ let {preview} = property;
+ let entries = preview.ownProperties || preview.items;
+ if (entries) {
+ for (let key of Object.keys(entries)) {
+ let entry = entries[key];
+ item[key] = entry.value || entry;
+ }
+ } else {
+ if (preview.key) {
+ item.key = preview.key;
+ }
+
+ item[VALUE_NAME] = preview.value || property;
+ }
+ } else {
+ item[VALUE_NAME] = property;
+ }
+
+ addItem(item);
+
+ if (items.length === TABLE_ROW_MAX_ITEMS) {
+ break;
+ }
+ }
+
+ // Some headers might not be present in the items, so we make sure to
+ // return all the headers set by the user.
+ if (Array.isArray(headers)) {
+ headers.forEach(header => addColumn(header));
+ }
+
+ // We want to always have the index column first
+ if (columns.has(INDEX_NAME)) {
+ let index = columns.get(INDEX_NAME);
+ columns.delete(INDEX_NAME);
+ columns = new Map([[INDEX_NAME, index], ...columns.entries()]);
+ }
+
+ // We want to always have the values column last
+ if (columns.has(VALUE_NAME)) {
+ let index = columns.get(VALUE_NAME);
+ columns.delete(VALUE_NAME);
+ columns.set(VALUE_NAME, index);
+ }
+
+ return {
+ columns,
+ items
+ };
+}
+
+module.exports = ConsoleTable;