| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| /** |
| * @unrestricted |
| * @extends {DataGrid.ViewportDataGrid<!NODE_TYPE>} |
| * @template NODE_TYPE |
| */ |
| export default class SortableDataGrid extends DataGrid.ViewportDataGrid { |
| /** |
| * @param {!Array<!DataGrid.DataGrid.ColumnDescriptor>} columnsArray |
| * @param {function(!NODE_TYPE, string, string, string)=} editCallback |
| * @param {function(!NODE_TYPE)=} deleteCallback |
| * @param {function()=} refreshCallback |
| */ |
| constructor(columnsArray, editCallback, deleteCallback, refreshCallback) { |
| super(columnsArray, editCallback, deleteCallback, refreshCallback); |
| /** @type {function(!NODE_TYPE, !NODE_TYPE):number} */ |
| this._sortingFunction = DataGrid.SortableDataGrid.TrivialComparator; |
| this.setRootNode(/** @type {!DataGrid.SortableDataGridNode<!NODE_TYPE>} */ (new DataGrid.SortableDataGridNode())); |
| } |
| |
| /** |
| * @param {!DataGrid.SortableDataGridNode} a |
| * @param {!DataGrid.SortableDataGridNode} b |
| * @return {number} |
| */ |
| static TrivialComparator(a, b) { |
| return 0; |
| } |
| |
| /** |
| * @param {string} columnId |
| * @param {!DataGrid.SortableDataGridNode} a |
| * @param {!DataGrid.SortableDataGridNode} b |
| * @return {number} |
| */ |
| static NumericComparator(columnId, a, b) { |
| const aValue = a.data[columnId]; |
| const bValue = b.data[columnId]; |
| const aNumber = Number(aValue instanceof Node ? aValue.textContent : aValue); |
| const bNumber = Number(bValue instanceof Node ? bValue.textContent : bValue); |
| return aNumber < bNumber ? -1 : (aNumber > bNumber ? 1 : 0); |
| } |
| |
| /** |
| * @param {string} columnId |
| * @param {!DataGrid.SortableDataGridNode} a |
| * @param {!DataGrid.SortableDataGridNode} b |
| * @return {number} |
| */ |
| static StringComparator(columnId, a, b) { |
| const aValue = a.data[columnId]; |
| const bValue = b.data[columnId]; |
| const aString = aValue instanceof Node ? aValue.textContent : String(aValue); |
| const bString = bValue instanceof Node ? bValue.textContent : String(bValue); |
| return aString < bString ? -1 : (aString > bString ? 1 : 0); |
| } |
| |
| /** |
| * @param {function(!NODE_TYPE, !NODE_TYPE):number} comparator |
| * @param {boolean} reverseMode |
| * @param {!NODE_TYPE} a |
| * @param {!NODE_TYPE} b |
| * @return {number} |
| * @template NODE_TYPE |
| */ |
| static Comparator(comparator, reverseMode, a, b) { |
| return reverseMode ? comparator(b, a) : comparator(a, b); |
| } |
| |
| /** |
| * @param {!Array.<string>} columnNames |
| * @param {!Array.<string>} values |
| * @return {?DataGrid.SortableDataGrid<!DataGrid.SortableDataGridNode>} |
| */ |
| static create(columnNames, values) { |
| const numColumns = columnNames.length; |
| if (!numColumns) { |
| return null; |
| } |
| |
| const columns = /** @type {!Array<!DataGrid.DataGrid.ColumnDescriptor>} */ ([]); |
| for (let i = 0; i < columnNames.length; ++i) { |
| columns.push({id: String(i), title: columnNames[i], width: columnNames[i].length, sortable: true}); |
| } |
| |
| const nodes = []; |
| for (let i = 0; i < values.length / numColumns; ++i) { |
| const data = {}; |
| for (let j = 0; j < columnNames.length; ++j) { |
| data[j] = values[numColumns * i + j]; |
| } |
| |
| const node = new DataGrid.SortableDataGridNode(data); |
| node.selectable = false; |
| nodes.push(node); |
| } |
| |
| const dataGrid = new DataGrid.SortableDataGrid(columns); |
| const length = nodes.length; |
| const rootNode = dataGrid.rootNode(); |
| for (let i = 0; i < length; ++i) { |
| rootNode.appendChild(nodes[i]); |
| } |
| |
| dataGrid.addEventListener(DataGrid.DataGrid.Events.SortingChanged, sortDataGrid); |
| |
| function sortDataGrid() { |
| const nodes = dataGrid.rootNode().children; |
| const sortColumnId = dataGrid.sortColumnId(); |
| if (!sortColumnId) { |
| return; |
| } |
| |
| let columnIsNumeric = true; |
| for (let i = 0; i < nodes.length; i++) { |
| const value = nodes[i].data[sortColumnId]; |
| if (isNaN(value instanceof Node ? value.textContent : value)) { |
| columnIsNumeric = false; |
| break; |
| } |
| } |
| |
| const comparator = |
| columnIsNumeric ? DataGrid.SortableDataGrid.NumericComparator : DataGrid.SortableDataGrid.StringComparator; |
| dataGrid.sortNodes(comparator.bind(null, sortColumnId), !dataGrid.isSortOrderAscending()); |
| } |
| return dataGrid; |
| } |
| |
| /** |
| * @param {!NODE_TYPE} node |
| */ |
| insertChild(node) { |
| const root = /** @type {!DataGrid.SortableDataGridNode<!NODE_TYPE>} */ (this.rootNode()); |
| root.insertChildOrdered(node); |
| } |
| |
| /** |
| * @param {function(!NODE_TYPE, !NODE_TYPE):number} comparator |
| * @param {boolean} reverseMode |
| */ |
| sortNodes(comparator, reverseMode) { |
| this._sortingFunction = DataGrid.SortableDataGrid.Comparator.bind(null, comparator, reverseMode); |
| this.rootNode().recalculateSiblings(0); |
| this.rootNode()._sortChildren(reverseMode); |
| this.scheduleUpdateStructure(); |
| } |
| } |
| |
| /** |
| * @unrestricted |
| * @extends {DataGrid.ViewportDataGridNode<!NODE_TYPE>} |
| * @template NODE_TYPE |
| */ |
| export class SortableDataGridNode extends DataGrid.ViewportDataGridNode { |
| /** |
| * @param {?Object.<string, *>=} data |
| * @param {boolean=} hasChildren |
| */ |
| constructor(data, hasChildren) { |
| super(data, hasChildren); |
| } |
| |
| /** |
| * @param {!NODE_TYPE} node |
| */ |
| insertChildOrdered(node) { |
| this.insertChild(node, this.children.upperBound(node, this.dataGrid._sortingFunction)); |
| } |
| |
| _sortChildren() { |
| this.children.sort(this.dataGrid._sortingFunction); |
| for (let i = 0; i < this.children.length; ++i) { |
| this.children[i].recalculateSiblings(i); |
| } |
| for (const child of this.children) { |
| child._sortChildren(); |
| } |
| } |
| } |
| |
| /* Legacy exported object */ |
| self.DataGrid = self.DataGrid || {}; |
| |
| /* Legacy exported object */ |
| DataGrid = DataGrid || {}; |
| |
| /** |
| * @unrestricted |
| * @constructor |
| */ |
| DataGrid.SortableDataGrid = SortableDataGrid; |
| |
| /** |
| * @unrestricted |
| * @constructor |
| * @extends {DataGrid.ViewportDataGridNode<!NODE_TYPE>} |
| */ |
| DataGrid.SortableDataGridNode = SortableDataGridNode; |