slickgrid
Version:
A lightning fast JavaScript grid/spreadsheet
622 lines (621 loc) • 300 kB
JavaScript
"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.grid.ts
var BindingEventService = Slick.BindingEventService, ColAutosizeMode = Slick.ColAutosizeMode, SlickEvent = Slick.Event, SlickEventData = Slick.EventData, GlobalEditorLock = Slick.GlobalEditorLock, GridAutosizeColsMode = Slick.GridAutosizeColsMode, keyCode = Slick.keyCode, preClickClassName = Slick.preClickClassName, SlickRange = Slick.Range, RowSelectionMode = Slick.RowSelectionMode, ValueFilterMode = Slick.ValueFilterMode, Utils = Slick.Utils, WidthEvalMode = Slick.WidthEvalMode, Draggable = Slick.Draggable, MouseWheel = Slick.MouseWheel, Resizable = Slick.Resizable;
var SlickGrid = class {
/**
* Creates a new instance of the grid.
* @class SlickGrid
* @constructor
* @param {Node} container - Container node to create the grid in.
* @param {Array|Object} data - An array of objects for databinding or an external DataView.
* @param {Array<C>} columns - An array of column definitions.
* @param {Object} [options] - Grid Options
* @param {Object} [externalPubSub] - optional External PubSub Service to use by SlickEvent
**/
constructor(container, data, columns, options, externalPubSub) {
this.container = container;
this.data = data;
this.columns = columns;
this.externalPubSub = externalPubSub;
//////////////////////////////////////////////////////////////////////////////////////////////
// Public API
__publicField(this, "slickGridVersion", "5.15.5");
/** optional grid state clientId */
__publicField(this, "cid", "");
// Events
__publicField(this, "onActiveCellChanged");
__publicField(this, "onActiveCellPositionChanged");
__publicField(this, "onAddNewRow");
__publicField(this, "onAfterSetColumns");
__publicField(this, "onAutosizeColumns");
__publicField(this, "onBeforeAppendCell");
__publicField(this, "onBeforeCellEditorDestroy");
__publicField(this, "onBeforeColumnsResize");
__publicField(this, "onBeforeDestroy");
__publicField(this, "onBeforeEditCell");
__publicField(this, "onBeforeFooterRowCellDestroy");
__publicField(this, "onBeforeHeaderCellDestroy");
__publicField(this, "onBeforeHeaderRowCellDestroy");
__publicField(this, "onBeforeRemoveCachedRow");
__publicField(this, "onBeforeSetColumns");
__publicField(this, "onBeforeSort");
__publicField(this, "onBeforeUpdateColumns");
__publicField(this, "onCellChange");
__publicField(this, "onCellCssStylesChanged");
__publicField(this, "onClick");
__publicField(this, "onColumnsReordered");
__publicField(this, "onColumnsDrag");
__publicField(this, "onColumnsResized");
__publicField(this, "onColumnsResizeDblClick");
__publicField(this, "onCompositeEditorChange");
__publicField(this, "onContextMenu");
__publicField(this, "onDrag");
__publicField(this, "onDblClick");
__publicField(this, "onDragInit");
__publicField(this, "onDragStart");
__publicField(this, "onDragEnd");
__publicField(this, "onFooterClick");
__publicField(this, "onFooterContextMenu");
__publicField(this, "onFooterRowCellRendered");
__publicField(this, "onHeaderCellRendered");
__publicField(this, "onHeaderClick");
__publicField(this, "onHeaderContextMenu");
__publicField(this, "onHeaderMouseEnter");
__publicField(this, "onHeaderMouseLeave");
__publicField(this, "onHeaderRowCellRendered");
__publicField(this, "onHeaderRowMouseEnter");
__publicField(this, "onHeaderRowMouseLeave");
__publicField(this, "onPreHeaderContextMenu");
__publicField(this, "onPreHeaderClick");
__publicField(this, "onKeyDown");
__publicField(this, "onMouseEnter");
__publicField(this, "onMouseLeave");
__publicField(this, "onRendered");
__publicField(this, "onScroll");
__publicField(this, "onSelectedRowsChanged");
__publicField(this, "onSetOptions");
__publicField(this, "onActivateChangedOptions");
__publicField(this, "onSort");
__publicField(this, "onValidationError");
__publicField(this, "onViewportChanged");
// ---
// protected variables
// shared across all grids on the page
__publicField(this, "scrollbarDimensions");
__publicField(this, "maxSupportedCssHeight");
// browser's breaking point
__publicField(this, "canvas", null);
__publicField(this, "canvas_context", null);
// settings
__publicField(this, "_options");
__publicField(this, "_defaults", {
alwaysShowVerticalScroll: !1,
alwaysAllowHorizontalScroll: !1,
explicitInitialization: !1,
rowHeight: 25,
defaultColumnWidth: 80,
enableHtmlRendering: !0,
enableAddRow: !1,
leaveSpaceForNewRows: !1,
editable: !1,
autoEdit: !0,
autoEditNewRow: !0,
autoCommitEdit: !1,
suppressActiveCellChangeOnEdit: !1,
enableCellNavigation: !0,
enableColumnReorder: !0,
unorderableColumnCssClass: "unorderable",
asyncEditorLoading: !1,
asyncEditorLoadDelay: 100,
forceFitColumns: !1,
enableAsyncPostRender: !1,
asyncPostRenderDelay: 50,
enableAsyncPostRenderCleanup: !1,
asyncPostRenderCleanupDelay: 40,
auto: !1,
nonce: "",
editorLock: GlobalEditorLock,
showColumnHeader: !0,
showHeaderRow: !1,
headerRowHeight: 25,
createFooterRow: !1,
showFooterRow: !1,
footerRowHeight: 25,
createPreHeaderPanel: !1,
createTopHeaderPanel: !1,
showPreHeaderPanel: !1,
showTopHeaderPanel: !1,
preHeaderPanelHeight: 25,
showTopPanel: !1,
topPanelHeight: 25,
preHeaderPanelWidth: "auto",
// mostly useful for Draggable Grouping dropzone to take full width
topHeaderPanelHeight: 25,
topHeaderPanelWidth: "auto",
// mostly useful for Draggable Grouping dropzone to take full width
formatterFactory: null,
editorFactory: null,
cellFlashingCssClass: "flashing",
rowHighlightCssClass: "highlight-animate",
rowHighlightDuration: 400,
selectedCellCssClass: "selected",
multiSelect: !0,
enableCellRowSpan: !1,
enableTextSelectionOnCells: !1,
dataItemColumnValueExtractor: null,
frozenBottom: !1,
frozenColumn: -1,
frozenRow: -1,
frozenRightViewportMinWidth: 100,
throwWhenFrozenNotAllViewable: !1,
fullWidthRows: !1,
multiColumnSort: !1,
numberedMultiColumnSort: !1,
tristateMultiColumnSort: !1,
sortColNumberInSeparateSpan: !1,
defaultFormatter: this.defaultFormatter,
forceSyncScrolling: !1,
addNewRowCssClass: "new-row",
preserveCopiedSelectionOnPaste: !1,
preventDragFromKeys: ["ctrlKey", "metaKey"],
showCellSelection: !0,
viewportClass: void 0,
minRowBuffer: 3,
emulatePagingWhenScrolling: !0,
// when scrolling off bottom of viewport, place new row at top of viewport
editorCellNavOnLRKeys: !1,
enableMouseWheelScrollHandler: !0,
doPaging: !0,
autosizeColsMode: GridAutosizeColsMode.LegacyOff,
autosizeColPaddingPx: 4,
rowTopOffsetRenderType: "top",
scrollRenderThrottling: 10,
autosizeTextAvgToMWidthRatio: 0.75,
viewportSwitchToScrollModeWidthPercent: void 0,
viewportMinWidthPx: void 0,
viewportMaxWidthPx: void 0,
suppressCssChangesOnHiddenInit: !1,
ffMaxSupportedCssHeight: 6e6,
maxSupportedCssHeight: 1e9,
maxPartialRowSpanRemap: 5e3,
sanitizer: void 0,
// sanitize function, built in basic sanitizer is: Slick.RegexSanitizer(dirtyHtml)
logSanitizedHtml: !1,
// log to console when sanitised - recommend true for testing of dev and production
mixinDefaults: !0,
shadowRoot: void 0
});
__publicField(this, "_columnDefaults", {
name: "",
headerCssClass: null,
defaultSortAsc: !0,
focusable: !0,
hidden: !1,
minWidth: 30,
maxWidth: void 0,
rerenderOnResize: !1,
reorderable: !0,
resizable: !0,
sortable: !1,
selectable: !0
});
__publicField(this, "_columnAutosizeDefaults", {
ignoreHeaderText: !1,
colValueArray: void 0,
allowAddlPercent: void 0,
formatterOverride: void 0,
autosizeMode: ColAutosizeMode.ContentIntelligent,
rowSelectionModeOnInit: void 0,
rowSelectionMode: RowSelectionMode.FirstNRows,
rowSelectionCount: 100,
valueFilterMode: ValueFilterMode.None,
widthEvalMode: WidthEvalMode.Auto,
sizeToRemaining: void 0,
widthPx: void 0,
contentSizePx: 0,
headerWidthPx: 0,
colDataTypeOf: void 0
});
__publicField(this, "_columnResizeTimer");
__publicField(this, "_executionBlockTimer");
__publicField(this, "_flashCellTimer");
__publicField(this, "_highlightRowTimer");
// scroller
__publicField(this, "th");
// virtual height
__publicField(this, "h");
// real scrollable height
__publicField(this, "ph");
// page height
__publicField(this, "n");
// number of pages
__publicField(this, "cj");
// "jumpiness" coefficient
__publicField(this, "page", 0);
// current page
__publicField(this, "offset", 0);
// current page offset
__publicField(this, "vScrollDir", 1);
__publicField(this, "_bindingEventService", new BindingEventService());
__publicField(this, "initialized", !1);
__publicField(this, "_container");
__publicField(this, "uid", `slickgrid_${Math.round(1e6 * Math.random())}`);
__publicField(this, "_focusSink");
__publicField(this, "_focusSink2");
__publicField(this, "_groupHeaders", []);
__publicField(this, "_headerScroller", []);
__publicField(this, "_headers", []);
__publicField(this, "_headerRows");
__publicField(this, "_headerRowScroller");
__publicField(this, "_headerRowSpacerL");
__publicField(this, "_headerRowSpacerR");
__publicField(this, "_footerRow");
__publicField(this, "_footerRowScroller");
__publicField(this, "_footerRowSpacerL");
__publicField(this, "_footerRowSpacerR");
__publicField(this, "_preHeaderPanel");
__publicField(this, "_preHeaderPanelScroller");
__publicField(this, "_preHeaderPanelSpacer");
__publicField(this, "_preHeaderPanelR");
__publicField(this, "_preHeaderPanelScrollerR");
__publicField(this, "_preHeaderPanelSpacerR");
__publicField(this, "_topHeaderPanel");
__publicField(this, "_topHeaderPanelScroller");
__publicField(this, "_topHeaderPanelSpacer");
__publicField(this, "_topPanelScrollers");
__publicField(this, "_topPanels");
__publicField(this, "_viewport");
__publicField(this, "_canvas");
__publicField(this, "_style");
__publicField(this, "_boundAncestors", []);
__publicField(this, "stylesheet");
__publicField(this, "columnCssRulesL");
__publicField(this, "columnCssRulesR");
__publicField(this, "viewportH", 0);
__publicField(this, "viewportW", 0);
__publicField(this, "canvasWidth", 0);
__publicField(this, "canvasWidthL", 0);
__publicField(this, "canvasWidthR", 0);
__publicField(this, "headersWidth", 0);
__publicField(this, "headersWidthL", 0);
__publicField(this, "headersWidthR", 0);
__publicField(this, "viewportHasHScroll", !1);
__publicField(this, "viewportHasVScroll", !1);
__publicField(this, "headerColumnWidthDiff", 0);
__publicField(this, "headerColumnHeightDiff", 0);
// border+padding
__publicField(this, "cellWidthDiff", 0);
__publicField(this, "cellHeightDiff", 0);
__publicField(this, "absoluteColumnMinWidth");
__publicField(this, "hasFrozenRows", !1);
__publicField(this, "frozenRowsHeight", 0);
__publicField(this, "actualFrozenRow", -1);
__publicField(this, "paneTopH", 0);
__publicField(this, "paneBottomH", 0);
__publicField(this, "viewportTopH", 0);
__publicField(this, "viewportBottomH", 0);
__publicField(this, "topPanelH", 0);
__publicField(this, "headerRowH", 0);
__publicField(this, "footerRowH", 0);
__publicField(this, "tabbingDirection", 1);
__publicField(this, "_activeCanvasNode");
__publicField(this, "_activeViewportNode");
__publicField(this, "activePosX");
__publicField(this, "activePosY");
__publicField(this, "activeRow");
__publicField(this, "activeCell");
__publicField(this, "activeCellNode", null);
__publicField(this, "currentEditor", null);
__publicField(this, "serializedEditorValue");
__publicField(this, "editController");
__publicField(this, "_prevDataLength", 0);
__publicField(this, "_prevInvalidatedRowsCount", 0);
__publicField(this, "_rowSpanIsCached", !1);
__publicField(this, "_colsWithRowSpanCache", {});
__publicField(this, "rowsCache", {});
__publicField(this, "renderedRows", 0);
__publicField(this, "numVisibleRows", 0);
__publicField(this, "prevScrollTop", 0);
__publicField(this, "scrollHeight", 0);
__publicField(this, "scrollTop", 0);
__publicField(this, "lastRenderedScrollTop", 0);
__publicField(this, "lastRenderedScrollLeft", 0);
__publicField(this, "prevScrollLeft", 0);
__publicField(this, "scrollLeft", 0);
__publicField(this, "selectionModel");
__publicField(this, "selectedRows", []);
__publicField(this, "plugins", []);
__publicField(this, "cellCssClasses", {});
__publicField(this, "columnsById", {});
__publicField(this, "sortColumns", []);
__publicField(this, "columnPosLeft", []);
__publicField(this, "columnPosRight", []);
__publicField(this, "pagingActive", !1);
__publicField(this, "pagingIsLastPage", !1);
__publicField(this, "scrollThrottle");
// async call handles
__publicField(this, "h_editorLoader");
__publicField(this, "h_postrender");
__publicField(this, "h_postrenderCleanup");
__publicField(this, "postProcessedRows", {});
__publicField(this, "postProcessToRow", null);
__publicField(this, "postProcessFromRow", null);
__publicField(this, "postProcessedCleanupQueue", []);
__publicField(this, "postProcessgroupId", 0);
// perf counters
__publicField(this, "counter_rows_rendered", 0);
__publicField(this, "counter_rows_removed", 0);
__publicField(this, "_paneHeaderL");
__publicField(this, "_paneHeaderR");
__publicField(this, "_paneTopL");
__publicField(this, "_paneTopR");
__publicField(this, "_paneBottomL");
__publicField(this, "_paneBottomR");
__publicField(this, "_headerScrollerL");
__publicField(this, "_headerScrollerR");
__publicField(this, "_headerL");
__publicField(this, "_headerR");
__publicField(this, "_groupHeadersL");
__publicField(this, "_groupHeadersR");
__publicField(this, "_headerRowScrollerL");
__publicField(this, "_headerRowScrollerR");
__publicField(this, "_footerRowScrollerL");
__publicField(this, "_footerRowScrollerR");
__publicField(this, "_headerRowL");
__publicField(this, "_headerRowR");
__publicField(this, "_footerRowL");
__publicField(this, "_footerRowR");
__publicField(this, "_topPanelScrollerL");
__publicField(this, "_topPanelScrollerR");
__publicField(this, "_topPanelL");
__publicField(this, "_topPanelR");
__publicField(this, "_viewportTopL");
__publicField(this, "_viewportTopR");
__publicField(this, "_viewportBottomL");
__publicField(this, "_viewportBottomR");
__publicField(this, "_canvasTopL");
__publicField(this, "_canvasTopR");
__publicField(this, "_canvasBottomL");
__publicField(this, "_canvasBottomR");
__publicField(this, "_viewportScrollContainerX");
__publicField(this, "_viewportScrollContainerY");
__publicField(this, "_headerScrollContainer");
__publicField(this, "_headerRowScrollContainer");
__publicField(this, "_footerRowScrollContainer");
// store css attributes if display:none is active in container or parent
__publicField(this, "cssShow", { position: "absolute", visibility: "hidden", display: "block" });
__publicField(this, "_hiddenParents", []);
__publicField(this, "oldProps", []);
__publicField(this, "enforceFrozenRowHeightRecalc", !1);
__publicField(this, "columnResizeDragging", !1);
__publicField(this, "slickDraggableInstance", null);
__publicField(this, "slickMouseWheelInstances", []);
__publicField(this, "slickResizableInstances", []);
__publicField(this, "sortableSideLeftInstance");
__publicField(this, "sortableSideRightInstance");
__publicField(this, "logMessageCount", 0);
__publicField(this, "logMessageMaxCount", 30);
__publicField(this, "_pubSubService");
if (this._container = typeof this.container == "string" ? document.querySelector(this.container) : this.container, !this._container)
throw new Error(`SlickGrid requires a valid container, ${this.container} does not exist in the DOM.`);
this._pubSubService = externalPubSub, this.onActiveCellChanged = new SlickEvent("onActiveCellChanged", externalPubSub), this.onActiveCellPositionChanged = new SlickEvent("onActiveCellPositionChanged", externalPubSub), this.onAddNewRow = new SlickEvent("onAddNewRow", externalPubSub), this.onAfterSetColumns = new SlickEvent("onAfterSetColumns", externalPubSub), this.onAutosizeColumns = new SlickEvent("onAutosizeColumns", externalPubSub), this.onBeforeAppendCell = new SlickEvent("onBeforeAppendCell", externalPubSub), this.onBeforeCellEditorDestroy = new SlickEvent("onBeforeCellEditorDestroy", externalPubSub), this.onBeforeColumnsResize = new SlickEvent("onBeforeColumnsResize", externalPubSub), this.onBeforeDestroy = new SlickEvent("onBeforeDestroy", externalPubSub), this.onBeforeEditCell = new SlickEvent("onBeforeEditCell", externalPubSub), this.onBeforeFooterRowCellDestroy = new SlickEvent("onBeforeFooterRowCellDestroy", externalPubSub), this.onBeforeHeaderCellDestroy = new SlickEvent("onBeforeHeaderCellDestroy", externalPubSub), this.onBeforeHeaderRowCellDestroy = new SlickEvent("onBeforeHeaderRowCellDestroy", externalPubSub), this.onBeforeRemoveCachedRow = new SlickEvent("onRowRemovedFromCache", externalPubSub), this.onBeforeSetColumns = new SlickEvent("onBeforeSetColumns", externalPubSub), this.onBeforeSort = new SlickEvent("onBeforeSort", externalPubSub), this.onBeforeUpdateColumns = new SlickEvent("onBeforeUpdateColumns", externalPubSub), this.onCellChange = new SlickEvent("onCellChange", externalPubSub), this.onCellCssStylesChanged = new SlickEvent("onCellCssStylesChanged", externalPubSub), this.onClick = new SlickEvent("onClick", externalPubSub), this.onColumnsReordered = new SlickEvent("onColumnsReordered", externalPubSub), this.onColumnsDrag = new SlickEvent("onColumnsDrag", externalPubSub), this.onColumnsResized = new SlickEvent("onColumnsResized", externalPubSub), this.onColumnsResizeDblClick = new SlickEvent("onColumnsResizeDblClick", externalPubSub), this.onCompositeEditorChange = new SlickEvent("onCompositeEditorChange", externalPubSub), this.onContextMenu = new SlickEvent("onContextMenu", externalPubSub), this.onDrag = new SlickEvent("onDrag", externalPubSub), this.onDblClick = new SlickEvent("onDblClick", externalPubSub), this.onDragInit = new SlickEvent("onDragInit", externalPubSub), this.onDragStart = new SlickEvent("onDragStart", externalPubSub), this.onDragEnd = new SlickEvent("onDragEnd", externalPubSub), this.onFooterClick = new SlickEvent("onFooterClick", externalPubSub), this.onFooterContextMenu = new SlickEvent("onFooterContextMenu", externalPubSub), this.onFooterRowCellRendered = new SlickEvent("onFooterRowCellRendered", externalPubSub), this.onHeaderCellRendered = new SlickEvent("onHeaderCellRendered", externalPubSub), this.onHeaderClick = new SlickEvent("onHeaderClick", externalPubSub), this.onHeaderContextMenu = new SlickEvent("onHeaderContextMenu", externalPubSub), this.onHeaderMouseEnter = new SlickEvent("onHeaderMouseEnter", externalPubSub), this.onHeaderMouseLeave = new SlickEvent("onHeaderMouseLeave", externalPubSub), this.onHeaderRowCellRendered = new SlickEvent("onHeaderRowCellRendered", externalPubSub), this.onHeaderRowMouseEnter = new SlickEvent("onHeaderRowMouseEnter", externalPubSub), this.onHeaderRowMouseLeave = new SlickEvent("onHeaderRowMouseLeave", externalPubSub), this.onPreHeaderClick = new SlickEvent("onPreHeaderClick", externalPubSub), this.onPreHeaderContextMenu = new SlickEvent("onPreHeaderContextMenu", externalPubSub), this.onKeyDown = new SlickEvent("onKeyDown", externalPubSub), this.onMouseEnter = new SlickEvent("onMouseEnter", externalPubSub), this.onMouseLeave = new SlickEvent("onMouseLeave", externalPubSub), this.onRendered = new SlickEvent("onRendered", externalPubSub), this.onScroll = new SlickEvent("onScroll", externalPubSub), this.onSelectedRowsChanged = new SlickEvent("onSelectedRowsChanged", externalPubSub), this.onSetOptions = new SlickEvent("onSetOptions", externalPubSub), this.onActivateChangedOptions = new SlickEvent("onActivateChangedOptions", externalPubSub), this.onSort = new SlickEvent("onSort", externalPubSub), this.onValidationError = new SlickEvent("onValidationError", externalPubSub), this.onViewportChanged = new SlickEvent("onViewportChanged", externalPubSub), this.initialize(options);
}
//////////////////////////////////////////////////////////////////////////////////////////////
// Grid and Dom Initialisation
//////////////////////////////////////////////////////////////////////////////////////////////
/** Initializes the grid. */
init() {
this.finishInitialization();
}
/**
* Processes the provided grid options (mixing in default settings as needed),
* validates required modules (for example, ensuring Sortable.js is loaded if column reordering is enabled),
* and creates all necessary DOM elements for the grid (including header containers, viewports, canvases, panels, etc.).
* It also caches CSS if the container or its ancestors are hidden and calls finish.
*
* @param {Partial<O>} options - Partial grid options to be applied during initialization.
*/
initialize(options) {
if (options != null && options.mixinDefaults ? (this._options || (this._options = options), Utils.applyDefaults(this._options, this._defaults)) : this._options = Utils.extend(!0, {}, this._defaults, options), this.scrollThrottle = this.actionThrottle(this.render.bind(this), this._options.scrollRenderThrottling), this.maxSupportedCssHeight = this.maxSupportedCssHeight || this.getMaxSupportedCssHeight(), this.validateAndEnforceOptions(), this._columnDefaults.width = this._options.defaultColumnWidth, this._options.suppressCssChangesOnHiddenInit || this.cacheCssForHiddenInit(), this.updateColumnProps(), this._options.enableColumnReorder && (!Sortable || !Sortable.create))
throw new Error("SlickGrid requires Sortable.js module to be loaded");
this.editController = {
commitCurrentEdit: this.commitCurrentEdit.bind(this),
cancelCurrentEdit: this.cancelCurrentEdit.bind(this)
}, Utils.emptyElement(this._container), this._container.style.outline = String(0), this._container.classList.add(this.uid), this._container.classList.add("ui-widget"), this._container.setAttribute("role", "grid");
let containerStyles = window.getComputedStyle(this._container);
/relative|absolute|fixed/.test(containerStyles.position) || (this._container.style.position = "relative"), this._focusSink = Utils.createDomElement("div", { tabIndex: 0, style: { position: "fixed", width: "0px", height: "0px", top: "0px", left: "0px", outline: "0px" } }, this._container), this._options.createTopHeaderPanel && (this._topHeaderPanelScroller = Utils.createDomElement("div", { className: "slick-topheader-panel slick-state-default", style: { overflow: "hidden", position: "relative" } }, this._container), this._topHeaderPanelScroller.appendChild(document.createElement("div")), this._topHeaderPanel = Utils.createDomElement("div", null, this._topHeaderPanelScroller), this._topHeaderPanelSpacer = Utils.createDomElement("div", { style: { display: "block", height: "1px", position: "absolute", top: "0px", left: "0px" } }, this._topHeaderPanelScroller), this._options.showTopHeaderPanel || Utils.hide(this._topHeaderPanelScroller)), this._paneHeaderL = Utils.createDomElement("div", { className: "slick-pane slick-pane-header slick-pane-left", tabIndex: 0 }, this._container), this._paneHeaderR = Utils.createDomElement("div", { className: "slick-pane slick-pane-header slick-pane-right", tabIndex: 0 }, this._container), this._paneTopL = Utils.createDomElement("div", { className: "slick-pane slick-pane-top slick-pane-left", tabIndex: 0 }, this._container), this._paneTopR = Utils.createDomElement("div", { className: "slick-pane slick-pane-top slick-pane-right", tabIndex: 0 }, this._container), this._paneBottomL = Utils.createDomElement("div", { className: "slick-pane slick-pane-bottom slick-pane-left", tabIndex: 0 }, this._container), this._paneBottomR = Utils.createDomElement("div", { className: "slick-pane slick-pane-bottom slick-pane-right", tabIndex: 0 }, this._container), this._options.createPreHeaderPanel && (this._preHeaderPanelScroller = Utils.createDomElement("div", { className: "slick-preheader-panel ui-state-default slick-state-default", style: { overflow: "hidden", position: "relative" } }, this._paneHeaderL), this._preHeaderPanelScroller.appendChild(document.createElement("div")), this._preHeaderPanel = Utils.createDomElement("div", null, this._preHeaderPanelScroller), this._preHeaderPanelSpacer = Utils.createDomElement("div", { style: { display: "block", height: "1px", position: "absolute", top: "0px", left: "0px" } }, this._preHeaderPanelScroller), this._preHeaderPanelScrollerR = Utils.createDomElement("div", { className: "slick-preheader-panel ui-state-default slick-state-default", style: { overflow: "hidden", position: "relative" } }, this._paneHeaderR), this._preHeaderPanelR = Utils.createDomElement("div", null, this._preHeaderPanelScrollerR), this._preHeaderPanelSpacerR = Utils.createDomElement("div", { style: { display: "block", height: "1px", position: "absolute", top: "0px", left: "0px" } }, this._preHeaderPanelScrollerR), this._options.showPreHeaderPanel || (Utils.hide(this._preHeaderPanelScroller), Utils.hide(this._preHeaderPanelScrollerR))), this._headerScrollerL = Utils.createDomElement("div", { className: "slick-header ui-state-default slick-state-default slick-header-left" }, this._paneHeaderL), this._headerScrollerR = Utils.createDomElement("div", { className: "slick-header ui-state-default slick-state-default slick-header-right" }, this._paneHeaderR), this._headerScroller.push(this._headerScrollerL), this._headerScroller.push(this._headerScrollerR), this._headerL = Utils.createDomElement("div", { className: "slick-header-columns slick-header-columns-left", role: "row", style: { left: "-1000px" } }, this._headerScrollerL), this._headerR = Utils.createDomElement("div", { className: "slick-header-columns slick-header-columns-right", role: "row", style: { left: "-1000px" } }, this._headerScrollerR), this._headers = [this._headerL, this._headerR], this._headerRowScrollerL = Utils.createDomElement("div", { className: "slick-headerrow ui-state-default slick-state-default" }, this._paneTopL), this._headerRowScrollerR = Utils.createDomElement("div", { className: "slick-headerrow ui-state-default slick-state-default" }, this._paneTopR), this._headerRowScroller = [this._headerRowScrollerL, this._headerRowScrollerR], this._headerRowSpacerL = Utils.createDomElement("div", { style: { display: "block", height: "1px", position: "absolute", top: "0px", left: "0px" } }, this._headerRowScrollerL), this._headerRowSpacerR = Utils.createDomElement("div", { style: { display: "block", height: "1px", position: "absolute", top: "0px", left: "0px" } }, this._headerRowScrollerR), this._headerRowL = Utils.createDomElement("div", { className: "slick-headerrow-columns slick-headerrow-columns-left" }, this._headerRowScrollerL), this._headerRowR = Utils.createDomElement("div", { className: "slick-headerrow-columns slick-headerrow-columns-right" }, this._headerRowScrollerR), this._headerRows = [this._headerRowL, this._headerRowR], this._topPanelScrollerL = Utils.createDomElement("div", { className: "slick-top-panel-scroller ui-state-default slick-state-default" }, this._paneTopL), this._topPanelScrollerR = Utils.createDomElement("div", { className: "slick-top-panel-scroller ui-state-default slick-state-default" }, this._paneTopR), this._topPanelScrollers = [this._topPanelScrollerL, this._topPanelScrollerR], this._topPanelL = Utils.createDomElement("div", { className: "slick-top-panel", style: { width: "10000px" } }, this._topPanelScrollerL), this._topPanelR = Utils.createDomElement("div", { className: "slick-top-panel", style: { width: "10000px" } }, this._topPanelScrollerR), this._topPanels = [this._topPanelL, this._topPanelR], this._options.showColumnHeader || this._headerScroller.forEach((el) => {
Utils.hide(el);
}), this._options.showTopPanel || this._topPanelScrollers.forEach((scroller) => {
Utils.hide(scroller);
}), this._options.showHeaderRow || this._headerRowScroller.forEach((scroller) => {
Utils.hide(scroller);
}), this._viewportTopL = Utils.createDomElement("div", { className: "slick-viewport slick-viewport-top slick-viewport-left", tabIndex: 0 }, this._paneTopL), this._viewportTopR = Utils.createDomElement("div", { className: "slick-viewport slick-viewport-top slick-viewport-right", tabIndex: 0 }, this._paneTopR), this._viewportBottomL = Utils.createDomElement("div", { className: "slick-viewport slick-viewport-bottom slick-viewport-left", tabIndex: 0 }, this._paneBottomL), this._viewportBottomR = Utils.createDomElement("div", { className: "slick-viewport slick-viewport-bottom slick-viewport-right", tabIndex: 0 }, this._paneBottomR), this._viewport = [this._viewportTopL, this._viewportTopR, this._viewportBottomL, this._viewportBottomR], this._options.viewportClass && this._viewport.forEach((view) => {
view.classList.add(...Utils.classNameToList(this._options.viewportClass));
}), this._activeViewportNode = this._viewportTopL, this._canvasTopL = Utils.createDomElement("div", { className: "grid-canvas grid-canvas-top grid-canvas-left", tabIndex: 0 }, this._viewportTopL), this._canvasTopR = Utils.createDomElement("div", { className: "grid-canvas grid-canvas-top grid-canvas-right", tabIndex: 0 }, this._viewportTopR), this._canvasBottomL = Utils.createDomElement("div", { className: "grid-canvas grid-canvas-bottom grid-canvas-left", tabIndex: 0 }, this._viewportBottomL), this._canvasBottomR = Utils.createDomElement("div", { className: "grid-canvas grid-canvas-bottom grid-canvas-right", tabIndex: 0 }, this._viewportBottomR), this._canvas = [this._canvasTopL, this._canvasTopR, this._canvasBottomL, this._canvasBottomR], this.scrollbarDimensions = this.scrollbarDimensions || this.measureScrollbar();
let canvasWithScrollbarWidth = this.getCanvasWidth() + this.scrollbarDimensions.width;
this._activeCanvasNode = this._canvasTopL, this._topHeaderPanelSpacer && Utils.width(this._topHeaderPanelSpacer, canvasWithScrollbarWidth), this._preHeaderPanelSpacer && Utils.width(this._preHeaderPanelSpacer, canvasWithScrollbarWidth), this._headers.forEach((el) => {
Utils.width(el, this.getHeadersWidth());
}), Utils.width(this._headerRowSpacerL, canvasWithScrollbarWidth), Utils.width(this._headerRowSpacerR, canvasWithScrollbarWidth), this._options.createFooterRow && (this._footerRowScrollerR = Utils.createDomElement("div", { className: "slick-footerrow ui-state-default slick-state-default" }, this._paneTopR), this._footerRowScrollerL = Utils.createDomElement("div", { className: "slick-footerrow ui-state-default slick-state-default" }, this._paneTopL), this._footerRowScroller = [this._footerRowScrollerL, this._footerRowScrollerR], this._footerRowSpacerL = Utils.createDomElement("div", { style: { display: "block", height: "1px", position: "absolute", top: "0px", left: "0px" } }, this._footerRowScrollerL), Utils.width(this._footerRowSpacerL, canvasWithScrollbarWidth), this._footerRowSpacerR = Utils.createDomElement("div", { style: { display: "block", height: "1px", position: "absolute", top: "0px", left: "0px" } }, this._footerRowScrollerR), Utils.width(this._footerRowSpacerR, canvasWithScrollbarWidth), this._footerRowL = Utils.createDomElement("div", { className: "slick-footerrow-columns slick-footerrow-columns-left" }, this._footerRowScrollerL), this._footerRowR = Utils.createDomElement("div", { className: "slick-footerrow-columns slick-footerrow-columns-right" }, this._footerRowScrollerR), this._footerRow = [this._footerRowL, this._footerRowR], this._options.showFooterRow || this._footerRowScroller.forEach((scroller) => {
Utils.hide(scroller);
})), this._focusSink2 = this._focusSink.cloneNode(!0), this._container.appendChild(this._focusSink2), this._options.explicitInitialization || this.finishInitialization();
}
/**
* Completes grid initialisation by calculating viewport dimensions, measuring cell padding and border differences,
* disabling text selection (except on editable inputs), setting frozen options and pane visibility,
* updating column caches, creating column headers and footers, setting up column sorting,
* creating CSS rules, binding ancestor scroll events, and binding various event handlers
* (e.g. for scrolling, mouse, keyboard, drag-and-drop).
* It also starts up any asynchronous post–render processing if enabled.
*/
finishInitialization() {
this.initialized || (this.initialized = !0, this.getViewportWidth(), this.getViewportHeight(), this.measureCellPaddingAndBorder(), this.disableSelection(this._headers), this._options.enableTextSelectionOnCells || this._viewport.forEach((view) => {
this._bindingEventService.bind(view, "selectstart", (event) => {
event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement;
});
}), this.setFrozenOptions(), this.setPaneFrozenClasses(), this.setPaneVisibility(), this.setScroller(), this.setOverflow(), this.updateColumnCaches(), this.createColumnHeaders(), this.createColumnFooter(), this.setupColumnSort(), this.createCssRules(), this.resizeCanvas(), this.bindAncestorScrollEvents(), this._bindingEventService.bind(this._container, "resize", this.resizeCanvas.bind(this)), this._viewport.forEach((view) => {
this._bindingEventService.bind(view, "scroll", this.handleScroll.bind(this));
}), this._options.enableMouseWheelScrollHandler && this._viewport.forEach((view) => {
this.slickMouseWheelInstances.push(MouseWheel({
element: view,
onMouseWheel: this.handleMouseWheel.bind(this)
}));
}), this._headerScroller.forEach((el) => {
this._bindingEventService.bind(el, "contextmenu", this.handleHeaderContextMenu.bind(this)), this._bindingEventService.bind(el, "click", this.handleHeaderClick.bind(this));
}), this._headerRowScroller.forEach((scroller) => {
this._bindingEventService.bind(scroller, "scroll", this.handleHeaderRowScroll.bind(this));
}), this._options.createFooterRow && (this._footerRow.forEach((footer) => {
this._bindingEventService.bind(footer, "contextmenu", this.handleFooterContextMenu.bind(this)), this._bindingEventService.bind(footer, "click", this.handleFooterClick.bind(this));
}), this._footerRowScroller.forEach((scroller) => {
this._bindingEventService.bind(scroller, "scroll", this.handleFooterRowScroll.bind(this));
})), this._options.createTopHeaderPanel && this._bindingEventService.bind(this._topHeaderPanelScroller, "scroll", this.handleTopHeaderPanelScroll.bind(this)), this._options.createPreHeaderPanel && (this._bindingEventService.bind(this._preHeaderPanelScroller, "scroll", this.handlePreHeaderPanelScroll.bind(this)), this._bindingEventService.bind(this._preHeaderPanelScroller, "contextmenu", this.handlePreHeaderContextMenu.bind(this)), this._bindingEventService.bind(this._preHeaderPanelScrollerR, "contextmenu", this.handlePreHeaderContextMenu.bind(this)), this._bindingEventService.bind(this._preHeaderPanelScroller, "click", this.handlePreHeaderClick.bind(this)), this._bindingEventService.bind(this._preHeaderPanelScrollerR, "click", this.handlePreHeaderClick.bind(this))), this._bindingEventService.bind(this._focusSink, "keydown", this.handleKeyDown.bind(this)), this._bindingEventService.bind(this._focusSink2, "keydown", this.handleKeyDown.bind(this)), this._canvas.forEach((element) => {
this._bindingEventService.bind(element, "keydown", this.handleKeyDown.bind(this)), this._bindingEventService.bind(element, "click", this.handleClick.bind(this)), this._bindingEventService.bind(element, "dblclick", this.handleDblClick.bind(this)), this._bindingEventService.bind(element, "contextmenu", this.handleContextMenu.bind(this)), this._bindingEventService.bind(element, "mouseover", this.handleCellMouseOver.bind(this)), this._bindingEventService.bind(element, "mouseout", this.handleCellMouseOut.bind(this));
}), Draggable && (this.slickDraggableInstance = Draggable({
containerElement: this._container,
allowDragFrom: "div.slick-cell",
// the slick cell parent must always contain `.dnd` and/or `.cell-reorder` class to be identified as draggable
allowDragFromClosest: "div.slick-cell.dnd, div.slick-cell.cell-reorder",
preventDragFromKeys: this._options.preventDragFromKeys,
onDragInit: this.handleDragInit.bind(this),
onDragStart: this.handleDragStart.bind(this),
onDrag: this.handleDrag.bind(this),
onDragEnd: this.handleDragEnd.bind(this)
})), this._options.suppressCssChangesOnHiddenInit || this.restoreCssFromHiddenInit());
}
/**
* Finds all container ancestors/parents (including the grid container itself) that are hidden (i.e. have display:none)
* and temporarily applies visible CSS properties (absolute positioning, hidden visibility, block display)
* so that dimensions can be measured correctly.
* It stores the original CSS properties in an internal array for later restoration.
*
* Related to issue: https://github.com/6pac/SlickGrid/issues/568 */
cacheCssForHiddenInit() {
this._hiddenParents = Utils.parents(this._container, ":hidden"), this.oldProps = [], this._hiddenParents.forEach((el) => {
let old = {};
Object.keys(this.cssShow).forEach((name) => {
this.cssShow && (old[name] = el.style[name], el.style[name] = this.cssShow[name]);
}), this.oldProps.push(old);
});
}
/**
* Restores the original CSS properties for the container and its hidden
* ancestors that were modified by cacheCssForHiddenInit.
* This ensures that after initial measurements the DOM elements revert
* to their original style settings.
*/
restoreCssFromHiddenInit() {
let i = 0;
this._hiddenParents && (this._hiddenParents.forEach((el) => {
let old = this.oldProps[i++];
Object.keys(this.cssShow).forEach((name) => {
this.cssShow && (el.style[name] = old[name]);
});
}), this._hiddenParents = []);
}
/**
* Registers an external plugin to the grid’s internal plugin list.
* Once added, it immediately initialises the plugin by calling its init()
* method with the grid instance.
* @param {T} plugin - The plugin instance to be registered.
*/
registerPlugin(plugin) {
this.plugins.unshift(plugin), plugin.init(this);
}
/**
* Unregister (destroy) an external Plugin.
* Searches for the specified plugin in the grid’s plugin list.
* When found, it calls the plugin’s destroy() method and removes the plugin from the list,
* thereby unregistering it from the grid.
* @param {T} plugin - The plugin instance to be registered.
*/
unregisterPlugin(plugin) {
var _a;
for (let i = this.plugins.length; i >= 0; i--)
if (this.plugins[i] === plugin) {
(_a = this.plugins[i]) == null || _a.destroy(), this.plugins.splice(i, 1);
break;
}
}
/**
* Destroy (dispose) of SlickGrid
*
* Unbinds all event handlers, cancels any active cell edits, triggers the onBeforeDestroy event,
* unregisters and destroys plugins, destroys sortable and other interaction instances,
* unbinds ancestor scroll events, removes CSS rules, unbinds events from all key DOM elements
* (canvas, viewports, header, footer, etc.), empties the grid container, removes the grid’s uid class,
* and clears all timers. Optionally, if shouldDestroyAllElements is true,
* calls destroyAllElements to nullify all DOM references.
*
* @param {boolean} shouldDestroyAllElements - do we want to destroy (nullify) all DOM elements as well? This help in avoiding mem leaks
*/
destroy(shouldDestroyAllElements) {
var _a, _b, _c, _d;
this._bindingEventService.unbindAll(), this.slickDraggableInstance = this.destroyAllInstances(this.slickDraggableInstance), this.slickMouseWheelInstances = this.destroyAllInstances(this.slickMouseWheelInstances), this.slickResizableInstances = this.destroyAllInstances(this.slickResizableInstances), (_a = this.getEditorLock()) == null || _a.cancelCurrentEdit(), this.trigger(this.onBeforeDestroy, {});
let i = this.plugins.length;
for (; i--; )
this.unregisterPlugin(this.plugins[i]);
this._options.enableColumnReorder && typeof ((_b = this.sortableSideLeftInstance) == null ? void 0 : _b.destroy) == "function" && ((_c = this.sortableSideLeftInstance) == null || _c.destroy(), (_d = this.sortableSideRightInstance) == null || _d.destroy()), this.unbindAncestorScrollEvents(), this._bindingEventService.unbindByEventName(this._container, "resize"), this.removeCssRules(), this._canvas.forEach((element) => {
this._bindingEventService.unbindByEventName(element, "keydown"), this._bindingEventService.unbindByEventName(element, "click"), this._bindingEventService.unbindByEventName(element, "dblclick"), this._bindingEventService.unbindByEventName(element, "contextmenu"), this._bindingEventService.unbindByEventName(element, "mouseover"), this._bindingEventService.unbindByEventName(element, "mouseout");
}), this._viewport.forEach((view) => {
this._bindingEventService.unbindByEventName(view, "scroll");
}), this._headerScroller.forEach((el) => {
this._bindingEventService.unbindByEventName(el, "contextmenu"), this._bindingEventService.unbindByEventName(el, "click");
}), this._headerRowScroller.forEach((scroller) => {
this._bindingEventService.unbindByEventName(scroller, "scroll");
}), this._footerRow && this._footerRow.forEach((footer) => {
this._bindingEventService.unbindByEventName(footer, "contextmenu"), this._bindingEventService.unbindByEventName(footer, "click");
}), this._footerRowScroller && this._footerRowScroller.forEach((scroller) => {
this._bindingEventService.unbindByEventName(scroller, "scroll");
}), this._preHeaderPanelScroller && this._bindingEventService.unbindByEventName(this._preHeaderPanelScroller, "scroll"), this._topHeaderPanelScroller && this._bindingEventService.unbindByEventName(this._topHeaderPanelScroller, "scroll"), this._bindingEventService.unbindByEventName(this._focusSink, "keydown"), this._bindingEventService.unbindByEventName(this._focusSink2, "keydown");
let resizeHandles = this._container.querySelectorAll(".slick-resizable-handle");
[].forEach.call(resizeHandles, (handle) => {
this._bindingEventService.unbindByEventName(handle, "dblclick");
});
let headerColumns = this._container.querySelectorAll(".slick-header-column");
[].forEach.call(headerColumns, (column) => {
this._bindingEventService.unbindByEventName(column, "mouseenter"), this._bindingEventService.unbindByEventName(column, "mouseleave"), this._bindingEventService.unbindByEventName(column, "mouseenter"), this._bindingEventService.unbindByEventName(column, "mouseleave");
}), Utils.emptyElement(this._container), this._container.classList.remove(this.uid), this.clearAllTimers(), shouldDestroyAllElements && this.destroyAllElements();
}
/**
* Call destroy method, when exists, on all the instance(s) it found
*
* Given either a single instance or an array of instances (e.g. draggable, mousewheel, resizable),
* pops each one and calls its destroy method if available, then resets the input to an empty array
* (or null for a single instance). Returns the reset value.
*
* @params instances - can be a single instance or a an array of instances
*/
destroyAllInstances(inputInstances) {
if (inputInstances) {
let instances = Array.isArray(inputInstances) ? inputInstances : [inputInstances], instance;
for (; Utils.isDefined(instance = instances.pop()); )
instance && typeof instance.destroy == "function" && instance.destroy();
}
return inputInstances = Array.isArray(inputInstances) ? [] : null, inputInstances;
}
/**
* Sets all internal references to DOM elements
* (e.g. canvas containers, headers, viewports, focus sinks, etc.)
* to null so that they can be garbage collected.
*/
destroyAllElements() {
this._activeCanvasNode = null, this._activeViewportNode = null, this._boundAncestors = null, this._canvas = null, this._canvasTopL = null, this._canvasTopR = null, this._canvasBottomL = null, this._canvasBottomR = null, this._container = null, this._focusSink = null, this._focusSink2 = null, this._groupHeaders = null, this._groupHeadersL = null, this._groupHeadersR = null, this._headerL = null, this._headerR = null, this._headers = null, this._headerRows = null, this._headerRowL = null, this._headerRowR = null, this._headerRowSpacerL = null, this._headerRowSpacerR = null, this._headerRowScrollContainer = null, this._headerRowScroller = null, this._headerRowScrollerL = null, this._headerRowScrollerR = null, this._headerScrollContainer = null, this._headerScroller = null, this._headerScrollerL = null, this._headerScrollerR = null, this._hiddenParents = null, this._footerRow = null, this._footerRowL = null, this._footerRowR = null, this._footerRowSpacerL = null, this._footerRowSpacerR = null, this._footerRowScroller = null, this._footerRowScrollerL = null, this._footerRowScrollerR = null, this._footerRowScrollContainer = null, this._preHeaderPanel = null, this._preHeaderPanelR = null, this._preHeaderPanelScroller = null, this._preHeaderPanelScrollerR = null, this._preHeaderPanelSpacer = null, this._preHeaderPanelSpacerR = null, this._topPanels = null, this._topPanelScrollers = null, this._style = null, this._topPanelScrollerL = null, this._topPanelScrollerR = null, this._topPanelL = null, this._topPanelR = null, this._paneHeaderL = null, this._paneHeaderR = null, this._paneTopL = null, this._paneTopR = null, this._paneBottomL = null, this._paneBottomR = null, this._viewport = null, this._viewportTopL = null, this._viewportTopR = null, this._viewportBottomL = null, this._viewportBottomR = null, this._viewportScrollContainerX = null, this._viewportScrollContainerY = null;
}
/** Returns an object containing all of the Grid options set on the grid. See a list of Grid Options here. */
getOptions() {
return this._options;
}
/**
* Extends grid options with a given hash. If an there is an active edit, the grid will attempt to commit the changes and only continue if the attempt succeeds.
* @param {Object} options - an object with configuration options.
* @param {Boolean} [suppressRender] - do we want to supress the grid re-rendering? (defaults to false)
* @param {Boolean} [suppressColumnSet] - do we want to supress the columns set, via "setColumns()" method? (defaults to false)
* @param {Boolean} [suppressSetOverflow] - do we want to suppress the call to `setOverflow`
*/
setOptions(newOptions, suppressRender, suppressColumnSet, suppressSetOverflow) {
this.prepareForOptionsChange(), this._options.enableAddRow !== newOptions.enableAddRow && this.invalidateRow(this.getDataLength()), newOptions.frozenColumn !== void 0 && newOptions.frozenColumn >= 0 && (this.getViewports().forEach((vp) => vp.scrollLeft = 0), this.handleScroll());
let originalOptions = Utils.extend(!0, {}, this._options);
this._options = Utils.extend(this._options, newOptions), this.trigger(this.onSetOptions, { opt