chromium/chrome/test/data/third_party/spaceport/js/util/report.js

define([ ], function () {
    function serializeCsvCell(text) {
        if (typeof text === 'undefined' || text === null) {
            return serializeCsvCell('N/A');
        } else if (/[",]/.test(text)) {
            return '"' + text.replace(/"/g, '""') + '"';
        } else {
            return text;
        }
    }

    function th(text) {
        var th = document.createElement('th');
        th.textContent = text;
        return th;
    }

    function td(text) {
        var td = document.createElement('td');
        td.textContent = text;
        return td;
    }

    function tr(cells) {
        var tr = document.createElement('tr');
        cells.forEach(function (cell) {
            tr.appendChild(cell);
        });
        return tr;
    }

    var report = {
        makeTableLayout: function tabulate(sourceTable) {
            function levelKeys(level) {
                return Object.keys(level).filter(function (key) {
                    return !/^\$/.test(key);
                });
            }

            var levels = [ ];
            var c = sourceTable;
            while (c) {
                levels.push(c);
                c = c.$children;
            }

            // Array name means vertical; string name means horizontal
            var columns = [ ];
            levels.forEach(function (level, i) {
                switch (level.$mode) {
                default:
                case 'vertical':
                    columns.push({
                        name: levelKeys(level),
                        rowSpan: null,
                        title: level.$title,
                        level: level
                    });

                    if (i === levels.length - 1) {
                        // If the last level is vertical, insert a new column
                        // just for the data.
                        columns.push({
                            name: null,
                            rowSpan: 1,
                            title: '(null)',
                            level: null
                        });
                    }

                    break;

                case 'horizontal':
                    levelKeys(level).forEach(function (name) {
                        columns.push({
                            name: name,
                            rowSpan: null,
                            title: level[name],
                            level: level
                        });
                    });
                    break;
                }
            });

            var verticalSizes = [ ];
            var currentSize = 1;
            levels.reverse();
            levels.forEach(function (level) {
                verticalSizes.unshift(currentSize);

                switch (level.$mode) {
                default:
                case 'vertical':
                    currentSize *= levelKeys(level).length;
                    break;

                case 'horizontal':
                    levelKeys(level).slice(1).forEach(function () {
                        verticalSizes.unshift(currentSize);
                    });
                    break;
                }
            });
            levels.reverse();

            columns.forEach(function (column, i) {
                column.rowSpan = verticalSizes[i];
            });

            return {
                columns: columns,
                rowCount: currentSize
            };
        },

        tableTemplate: function table(rootPath, layout) {
            var table = document.createElement('table');
            var header = document.createElement('thead');
            table.appendChild(header);

            header.appendChild(tr(layout.columns.map(function (column) {
                return th(column.title);
            })));

            var body = document.createElement('tbody');
            table.appendChild(body);

            var rowIndex, columnIndex;
            for (rowIndex = 0; rowIndex < layout.rowCount; ++rowIndex) {
                var path = [ rootPath ];
                var columnEls = [ ];
                for (columnIndex = 0; columnIndex < layout.columns.length; ++columnIndex) {
                    var column = layout.columns[columnIndex];

                    var cell;
                    var name = column.name;
                    if (Array.isArray(name)) {
                        name = name[Math.floor(rowIndex / column.rowSpan) % name.length];
                        cell = th(column.level[name]);
                        path.push(name);
                    } else {
                        cell = td('');
                        cell.setAttribute('data-property', name);
                    }

                    if (column.level.$errors) {
                        var errorMessageEl = document.createElement('span');
                        errorMessageEl.className = 'error-message';
                        cell.appendChild(errorMessageEl);
                    }

                    if (rowIndex % column.rowSpan === 0) {
                        cell.rowSpan = column.rowSpan;
                        columnEls.push(cell);
                    }
                }

                var rowEl = tr(columnEls);
                rowEl.id = path.join('-');
                rowEl.className = 'test';
                body.appendChild(rowEl);
            }

            return table;
        },

        csvByTable: function csvByTable(records) {
            return records.map(function (record) {
                return record.map(serializeCsvCell).join(',');
            }).join('\n');
        },

        csvByObject: function csvByObject(object) {
            var records = [ ];

            function write(object, stack) {
                if (object && typeof object.valueOf === 'function') {
                    object = object.valueOf();
                }

                if (object === null) {
                    return;
                }

                switch (typeof object) {
                case 'object':
                    Object.keys(object).forEach(function (key) {
                        write(object[key], stack.concat([ key ]));
                    });
                    break;

                case 'string':
                case 'number':
                case 'boolean':
                    records.push(stack.concat([ String(object) ]));
                    break;

                default:
                    throw new TypeError('Cannot serialize object ' + object);
                }
            }

            write(object, [ ]);
            return report.csvByTable(records);
        },

        csvByLayout: function csv(data, layout, prefix) {
            function getValue(object, path) {
                path = path.slice();
                while (object && path.length) {
                    object = object[path.shift()];
                }
                return object;
            }

            var records = [ ];

            var rowIndex, columnIndex;
            for (rowIndex = 0; rowIndex < layout.rowCount; ++rowIndex) {
                var path = [ ];
                var record = prefix.slice(); // PREFIX IS A HACK FIXME
                records.push(record);
                for (columnIndex = 0; columnIndex < layout.columns.length; ++columnIndex) {
                    var column = layout.columns[columnIndex];

                    var cell;
                    var name = column.name;
                    if (Array.isArray(name)) {
                        name = name[Math.floor(rowIndex / column.rowSpan) % name.length];
                        cell = column.level[name];
                        path.push(name);
                    } else if (name === null) {
                        cell = getValue(data, path);
                    } else {
                        cell = getValue(data, path.concat([ name ]));
                    }

                    record.push(cell);
                }
            }

            return report.csvByTable(records);
        }
    };

    return report;
});