UNPKG

slickgrid

Version:

A lightning fast JavaScript grid/spreadsheet

942 lines (941 loc) 51.5 kB
"use strict"; (() => { var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: !0, configurable: !0, writable: !0, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key != "symbol" ? key + "" : key, value); // src/slick.dataview.ts var SlickEvent = Slick.Event, SlickEventData = Slick.EventData, SlickGroup = Slick.Group, SlickGroupTotals = Slick.GroupTotals, Utils = Slick.Utils, _a, _b, SlickGroupItemMetadataProvider = (_b = (_a = Slick.Data) == null ? void 0 : _a.GroupItemMetadataProvider) != null ? _b : {}, SlickDataView = class { constructor(options, externalPubSub) { this.externalPubSub = externalPubSub; __publicField(this, "defaults", { globalItemMetadataProvider: null, groupItemMetadataProvider: null, inlineFilters: !1, useCSPSafeFilter: !1 }); // private __publicField(this, "idProperty", "id"); // property holding a unique row id __publicField(this, "items", []); // data by index __publicField(this, "rows", []); // data by row __publicField(this, "idxById", /* @__PURE__ */ new Map()); // indexes by id __publicField(this, "rowsById"); // rows by id; lazy-calculated __publicField(this, "filter", null); // filter function __publicField(this, "filterCSPSafe", null); // filter function __publicField(this, "updated", null); // updated item ids __publicField(this, "suspend", !1); // suspends the recalculation __publicField(this, "isBulkSuspend", !1); // delays protectedious operations like the // index update and delete to efficient // versions at endUpdate __publicField(this, "bulkDeleteIds", /* @__PURE__ */ new Map()); __publicField(this, "sortAsc", !0); __publicField(this, "fastSortField"); __publicField(this, "sortComparer"); __publicField(this, "refreshHints", {}); __publicField(this, "prevRefreshHints", {}); __publicField(this, "filterArgs"); __publicField(this, "filteredItems", []); __publicField(this, "compiledFilter"); __publicField(this, "compiledFilterCSPSafe"); __publicField(this, "compiledFilterWithCaching"); __publicField(this, "compiledFilterWithCachingCSPSafe"); __publicField(this, "filterCache", []); __publicField(this, "_grid"); // grid object will be defined only after using "syncGridSelection()" method" // grouping __publicField(this, "groupingInfoDefaults", { getter: void 0, formatter: void 0, comparer: (a, b) => a.value === b.value ? 0 : a.value > b.value ? 1 : -1, predefinedValues: [], aggregators: [], aggregateEmpty: !1, aggregateCollapsed: !1, aggregateChildGroups: !1, collapsed: !1, displayTotalsRow: !0, lazyTotalsCalculation: !1 }); __publicField(this, "groupingInfos", []); __publicField(this, "groups", []); __publicField(this, "toggledGroupsByLevel", []); __publicField(this, "groupingDelimiter", ":|:"); __publicField(this, "selectedRowIds", []); __publicField(this, "preSelectedRowIdsChangeFn"); __publicField(this, "pagesize", 0); __publicField(this, "pagenum", 0); __publicField(this, "totalRows", 0); __publicField(this, "_options"); __publicField(this, "_container"); // public events __publicField(this, "onBeforePagingInfoChanged"); __publicField(this, "onGroupExpanded"); __publicField(this, "onGroupCollapsed"); __publicField(this, "onPagingInfoChanged"); __publicField(this, "onRowCountChanged"); __publicField(this, "onRowsChanged"); __publicField(this, "onRowsOrCountChanged"); __publicField(this, "onSelectedRowIdsChanged"); __publicField(this, "onSetItemsCalled"); this.onBeforePagingInfoChanged = new SlickEvent("onBeforePagingInfoChanged", externalPubSub), this.onGroupExpanded = new SlickEvent("onGroupExpanded", externalPubSub), this.onGroupCollapsed = new SlickEvent("onGroupCollapsed", externalPubSub), this.onPagingInfoChanged = new SlickEvent("onPagingInfoChanged", externalPubSub), this.onRowCountChanged = new SlickEvent("onRowCountChanged", externalPubSub), this.onRowsChanged = new SlickEvent("onRowsChanged", externalPubSub), this.onRowsOrCountChanged = new SlickEvent("onRowsOrCountChanged", externalPubSub), this.onSelectedRowIdsChanged = new SlickEvent("onSelectedRowIdsChanged", externalPubSub), this.onSetItemsCalled = new SlickEvent("onSetItemsCalled", externalPubSub), this._options = Utils.extend(!0, {}, this.defaults, options); } /** * Begins a bached update of the items in the data view. * including deletes and the related events are postponed to the endUpdate call. * As certain operations are postponed during this update, some methods might not * deliver fully consistent information. * @param {Boolean} [bulkUpdate] - if set to true, most data view modifications */ beginUpdate(bulkUpdate) { this.suspend = !0, this.isBulkSuspend = bulkUpdate === !0; } endUpdate() { let wasBulkSuspend = this.isBulkSuspend; this.isBulkSuspend = !1, this.suspend = !1, wasBulkSuspend && (this.processBulkDelete(), this.ensureIdUniqueness()), this.refresh(); } destroy() { this.items = [], this.idxById = null, this.rowsById = null, this.filter = null, this.filterCSPSafe = null, this.updated = null, this.sortComparer = null, this.filterCache = [], this.filteredItems = [], this.compiledFilter = null, this.compiledFilterCSPSafe = null, this.compiledFilterWithCaching = null, this.compiledFilterWithCachingCSPSafe = null, this._grid && this._grid.onSelectedRowsChanged && this._grid.onCellCssStylesChanged && (this._grid.onSelectedRowsChanged.unsubscribe(), this._grid.onCellCssStylesChanged.unsubscribe()), this.onRowsOrCountChanged && this.onRowsOrCountChanged.unsubscribe(); } /** provide some refresh hints as to what to rows needs refresh */ setRefreshHints(hints) { this.refreshHints = hints; } /** get extra filter arguments of the filter method */ getFilterArgs() { return this.filterArgs; } /** add extra filter arguments to the filter method */ setFilterArgs(args) { this.filterArgs = args; } /** * Processes all delete requests placed during bulk update * by recomputing the items and idxById members. */ processBulkDelete() { if (!this.idxById) return; let id, item, newIdx = 0; for (let i = 0, l = this.items.length; i < l; i++) { if (item = this.items[i], id = item[this.idProperty], id === void 0) throw new Error("[SlickGrid DataView] Each data element must implement a unique 'id' property"); this.bulkDeleteIds.has(id) ? this.idxById.delete(id) : (this.items[newIdx] = item, this.idxById.set(id, newIdx), ++newIdx); } this.items.length = newIdx, this.bulkDeleteIds = /* @__PURE__ */ new Map(); } updateIdxById(startingIndex) { if (this.isBulkSuspend || !this.idxById) return; startingIndex = startingIndex || 0; let id; for (let i = startingIndex, l = this.items.length; i < l; i++) { if (id = this.items[i][this.idProperty], id === void 0) throw new Error("[SlickGrid DataView] Each data element must implement a unique 'id' property"); this.idxById.set(id, i); } } ensureIdUniqueness() { if (this.isBulkSuspend || !this.idxById) return; let id; for (let i = 0, l = this.items.length; i < l; i++) if (id = this.items[i][this.idProperty], id === void 0 || this.idxById.get(id) !== i) throw new Error("[SlickGrid DataView] Each data element must implement a unique 'id' property"); } /** Get all DataView Items */ getItems() { return this.items; } /** Get the DataView Id property name to use (defaults to "Id" but could be customized to something else when instantiating the DataView) */ getIdPropertyName() { return this.idProperty; } /** * Set the Items with a new Dataset and optionally pass a different Id property name * @param {Array<*>} data - array of data * @param {String} [objectIdProperty] - optional id property to use as primary id */ setItems(data, objectIdProperty) { objectIdProperty !== void 0 && (this.idProperty = objectIdProperty), this.items = this.filteredItems = data, this.onSetItemsCalled.notify({ idProperty: this.idProperty, itemCount: this.items.length }, null, this), this.idxById = /* @__PURE__ */ new Map(), this.updateIdxById(), this.ensureIdUniqueness(), this.refresh(); } /** Set Paging Options */ setPagingOptions(args) { this.onBeforePagingInfoChanged.notify(this.getPagingInfo(), null, this).getReturnValue() !== !1 && (Utils.isDefined(args.pageSize) && (this.pagesize = args.pageSize, this.pagenum = this.pagesize ? Math.min(this.pagenum, Math.max(0, Math.ceil(this.totalRows / this.pagesize) - 1)) : 0), Utils.isDefined(args.pageNum) && (this.pagenum = Math.min(args.pageNum, Math.max(0, Math.ceil(this.totalRows / this.pagesize) - 1))), this.onPagingInfoChanged.notify(this.getPagingInfo(), null, this), this.refresh()); } /** Get Paging Options */ getPagingInfo() { let totalPages = this.pagesize ? Math.max(1, Math.ceil(this.totalRows / this.pagesize)) : 1; return { pageSize: this.pagesize, pageNum: this.pagenum, totalRows: this.totalRows, totalPages, dataView: this }; } /** Sort Method to use by the DataView */ sort(comparer, ascending) { this.sortAsc = ascending, this.sortComparer = comparer, this.fastSortField = null, ascending === !1 && this.items.reverse(), this.items.sort(comparer), ascending === !1 && this.items.reverse(), this.idxById = /* @__PURE__ */ new Map(), this.updateIdxById(), this.refresh(); } /** * @deprecated, to be more removed in next major since IE is no longer supported and this is no longer useful. * Provides a workaround for the extremely slow sorting in IE. * Does a [lexicographic] sort on a give column by temporarily overriding Object.prototype.toString * to return the value of that field and then doing a native Array.sort(). */ fastSort(field, ascending) { this.sortAsc = ascending, this.fastSortField = field, this.sortComparer = null; let oldToString = Object.prototype.toString; Object.prototype.toString = typeof field == "function" ? field : function() { return this[field]; }, ascending === !1 && this.items.reverse(), this.items.sort(), Object.prototype.toString = oldToString, ascending === !1 && this.items.reverse(), this.idxById = /* @__PURE__ */ new Map(), this.updateIdxById(), this.refresh(); } /** Re-Sort the dataset */ reSort() { this.sortComparer ? this.sort(this.sortComparer, this.sortAsc) : this.fastSortField && this.fastSort(this.fastSortField, this.sortAsc); } /** Get only the DataView filtered items */ getFilteredItems() { return this.filteredItems; } /** Get the array length (count) of only the DataView filtered items */ getFilteredItemCount() { return this.filteredItems.length; } /** Get current Filter used by the DataView */ getFilter() { return this._options.useCSPSafeFilter ? this.filterCSPSafe : this.filter; } /** * Set a Filter that will be used by the DataView * @param {Function} fn - filter callback function */ setFilter(filterFn) { this.filterCSPSafe = filterFn, this.filter = filterFn, this._options.inlineFilters && (this.compiledFilterCSPSafe = this.compileFilterCSPSafe, this.compiledFilterWithCachingCSPSafe = this.compileFilterWithCachingCSPSafe, this.compiledFilter = this.compileFilter(this._options.useCSPSafeFilter), this.compiledFilterWithCaching = this.compileFilterWithCaching(this._options.useCSPSafeFilter)), this.refresh(); } /** Get current Grouping info */ getGrouping() { return this.groupingInfos; } /** Set some Grouping */ setGrouping(groupingInfo) { this._options.groupItemMetadataProvider || (this._options.groupItemMetadataProvider = new SlickGroupItemMetadataProvider()), this.groups = [], this.toggledGroupsByLevel = [], groupingInfo = groupingInfo || [], this.groupingInfos = groupingInfo instanceof Array ? groupingInfo : [groupingInfo]; for (let i = 0; i < this.groupingInfos.length; i++) { let gi = this.groupingInfos[i] = Utils.extend(!0, {}, this.groupingInfoDefaults, this.groupingInfos[i]); gi.getterIsAFn = typeof gi.getter == "function", gi.compiledAccumulators = []; let idx = gi.aggregators.length; for (; idx--; ) gi.compiledAccumulators[idx] = this.compileAccumulatorLoopCSPSafe(gi.aggregators[idx]); this.toggledGroupsByLevel[i] = {}; } this.refresh(); } /** Get an item in the DataView by its row index */ getItemByIdx(i) { return this.items[i]; } /** Get row index in the DataView by its Id */ getIdxById(id) { var _a2; return (_a2 = this.idxById) == null ? void 0 : _a2.get(id); } ensureRowsByIdCache() { if (!this.rowsById) { this.rowsById = {}; for (let i = 0, l = this.rows.length; i < l; i++) this.rowsById[this.rows[i][this.idProperty]] = i; } } /** Get row number in the grid by its item object */ getRowByItem(item) { var _a2; return this.ensureRowsByIdCache(), (_a2 = this.rowsById) == null ? void 0 : _a2[item[this.idProperty]]; } /** Get row number in the grid by its Id */ getRowById(id) { var _a2; return this.ensureRowsByIdCache(), (_a2 = this.rowsById) == null ? void 0 : _a2[id]; } /** Get an item in the DataView by its Id */ getItemById(id) { return this.items[this.idxById.get(id)]; } /** From the items array provided, return the mapped rows */ mapItemsToRows(itemArray) { var _a2; let rows = []; this.ensureRowsByIdCache(); for (let i = 0, l = itemArray.length; i < l; i++) { let row = (_a2 = this.rowsById) == null ? void 0 : _a2[itemArray[i][this.idProperty]]; Utils.isDefined(row) && (rows[rows.length] = row); } return rows; } /** From the Ids array provided, return the mapped rows */ mapIdsToRows(idArray) { var _a2; let rows = []; this.ensureRowsByIdCache(); for (let i = 0, l = idArray.length; i < l; i++) { let row = (_a2 = this.rowsById) == null ? void 0 : _a2[idArray[i]]; Utils.isDefined(row) && (rows[rows.length] = row); } return rows; } /** From the rows array provided, return the mapped Ids */ mapRowsToIds(rowArray) { let ids = []; for (let i = 0, l = rowArray.length; i < l; i++) if (rowArray[i] < this.rows.length) { let rowItem = this.rows[rowArray[i]]; ids[ids.length] = rowItem[this.idProperty]; } return ids; } /** * Performs the update operations of a single item by id without * triggering any events or refresh operations. * @param id The new id of the item. * @param item The item which should be the new value for the given id. */ updateSingleItem(id, item) { var _a2; if (this.idxById) { if (!this.idxById.has(id)) throw new Error("[SlickGrid DataView] Invalid id"); if (id !== item[this.idProperty]) { let newId = item[this.idProperty]; if (!Utils.isDefined(newId)) throw new Error("[SlickGrid DataView] Cannot update item to associate with a null id"); if (this.idxById.has(newId)) throw new Error("[SlickGrid DataView] Cannot update item to associate with a non-unique id"); this.idxById.set(newId, this.idxById.get(id)), this.idxById.delete(id), (_a2 = this.updated) != null && _a2[id] && delete this.updated[id], id = newId; } this.items[this.idxById.get(id)] = item, this.updated || (this.updated = {}), this.updated[id] = !0; } } /** * Updates a single item in the data view given the id and new value. * @param id The new id of the item. * @param item The item which should be the new value for the given id. */ updateItem(id, item) { this.updateSingleItem(id, item), this.refresh(); } /** * Updates multiple items in the data view given the new ids and new values. * @param id {Array} The array of new ids which is in the same order as the items. * @param newItems {Array} The new items that should be set in the data view for the given ids. */ updateItems(ids, newItems) { if (ids.length !== newItems.length) throw new Error("[SlickGrid DataView] Mismatch on the length of ids and items provided to update"); for (let i = 0, l = newItems.length; i < l; i++) this.updateSingleItem(ids[i], newItems[i]); this.refresh(); } /** * Inserts a single item into the data view at the given position. * @param insertBefore {Number} The 0-based index before which the item should be inserted. * @param item The item to insert. */ insertItem(insertBefore, item) { this.items.splice(insertBefore, 0, item), this.updateIdxById(insertBefore), this.refresh(); } /** * Inserts multiple items into the data view at the given position. * @param insertBefore {Number} The 0-based index before which the items should be inserted. * @param newItems {Array} The items to insert. */ insertItems(insertBefore, newItems) { Array.prototype.splice.apply(this.items, [insertBefore, 0].concat(newItems)), this.updateIdxById(insertBefore), this.refresh(); } /** * Adds a single item at the end of the data view. * @param item The item to add at the end. */ addItem(item) { this.items.push(item), this.updateIdxById(this.items.length - 1), this.refresh(); } /** * Adds multiple items at the end of the data view. * @param {Array} newItems The items to add at the end. */ addItems(newItems) { this.items = this.items.concat(newItems), this.updateIdxById(this.items.length - newItems.length), this.refresh(); } /** * Deletes a single item identified by the given id from the data view. * @param {String|Number} id The id identifying the object to delete. */ deleteItem(id) { if (this.idxById) if (this.isBulkSuspend) this.bulkDeleteIds.set(id, !0); else { let idx = this.idxById.get(id); if (idx === void 0) throw new Error("[SlickGrid DataView] Invalid id"); this.idxById.delete(id), this.items.splice(idx, 1), this.updateIdxById(idx), this.refresh(); } } /** * Deletes multiple item identified by the given ids from the data view. * @param {Array} ids The ids of the items to delete. */ deleteItems(ids) { if (!(ids.length === 0 || !this.idxById)) if (this.isBulkSuspend) for (let i = 0, l = ids.length; i < l; i++) { let id = ids[i]; if (this.idxById.get(id) === void 0) throw new Error("[SlickGrid DataView] Invalid id"); this.bulkDeleteIds.set(id, !0); } else { let indexesToDelete = []; for (let i = 0, l = ids.length; i < l; i++) { let id = ids[i], idx = this.idxById.get(id); if (idx === void 0) throw new Error("[SlickGrid DataView] Invalid id"); this.idxById.delete(id), indexesToDelete.push(idx); } indexesToDelete.sort(); for (let i = indexesToDelete.length - 1; i >= 0; --i) this.items.splice(indexesToDelete[i], 1); this.updateIdxById(indexesToDelete[0]), this.refresh(); } } /** Add an item in a sorted dataset (a Sort function must be defined) */ sortedAddItem(item) { if (!this.sortComparer) throw new Error("[SlickGrid DataView] sortedAddItem() requires a sort comparer, use sort()"); this.insertItem(this.sortedIndex(item), item); } /** Update an item in a sorted dataset (a Sort function must be defined) */ sortedUpdateItem(id, item) { if (!this.idxById) return; if (!this.idxById.has(id) || id !== item[this.idProperty]) throw new Error("[SlickGrid DataView] Invalid or non-matching id " + this.idxById.get(id)); if (!this.sortComparer) throw new Error("[SlickGrid DataView] sortedUpdateItem() requires a sort comparer, use sort()"); let oldItem = this.getItemById(id); this.sortComparer(oldItem, item) !== 0 ? (this.deleteItem(id), this.sortedAddItem(item)) : this.updateItem(id, item); } sortedIndex(searchItem) { let low = 0, high = this.items.length; for (; low < high; ) { let mid = low + high >>> 1; this.sortComparer(this.items[mid], searchItem) === -1 ? low = mid + 1 : high = mid; } return low; } /** Get item count, that is the full dataset lenght of the DataView */ getItemCount() { return this.items.length; } /** Get row count (rows displayed in current page) */ getLength() { return this.rows.length; } /** Retrieve an item from the DataView at specific index */ getItem(i) { var _a2; let item = this.rows[i]; if (item != null && item.__group && item.totals && !((_a2 = item.totals) != null && _a2.initialized)) { let gi = this.groupingInfos[item.level]; gi.displayTotalsRow || (this.calculateTotals(item.totals), item.title = gi.formatter ? gi.formatter(item) : item.value); } else item != null && item.__groupTotals && !item.initialized && this.calculateTotals(item); return item; } getItemMetadata(row) { var _a2, _b2, _c; let item = this.rows[row]; return item === void 0 ? null : (_a2 = this._options.globalItemMetadataProvider) != null && _a2.getRowMetadata ? this._options.globalItemMetadataProvider.getRowMetadata(item, row) : item.__group && ((_b2 = this._options.groupItemMetadataProvider) != null && _b2.getGroupRowMetadata) ? this._options.groupItemMetadataProvider.getGroupRowMetadata(item, row) : item.__groupTotals && ((_c = this._options.groupItemMetadataProvider) != null && _c.getTotalsRowMetadata) ? this._options.groupItemMetadataProvider.getTotalsRowMetadata(item, row) : null; } expandCollapseAllGroups(level, collapse) { if (Utils.isDefined(level)) this.toggledGroupsByLevel[level] = {}, this.groupingInfos[level].collapsed = collapse, collapse === !0 ? this.onGroupCollapsed.notify({ level, groupingKey: null }) : this.onGroupExpanded.notify({ level, groupingKey: null }); else for (let i = 0; i < this.groupingInfos.length; i++) this.toggledGroupsByLevel[i] = {}, this.groupingInfos[i].collapsed = collapse, collapse === !0 ? this.onGroupCollapsed.notify({ level: i, groupingKey: null }) : this.onGroupExpanded.notify({ level: i, groupingKey: null }); this.refresh(); } /** * @param {Number} [level] Optional level to collapse. If not specified, applies to all levels. */ collapseAllGroups(level) { this.expandCollapseAllGroups(level, !0); } /** * @param {Number} [level] Optional level to expand. If not specified, applies to all levels. */ expandAllGroups(level) { this.expandCollapseAllGroups(level, !1); } expandCollapseGroup(level, groupingKey, collapse) { this.toggledGroupsByLevel[level][groupingKey] = this.groupingInfos[level].collapsed ^ collapse, this.refresh(); } /** * @param varArgs Either a Slick.Group's "groupingKey" property, or a * variable argument list of grouping values denoting a unique path to the row. For * example, calling collapseGroup('high', '10%') will collapse the '10%' subgroup of * the 'high' group. */ collapseGroup(...args) { let arg0 = Array.prototype.slice.call(args)[0], groupingKey, level; args.length === 1 && arg0.indexOf(this.groupingDelimiter) !== -1 ? (groupingKey = arg0, level = arg0.split(this.groupingDelimiter).length - 1) : (groupingKey = args.join(this.groupingDelimiter), level = args.length - 1), this.expandCollapseGroup(level, groupingKey, !0), this.onGroupCollapsed.notify({ level, groupingKey }); } /** * @param varArgs Either a Slick.Group's "groupingKey" property, or a * variable argument list of grouping values denoting a unique path to the row. For * example, calling expandGroup('high', '10%') will expand the '10%' subgroup of * the 'high' group. */ expandGroup(...args) { let arg0 = Array.prototype.slice.call(args)[0], groupingKey, level; args.length === 1 && arg0.indexOf(this.groupingDelimiter) !== -1 ? (level = arg0.split(this.groupingDelimiter).length - 1, groupingKey = arg0) : (level = args.length - 1, groupingKey = args.join(this.groupingDelimiter)), this.expandCollapseGroup(level, groupingKey, !1), this.onGroupExpanded.notify({ level, groupingKey }); } getGroups() { return this.groups; } extractGroups(rows, parentGroup) { var _a2, _b2, _c; let group, val, groups = [], groupsByVal = {}, r, level = parentGroup ? parentGroup.level + 1 : 0, gi = this.groupingInfos[level]; for (let i = 0, l = (_b2 = (_a2 = gi.predefinedValues) == null ? void 0 : _a2.length) != null ? _b2 : 0; i < l; i++) val = (_c = gi.predefinedValues) == null ? void 0 : _c[i], group = groupsByVal[val], group || (group = new SlickGroup(), group.value = val, group.level = level, group.groupingKey = (parentGroup ? parentGroup.groupingKey + this.groupingDelimiter : "") + val, groups[groups.length] = group, groupsByVal[val] = group); for (let i = 0, l = rows.length; i < l; i++) r = rows[i], val = gi.getterIsAFn ? gi.getter(r) : r[gi.getter], group = groupsByVal[val], group || (group = new SlickGroup(), group.value = val, group.level = level, group.groupingKey = (parentGroup ? parentGroup.groupingKey + this.groupingDelimiter : "") + val, groups[groups.length] = group, groupsByVal[val] = group), group.rows[group.count++] = r; if (level < this.groupingInfos.length - 1) for (let i = 0; i < groups.length; i++) group = groups[i], group.groups = this.extractGroups(group.rows, group); return groups.length && this.addTotals(groups, level), groups.sort(this.groupingInfos[level].comparer), groups; } /** claculate Group Totals */ calculateTotals(totals) { var _a2, _b2, _c; let group = totals.group, gi = this.groupingInfos[(_a2 = group.level) != null ? _a2 : 0], isLeafLevel = group.level === this.groupingInfos.length, agg, idx = gi.aggregators.length; if (!isLeafLevel && gi.aggregateChildGroups) { let i = (_c = (_b2 = group.groups) == null ? void 0 : _b2.length) != null ? _c : 0; for (; i--; ) group.groups[i].totals.initialized || this.calculateTotals(group.groups[i].totals); } for (; idx--; ) agg = gi.aggregators[idx], agg.init(), !isLeafLevel && gi.aggregateChildGroups ? gi.compiledAccumulators[idx].call(agg, group.groups) : gi.compiledAccumulators[idx].call(agg, group.rows), agg.storeResult(totals); totals.initialized = !0; } addGroupTotals(group) { let gi = this.groupingInfos[group.level], totals = new SlickGroupTotals(); totals.group = group, group.totals = totals, gi.lazyTotalsCalculation || this.calculateTotals(totals); } addTotals(groups, level) { var _a2, _b2; level = level || 0; let gi = this.groupingInfos[level], groupCollapsed = gi.collapsed, toggledGroups = this.toggledGroupsByLevel[level], idx = groups.length, g; for (; idx--; ) g = groups[idx], !(g.collapsed && !gi.aggregateCollapsed) && (g.groups && this.addTotals(g.groups, level + 1), (_a2 = gi.aggregators) != null && _a2.length && (gi.aggregateEmpty || g.rows.length || (_b2 = g.groups) != null && _b2.length) && this.addGroupTotals(g), g.collapsed = groupCollapsed ^ toggledGroups[g.groupingKey], g.title = gi.formatter ? gi.formatter(g) : g.value); } flattenGroupedRows(groups, level) { level = level || 0; let gi = this.groupingInfos[level], groupedRows = [], rows, gl = 0, g; for (let i = 0, l = groups.length; i < l; i++) { if (g = groups[i], groupedRows[gl++] = g, !g.collapsed) { rows = g.groups ? this.flattenGroupedRows(g.groups, level + 1) : g.rows; for (let j = 0, jj = rows.length; j < jj; j++) groupedRows[gl++] = rows[j]; } g.totals && gi.displayTotalsRow && (!g.collapsed || gi.aggregateCollapsed) && (groupedRows[gl++] = g.totals); } return groupedRows; } compileAccumulatorLoopCSPSafe(aggregator) { return aggregator.accumulate ? function(items) { let result; for (let i = 0; i < items.length; i++) { let item = items[i]; result = aggregator.accumulate.call(aggregator, item); } return result; } : function() { }; } compileFilterCSPSafe(items, args) { if (typeof this.filterCSPSafe != "function") return []; let _retval = [], _il = items.length; for (let _i = 0; _i < _il; _i++) this.filterCSPSafe(items[_i], args) && _retval.push(items[_i]); return _retval; } compileFilter(stopRunningIfCSPSafeIsActive = !1) { if (stopRunningIfCSPSafeIsActive) return null; let filterInfo = Utils.getFunctionDetails(this.filter), filterPath1 = "{ continue _coreloop; }$1", filterPath2 = "{ _retval[_idx++] = $item$; continue _coreloop; }$1", filterBody = filterInfo.body.replace(/return false\s*([;}]|\}|$)/gi, filterPath1).replace(/return!1([;}]|\}|$)/gi, filterPath1).replace(/return true\s*([;}]|\}|$)/gi, filterPath2).replace(/return!0([;}]|\}|$)/gi, filterPath2).replace( /return ([^;}]+?)\s*([;}]|$)/gi, "{ if ($1) { _retval[_idx++] = $item$; }; continue _coreloop; }$2" ), tpl = [ // 'function(_items, _args) { ', "var _retval = [], _idx = 0; ", "var $item$, $args$ = _args; ", "_coreloop: ", "for (var _i = 0, _il = _items.length; _i < _il; _i++) { ", "$item$ = _items[_i]; ", "$filter$; ", "} ", "return _retval; " // '}' ].join(""); tpl = tpl.replace(/\$filter\$/gi, filterBody), tpl = tpl.replace(/\$item\$/gi, filterInfo.params[0]), tpl = tpl.replace(/\$args\$/gi, filterInfo.params[1]); let fn = new Function("_items,_args", tpl), fnName = "compiledFilter"; return fn.displayName = fnName, fn.name = this.setFunctionName(fn, fnName), fn; } compileFilterWithCaching(stopRunningIfCSPSafeIsActive = !1) { if (stopRunningIfCSPSafeIsActive) return null; let filterInfo = Utils.getFunctionDetails(this.filter), filterPath1 = "{ continue _coreloop; }$1", filterPath2 = "{ _cache[_i] = true;_retval[_idx++] = $item$; continue _coreloop; }$1", filterBody = filterInfo.body.replace(/return false\s*([;}]|\}|$)/gi, filterPath1).replace(/return!1([;}]|\}|$)/gi, filterPath1).replace(/return true\s*([;}]|\}|$)/gi, filterPath2).replace(/return!0([;}]|\}|$)/gi, filterPath2).replace( /return ([^;}]+?)\s*([;}]|$)/gi, "{ if ((_cache[_i] = $1)) { _retval[_idx++] = $item$; }; continue _coreloop; }$2" ), tpl = [ // 'function(_items, _args, _cache) { ', "var _retval = [], _idx = 0; ", "var $item$, $args$ = _args; ", "_coreloop: ", "for (var _i = 0, _il = _items.length; _i < _il; _i++) { ", "$item$ = _items[_i]; ", "if (_cache[_i]) { ", "_retval[_idx++] = $item$; ", "continue _coreloop; ", "} ", "$filter$; ", "} ", "return _retval; " // '}' ].join(""); tpl = tpl.replace(/\$filter\$/gi, filterBody), tpl = tpl.replace(/\$item\$/gi, filterInfo.params[0]), tpl = tpl.replace(/\$args\$/gi, filterInfo.params[1]); let fn = new Function("_items,_args,_cache", tpl), fnName = "compiledFilterWithCaching"; return fn.displayName = fnName, fn.name = this.setFunctionName(fn, fnName), fn; } compileFilterWithCachingCSPSafe(items, args, filterCache) { if (typeof this.filterCSPSafe != "function") return []; let retval = [], il = items.length; for (let _i = 0; _i < il; _i++) (filterCache[_i] || this.filterCSPSafe(items[_i], args)) && retval.push(items[_i]); return retval; } /** * In ES5 we could set the function name on the fly but in ES6 this is forbidden and we need to set it through differently * We can use Object.defineProperty and set it the property to writable, see MDN for reference * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty * @param {*} fn * @param {string} fnName */ setFunctionName(fn, fnName) { try { Object.defineProperty(fn, "name", { writable: !0, value: fnName }); } catch (err) { fn.name = fnName; } } uncompiledFilter(items, args) { var _a2; let retval = [], idx = 0; for (let i = 0, ii = items.length; i < ii; i++) (_a2 = this.filter) != null && _a2.call(this, items[i], args) && (retval[idx++] = items[i]); return retval; } uncompiledFilterWithCaching(items, args, cache) { var _a2; let retval = [], idx = 0, item; for (let i = 0, ii = items.length; i < ii; i++) item = items[i], cache[i] ? retval[idx++] = item : (_a2 = this.filter) != null && _a2.call(this, item, args) && (retval[idx++] = item, cache[i] = !0); return retval; } getFilteredAndPagedItems(items) { if (this._options.useCSPSafeFilter ? this.filterCSPSafe : this.filter) { let batchFilter, batchFilterWithCaching; this._options.useCSPSafeFilter ? (batchFilter = this._options.inlineFilters ? this.compiledFilterCSPSafe : this.uncompiledFilter, batchFilterWithCaching = this._options.inlineFilters ? this.compiledFilterWithCachingCSPSafe : this.uncompiledFilterWithCaching) : (batchFilter = this._options.inlineFilters ? this.compiledFilter : this.uncompiledFilter, batchFilterWithCaching = this._options.inlineFilters ? this.compiledFilterWithCaching : this.uncompiledFilterWithCaching), this.refreshHints.isFilterNarrowing ? this.filteredItems = batchFilter.call(this, this.filteredItems, this.filterArgs) : this.refreshHints.isFilterExpanding ? this.filteredItems = batchFilterWithCaching.call(this, items, this.filterArgs, this.filterCache) : this.refreshHints.isFilterUnchanged || (this.filteredItems = batchFilter.call(this, items, this.filterArgs)); } else this.filteredItems = this.pagesize ? items : items.concat(); let paged; return this.pagesize ? (this.filteredItems.length <= this.pagenum * this.pagesize && (this.filteredItems.length === 0 ? this.pagenum = 0 : this.pagenum = Math.floor((this.filteredItems.length - 1) / this.pagesize)), paged = this.filteredItems.slice(this.pagesize * this.pagenum, this.pagesize * this.pagenum + this.pagesize)) : paged = this.filteredItems, { totalRows: this.filteredItems.length, rows: paged }; } getRowDiffs(rows, newRows) { var _a2, _b2, _c; let item, r, eitherIsNonData, diff = [], from = 0, to = Math.max(newRows.length, rows.length); (_a2 = this.refreshHints) != null && _a2.ignoreDiffsBefore && (from = Math.max( 0, Math.min(newRows.length, this.refreshHints.ignoreDiffsBefore) )), (_b2 = this.refreshHints) != null && _b2.ignoreDiffsAfter && (to = Math.min( newRows.length, Math.max(0, this.refreshHints.ignoreDiffsAfter) )); for (let i = from, rl = rows.length; i < to; i++) i >= rl ? diff[diff.length] = i : (item = newRows[i], r = rows[i], (!item || this.groupingInfos.length && (eitherIsNonData = item.__nonDataRow || r.__nonDataRow) && item.__group !== r.__group || item.__group && !item.equals(r) || eitherIsNonData && // no good way to compare totals since they are arbitrary DTOs // deep object comparison is pretty expensive // always considering them 'dirty' seems easier for the time being (item.__groupTotals || r.__groupTotals) || item[this.idProperty] !== r[this.idProperty] || (_c = this.updated) != null && _c[item[this.idProperty]]) && (diff[diff.length] = i)); return diff; } recalc(_items) { this.rowsById = void 0, (this.refreshHints.isFilterNarrowing !== this.prevRefreshHints.isFilterNarrowing || this.refreshHints.isFilterExpanding !== this.prevRefreshHints.isFilterExpanding) && (this.filterCache = []); let filteredItems = this.getFilteredAndPagedItems(_items); this.totalRows = filteredItems.totalRows; let newRows = filteredItems.rows; this.groups = [], this.groupingInfos.length && (this.groups = this.extractGroups(newRows), this.groups.length && (newRows = this.flattenGroupedRows(this.groups))); let diff = this.getRowDiffs(this.rows, newRows); return this.rows = newRows, diff; } refresh() { if (this.suspend) return; let previousPagingInfo = Utils.extend(!0, {}, this.getPagingInfo()), countBefore = this.rows.length, totalRowsBefore = this.totalRows, diff = this.recalc(this.items); this.pagesize && this.totalRows < this.pagenum * this.pagesize && (this.pagenum = Math.max(0, Math.ceil(this.totalRows / this.pagesize) - 1), diff = this.recalc(this.items)), this.updated = null, this.prevRefreshHints = this.refreshHints, this.refreshHints = {}, totalRowsBefore !== this.totalRows && this.onBeforePagingInfoChanged.notify(previousPagingInfo, null, this).getReturnValue() !== !1 && this.onPagingInfoChanged.notify(this.getPagingInfo(), null, this), countBefore !== this.rows.length && this.onRowCountChanged.notify({ previous: countBefore, current: this.rows.length, itemCount: this.items.length, dataView: this, callingOnRowsChanged: diff.length > 0 }, null, this), diff.length > 0 && this.onRowsChanged.notify({ rows: diff, itemCount: this.items.length, dataView: this, calledOnRowCountChanged: countBefore !== this.rows.length }, null, this), (countBefore !== this.rows.length || diff.length > 0) && this.onRowsOrCountChanged.notify({ rowsDiff: diff, previousRowCount: countBefore, currentRowCount: this.rows.length, itemCount: this.items.length, rowCountChanged: countBefore !== this.rows.length, rowsChanged: diff.length > 0, dataView: this }, null, this); } /** * Wires the grid and the DataView together to keep row selection tied to item ids. * This is useful since, without it, the grid only knows about rows, so if the items * move around, the same rows stay selected instead of the selection moving along * with the items. * * NOTE: This doesn't work with cell selection model. * * @param {SlickGrid} grid - The grid to sync selection with. * @param {Boolean} preserveHidden - Whether to keep selected items that go out of the * view due to them getting filtered out. * @param {Boolean} [preserveHiddenOnSelectionChange] - Whether to keep selected items * that are currently out of the view (see preserveHidden) as selected when selection * changes. * @return {Event} An event that notifies when an internal list of selected row ids * changes. This is useful since, in combination with the above two options, it allows * access to the full list selected row ids, and not just the ones visible to the grid. * @method syncGridSelection */ syncGridSelection(grid, preserveHidden, preserveHiddenOnSelectionChange) { this._grid = grid; let inHandler; this.selectedRowIds = this.mapRowsToIds(grid.getSelectedRows()); let setSelectedRowIds = (rowIds) => { rowIds === !1 ? this.selectedRowIds = [] : this.selectedRowIds.sort().join(",") !== rowIds.sort().join(",") && (this.selectedRowIds = rowIds); }, update = () => { if ((this.selectedRowIds || []).length > 0 && !inHandler) { inHandler = !0; let selectedRows = this.mapIdsToRows(this.selectedRowIds || []); if (!preserveHidden) { let selectedRowsChangedArgs = { grid: this._grid, ids: this.mapRowsToIds(selectedRows), rows: selectedRows, dataView: this }; this.preSelectedRowIdsChangeFn(selectedRowsChangedArgs), this.onSelectedRowIdsChanged.notify(Object.assign(selectedRowsChangedArgs, { selectedRowIds: this.selectedRowIds, filteredIds: this.getAllSelectedFilteredIds() }), new SlickEventData(), this); } grid.setSelectedRows(selectedRows), inHandler = !1; } }; return grid.onSelectedRowsChanged.subscribe((_e, args) => { if (!inHandler) { let newSelectedRowIds = this.mapRowsToIds(args.rows), selectedRowsChangedArgs = { grid: this._grid, ids: newSelectedRowIds, rows: args.rows, added: !0, dataView: this }; this.preSelectedRowIdsChangeFn(selectedRowsChangedArgs), this.onSelectedRowIdsChanged.notify(Object.assign(selectedRowsChangedArgs, { selectedRowIds: this.selectedRowIds, filteredIds: this.getAllSelectedFilteredIds() }), new SlickEventData(), this); } }), this.preSelectedRowIdsChangeFn = (args) => { var _a2, _b2; if (!inHandler) { if (inHandler = !0, typeof args.added == "undefined") setSelectedRowIds(args.ids); else { let rowIds; if (args.added) preserveHiddenOnSelectionChange && grid.getOptions().multiSelect ? rowIds = ((_a2 = this.selectedRowIds) == null ? void 0 : _a2.filter((id) => this.getRowById(id) === void 0)).concat(args.ids) : rowIds = args.ids; else if (preserveHiddenOnSelectionChange && grid.getOptions().multiSelect) { let argsIdsSet = new Set(args.ids); rowIds = (_b2 = this.selectedRowIds) == null ? void 0 : _b2.filter((id) => !argsIdsSet.has(id)); } else rowIds = []; setSelectedRowIds(rowIds); } inHandler = !1; } }, this.onRowsOrCountChanged.subscribe(update.bind(this)), this.onSelectedRowIdsChanged; } /** * Get all selected IDs * Note: when using Pagination it will also include hidden selections assuming `preserveHiddenOnSelectionChange` is set to true. */ getAllSelectedIds() { return this.selectedRowIds; } /** * Get all selected filtered IDs (similar to "getAllSelectedIds" but only return filtered data) * Note: when using Pagination it will also include hidden selections assuming `preserveHiddenOnSelectionChange` is set to true. */ getAllSelectedFilteredIds() { return this.getAllSelectedFilteredItems().map((item) => item[this.idProperty]); } /** * Set current row selected IDs array (regardless of Pagination) * NOTE: This will NOT change the selection in the grid, if you need to do that then you still need to call * "grid.setSelectedRows(rows)" * @param {Array} selectedIds - list of IDs which have been selected for this action * @param {Object} options * - `isRowBeingAdded`: defaults to true, are the new selected IDs being added (or removed) as new row selections * - `shouldTriggerEvent`: defaults to true, should we trigger `onSelectedRowIdsChanged` event * - `applyRowSelectionToGrid`: defaults to true, should we apply the row selections to the grid in the UI */ setSelectedIds(selectedIds, options) { var _a2; let isRowBeingAdded = options == null ? void 0 : options.isRowBeingAdded, shouldTriggerEvent = options == null ? void 0 : options.shouldTriggerEvent, applyRowSelectionToGrid = options == null ? void 0 : options.applyRowSelectionToGrid; isRowBeingAdded !== !1 && (isRowBeingAdded = !0); let selectedRows = this.mapIdsToRows(selectedIds), selectedRowsChangedArgs = { grid: this._grid, ids: selectedIds, rows: selectedRows, added: isRowBeingAdded, dataView: this }; (_a2 = this.preSelectedRowIdsChangeFn) == null || _a2.call(this, selectedRowsChangedArgs), shouldTriggerEvent !== !1 && this.onSelectedRowIdsChanged.notify(Object.assign(selectedRowsChangedArgs, { selectedRowIds: this.selectedRowIds, filteredIds: this.getAllSelectedFilteredIds() }), new SlickEventData(), this), applyRowSelectionToGrid !== !1 && this._grid && this._grid.setSelectedRows(selectedRows); } /** * Get all selected dataContext items * Note: when using Pagination it will also include hidden selections assuming `preserveHiddenOnSelectionChange` is set to true. */ getAllSelectedItems() { let selectedData = []; return this.getAllSelectedIds().forEach((id) => { selectedData.push(this.getItemById(id)); }), selectedData; } /** * Get all selected filtered dataContext items (similar to "getAllSelectedItems" but only return filtered data) * Note: when using Pagination it will also include hidden selections assuming `preserveHiddenOnSelectionChange` is set to true. */ getAllSelectedFilteredItems() { if (!Array.isArray(this.selectedRowIds)) return []; let selectedRowIdSet = new Set(this.selectedRowIds); return this.filteredItems.filter((a) => selectedRowIdSet.has(a[this.idProperty])) || []; } syncGridCellCssStyles(grid, key) { let hashById, inHandler, storeCellCssStyles = (hash) => { hashById = {}, typeof hash == "object" && Object.keys(hash).forEach((row) => { if (hash) { let id = this.rows[row][this.idProperty]; hashById[id] = hash[row]; } }); }; storeCellCssStyles(grid.getCellCssStyles(key)); let update = () => { if (typeof hashById == "object") { inHandler = !0, this.ensureRowsByIdCache(); let newHash = {}; Object.keys(hashById).forEach((id) => { var _a2; let row = (_a2 = this.rowsById) == null ? void 0 : _a2[id]; Utils.isDefined(row) && (newHash[row] = hashById[id]); }), grid.setCellCssStyles(key, newHash), inHandler = !1; } }; grid.onCellCssStylesChanged.subscribe((_e, args) => { inHandler || key === args.key && (args.hash ? storeCellCssStyles(args.hash) : (grid.onCellCssStylesChanged.unsubscribe(), this.onRowsOrCountChanged.unsubscribe(update))); }), this.onRowsOrCountChanged.subscribe(update.bind(this)); } }, AvgAggregator = class { constructor(field) { __publicField(this, "_nonNullCount", 0); __publicField(this, "_sum", 0); __publicField(this, "_field"); __publicField(this, "_type", "avg"); this._field = field; } get field() { return this._field; } get type() { return this._type; } init() { this._nonNullCount = 0, this._sum = 0; } accumulate(item) { let val = item != null && item.hasOwnProperty(this._field) ? item[this._field] : null; val !== null && val !== "" && !isNaN(val) && (this._nonNullCount++, this._sum += parseFloat(val)); } storeResult(groupTotals) { (!groupTotals || groupTotals[this._type] === void 0) && (groupTotals[this._type] = {}), this._nonNullCount !== 0 && (groupTotals[this._type][this._field] = this._sum / this._nonNullCount); } }, MinAggregator = class { constructor(field) { __publicField(this, "_min", null); __publicField(this, "_field"); __publicField(this, "_type", "min"); this._field = field; } get field() { return this._field; } get type() { return this._type; } init() { this._min = null; } accumulate(item) { let val = item != null && item.hasOwnProperty(this._field) ? item[this._field] : null; val !== null && val !== "" && !isNaN(val) && (this._min === null || val < this._min) && (this._min = parseFloat(val)); } storeResult(groupTotals) { (!groupTotals || groupTotals[this._type] === void 0) && (groupTotals[this._type] = {}), groupTotals[this._type][this._field] = this._min; } }, MaxAggregator = class { constructor(field) { __publicField(this, "_max", null); __publicField(this, "_field"); __publicField(this, "_type", "max"); this._field = field; } get field() { return this._field; } get type() { return this._type; } init() { this._max = null; } accumulate(item) { let val = item != null && item.hasOwnProperty(this._field) ? item[this._field] : null; val !== null && val !== "" && !isNaN(val) && (this._max === null || val > this._max) && (this._max = parseFloat(val)); } storeResult(groupTotals) { (!groupTotals || groupTotals[this._type] === void 0) && (groupTotals[this._type] = {}), groupTotals[this._type][this._field] = this._max; } }, SumAggregator = class { constructor(