morpheus.Grid = function (options) { this.options = options; var _this = this; var grid; this.items = options.items; /** * Maps from model index to view index. Note that not all model indices are * contained in the map because they might have been filtered from the view. */ this.modelToView = null; /** view order in model space */ this.viewOrder = null; function getItemColumnValue(item, column) { return column.getter(item); } var model = { getLength: function () { return _this.viewOrder != null ? _this.viewOrder.length : _this.items.length; }, getItem: function (index) { return _this.items[_this.viewOrder != null ? _this.viewOrder[index] : index]; } }; this.$el = options.$el; var gridOptions = $.extend({}, { select: true, headerRowHeight: 0, showHeaderRow: false, multiColumnSort: true, multiSelect: false, topPanelHeight: 0, enableTextSelectionOnCells: true, forceFitColumns: true, dataItemColumnValueExtractor: getItemColumnValue, defaultFormatter: function (row, cell, value, columnDef, dataContext) { if (_.isNumber(value)) { return morpheus.Util.nf(value); } else if (morpheus.Util.isArray(value)) { var s = []; for (var i = 0, length = value.length; i < length; i++) { if (i > 0) { s.push(', '); } var val = value[i]; s.push(value[i]); } return s.join(''); } else { return value; } } }, options.gridOptions || {}); grid = new Slick.Grid(options.$el, model, options.columns, gridOptions); this.grid = grid; grid.registerPlugin(new morpheus.AutoTooltips2()); grid.onCellChange.subscribe(function (e, args) { _this.trigger('edit', args); }); if (gridOptions.select) { grid.setSelectionModel(new Slick.RowSelectionModel({ selectActiveRow: true, multiSelect: gridOptions.multiSelect })); grid.getSelectionModel().onSelectedRangesChanged.subscribe(function (e) { var nitems = grid.getDataLength(); _this.trigger('selectionChanged', { selectedRows: grid.getSelectedRows().filter(function (row) { return row >= 0 && row <= nitems; }) }); }); } grid.onSort.subscribe(function (e, args) { _this.sortCols = args.sortCols; _this._updateMappings(); grid.invalidate(); }); options.$el.on('click', function (e) { var cell = grid.getCellFromEvent(e); if (cell) { _this.trigger('click', { row: cell.row, target: e.target }); } }); options.$el.on('dblclick', function (e) { var cell = grid.getCellFromEvent(e); if (cell) { _this.trigger('dblclick', { row: cell.row, target: e.target }); } }); if (options.sort) { var gridSortColumns = []; var gridColumns = grid.getColumns(); var sortCols = []; options.sort.forEach(function (c) { var column = null; for (var i = 0; i < gridColumns.length; i++) { if (gridColumns[i].name === c.name) { column = gridColumns[i]; break; } } if (column != null) { sortCols.push({ sortCol: column, sortAsc: c.sortAsc }); gridSortColumns.push({ columnId: column.id, sortAsc: c.sortAsc }); } else { console.log(c.name + ' not found.'); } }); grid.setSortColumns(gridSortColumns); this.sortCols = sortCols; this._updateMappings(); grid.invalidate(); } this.grid.invalidate(); }; morpheus.Grid.prototype = { columnsAutosized: false, setColumns: function (columns) { this.grid.setColumns(columns); this.grid.resizeCanvas(); this.grid.invalidate(); }, getColumns: function () { return this.grid.getColumns(); }, getSelectedRows: function () { var nitems = this.grid.getDataLength(); return this.grid.getSelectedRows().filter(function (row) { return row >= 0 && row <= nitems; }); }, getSelectedItems: function () { var rows = this.grid.getSelectedRows(); var selection = []; for (var i = 0, nrows = rows.length; i < nrows; i++) { selection.push(this.items[this.convertViewIndexToModel(rows[i])]); } return selection; }, getSelectedItem: function () { var rows = this.grid.getSelectedRows(); if (rows.length === 1) { return this.items[this.convertViewIndexToModel(rows[0])]; } return null; }, /** * Gets the sorted, visible items */ getItems: function () { var items = []; for (var i = 0, length = this.getFilteredItemCount(); i < length; i++) { items.push(this.items[this.convertViewIndexToModel(i)]); } return items; }, getAllItemCount: function () { return this.items.length; }, getAllItems: function () { return this.items; }, getFilteredItemCount: function () { return this.viewOrder ? this.viewOrder.length : this.items.length; }, redraw: function () { this.grid.invalidate(); }, redrawRows: function (rows) { this.grid.invalidateRows(rows); this.grid.render(); }, setItems: function (items) { // clear the selection this.items = items; if (this.grid.getSelectionModel()) { this.grid.setSelectedRows([]); } this.setFilter(this.filter); if (!this.columnsAutosized) { this.autosizeColumns(); } }, convertModelIndexToView: function (modelIndex) { if (this.modelToView !== null) { var index = this.modelToView.get(modelIndex); return index !== undefined ? index : -1; } return modelIndex; }, convertViewIndexToModel: function (viewIndex) { return this.viewOrder != null ? (viewIndex < this.viewOrder.length && viewIndex >= 0 ? this.viewOrder[viewIndex] : -1) : viewIndex; }, _updateMappings: function () { var selectedViewIndices = this.grid.getSelectionModel() != null ? this.grid .getSelectedRows() : null; var selectedModelIndices = []; if (selectedViewIndices) { for (var i = 0, length = selectedViewIndices.length; i < length; i++) { selectedModelIndices.push(this .convertViewIndexToModel(selectedViewIndices[i])); } } this.viewOrder = null; if (this.filter != null) { this.viewOrder = []; for (var i = 0, length = this.items.length; i < length; i++) { if (this.filter(this.items[i])) { this.viewOrder.push(i); } } } var cols = this.sortCols; if (cols && cols.length > 0) { if (this.viewOrder == null) { this.viewOrder = []; for (var i = 0, length = this.items.length; i < length; i++) { this.viewOrder.push(i); } } var ncols = cols.length; var items = this.items; this.viewOrder.sort(function (index1, index2) { for (var i = 0; i < ncols; i++) { var getter = cols[i].sortCol.getter; var sign = cols[i].sortAsc ? 1 : -1; var value1 = getter(items[index1]); var value2 = getter(items[index2]); var comparator = cols[i].sortCol.comparator; var result = comparator(value1, value2) * sign; if (result !== 0) { return result; } } return 0; }); } if (this.viewOrder != null) { this.modelToView = new morpheus.Map(); for (var i = 0, length = this.viewOrder.length; i < length; i++) { this.modelToView.set(this.viewOrder[i], i); } } else { this.modelToView = null; } if (this.grid.getSelectionModel() != null) { var newSelectedViewIndices = []; for (var i = 0, length = selectedModelIndices.length; i < length; i++) { var index = this .convertModelIndexToView(selectedModelIndices[i]); if (index !== undefined) { newSelectedViewIndices.push(index); } } this.grid.setSelectedRows(newSelectedViewIndices); } }, setSelectedRows: function (rows) { this.grid.setSelectedRows(rows); }, setFilter: function (filter) { this.filter = filter; this._updateMappings(); this.grid.invalidate(); this.trigger('filter'); }, getFilter: function () { return this.filter; }, autosizeColumns: function () { var columns = this.grid.getColumns(); var items = this.getItems(); if (!items || items.length == 0) { return; } if (!columns || columns.length <= 1) { return; } this.columnsAutosized = true; var div = document.createElement('div'); document.body.appendChild(div); var $d = $(div); $d.css({ position: 'absolute', left: -1000, top: -1000 }); var $row = $('