diff --git a/CHANGELOG.md b/CHANGELOG.md index d17f18f4..51313ba1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,28 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.11.0](https://github.com/6pac/SlickGrid/compare/5.10.1...5.11.0) (2024-07-27) + +### Bug Fixes + +* issue where pinning the first column caused the header to get misaligned, fixes [#1038](https://github.com/6pac/SlickGrid/issues/1038) ([#1039](https://github.com/6pac/SlickGrid/issues/1039)) ([d006605](https://github.com/6pac/SlickGrid/commit/d006605de4adea3ed3e18d7bc180e81d7f1b8493)) + +### Features + +* add new Infinite Scroll example ([#1040](https://github.com/6pac/SlickGrid/issues/1040)) ([060c8a0](https://github.com/6pac/SlickGrid/commit/060c8a0c6c13e4e0389e61bb10403927df508d46)) + +# Change Log + +All notable changes to this project will be documented in this file. + +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + ## [5.10.1](https://github.com/6pac/SlickGrid/compare/5.10.0...5.10.1) (2024-07-06) ### Bug Fixes * Header Menu should be on top of grid not inside ([#1033](https://github.com/6pac/SlickGrid/issues/1033)) ([b704a81](https://github.com/6pac/SlickGrid/commit/b704a815e97c45d81f59421db36073a4db470981)) + * new preheader event should work with any prehader content ([#1034](https://github.com/6pac/SlickGrid/issues/1034)) ([28113f4](https://github.com/6pac/SlickGrid/commit/28113f4473c78fa9fccda7ade279d57c7b4b5d5e)) # [5.10.0](https://github.com/6pac/SlickGrid/compare/5.9.2...5.10.0) (2024-06-19) @@ -14,14 +31,19 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Bug Fixes * Draggable Grouping drop zone in preheader should take full width ([#1025](https://github.com/6pac/SlickGrid/issues/1025)) ([2c0a41f](https://github.com/6pac/SlickGrid/commit/2c0a41fb11c6b2e2dc136c6c5d766d0b176fd855)) + * Draggable Grouping onColumnsReordered missing impactedColumns ([#1026](https://github.com/6pac/SlickGrid/issues/1026)) ([3d342cc](https://github.com/6pac/SlickGrid/commit/3d342cccbe1db9bfd8f2c15a7f746cce738614d6)) + * make sure pager element exists before toggling CSS classes ([#1028](https://github.com/6pac/SlickGrid/issues/1028)) ([fe46af0](https://github.com/6pac/SlickGrid/commit/fe46af08662894dc26f1bbd4d182aa0d67cfa1cf)) ### Features * add `iconButtonContainer` option to Grid Menu ([#1018](https://github.com/6pac/SlickGrid/issues/1018)) ([56a24db](https://github.com/6pac/SlickGrid/commit/56a24db1627546d3ff11967af3cc943acba6de44)) + * add new `preventDragFromKeys` grid option ([#1024](https://github.com/6pac/SlickGrid/issues/1024)) ([b82f476](https://github.com/6pac/SlickGrid/commit/b82f4762da4d8c8d8f72432c3bdcea7f83bd812f)) + * add onPreHeaderContextMenu for Column Picker usage ([#1030](https://github.com/6pac/SlickGrid/issues/1030)) ([ea2c175](https://github.com/6pac/SlickGrid/commit/ea2c1759fa78c47411ba65fda5a8d619d0d8f7e3)) + * add optional Top-Header for Drag Grouping + Header Grouping ([#1029](https://github.com/6pac/SlickGrid/issues/1029)) ([cec789c](https://github.com/6pac/SlickGrid/commit/cec789c563378d190529db4836b60d7e34878788)) # Change Log diff --git a/dist/browser/slick.grid.js b/dist/browser/slick.grid.js index 9e99f3d0..8de63efd 100644 --- a/dist/browser/slick.grid.js +++ b/dist/browser/slick.grid.js @@ -24,7 +24,7 @@ this.externalPubSub = externalPubSub; ////////////////////////////////////////////////////////////////////////////////////////////// // Public API - __publicField(this, "slickGridVersion", "5.10.1"); + __publicField(this, "slickGridVersion", "5.11.0"); /** optional grid state clientId */ __publicField(this, "cid", ""); // Events @@ -311,6 +311,7 @@ __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); @@ -1536,7 +1537,7 @@ * @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 && (this.getViewports().forEach((vp) => vp.scrollLeft = 0), this.handleScroll()); + 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, { optionsBefore: originalOptions, optionsAfter: this._options }), this.internal_setOptions(suppressRender, suppressColumnSet, suppressSetOverflow); } @@ -1941,7 +1942,7 @@ typeof this.rowsCache == "object" && Object.keys(this.rowsCache).forEach((row) => { let cachedRow = +row; cachedRow > r1 && this.removeRowFromCache(cachedRow); - }), this._options.enableAsyncPostRenderCleanup && this.startPostProcessingCleanup(), this.activeCellNode && this.activeRow > r1 && this.resetActiveCell(), oldH = this.h, this._options.autoHeight ? this.h = this._options.rowHeight * numberOfRows : (this.th = Math.max(this._options.rowHeight * numberOfRows, tempViewportH - ((_b = (_a = this.scrollbarDimensions) == null ? void 0 : _a.height) != null ? _b : 0)), this.th < this.maxSupportedCssHeight ? (this.h = this.ph = this.th, this.n = 1, this.cj = 0) : (this.h = this.maxSupportedCssHeight, this.ph = this.h / 100, this.n = Math.floor(this.th / this.ph), this.cj = (this.th - this.h) / (this.n - 1))), (this.h !== oldH || this.enforceFrozenRowHeightRecalc) && (this.hasFrozenRows && !this._options.frozenBottom ? (Utils.height(this._canvasBottomL, this.h), this.hasFrozenColumns() && Utils.height(this._canvasBottomR, this.h)) : (Utils.height(this._canvasTopL, this.h), Utils.height(this._canvasTopR, this.h)), this.scrollTop = this._viewportScrollContainerY.scrollTop, this.enforceFrozenRowHeightRecalc = !1); + }), this._options.enableAsyncPostRenderCleanup && this.startPostProcessingCleanup(), this.activeCellNode && this.activeRow > r1 && this.resetActiveCell(), oldH = this.h, this._options.autoHeight ? this.h = this._options.rowHeight * numberOfRows : (this.th = Math.max(this._options.rowHeight * numberOfRows, tempViewportH - ((_b = (_a = this.scrollbarDimensions) == null ? void 0 : _a.height) != null ? _b : 0)), this.th < this.maxSupportedCssHeight ? (this.h = this.ph = this.th, this.n = 1, this.cj = 0) : (this.h = this.maxSupportedCssHeight, this.ph = this.h / 100, this.n = Math.floor(this.th / this.ph), this.cj = (this.th - this.h) / (this.n - 1))), (this.h !== oldH || this.enforceFrozenRowHeightRecalc) && (this.hasFrozenRows && !this._options.frozenBottom ? (Utils.height(this._canvasBottomL, this.h), this.hasFrozenColumns() && Utils.height(this._canvasBottomR, this.h)) : (Utils.height(this._canvasTopL, this.h), Utils.height(this._canvasTopR, this.h)), this.scrollTop = this._viewportScrollContainerY.scrollTop, this.scrollHeight = this._viewportScrollContainerY.scrollHeight, this.enforceFrozenRowHeightRecalc = !1); let oldScrollTopInRange = this.scrollTop + this.offset <= this.th - tempViewportH; this.th === 0 || this.scrollTop === 0 ? this.page = this.offset = 0 : oldScrollTopInRange ? this.scrollTo(this.scrollTop + this.offset) : this.scrollTo(this.th - tempViewportH + ((_d = (_c = this.scrollbarDimensions) == null ? void 0 : _c.height) != null ? _d : 0)), this.h !== oldH && this._options.autoHeight && this.resizeCanvas(), this._options.autosizeColsMode === GridAutosizeColsMode.LegacyForceFit && oldViewportHasVScroll !== this.viewportHasVScroll && this.autosizeColumns(), this.updateCanvasWidth(!1); } @@ -2116,15 +2117,15 @@ let scrollLeft = element.scrollLeft; scrollLeft !== this._viewportScrollContainerX.scrollLeft && (this._viewportScrollContainerX.scrollLeft = scrollLeft); } - handleScroll() { - return this.scrollTop = this._viewportScrollContainerY.scrollTop, this.scrollLeft = this._viewportScrollContainerX.scrollLeft, this._handleScroll(!1); + handleScroll(e) { + return this.scrollHeight = this._viewportScrollContainerY.scrollHeight, this.scrollTop = this._viewportScrollContainerY.scrollTop, this.scrollLeft = this._viewportScrollContainerX.scrollLeft, this._handleScroll(e ? "scroll" : "system"); } - _handleScroll(isMouseWheel) { + _handleScroll(eventType = "system") { let maxScrollDistanceY = this._viewportScrollContainerY.scrollHeight - this._viewportScrollContainerY.clientHeight, maxScrollDistanceX = this._viewportScrollContainerY.scrollWidth - this._viewportScrollContainerY.clientWidth; - maxScrollDistanceY = Math.max(0, maxScrollDistanceY), maxScrollDistanceX = Math.max(0, maxScrollDistanceX), this.scrollTop > maxScrollDistanceY && (this.scrollTop = maxScrollDistanceY), this.scrollLeft > maxScrollDistanceX && (this.scrollLeft = maxScrollDistanceX); + maxScrollDistanceY = Math.max(0, maxScrollDistanceY), maxScrollDistanceX = Math.max(0, maxScrollDistanceX), this.scrollTop > maxScrollDistanceY && (this.scrollTop = maxScrollDistanceY, this.scrollHeight = maxScrollDistanceY), this.scrollLeft > maxScrollDistanceX && (this.scrollLeft = maxScrollDistanceX); let vScrollDist = Math.abs(this.scrollTop - this.prevScrollTop), hScrollDist = Math.abs(this.scrollLeft - this.prevScrollLeft); if (hScrollDist && (this.prevScrollLeft = this.scrollLeft, this._viewportScrollContainerX.scrollLeft = this.scrollLeft, this._headerScrollContainer.scrollLeft = this.scrollLeft, this._topPanelScrollers[0].scrollLeft = this.scrollLeft, this._options.createFooterRow && (this._footerRowScrollContainer.scrollLeft = this.scrollLeft), this._options.createPreHeaderPanel && (this.hasFrozenColumns() ? this._preHeaderPanelScrollerR.scrollLeft = this.scrollLeft : this._preHeaderPanelScroller.scrollLeft = this.scrollLeft), this._options.createTopHeaderPanel && (this._topHeaderPanelScroller.scrollLeft = this.scrollLeft), this.hasFrozenColumns() ? (this.hasFrozenRows && (this._viewportTopR.scrollLeft = this.scrollLeft), this._headerRowScrollerR.scrollLeft = this.scrollLeft) : (this.hasFrozenRows && (this._viewportTopL.scrollLeft = this.scrollLeft), this._headerRowScrollerL.scrollLeft = this.scrollLeft)), vScrollDist && !this._options.autoHeight) - if (this.vScrollDir = this.prevScrollTop < this.scrollTop ? 1 : -1, this.prevScrollTop = this.scrollTop, isMouseWheel && (this._viewportScrollContainerY.scrollTop = this.scrollTop), this.hasFrozenColumns() && (this.hasFrozenRows && !this._options.frozenBottom ? this._viewportBottomL.scrollTop = this.scrollTop : this._viewportTopL.scrollTop = this.scrollTop), vScrollDist < this.viewportH) + if (this.vScrollDir = this.prevScrollTop < this.scrollTop ? 1 : -1, this.prevScrollTop = this.scrollTop, eventType === "mousewheel" && (this._viewportScrollContainerY.scrollTop = this.scrollTop), this.hasFrozenColumns() && (this.hasFrozenRows && !this._options.frozenBottom ? this._viewportBottomL.scrollTop = this.scrollTop : this._viewportTopL.scrollTop = this.scrollTop), vScrollDist < this.viewportH) this.scrollTo(this.scrollTop + this.offset); else { let oldOffset = this.offset; @@ -2134,7 +2135,12 @@ let dx = Math.abs(this.lastRenderedScrollLeft - this.scrollLeft), dy = Math.abs(this.lastRenderedScrollTop - this.scrollTop); (dx > 20 || dy > 20) && (this._options.forceSyncScrolling || dy < this.viewportH && dx < this.viewportW ? this.render() : this.scrollThrottle.enqueue(), this.trigger(this.onViewportChanged, {})); } - return this.trigger(this.onScroll, { scrollLeft: this.scrollLeft, scrollTop: this.scrollTop }), !!(hScrollDist || vScrollDist); + return this.trigger(this.onScroll, { + triggeredBy: eventType, + scrollHeight: this.scrollHeight, + scrollLeft: this.scrollLeft, + scrollTop: this.scrollTop + }), !!(hScrollDist || vScrollDist); } /** * limits the frequency at which the provided action is executed. @@ -2272,7 +2278,7 @@ ////////////////////////////////////////////////////////////////////////////////////////////// // Interactivity handleMouseWheel(e, _delta, deltaX, deltaY) { - this.scrollTop = Math.max(0, this._viewportScrollContainerY.scrollTop - deltaY * this._options.rowHeight), this.scrollLeft = this._viewportScrollContainerX.scrollLeft + deltaX * 10, this._handleScroll(!0) && e.preventDefault(); + this.scrollHeight = this._viewportScrollContainerY.scrollHeight, this.scrollTop = Math.max(0, this._viewportScrollContainerY.scrollTop - deltaY * this._options.rowHeight), this.scrollLeft = this._viewportScrollContainerX.scrollLeft + deltaX * 10, this._handleScroll("mousewheel") && e.preventDefault(); } handleDragInit(e, dd) { let cell = this.getCellFromEvent(e); @@ -3105,7 +3111,7 @@ * Distributed under MIT license. * All rights reserved. * - * SlickGrid v5.10.1 + * SlickGrid v5.11.0 * * NOTES: * Cell/row DOM manipulations are done directly bypassing JS DOM manipulation methods. diff --git a/dist/browser/slick.grid.js.map b/dist/browser/slick.grid.js.map index 7a969500..0a6024a6 100644 --- a/dist/browser/slick.grid.js.map +++ b/dist/browser/slick.grid.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../../src/slick.grid.ts"], - "sourcesContent": ["// @ts-ignore\r\nimport type SortableInstance from 'sortablejs';\r\n\r\nimport type {\r\n AutoSize,\r\n CellViewportRange,\r\n Column,\r\n ColumnSort,\r\n CssStyleHash,\r\n CSSStyleDeclarationWritable,\r\n CustomDataView,\r\n DOMEvent,\r\n DragPosition,\r\n DragRowMove,\r\n Editor,\r\n EditorArguments,\r\n EditorConstructor,\r\n EditController,\r\n Formatter,\r\n FormatterOverrideCallback,\r\n FormatterResultObject,\r\n FormatterResultWithHtml,\r\n FormatterResultWithText,\r\n GridOption as BaseGridOption,\r\n InteractionBase,\r\n ItemMetadata,\r\n MenuCommandItemCallbackArgs,\r\n MultiColumnSort,\r\n OnActivateChangedOptionsEventArgs,\r\n OnActiveCellChangedEventArgs,\r\n OnAddNewRowEventArgs,\r\n OnAutosizeColumnsEventArgs,\r\n OnBeforeUpdateColumnsEventArgs,\r\n OnBeforeAppendCellEventArgs,\r\n OnBeforeCellEditorDestroyEventArgs,\r\n OnBeforeColumnsResizeEventArgs,\r\n OnBeforeEditCellEventArgs,\r\n OnBeforeHeaderCellDestroyEventArgs,\r\n OnBeforeHeaderRowCellDestroyEventArgs,\r\n OnBeforeFooterRowCellDestroyEventArgs,\r\n OnBeforeSetColumnsEventArgs,\r\n OnCellChangeEventArgs,\r\n OnCellCssStylesChangedEventArgs,\r\n OnClickEventArgs,\r\n OnColumnsDragEventArgs,\r\n OnColumnsReorderedEventArgs,\r\n OnColumnsResizedEventArgs,\r\n OnColumnsResizeDblClickEventArgs,\r\n OnCompositeEditorChangeEventArgs,\r\n OnDblClickEventArgs,\r\n OnFooterContextMenuEventArgs,\r\n OnFooterRowCellRenderedEventArgs,\r\n OnHeaderCellRenderedEventArgs,\r\n OnFooterClickEventArgs,\r\n OnHeaderClickEventArgs,\r\n OnHeaderContextMenuEventArgs,\r\n OnHeaderMouseEventArgs,\r\n OnHeaderRowCellRenderedEventArgs,\r\n OnKeyDownEventArgs,\r\n OnPreHeaderContextMenuEventArgs,\r\n OnPreHeaderClickEventArgs,\r\n OnRenderedEventArgs,\r\n OnSelectedRowsChangedEventArgs,\r\n OnSetOptionsEventArgs,\r\n OnScrollEventArgs,\r\n OnValidationErrorEventArgs,\r\n PagingInfo,\r\n RowInfo,\r\n SelectionModel,\r\n SingleColumnSort,\r\n SlickGridModel,\r\n SlickPlugin,\r\n} from './models/index';\r\nimport {\r\n type BasePubSub,\r\n BindingEventService as BindingEventService_,\r\n ColAutosizeMode as ColAutosizeMode_,\r\n GlobalEditorLock as GlobalEditorLock_,\r\n GridAutosizeColsMode as GridAutosizeColsMode_,\r\n keyCode as keyCode_,\r\n preClickClassName as preClickClassName_,\r\n RowSelectionMode as RowSelectionMode_,\r\n type SlickEditorLock,\r\n SlickEvent as SlickEvent_,\r\n SlickEventData as SlickEventData_,\r\n SlickRange as SlickRange_,\r\n Utils as Utils_,\r\n ValueFilterMode as ValueFilterMode_,\r\n WidthEvalMode as WidthEvalMode_,\r\n} from './slick.core';\r\nimport { Draggable as Draggable_, MouseWheel as MouseWheel_, Resizable as Resizable_ } from './slick.interactions';\r\n\r\n// for (iife) load Slick methods from global Slick object, or use imports for (esm)\r\nconst BindingEventService = IIFE_ONLY ? Slick.BindingEventService : BindingEventService_;\r\nconst ColAutosizeMode = IIFE_ONLY ? Slick.ColAutosizeMode : ColAutosizeMode_;\r\nconst SlickEvent = IIFE_ONLY ? Slick.Event : SlickEvent_;\r\nconst SlickEventData = IIFE_ONLY ? Slick.EventData : SlickEventData_;\r\nconst GlobalEditorLock = IIFE_ONLY ? Slick.GlobalEditorLock : GlobalEditorLock_;\r\nconst GridAutosizeColsMode = IIFE_ONLY ? Slick.GridAutosizeColsMode : GridAutosizeColsMode_;\r\nconst keyCode = IIFE_ONLY ? Slick.keyCode : keyCode_;\r\nconst preClickClassName = IIFE_ONLY ? Slick.preClickClassName : preClickClassName_;\r\nconst SlickRange = IIFE_ONLY ? Slick.Range : SlickRange_;\r\nconst RowSelectionMode = IIFE_ONLY ? Slick.RowSelectionMode : RowSelectionMode_;\r\nconst ValueFilterMode = IIFE_ONLY ? Slick.ValueFilterMode : ValueFilterMode_;\r\nconst Utils = IIFE_ONLY ? Slick.Utils : Utils_;\r\nconst WidthEvalMode = IIFE_ONLY ? Slick.WidthEvalMode : WidthEvalMode_;\r\nconst Draggable = IIFE_ONLY ? Slick.Draggable : Draggable_;\r\nconst MouseWheel = IIFE_ONLY ? Slick.MouseWheel : MouseWheel_;\r\nconst Resizable = IIFE_ONLY ? Slick.Resizable : Resizable_;\r\n\r\n/**\r\n * @license\r\n * (c) 2009-present Michael Leibman\r\n * michael{dot}leibman{at}gmail{dot}com\r\n * http://github.com/mleibman/slickgrid\r\n *\r\n * Distributed under MIT license.\r\n * All rights reserved.\r\n *\r\n * SlickGrid v5.10.1\r\n *\r\n * NOTES:\r\n * Cell/row DOM manipulations are done directly bypassing JS DOM manipulation methods.\r\n * This increases the speed dramatically, but can only be done safely because there are no event handlers\r\n * or data associated with any cell/row DOM nodes. Cell editors must make sure they implement .destroy()\r\n * and do proper cleanup.\r\n */\r\n\r\n//////////////////////////////////////////////////////////////////////////////////////////////\r\n// SlickGrid class implementation (available as SlickGrid)\r\n\r\ninterface RowCaching {\r\n rowNode: HTMLElement[] | null,\r\n cellColSpans: Array;\r\n cellNodesByColumnIdx: HTMLElement[];\r\n cellRenderQueue: any[];\r\n}\r\n\r\nexport class SlickGrid = Column, O extends BaseGridOption = BaseGridOption> {\r\n //////////////////////////////////////////////////////////////////////////////////////////////\r\n // Public API\r\n slickGridVersion = '5.10.1';\r\n\r\n /** optional grid state clientId */\r\n cid = '';\r\n\r\n // Events\r\n onActiveCellChanged: SlickEvent_;\r\n onActiveCellPositionChanged: SlickEvent_<{ grid: SlickGrid; }>;\r\n onAddNewRow: SlickEvent_;\r\n onAutosizeColumns: SlickEvent_;\r\n onBeforeAppendCell: SlickEvent_;\r\n onBeforeCellEditorDestroy: SlickEvent_;\r\n onBeforeColumnsResize: SlickEvent_;\r\n onBeforeDestroy: SlickEvent_<{ grid: SlickGrid; }>;\r\n onBeforeEditCell: SlickEvent_;\r\n onBeforeFooterRowCellDestroy: SlickEvent_;\r\n onBeforeHeaderCellDestroy: SlickEvent_;\r\n onBeforeHeaderRowCellDestroy: SlickEvent_;\r\n onBeforeSetColumns: SlickEvent_;\r\n onBeforeSort: SlickEvent_;\r\n onBeforeUpdateColumns: SlickEvent_;\r\n onCellChange: SlickEvent_;\r\n onCellCssStylesChanged: SlickEvent_;\r\n onClick: SlickEvent_;\r\n onColumnsReordered: SlickEvent_;\r\n onColumnsDrag: SlickEvent_;\r\n onColumnsResized: SlickEvent_;\r\n onColumnsResizeDblClick: SlickEvent_;\r\n onCompositeEditorChange: SlickEvent_;\r\n onContextMenu: SlickEvent_;\r\n onDrag: SlickEvent_;\r\n onDblClick: SlickEvent_;\r\n onDragInit: SlickEvent_;\r\n onDragStart: SlickEvent_;\r\n onDragEnd: SlickEvent_;\r\n onFooterClick: SlickEvent_;\r\n onFooterContextMenu: SlickEvent_;\r\n onFooterRowCellRendered: SlickEvent_;\r\n onHeaderCellRendered: SlickEvent_;\r\n onHeaderClick: SlickEvent_;\r\n onHeaderContextMenu: SlickEvent_;\r\n onHeaderMouseEnter: SlickEvent_;\r\n onHeaderMouseLeave: SlickEvent_;\r\n onHeaderRowCellRendered: SlickEvent_;\r\n onHeaderRowMouseEnter: SlickEvent_;\r\n onHeaderRowMouseLeave: SlickEvent_;\r\n onPreHeaderContextMenu: SlickEvent_;\r\n onPreHeaderClick: SlickEvent_;\r\n onKeyDown: SlickEvent_;\r\n onMouseEnter: SlickEvent_;\r\n onMouseLeave: SlickEvent_;\r\n onRendered: SlickEvent_;\r\n onScroll: SlickEvent_;\r\n onSelectedRowsChanged: SlickEvent_;\r\n onSetOptions: SlickEvent_;\r\n onActivateChangedOptions: SlickEvent_;\r\n onSort: SlickEvent_;\r\n onValidationError: SlickEvent_;\r\n onViewportChanged: SlickEvent_<{ grid: SlickGrid; }>;\r\n\r\n // ---\r\n // protected variables\r\n\r\n // shared across all grids on the page\r\n protected scrollbarDimensions?: { height: number; width: number; };\r\n protected maxSupportedCssHeight!: number; // browser's breaking point\r\n\r\n protected canvas: HTMLCanvasElement | null = null;\r\n protected canvas_context: CanvasRenderingContext2D | null = null;\r\n\r\n // settings\r\n protected _options!: O;\r\n protected _defaults: BaseGridOption = {\r\n alwaysShowVerticalScroll: false,\r\n alwaysAllowHorizontalScroll: false,\r\n explicitInitialization: false,\r\n rowHeight: 25,\r\n defaultColumnWidth: 80,\r\n enableHtmlRendering: true,\r\n enableAddRow: false,\r\n leaveSpaceForNewRows: false,\r\n editable: false,\r\n autoEdit: true,\r\n autoEditNewRow: true,\r\n autoCommitEdit: false,\r\n suppressActiveCellChangeOnEdit: false,\r\n enableCellNavigation: true,\r\n enableColumnReorder: true,\r\n unorderableColumnCssClass: 'unorderable',\r\n asyncEditorLoading: false,\r\n asyncEditorLoadDelay: 100,\r\n forceFitColumns: false,\r\n enableAsyncPostRender: false,\r\n asyncPostRenderDelay: 50,\r\n enableAsyncPostRenderCleanup: false,\r\n asyncPostRenderCleanupDelay: 40,\r\n auto: false,\r\n nonce: '',\r\n editorLock: GlobalEditorLock,\r\n showColumnHeader: true,\r\n showHeaderRow: false,\r\n headerRowHeight: 25,\r\n createFooterRow: false,\r\n showFooterRow: false,\r\n footerRowHeight: 25,\r\n createPreHeaderPanel: false,\r\n createTopHeaderPanel: false,\r\n showPreHeaderPanel: false,\r\n showTopHeaderPanel: false,\r\n preHeaderPanelHeight: 25,\r\n showTopPanel: false,\r\n topPanelHeight: 25,\r\n preHeaderPanelWidth: 'auto', // mostly useful for Draggable Grouping dropzone to take full width\r\n topHeaderPanelHeight: 25,\r\n topHeaderPanelWidth: 'auto', // mostly useful for Draggable Grouping dropzone to take full width\r\n formatterFactory: null,\r\n editorFactory: null,\r\n cellFlashingCssClass: 'flashing',\r\n rowHighlightCssClass: 'highlight-animate',\r\n rowHighlightDuration: 400,\r\n selectedCellCssClass: 'selected',\r\n multiSelect: true,\r\n enableTextSelectionOnCells: false,\r\n dataItemColumnValueExtractor: null,\r\n frozenBottom: false,\r\n frozenColumn: -1,\r\n frozenRow: -1,\r\n frozenRightViewportMinWidth: 100,\r\n throwWhenFrozenNotAllViewable: false,\r\n fullWidthRows: false,\r\n multiColumnSort: false,\r\n numberedMultiColumnSort: false,\r\n tristateMultiColumnSort: false,\r\n sortColNumberInSeparateSpan: false,\r\n defaultFormatter: this.defaultFormatter,\r\n forceSyncScrolling: false,\r\n addNewRowCssClass: 'new-row',\r\n preserveCopiedSelectionOnPaste: false,\r\n preventDragFromKeys: ['ctrlKey', 'metaKey'],\r\n showCellSelection: true,\r\n viewportClass: undefined,\r\n minRowBuffer: 3,\r\n emulatePagingWhenScrolling: true, // when scrolling off bottom of viewport, place new row at top of viewport\r\n editorCellNavOnLRKeys: false,\r\n enableMouseWheelScrollHandler: true,\r\n doPaging: true,\r\n autosizeColsMode: GridAutosizeColsMode.LegacyOff,\r\n autosizeColPaddingPx: 4,\r\n scrollRenderThrottling: 50,\r\n autosizeTextAvgToMWidthRatio: 0.75,\r\n viewportSwitchToScrollModeWidthPercent: undefined,\r\n viewportMinWidthPx: undefined,\r\n viewportMaxWidthPx: undefined,\r\n suppressCssChangesOnHiddenInit: false,\r\n ffMaxSupportedCssHeight: 6000000,\r\n maxSupportedCssHeight: 1000000000,\r\n sanitizer: undefined, // sanitize function, built in basic sanitizer is: Slick.RegexSanitizer(dirtyHtml)\r\n logSanitizedHtml: false, // log to console when sanitised - recommend true for testing of dev and production\r\n mixinDefaults: true,\r\n shadowRoot: undefined\r\n };\r\n\r\n protected _columnDefaults = {\r\n name: '',\r\n headerCssClass: null,\r\n defaultSortAsc: true,\r\n focusable: true,\r\n hidden: false,\r\n minWidth: 30,\r\n maxWidth: undefined,\r\n rerenderOnResize: false,\r\n reorderable: true,\r\n resizable: true,\r\n sortable: false,\r\n selectable: true,\r\n } as Partial;\r\n\r\n protected _columnAutosizeDefaults: AutoSize = {\r\n ignoreHeaderText: false,\r\n colValueArray: undefined,\r\n allowAddlPercent: undefined,\r\n formatterOverride: undefined,\r\n autosizeMode: ColAutosizeMode.ContentIntelligent,\r\n rowSelectionModeOnInit: undefined,\r\n rowSelectionMode: RowSelectionMode.FirstNRows,\r\n rowSelectionCount: 100,\r\n valueFilterMode: ValueFilterMode.None,\r\n widthEvalMode: WidthEvalMode.Auto,\r\n sizeToRemaining: undefined,\r\n widthPx: undefined,\r\n contentSizePx: 0,\r\n headerWidthPx: 0,\r\n colDataTypeOf: undefined\r\n };\r\n\r\n protected _columnResizeTimer?: any;\r\n protected _executionBlockTimer?: any;\r\n protected _flashCellTimer?: any;\r\n protected _highlightRowTimer?: any;\r\n\r\n // scroller\r\n protected th!: number; // virtual height\r\n protected h!: number; // real scrollable height\r\n protected ph!: number; // page height\r\n protected n!: number; // number of pages\r\n protected cj!: number; // \"jumpiness\" coefficient\r\n\r\n protected page = 0; // current page\r\n protected offset = 0; // current page offset\r\n protected vScrollDir = 1;\r\n protected _bindingEventService = new BindingEventService();\r\n protected initialized = false;\r\n protected _container!: HTMLElement;\r\n protected uid = `slickgrid_${Math.round(1000000 * Math.random())}`;\r\n protected _focusSink!: HTMLDivElement;\r\n protected _focusSink2!: HTMLDivElement;\r\n protected _groupHeaders: HTMLDivElement[] = [];\r\n protected _headerScroller: HTMLDivElement[] = [];\r\n protected _headers: HTMLDivElement[] = [];\r\n protected _headerRows!: HTMLDivElement[];\r\n protected _headerRowScroller!: HTMLDivElement[];\r\n protected _headerRowSpacerL!: HTMLDivElement;\r\n protected _headerRowSpacerR!: HTMLDivElement;\r\n protected _footerRow!: HTMLDivElement[];\r\n protected _footerRowScroller!: HTMLDivElement[];\r\n protected _footerRowSpacerL!: HTMLDivElement;\r\n protected _footerRowSpacerR!: HTMLDivElement;\r\n protected _preHeaderPanel!: HTMLDivElement;\r\n protected _preHeaderPanelScroller!: HTMLDivElement;\r\n protected _preHeaderPanelSpacer!: HTMLDivElement;\r\n protected _preHeaderPanelR!: HTMLDivElement;\r\n protected _preHeaderPanelScrollerR!: HTMLDivElement;\r\n protected _preHeaderPanelSpacerR!: HTMLDivElement;\r\n protected _topHeaderPanel!: HTMLDivElement;\r\n protected _topHeaderPanelScroller!: HTMLDivElement;\r\n protected _topHeaderPanelSpacer!: HTMLDivElement;\r\n protected _topPanelScrollers!: HTMLDivElement[];\r\n protected _topPanels!: HTMLDivElement[];\r\n protected _viewport!: HTMLDivElement[];\r\n protected _canvas!: HTMLDivElement[];\r\n protected _style?: HTMLStyleElement;\r\n protected _boundAncestors: HTMLElement[] = [];\r\n protected stylesheet?: { cssRules: Array<{ selectorText: string; }>; rules: Array<{ selectorText: string; }>; } | null;\r\n protected columnCssRulesL?: Array<{ selectorText: string; }>;\r\n protected columnCssRulesR?: Array<{ selectorText: string; }>;\r\n protected viewportH = 0;\r\n protected viewportW = 0;\r\n protected canvasWidth = 0;\r\n protected canvasWidthL = 0;\r\n protected canvasWidthR = 0;\r\n protected headersWidth = 0;\r\n protected headersWidthL = 0;\r\n protected headersWidthR = 0;\r\n protected viewportHasHScroll = false;\r\n protected viewportHasVScroll = false;\r\n protected headerColumnWidthDiff = 0;\r\n protected headerColumnHeightDiff = 0; // border+padding\r\n protected cellWidthDiff = 0;\r\n protected cellHeightDiff = 0;\r\n protected absoluteColumnMinWidth!: number;\r\n protected hasFrozenRows = false;\r\n protected frozenRowsHeight = 0;\r\n protected actualFrozenRow = -1;\r\n protected paneTopH = 0;\r\n protected paneBottomH = 0;\r\n protected viewportTopH = 0;\r\n protected viewportBottomH = 0;\r\n protected topPanelH = 0;\r\n protected headerRowH = 0;\r\n protected footerRowH = 0;\r\n\r\n protected tabbingDirection = 1;\r\n protected _activeCanvasNode!: HTMLDivElement;\r\n protected _activeViewportNode!: HTMLDivElement;\r\n protected activePosX!: number;\r\n protected activeRow!: number;\r\n protected activeCell!: number;\r\n protected activeCellNode: HTMLDivElement | null = null;\r\n protected currentEditor: Editor | null = null;\r\n protected serializedEditorValue: any;\r\n protected editController?: EditController;\r\n\r\n protected rowsCache: Array = {} as any;\r\n protected renderedRows = 0;\r\n protected numVisibleRows = 0;\r\n protected prevScrollTop = 0;\r\n protected scrollTop = 0;\r\n protected lastRenderedScrollTop = 0;\r\n protected lastRenderedScrollLeft = 0;\r\n protected prevScrollLeft = 0;\r\n protected scrollLeft = 0;\r\n\r\n protected selectionModel?: SelectionModel;\r\n protected selectedRows: number[] = [];\r\n\r\n protected plugins: SlickPlugin[] = [];\r\n protected cellCssClasses: CssStyleHash = {};\r\n\r\n protected columnsById: Record = {};\r\n protected sortColumns: ColumnSort[] = [];\r\n protected columnPosLeft: number[] = [];\r\n protected columnPosRight: number[] = [];\r\n\r\n protected pagingActive = false;\r\n protected pagingIsLastPage = false;\r\n\r\n protected scrollThrottle!: { enqueue: () => void; dequeue: () => void; };\r\n\r\n // async call handles\r\n protected h_editorLoader: any = null;\r\n protected h_render = null;\r\n protected h_postrender: any = null;\r\n protected h_postrenderCleanup: any = null;\r\n protected postProcessedRows: any = {};\r\n protected postProcessToRow: number = null as any;\r\n protected postProcessFromRow: number = null as any;\r\n protected postProcessedCleanupQueue: Array<{\r\n actionType: string;\r\n groupId: number;\r\n node: HTMLElement | HTMLElement[];\r\n columnIdx?: number;\r\n rowIdx?: number;\r\n }> = [];\r\n protected postProcessgroupId = 0;\r\n\r\n // perf counters\r\n protected counter_rows_rendered = 0;\r\n protected counter_rows_removed = 0;\r\n\r\n protected _paneHeaderL!: HTMLDivElement;\r\n protected _paneHeaderR!: HTMLDivElement;\r\n protected _paneTopL!: HTMLDivElement;\r\n protected _paneTopR!: HTMLDivElement;\r\n protected _paneBottomL!: HTMLDivElement;\r\n protected _paneBottomR!: HTMLDivElement;\r\n protected _headerScrollerL!: HTMLDivElement;\r\n protected _headerScrollerR!: HTMLDivElement;\r\n protected _headerL!: HTMLDivElement;\r\n protected _headerR!: HTMLDivElement;\r\n protected _groupHeadersL!: HTMLDivElement;\r\n protected _groupHeadersR!: HTMLDivElement;\r\n protected _headerRowScrollerL!: HTMLDivElement;\r\n protected _headerRowScrollerR!: HTMLDivElement;\r\n protected _footerRowScrollerL!: HTMLDivElement;\r\n protected _footerRowScrollerR!: HTMLDivElement;\r\n protected _headerRowL!: HTMLDivElement;\r\n protected _headerRowR!: HTMLDivElement;\r\n protected _footerRowL!: HTMLDivElement;\r\n protected _footerRowR!: HTMLDivElement;\r\n protected _topPanelScrollerL!: HTMLDivElement;\r\n protected _topPanelScrollerR!: HTMLDivElement;\r\n protected _topPanelL!: HTMLDivElement;\r\n protected _topPanelR!: HTMLDivElement;\r\n protected _viewportTopL!: HTMLDivElement;\r\n protected _viewportTopR!: HTMLDivElement;\r\n protected _viewportBottomL!: HTMLDivElement;\r\n protected _viewportBottomR!: HTMLDivElement;\r\n protected _canvasTopL!: HTMLDivElement;\r\n protected _canvasTopR!: HTMLDivElement;\r\n protected _canvasBottomL!: HTMLDivElement;\r\n protected _canvasBottomR!: HTMLDivElement;\r\n protected _viewportScrollContainerX!: HTMLDivElement;\r\n protected _viewportScrollContainerY!: HTMLDivElement;\r\n protected _headerScrollContainer!: HTMLDivElement;\r\n protected _headerRowScrollContainer!: HTMLDivElement;\r\n protected _footerRowScrollContainer!: HTMLDivElement;\r\n\r\n // store css attributes if display:none is active in container or parent\r\n protected cssShow = { position: 'absolute', visibility: 'hidden', display: 'block' };\r\n protected _hiddenParents: HTMLElement[] = [];\r\n protected oldProps: Array> = [];\r\n protected enforceFrozenRowHeightRecalc = false;\r\n protected columnResizeDragging = false;\r\n protected slickDraggableInstance: InteractionBase | null = null;\r\n protected slickMouseWheelInstances: Array = [];\r\n protected slickResizableInstances: Array = [];\r\n protected sortableSideLeftInstance?: SortableInstance;\r\n protected sortableSideRightInstance?: SortableInstance;\r\n protected logMessageCount = 0;\r\n protected logMessageMaxCount = 30;\r\n protected _pubSubService?: BasePubSub;\r\n\r\n /**\r\n * Creates a new instance of the grid.\r\n * @class SlickGrid\r\n * @constructor\r\n * @param {Node} container - Container node to create the grid in.\r\n * @param {Array|Object} data - An array of objects for databinding or an external DataView.\r\n * @param {Array} columns - An array of column definitions.\r\n * @param {Object} [options] - Grid Options\r\n * @param {Object} [externalPubSub] - optional External PubSub Service to use by SlickEvent\r\n **/\r\n constructor(protected readonly container: HTMLElement | string, protected data: CustomDataView | TData[], protected columns: C[], options: Partial, protected readonly externalPubSub?: BasePubSub) {\r\n this._container = typeof this.container === 'string'\r\n ? document.querySelector(this.container) as HTMLDivElement\r\n : this.container;\r\n\r\n if (!this._container) {\r\n throw new Error(`SlickGrid requires a valid container, ${this.container} does not exist in the DOM.`);\r\n }\r\n\r\n this._pubSubService = externalPubSub;\r\n this.onActiveCellChanged = new SlickEvent('onActiveCellChanged', externalPubSub);\r\n this.onActiveCellPositionChanged = new SlickEvent<{ grid: SlickGrid; }>('onActiveCellPositionChanged', externalPubSub);\r\n this.onAddNewRow = new SlickEvent('onAddNewRow', externalPubSub);\r\n this.onAutosizeColumns = new SlickEvent('onAutosizeColumns', externalPubSub);\r\n this.onBeforeAppendCell = new SlickEvent('onBeforeAppendCell', externalPubSub);\r\n this.onBeforeCellEditorDestroy = new SlickEvent('onBeforeCellEditorDestroy', externalPubSub);\r\n this.onBeforeColumnsResize = new SlickEvent('onBeforeColumnsResize', externalPubSub);\r\n this.onBeforeDestroy = new SlickEvent<{ grid: SlickGrid; }>('onBeforeDestroy', externalPubSub);\r\n this.onBeforeEditCell = new SlickEvent('onBeforeEditCell', externalPubSub);\r\n this.onBeforeFooterRowCellDestroy = new SlickEvent('onBeforeFooterRowCellDestroy', externalPubSub);\r\n this.onBeforeHeaderCellDestroy = new SlickEvent('onBeforeHeaderCellDestroy', externalPubSub);\r\n this.onBeforeHeaderRowCellDestroy = new SlickEvent('onBeforeHeaderRowCellDestroy', externalPubSub);\r\n this.onBeforeSetColumns = new SlickEvent('onBeforeSetColumns', externalPubSub);\r\n this.onBeforeSort = new SlickEvent('onBeforeSort', externalPubSub);\r\n this.onBeforeUpdateColumns = new SlickEvent('onBeforeUpdateColumns', externalPubSub);\r\n this.onCellChange = new SlickEvent('onCellChange', externalPubSub);\r\n this.onCellCssStylesChanged = new SlickEvent('onCellCssStylesChanged', externalPubSub);\r\n this.onClick = new SlickEvent('onClick', externalPubSub);\r\n this.onColumnsReordered = new SlickEvent('onColumnsReordered', externalPubSub);\r\n this.onColumnsDrag = new SlickEvent('onColumnsDrag', externalPubSub);\r\n this.onColumnsResized = new SlickEvent('onColumnsResized', externalPubSub);\r\n this.onColumnsResizeDblClick = new SlickEvent('onColumnsResizeDblClick', externalPubSub);\r\n this.onCompositeEditorChange = new SlickEvent('onCompositeEditorChange', externalPubSub);\r\n this.onContextMenu = new SlickEvent('onContextMenu', externalPubSub);\r\n this.onDrag = new SlickEvent('onDrag', externalPubSub);\r\n this.onDblClick = new SlickEvent('onDblClick', externalPubSub);\r\n this.onDragInit = new SlickEvent('onDragInit', externalPubSub);\r\n this.onDragStart = new SlickEvent('onDragStart', externalPubSub);\r\n this.onDragEnd = new SlickEvent('onDragEnd', externalPubSub);\r\n this.onFooterClick = new SlickEvent('onFooterClick', externalPubSub);\r\n this.onFooterContextMenu = new SlickEvent('onFooterContextMenu', externalPubSub);\r\n this.onFooterRowCellRendered = new SlickEvent('onFooterRowCellRendered', externalPubSub);\r\n this.onHeaderCellRendered = new SlickEvent('onHeaderCellRendered', externalPubSub);\r\n this.onHeaderClick = new SlickEvent('onHeaderClick', externalPubSub);\r\n this.onHeaderContextMenu = new SlickEvent('onHeaderContextMenu', externalPubSub);\r\n this.onHeaderMouseEnter = new SlickEvent('onHeaderMouseEnter', externalPubSub);\r\n this.onHeaderMouseLeave = new SlickEvent('onHeaderMouseLeave', externalPubSub);\r\n this.onHeaderRowCellRendered = new SlickEvent('onHeaderRowCellRendered', externalPubSub);\r\n this.onHeaderRowMouseEnter = new SlickEvent('onHeaderRowMouseEnter', externalPubSub);\r\n this.onHeaderRowMouseLeave = new SlickEvent('onHeaderRowMouseLeave', externalPubSub);\r\n this.onPreHeaderClick = new SlickEvent('onPreHeaderClick', externalPubSub);\r\n this.onPreHeaderContextMenu = new SlickEvent('onPreHeaderContextMenu', externalPubSub);\r\n this.onKeyDown = new SlickEvent('onKeyDown', externalPubSub);\r\n this.onMouseEnter = new SlickEvent('onMouseEnter', externalPubSub);\r\n this.onMouseLeave = new SlickEvent('onMouseLeave', externalPubSub);\r\n this.onRendered = new SlickEvent('onRendered', externalPubSub);\r\n this.onScroll = new SlickEvent('onScroll', externalPubSub);\r\n this.onSelectedRowsChanged = new SlickEvent('onSelectedRowsChanged', externalPubSub);\r\n this.onSetOptions = new SlickEvent('onSetOptions', externalPubSub);\r\n this.onActivateChangedOptions = new SlickEvent('onActivateChangedOptions', externalPubSub);\r\n this.onSort = new SlickEvent('onSort', externalPubSub);\r\n this.onValidationError = new SlickEvent('onValidationError', externalPubSub);\r\n this.onViewportChanged = new SlickEvent<{ grid: SlickGrid; }>('onViewportChanged', externalPubSub);\r\n\r\n this.initialize(options);\r\n }\r\n\r\n //////////////////////////////////////////////////////////////////////////////////////////////\r\n // Initialization\r\n\r\n /** Initializes the grid. */\r\n init() {\r\n this.finishInitialization();\r\n }\r\n\r\n /**\r\n * Apply HTML code by 3 different ways depending on what is provided as input and what options are enabled.\r\n * 1. value is an HTMLElement or DocumentFragment, then first empty the target and simply append the HTML to the target element.\r\n * 2. value is string and `enableHtmlRendering` is enabled, then use `target.innerHTML = value;`\r\n * 3. value is string and `enableHtmlRendering` is disabled, then use `target.textContent = value;`\r\n * @param target - target element to apply to\r\n * @param val - input value can be either a string or an HTMLElement\r\n * @param options -\r\n * `emptyTarget`, defaults to true, will empty the target.\r\n * `skipEmptyReassignment`, defaults to true, when enabled it will not try to reapply an empty value when the target is already empty\r\n */\r\n applyHtmlCode(target: HTMLElement, val: string | HTMLElement | DocumentFragment, options?: { emptyTarget?: boolean; skipEmptyReassignment?: boolean; }) {\r\n if (target) {\r\n if (val instanceof HTMLElement || val instanceof DocumentFragment) {\r\n // first empty target and then append new HTML element\r\n const emptyTarget = options?.emptyTarget !== false;\r\n if (emptyTarget) {\r\n Utils.emptyElement(target);\r\n }\r\n target.appendChild(val);\r\n } else {\r\n // when it's already empty and we try to reassign empty, it's probably ok to skip the assignment\r\n const skipEmptyReassignment = options?.skipEmptyReassignment !== false;\r\n if (skipEmptyReassignment && !Utils.isDefined(val) && !target.innerHTML) {\r\n return;\r\n }\r\n\r\n let sanitizedText = val;\r\n if (typeof sanitizedText === 'number' || typeof sanitizedText === 'boolean') {\r\n target.textContent = sanitizedText;\r\n } else {\r\n sanitizedText = this.sanitizeHtmlString(val as string);\r\n\r\n // apply HTML when enableHtmlRendering is enabled but make sure we do have a value (without a value, it will simply use `textContent` to clear text content)\r\n if (this._options.enableHtmlRendering && sanitizedText) {\r\n target.innerHTML = sanitizedText;\r\n } else {\r\n target.textContent = sanitizedText;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n protected initialize(options: Partial) {\r\n // calculate these only once and share between grid instances\r\n if (options?.mixinDefaults) {\r\n // use provided options and then assign defaults\r\n if (!this._options) { this._options = options as O; }\r\n Utils.applyDefaults(this._options, this._defaults);\r\n } else {\r\n this._options = Utils.extend(true, {}, this._defaults, options);\r\n }\r\n this.scrollThrottle = this.actionThrottle(this.render.bind(this), this._options.scrollRenderThrottling as number);\r\n this.maxSupportedCssHeight = this.maxSupportedCssHeight || this.getMaxSupportedCssHeight();\r\n this.validateAndEnforceOptions();\r\n this._columnDefaults.width = this._options.defaultColumnWidth;\r\n\r\n if (!this._options.suppressCssChangesOnHiddenInit) {\r\n this.cacheCssForHiddenInit();\r\n }\r\n\r\n this.updateColumnProps();\r\n\r\n // validate loaded JavaScript modules against requested options\r\n if (this._options.enableColumnReorder && (!Sortable || !Sortable.create)) {\r\n throw new Error('SlickGrid requires Sortable.js module to be loaded');\r\n }\r\n\r\n this.editController = {\r\n commitCurrentEdit: this.commitCurrentEdit.bind(this),\r\n cancelCurrentEdit: this.cancelCurrentEdit.bind(this),\r\n };\r\n\r\n Utils.emptyElement(this._container);\r\n this._container.style.outline = String(0);\r\n this._container.classList.add(this.uid);\r\n this._container.classList.add('ui-widget');\r\n this._container.setAttribute('role', 'grid');\r\n\r\n const containerStyles = window.getComputedStyle(this._container);\r\n if (!(/relative|absolute|fixed/).test(containerStyles.position)) {\r\n this._container.style.position = 'relative';\r\n }\r\n\r\n this._focusSink = Utils.createDomElement('div', { tabIndex: 0, style: { position: 'fixed', width: '0px', height: '0px', top: '0px', left: '0px', outline: '0px' } }, this._container);\r\n\r\n if (this._options.createTopHeaderPanel) {\r\n this._topHeaderPanelScroller = Utils.createDomElement('div', { className: 'slick-topheader-panel slick-state-default', style: { overflow: 'hidden', position: 'relative' } }, this._container);\r\n this._topHeaderPanelScroller.appendChild(document.createElement('div'));\r\n this._topHeaderPanel = Utils.createDomElement('div', null, this._topHeaderPanelScroller);\r\n this._topHeaderPanelSpacer = Utils.createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._topHeaderPanelScroller);\r\n\r\n if (!this._options.showTopHeaderPanel) {\r\n Utils.hide(this._topHeaderPanelScroller);\r\n }\r\n }\r\n\r\n // Containers used for scrolling frozen columns and rows\r\n this._paneHeaderL = Utils.createDomElement('div', { className: 'slick-pane slick-pane-header slick-pane-left', tabIndex: 0 }, this._container);\r\n this._paneHeaderR = Utils.createDomElement('div', { className: 'slick-pane slick-pane-header slick-pane-right', tabIndex: 0 }, this._container);\r\n this._paneTopL = Utils.createDomElement('div', { className: 'slick-pane slick-pane-top slick-pane-left', tabIndex: 0 }, this._container);\r\n this._paneTopR = Utils.createDomElement('div', { className: 'slick-pane slick-pane-top slick-pane-right', tabIndex: 0 }, this._container);\r\n this._paneBottomL = Utils.createDomElement('div', { className: 'slick-pane slick-pane-bottom slick-pane-left', tabIndex: 0 }, this._container);\r\n this._paneBottomR = Utils.createDomElement('div', { className: 'slick-pane slick-pane-bottom slick-pane-right', tabIndex: 0 }, this._container);\r\n\r\n if (this._options.createPreHeaderPanel) {\r\n this._preHeaderPanelScroller = Utils.createDomElement('div', { className: 'slick-preheader-panel ui-state-default slick-state-default', style: { overflow: 'hidden', position: 'relative' } }, this._paneHeaderL);\r\n this._preHeaderPanelScroller.appendChild(document.createElement('div'));\r\n this._preHeaderPanel = Utils.createDomElement('div', null, this._preHeaderPanelScroller);\r\n this._preHeaderPanelSpacer = Utils.createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._preHeaderPanelScroller);\r\n\r\n this._preHeaderPanelScrollerR = Utils.createDomElement('div', { className: 'slick-preheader-panel ui-state-default slick-state-default', style: { overflow: 'hidden', position: 'relative' } }, this._paneHeaderR);\r\n this._preHeaderPanelR = Utils.createDomElement('div', null, this._preHeaderPanelScrollerR);\r\n this._preHeaderPanelSpacerR = Utils.createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._preHeaderPanelScrollerR);\r\n\r\n if (!this._options.showPreHeaderPanel) {\r\n Utils.hide(this._preHeaderPanelScroller);\r\n Utils.hide(this._preHeaderPanelScrollerR);\r\n }\r\n }\r\n\r\n // Append the header scroller containers\r\n this._headerScrollerL = Utils.createDomElement('div', { className: 'slick-header ui-state-default slick-state-default slick-header-left' }, this._paneHeaderL);\r\n this._headerScrollerR = Utils.createDomElement('div', { className: 'slick-header ui-state-default slick-state-default slick-header-right' }, this._paneHeaderR);\r\n\r\n // Cache the header scroller containers\r\n this._headerScroller.push(this._headerScrollerL);\r\n this._headerScroller.push(this._headerScrollerR);\r\n\r\n // Append the columnn containers to the headers\r\n this._headerL = Utils.createDomElement('div', { className: 'slick-header-columns slick-header-columns-left', role: 'row', style: { left: '-1000px' } }, this._headerScrollerL);\r\n this._headerR = Utils.createDomElement('div', { className: 'slick-header-columns slick-header-columns-right', role: 'row', style: { left: '-1000px' } }, this._headerScrollerR);\r\n\r\n // Cache the header columns\r\n this._headers = [this._headerL, this._headerR];\r\n\r\n this._headerRowScrollerL = Utils.createDomElement('div', { className: 'slick-headerrow ui-state-default slick-state-default' }, this._paneTopL);\r\n this._headerRowScrollerR = Utils.createDomElement('div', { className: 'slick-headerrow ui-state-default slick-state-default' }, this._paneTopR);\r\n\r\n this._headerRowScroller = [this._headerRowScrollerL, this._headerRowScrollerR];\r\n\r\n this._headerRowSpacerL = Utils.createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._headerRowScrollerL);\r\n this._headerRowSpacerR = Utils.createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._headerRowScrollerR);\r\n\r\n this._headerRowL = Utils.createDomElement('div', { className: 'slick-headerrow-columns slick-headerrow-columns-left' }, this._headerRowScrollerL);\r\n this._headerRowR = Utils.createDomElement('div', { className: 'slick-headerrow-columns slick-headerrow-columns-right' }, this._headerRowScrollerR);\r\n\r\n this._headerRows = [this._headerRowL, this._headerRowR];\r\n\r\n // Append the top panel scroller\r\n this._topPanelScrollerL = Utils.createDomElement('div', { className: 'slick-top-panel-scroller ui-state-default slick-state-default' }, this._paneTopL);\r\n this._topPanelScrollerR = Utils.createDomElement('div', { className: 'slick-top-panel-scroller ui-state-default slick-state-default' }, this._paneTopR);\r\n\r\n this._topPanelScrollers = [this._topPanelScrollerL, this._topPanelScrollerR];\r\n\r\n // Append the top panel\r\n this._topPanelL = Utils.createDomElement('div', { className: 'slick-top-panel', style: { width: '10000px' } }, this._topPanelScrollerL);\r\n this._topPanelR = Utils.createDomElement('div', { className: 'slick-top-panel', style: { width: '10000px' } }, this._topPanelScrollerR);\r\n\r\n this._topPanels = [this._topPanelL, this._topPanelR];\r\n\r\n if (!this._options.showColumnHeader) {\r\n this._headerScroller.forEach((el) => {\r\n Utils.hide(el);\r\n });\r\n }\r\n\r\n if (!this._options.showTopPanel) {\r\n this._topPanelScrollers.forEach((scroller) => {\r\n Utils.hide(scroller);\r\n });\r\n }\r\n\r\n if (!this._options.showHeaderRow) {\r\n this._headerRowScroller.forEach((scroller) => {\r\n Utils.hide(scroller);\r\n });\r\n }\r\n\r\n // Append the viewport containers\r\n this._viewportTopL = Utils.createDomElement('div', { className: 'slick-viewport slick-viewport-top slick-viewport-left', tabIndex: 0 }, this._paneTopL);\r\n this._viewportTopR = Utils.createDomElement('div', { className: 'slick-viewport slick-viewport-top slick-viewport-right', tabIndex: 0 }, this._paneTopR);\r\n this._viewportBottomL = Utils.createDomElement('div', { className: 'slick-viewport slick-viewport-bottom slick-viewport-left', tabIndex: 0 }, this._paneBottomL);\r\n this._viewportBottomR = Utils.createDomElement('div', { className: 'slick-viewport slick-viewport-bottom slick-viewport-right', tabIndex: 0 }, this._paneBottomR);\r\n\r\n // Cache the viewports\r\n this._viewport = [this._viewportTopL, this._viewportTopR, this._viewportBottomL, this._viewportBottomR];\r\n if (this._options.viewportClass) {\r\n this._viewport.forEach((view) => {\r\n view.classList.add(...Utils.classNameToList((this._options.viewportClass)));\r\n });\r\n }\r\n\r\n // Default the active viewport to the top left\r\n this._activeViewportNode = this._viewportTopL;\r\n\r\n // Append the canvas containers\r\n this._canvasTopL = Utils.createDomElement('div', { className: 'grid-canvas grid-canvas-top grid-canvas-left', tabIndex: 0 }, this._viewportTopL);\r\n this._canvasTopR = Utils.createDomElement('div', { className: 'grid-canvas grid-canvas-top grid-canvas-right', tabIndex: 0 }, this._viewportTopR);\r\n this._canvasBottomL = Utils.createDomElement('div', { className: 'grid-canvas grid-canvas-bottom grid-canvas-left', tabIndex: 0 }, this._viewportBottomL);\r\n this._canvasBottomR = Utils.createDomElement('div', { className: 'grid-canvas grid-canvas-bottom grid-canvas-right', tabIndex: 0 }, this._viewportBottomR);\r\n\r\n // Cache the canvases\r\n this._canvas = [this._canvasTopL, this._canvasTopR, this._canvasBottomL, this._canvasBottomR];\r\n\r\n this.scrollbarDimensions = this.scrollbarDimensions || this.measureScrollbar();\r\n\r\n // Default the active canvas to the top left\r\n this._activeCanvasNode = this._canvasTopL;\r\n\r\n // top-header\r\n if (this._topHeaderPanelSpacer) {\r\n Utils.width(this._topHeaderPanelSpacer, this.getCanvasWidth() + this.scrollbarDimensions.width);\r\n }\r\n\r\n // pre-header\r\n if (this._preHeaderPanelSpacer) {\r\n Utils.width(this._preHeaderPanelSpacer, this.getCanvasWidth() + this.scrollbarDimensions.width);\r\n }\r\n\r\n this._headers.forEach((el) => {\r\n Utils.width(el, this.getHeadersWidth());\r\n });\r\n\r\n Utils.width(this._headerRowSpacerL, this.getCanvasWidth() + this.scrollbarDimensions.width);\r\n Utils.width(this._headerRowSpacerR, this.getCanvasWidth() + this.scrollbarDimensions.width);\r\n\r\n // footer Row\r\n if (this._options.createFooterRow) {\r\n this._footerRowScrollerR = Utils.createDomElement('div', { className: 'slick-footerrow ui-state-default slick-state-default' }, this._paneTopR);\r\n this._footerRowScrollerL = Utils.createDomElement('div', { className: 'slick-footerrow ui-state-default slick-state-default' }, this._paneTopL);\r\n\r\n this._footerRowScroller = [this._footerRowScrollerL, this._footerRowScrollerR];\r\n\r\n this._footerRowSpacerL = Utils.createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._footerRowScrollerL);\r\n Utils.width(this._footerRowSpacerL, this.getCanvasWidth() + this.scrollbarDimensions.width);\r\n this._footerRowSpacerR = Utils.createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._footerRowScrollerR);\r\n Utils.width(this._footerRowSpacerR, this.getCanvasWidth() + this.scrollbarDimensions.width);\r\n\r\n this._footerRowL = Utils.createDomElement('div', { className: 'slick-footerrow-columns slick-footerrow-columns-left' }, this._footerRowScrollerL);\r\n this._footerRowR = Utils.createDomElement('div', { className: 'slick-footerrow-columns slick-footerrow-columns-right' }, this._footerRowScrollerR);\r\n\r\n this._footerRow = [this._footerRowL, this._footerRowR];\r\n\r\n if (!this._options.showFooterRow) {\r\n this._footerRowScroller.forEach((scroller) => {\r\n Utils.hide(scroller);\r\n });\r\n }\r\n }\r\n\r\n this._focusSink2 = this._focusSink.cloneNode(true) as HTMLDivElement;\r\n this._container.appendChild(this._focusSink2);\r\n\r\n if (!this._options.explicitInitialization) {\r\n this.finishInitialization();\r\n }\r\n }\r\n\r\n protected finishInitialization() {\r\n if (!this.initialized) {\r\n this.initialized = true;\r\n\r\n this.getViewportWidth();\r\n this.getViewportHeight();\r\n\r\n // header columns and cells may have different padding/border skewing width calculations (box-sizing, hello?)\r\n // calculate the diff so we can set consistent sizes\r\n this.measureCellPaddingAndBorder();\r\n\r\n // for usability reasons, all text selection in SlickGrid is disabled\r\n // with the exception of input and textarea elements (selection must\r\n // be enabled there so that editors work as expected); note that\r\n // selection in grid cells (grid body) is already unavailable in\r\n // all browsers except IE\r\n this.disableSelection(this._headers); // disable all text selection in header (including input and textarea)\r\n\r\n if (!this._options.enableTextSelectionOnCells) {\r\n // disable text selection in grid cells except in input and textarea elements\r\n // (this is IE-specific, because selectstart event will only fire in IE)\r\n this._viewport.forEach((view) => {\r\n this._bindingEventService.bind(view, 'selectstart', (event) => {\r\n if (event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement) {\r\n return;\r\n }\r\n });\r\n });\r\n }\r\n\r\n this.setFrozenOptions();\r\n this.setPaneVisibility();\r\n this.setScroller();\r\n this.setOverflow();\r\n\r\n this.updateColumnCaches();\r\n this.createColumnHeaders();\r\n this.createColumnFooter();\r\n this.setupColumnSort();\r\n this.createCssRules();\r\n this.resizeCanvas();\r\n this.bindAncestorScrollEvents();\r\n\r\n this._bindingEventService.bind(this._container, 'resize', this.resizeCanvas.bind(this));\r\n this._viewport.forEach((view) => {\r\n this._bindingEventService.bind(view, 'scroll', this.handleScroll.bind(this));\r\n });\r\n\r\n if (this._options.enableMouseWheelScrollHandler) {\r\n this._viewport.forEach((view) => {\r\n this.slickMouseWheelInstances.push(MouseWheel({\r\n element: view,\r\n onMouseWheel: this.handleMouseWheel.bind(this)\r\n }));\r\n });\r\n }\r\n\r\n this._headerScroller.forEach((el) => {\r\n this._bindingEventService.bind(el, 'contextmenu', this.handleHeaderContextMenu.bind(this) as EventListener);\r\n this._bindingEventService.bind(el, 'click', this.handleHeaderClick.bind(this) as EventListener);\r\n });\r\n\r\n this._headerRowScroller.forEach((scroller) => {\r\n this._bindingEventService.bind(scroller, 'scroll', this.handleHeaderRowScroll.bind(this) as EventListener);\r\n });\r\n\r\n if (this._options.createFooterRow) {\r\n this._footerRow.forEach((footer) => {\r\n this._bindingEventService.bind(footer, 'contextmenu', this.handleFooterContextMenu.bind(this) as EventListener);\r\n this._bindingEventService.bind(footer, 'click', this.handleFooterClick.bind(this) as EventListener);\r\n });\r\n\r\n this._footerRowScroller.forEach((scroller) => {\r\n this._bindingEventService.bind(scroller, 'scroll', this.handleFooterRowScroll.bind(this) as EventListener);\r\n });\r\n }\r\n\r\n if (this._options.createTopHeaderPanel) {\r\n this._bindingEventService.bind(this._topHeaderPanelScroller, 'scroll', this.handleTopHeaderPanelScroll.bind(this) as EventListener);\r\n }\r\n\r\n if (this._options.createPreHeaderPanel) {\r\n this._bindingEventService.bind(this._preHeaderPanelScroller, 'scroll', this.handlePreHeaderPanelScroll.bind(this) as EventListener);\r\n this._bindingEventService.bind(this._preHeaderPanelScroller, 'contextmenu', this.handlePreHeaderContextMenu.bind(this) as EventListener);\r\n this._bindingEventService.bind(this._preHeaderPanelScrollerR, 'contextmenu', this.handlePreHeaderContextMenu.bind(this) as EventListener);\r\n this._bindingEventService.bind(this._preHeaderPanelScroller, 'click', this.handlePreHeaderClick.bind(this) as EventListener);\r\n this._bindingEventService.bind(this._preHeaderPanelScrollerR, 'click', this.handlePreHeaderClick.bind(this) as EventListener);\r\n }\r\n\r\n this._bindingEventService.bind(this._focusSink, 'keydown', this.handleKeyDown.bind(this) as EventListener);\r\n this._bindingEventService.bind(this._focusSink2, 'keydown', this.handleKeyDown.bind(this) as EventListener);\r\n\r\n this._canvas.forEach((element) => {\r\n this._bindingEventService.bind(element, 'keydown', this.handleKeyDown.bind(this) as EventListener);\r\n this._bindingEventService.bind(element, 'click', this.handleClick.bind(this) as EventListener);\r\n this._bindingEventService.bind(element, 'dblclick', this.handleDblClick.bind(this) as EventListener);\r\n this._bindingEventService.bind(element, 'contextmenu', this.handleContextMenu.bind(this) as EventListener);\r\n this._bindingEventService.bind(element, 'mouseover', this.handleCellMouseOver.bind(this) as EventListener);\r\n this._bindingEventService.bind(element, 'mouseout', this.handleCellMouseOut.bind(this) as EventListener);\r\n });\r\n\r\n if (Draggable) {\r\n this.slickDraggableInstance = Draggable({\r\n containerElement: this._container,\r\n allowDragFrom: 'div.slick-cell',\r\n // the slick cell parent must always contain `.dnd` and/or `.cell-reorder` class to be identified as draggable\r\n allowDragFromClosest: 'div.slick-cell.dnd, div.slick-cell.cell-reorder',\r\n preventDragFromKeys: this._options.preventDragFromKeys,\r\n onDragInit: this.handleDragInit.bind(this),\r\n onDragStart: this.handleDragStart.bind(this),\r\n onDrag: this.handleDrag.bind(this),\r\n onDragEnd: this.handleDragEnd.bind(this)\r\n });\r\n }\r\n\r\n if (!this._options.suppressCssChangesOnHiddenInit) {\r\n this.restoreCssFromHiddenInit();\r\n }\r\n }\r\n }\r\n\r\n /** handles \"display:none\" on container or container parents, related to issue: https://github.com/6pac/SlickGrid/issues/568 */\r\n cacheCssForHiddenInit() {\r\n this._hiddenParents = Utils.parents(this._container, ':hidden') as HTMLElement[];\r\n this._hiddenParents.forEach(el => {\r\n const old: Partial = {};\r\n Object.keys(this.cssShow).forEach(name => {\r\n if (this.cssShow) {\r\n old[name as any] = el.style[name as 'position' | 'visibility' | 'display'];\r\n el.style[name as any] = this.cssShow[name as 'position' | 'visibility' | 'display'];\r\n }\r\n });\r\n this.oldProps.push(old);\r\n });\r\n }\r\n\r\n restoreCssFromHiddenInit() {\r\n // finish handle display:none on container or container parents\r\n // - put values back the way they were\r\n let i = 0;\r\n if (this._hiddenParents) {\r\n this._hiddenParents.forEach(el => {\r\n const old = this.oldProps[i++];\r\n Object.keys(this.cssShow).forEach(name => {\r\n if (this.cssShow) {\r\n el.style[name as CSSStyleDeclarationWritable] = (old as any)[name];\r\n }\r\n });\r\n });\r\n }\r\n }\r\n\r\n protected hasFrozenColumns() {\r\n return this._options.frozenColumn! > -1;\r\n }\r\n\r\n /** Register an external Plugin */\r\n registerPlugin(plugin: T) {\r\n this.plugins.unshift(plugin);\r\n plugin.init(this as unknown as SlickGridModel);\r\n }\r\n\r\n /** Unregister (destroy) an external Plugin */\r\n unregisterPlugin(plugin: SlickPlugin) {\r\n for (let i = this.plugins.length; i >= 0; i--) {\r\n if (this.plugins[i] === plugin) {\r\n this.plugins[i]?.destroy();\r\n this.plugins.splice(i, 1);\r\n break;\r\n }\r\n }\r\n }\r\n\r\n /** Get a Plugin (addon) by its name */\r\n getPluginByName

(name: string) {\r\n for (let i = this.plugins.length - 1; i >= 0; i--) {\r\n if (this.plugins[i]?.pluginName === name) {\r\n return this.plugins[i] as P;\r\n }\r\n }\r\n return undefined;\r\n }\r\n\r\n /**\r\n * Unregisters a current selection model and registers a new one. See the definition of SelectionModel for more information.\r\n * @param {Object} selectionModel A SelectionModel.\r\n */\r\n setSelectionModel(model: SelectionModel) {\r\n if (this.selectionModel) {\r\n this.selectionModel.onSelectedRangesChanged.unsubscribe(this.handleSelectedRangesChanged.bind(this));\r\n if (this.selectionModel.destroy) {\r\n this.selectionModel.destroy();\r\n }\r\n }\r\n\r\n this.selectionModel = model;\r\n if (this.selectionModel) {\r\n this.selectionModel.init(this as unknown as SlickGridModel);\r\n this.selectionModel.onSelectedRangesChanged.subscribe(this.handleSelectedRangesChanged.bind(this));\r\n }\r\n }\r\n\r\n /** Returns the current SelectionModel. See here for more information about SelectionModels. */\r\n getSelectionModel() {\r\n return this.selectionModel;\r\n }\r\n\r\n /** Get Grid Canvas Node DOM Element */\r\n getCanvasNode(columnIdOrIdx?: number | string, rowIndex?: number) {\r\n return this._getContainerElement(this.getCanvases(), columnIdOrIdx, rowIndex) as HTMLDivElement;\r\n }\r\n\r\n /** Get the canvas DOM element */\r\n getActiveCanvasNode(e?: Event | SlickEventData_) {\r\n if (e === undefined) {\r\n return this._activeCanvasNode;\r\n }\r\n\r\n if (e instanceof SlickEventData) {\r\n e = e.getNativeEvent();\r\n }\r\n\r\n this._activeCanvasNode = (e as any)?.target.closest('.grid-canvas');\r\n return this._activeCanvasNode;\r\n }\r\n\r\n /** Get the canvas DOM element */\r\n getCanvases() {\r\n return this._canvas;\r\n }\r\n\r\n /** Get the Viewport DOM node element */\r\n getViewportNode(columnIdOrIdx?: number | string, rowIndex?: number) {\r\n return this._getContainerElement(this.getViewports(), columnIdOrIdx, rowIndex);\r\n }\r\n\r\n /** Get all the Viewport node elements */\r\n getViewports() {\r\n return this._viewport;\r\n }\r\n\r\n getActiveViewportNode(e: Event | SlickEventData_) {\r\n this.setActiveViewportNode(e);\r\n\r\n return this._activeViewportNode;\r\n }\r\n\r\n /** Sets an active viewport node */\r\n setActiveViewportNode(e: Event | SlickEventData_) {\r\n if (e instanceof SlickEventData) {\r\n e = e.getNativeEvent();\r\n }\r\n this._activeViewportNode = (e as any)?.target.closest('.slick-viewport');\r\n return this._activeViewportNode;\r\n }\r\n\r\n protected _getContainerElement(targetContainers: HTMLElement[], columnIdOrIdx?: number | string, rowIndex?: number) {\r\n if (!targetContainers) { return; }\r\n if (!columnIdOrIdx) { columnIdOrIdx = 0; }\r\n if (!rowIndex) { rowIndex = 0; }\r\n\r\n const idx = (typeof columnIdOrIdx === 'number' ? columnIdOrIdx : this.getColumnIndex(columnIdOrIdx));\r\n\r\n const isBottomSide = this.hasFrozenRows && rowIndex >= this.actualFrozenRow + (this._options.frozenBottom ? 0 : 1);\r\n const isRightSide = this.hasFrozenColumns() && idx > this._options.frozenColumn!;\r\n\r\n return targetContainers[(isBottomSide ? 2 : 0) + (isRightSide ? 1 : 0)];\r\n }\r\n\r\n protected measureScrollbar() {\r\n let className = '';\r\n this._viewport.forEach(v => className += v.className);\r\n const outerdiv = Utils.createDomElement('div', { className, style: { position: 'absolute', top: '-10000px', left: '-10000px', overflow: 'auto', width: '100px', height: '100px' } }, document.body);\r\n const innerdiv = Utils.createDomElement('div', { style: { width: '200px', height: '200px', overflow: 'auto' } }, outerdiv);\r\n const dim = {\r\n width: outerdiv.offsetWidth - outerdiv.clientWidth,\r\n height: outerdiv.offsetHeight - outerdiv.clientHeight\r\n };\r\n innerdiv.remove();\r\n outerdiv.remove();\r\n return dim;\r\n }\r\n\r\n /** Get the headers width in pixel */\r\n getHeadersWidth() {\r\n this.headersWidth = this.headersWidthL = this.headersWidthR = 0;\r\n const includeScrollbar = !this._options.autoHeight;\r\n\r\n let i = 0;\r\n const ii = this.columns.length;\r\n for (i = 0; i < ii; i++) {\r\n if (!this.columns[i] || this.columns[i].hidden) { continue; }\r\n\r\n const width = this.columns[i].width;\r\n\r\n if ((this._options.frozenColumn!) > -1 && (i > this._options.frozenColumn!)) {\r\n this.headersWidthR += width || 0;\r\n } else {\r\n this.headersWidthL += width || 0;\r\n }\r\n }\r\n\r\n if (includeScrollbar) {\r\n if ((this._options.frozenColumn!) > -1 && (i > this._options.frozenColumn!)) {\r\n this.headersWidthR += this.scrollbarDimensions?.width ?? 0;\r\n } else {\r\n this.headersWidthL += this.scrollbarDimensions?.width ?? 0;\r\n }\r\n }\r\n\r\n if (this.hasFrozenColumns()) {\r\n this.headersWidthL = this.headersWidthL + 1000;\r\n\r\n this.headersWidthR = Math.max(this.headersWidthR, this.viewportW) + this.headersWidthL;\r\n this.headersWidthR += this.scrollbarDimensions?.width ?? 0;\r\n } else {\r\n this.headersWidthL += this.scrollbarDimensions?.width ?? 0;\r\n this.headersWidthL = Math.max(this.headersWidthL, this.viewportW) + 1000;\r\n }\r\n\r\n this.headersWidth = this.headersWidthL + this.headersWidthR;\r\n return Math.max(this.headersWidth, this.viewportW) + 1000;\r\n }\r\n\r\n /** Get the grid canvas width */\r\n getCanvasWidth(): number {\r\n const availableWidth = this.viewportHasVScroll ? this.viewportW - (this.scrollbarDimensions?.width ?? 0) : this.viewportW;\r\n let i = this.columns.length;\r\n\r\n this.canvasWidthL = this.canvasWidthR = 0;\r\n\r\n while (i--) {\r\n if (!this.columns[i] || this.columns[i].hidden) { continue; }\r\n\r\n if (this.hasFrozenColumns() && (i > this._options.frozenColumn!)) {\r\n this.canvasWidthR += this.columns[i].width || 0;\r\n } else {\r\n this.canvasWidthL += this.columns[i].width || 0;\r\n }\r\n }\r\n let totalRowWidth = this.canvasWidthL + this.canvasWidthR;\r\n if (this._options.fullWidthRows) {\r\n const extraWidth = Math.max(totalRowWidth, availableWidth) - totalRowWidth;\r\n if (extraWidth > 0) {\r\n totalRowWidth += extraWidth;\r\n if (this.hasFrozenColumns()) {\r\n this.canvasWidthR += extraWidth;\r\n } else {\r\n this.canvasWidthL += extraWidth;\r\n }\r\n }\r\n }\r\n return totalRowWidth;\r\n }\r\n\r\n protected updateCanvasWidth(forceColumnWidthsUpdate?: boolean) {\r\n const oldCanvasWidth = this.canvasWidth;\r\n const oldCanvasWidthL = this.canvasWidthL;\r\n const oldCanvasWidthR = this.canvasWidthR;\r\n this.canvasWidth = this.getCanvasWidth();\r\n\r\n if (this._options.createTopHeaderPanel) {\r\n Utils.width(this._topHeaderPanel, this._options.topHeaderPanelWidth ?? this.canvasWidth);\r\n }\r\n\r\n const widthChanged = this.canvasWidth !== oldCanvasWidth || this.canvasWidthL !== oldCanvasWidthL || this.canvasWidthR !== oldCanvasWidthR;\r\n\r\n if (widthChanged || this.hasFrozenColumns() || this.hasFrozenRows) {\r\n Utils.width(this._canvasTopL, this.canvasWidthL);\r\n\r\n this.getHeadersWidth();\r\n\r\n Utils.width(this._headerL, this.headersWidthL);\r\n Utils.width(this._headerR, this.headersWidthR);\r\n\r\n if (this.hasFrozenColumns()) {\r\n const cWidth = Utils.width(this._container) || 0;\r\n if (cWidth > 0 && this.canvasWidthL > cWidth && this._options.throwWhenFrozenNotAllViewable) {\r\n throw new Error('[SlickGrid] Frozen columns cannot be wider than the actual grid container width. '\r\n + 'Make sure to have less columns freezed or make your grid container wider');\r\n }\r\n Utils.width(this._canvasTopR, this.canvasWidthR);\r\n\r\n Utils.width(this._paneHeaderL, this.canvasWidthL);\r\n Utils.setStyleSize(this._paneHeaderR, 'left', this.canvasWidthL);\r\n Utils.setStyleSize(this._paneHeaderR, 'width', this.viewportW - this.canvasWidthL);\r\n\r\n Utils.width(this._paneTopL, this.canvasWidthL);\r\n Utils.setStyleSize(this._paneTopR, 'left', this.canvasWidthL);\r\n Utils.width(this._paneTopR, this.viewportW - this.canvasWidthL);\r\n\r\n Utils.width(this._headerRowScrollerL, this.canvasWidthL);\r\n Utils.width(this._headerRowScrollerR, this.viewportW - this.canvasWidthL);\r\n\r\n Utils.width(this._headerRowL, this.canvasWidthL);\r\n Utils.width(this._headerRowR, this.canvasWidthR);\r\n\r\n if (this._options.createFooterRow) {\r\n Utils.width(this._footerRowScrollerL, this.canvasWidthL);\r\n Utils.width(this._footerRowScrollerR, this.viewportW - this.canvasWidthL);\r\n\r\n Utils.width(this._footerRowL, this.canvasWidthL);\r\n Utils.width(this._footerRowR, this.canvasWidthR);\r\n }\r\n if (this._options.createPreHeaderPanel) {\r\n Utils.width(this._preHeaderPanel, this._options.preHeaderPanelWidth ?? this.canvasWidth);\r\n }\r\n Utils.width(this._viewportTopL, this.canvasWidthL);\r\n Utils.width(this._viewportTopR, this.viewportW - this.canvasWidthL);\r\n\r\n if (this.hasFrozenRows) {\r\n Utils.width(this._paneBottomL, this.canvasWidthL);\r\n Utils.setStyleSize(this._paneBottomR, 'left', this.canvasWidthL);\r\n\r\n Utils.width(this._viewportBottomL, this.canvasWidthL);\r\n Utils.width(this._viewportBottomR, this.viewportW - this.canvasWidthL);\r\n\r\n Utils.width(this._canvasBottomL, this.canvasWidthL);\r\n Utils.width(this._canvasBottomR, this.canvasWidthR);\r\n }\r\n } else {\r\n Utils.width(this._paneHeaderL, '100%');\r\n Utils.width(this._paneTopL, '100%');\r\n Utils.width(this._headerRowScrollerL, '100%');\r\n Utils.width(this._headerRowL, this.canvasWidth);\r\n\r\n if (this._options.createFooterRow) {\r\n Utils.width(this._footerRowScrollerL, '100%');\r\n Utils.width(this._footerRowL, this.canvasWidth);\r\n }\r\n\r\n if (this._options.createPreHeaderPanel) {\r\n Utils.width(this._preHeaderPanel, this._options.preHeaderPanelWidth ?? this.canvasWidth);\r\n }\r\n Utils.width(this._viewportTopL, '100%');\r\n\r\n if (this.hasFrozenRows) {\r\n Utils.width(this._viewportBottomL, '100%');\r\n Utils.width(this._canvasBottomL, this.canvasWidthL);\r\n }\r\n }\r\n }\r\n\r\n this.viewportHasHScroll = (this.canvasWidth >= this.viewportW - (this.scrollbarDimensions?.width ?? 0));\r\n\r\n Utils.width(this._headerRowSpacerL, this.canvasWidth + (this.viewportHasVScroll ? (this.scrollbarDimensions?.width ?? 0) : 0));\r\n Utils.width(this._headerRowSpacerR, this.canvasWidth + (this.viewportHasVScroll ? (this.scrollbarDimensions?.width ?? 0) : 0));\r\n\r\n if (this._options.createFooterRow) {\r\n Utils.width(this._footerRowSpacerL, this.canvasWidth + (this.viewportHasVScroll ? (this.scrollbarDimensions?.width ?? 0) : 0));\r\n Utils.width(this._footerRowSpacerR, this.canvasWidth + (this.viewportHasVScroll ? (this.scrollbarDimensions?.width ?? 0) : 0));\r\n }\r\n\r\n if (widthChanged || forceColumnWidthsUpdate) {\r\n this.applyColumnWidths();\r\n }\r\n }\r\n\r\n protected disableSelection(target: HTMLElement[]) {\r\n target.forEach((el) => {\r\n el.setAttribute('unselectable', 'on');\r\n (el.style as any).mozUserSelect = 'none';\r\n this._bindingEventService.bind(el, 'selectstart', () => false);\r\n });\r\n }\r\n\r\n protected getMaxSupportedCssHeight() {\r\n let supportedHeight = 1000000;\r\n // FF reports the height back but still renders blank after ~6M px\r\n // let testUpTo = navigator.userAgent.toLowerCase().match(/firefox/) ? 6000000 : 1000000000;\r\n const testUpTo = navigator.userAgent.toLowerCase().match(/firefox/) ? this._options.ffMaxSupportedCssHeight : this._options.maxSupportedCssHeight;\r\n const div = Utils.createDomElement('div', { style: { display: 'hidden' } }, document.body);\r\n\r\n while (true) {\r\n const test = supportedHeight * 2;\r\n Utils.height(div, test);\r\n const height = Utils.height(div);\r\n\r\n if (test > testUpTo! || height !== test) {\r\n break;\r\n } else {\r\n supportedHeight = test;\r\n }\r\n }\r\n\r\n div.remove();\r\n return supportedHeight;\r\n }\r\n\r\n /** Get grid unique identifier */\r\n getUID() {\r\n return this.uid;\r\n }\r\n\r\n /** Get Header Column Width Difference in pixel */\r\n getHeaderColumnWidthDiff() {\r\n return this.headerColumnWidthDiff;\r\n }\r\n\r\n /** Get scrollbar dimensions */\r\n getScrollbarDimensions() {\r\n return this.scrollbarDimensions;\r\n }\r\n\r\n /** Get the displayed scrollbar dimensions */\r\n getDisplayedScrollbarDimensions() {\r\n return {\r\n width: this.viewportHasVScroll ? (this.scrollbarDimensions?.width ?? 0) : 0,\r\n height: this.viewportHasHScroll ? (this.scrollbarDimensions?.height ?? 0) : 0\r\n };\r\n }\r\n\r\n /** Get the absolute column minimum width */\r\n getAbsoluteColumnMinWidth(): number {\r\n return this.absoluteColumnMinWidth;\r\n }\r\n\r\n getPubSubService(): BasePubSub | undefined {\r\n return this._pubSubService;\r\n }\r\n\r\n // TODO: this is static. need to handle page mutation.\r\n protected bindAncestorScrollEvents() {\r\n let elem: HTMLElement | null = (this.hasFrozenRows && !this._options.frozenBottom) ? this._canvasBottomL : this._canvasTopL;\r\n while ((elem = elem!.parentNode as HTMLElement) !== document.body && elem) {\r\n // bind to scroll containers only\r\n if (elem === this._viewportTopL || elem.scrollWidth !== elem.clientWidth || elem.scrollHeight !== elem.clientHeight) {\r\n this._boundAncestors.push(elem);\r\n this._bindingEventService.bind(elem, 'scroll', this.handleActiveCellPositionChange.bind(this));\r\n }\r\n }\r\n }\r\n\r\n protected unbindAncestorScrollEvents() {\r\n this._boundAncestors.forEach((ancestor) => {\r\n this._bindingEventService.unbindByEventName(ancestor, 'scroll');\r\n });\r\n this._boundAncestors = [];\r\n }\r\n\r\n /**\r\n * Updates an existing column definition and a corresponding header DOM element with the new title and tooltip.\r\n * @param {Number|String} columnId Column id.\r\n * @param {string | HTMLElement | DocumentFragment} [title] New column name.\r\n * @param {String} [toolTip] New column tooltip.\r\n */\r\n updateColumnHeader(columnId: number | string, title?: string | HTMLElement | DocumentFragment, toolTip?: string) {\r\n if (this.initialized) {\r\n const idx = this.getColumnIndex(columnId);\r\n if (!Utils.isDefined(idx)) {\r\n return;\r\n }\r\n\r\n const columnDef = this.columns[idx];\r\n const header: HTMLElement | undefined = this.getColumnByIndex(idx);\r\n if (header) {\r\n if (title !== undefined) {\r\n this.columns[idx].name = title;\r\n }\r\n if (toolTip !== undefined) {\r\n this.columns[idx].toolTip = toolTip;\r\n }\r\n\r\n this.trigger(this.onBeforeHeaderCellDestroy, {\r\n node: header,\r\n column: columnDef,\r\n grid: this\r\n });\r\n\r\n header.setAttribute('title', toolTip || '');\r\n if (title !== undefined) {\r\n this.applyHtmlCode(header.children[0] as HTMLElement, title);\r\n }\r\n\r\n this.trigger(this.onHeaderCellRendered, {\r\n node: header,\r\n column: columnDef,\r\n grid: this\r\n });\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Get the Header DOM element\r\n * @param {C} columnDef - column definition\r\n */\r\n getHeader(columnDef: C) {\r\n if (!columnDef) {\r\n return this.hasFrozenColumns() ? this._headers : this._headerL;\r\n }\r\n const idx = this.getColumnIndex(columnDef.id);\r\n return this.hasFrozenColumns() ? ((idx <= this._options.frozenColumn!) ? this._headerL : this._headerR) : this._headerL;\r\n }\r\n\r\n /**\r\n * Get a specific Header Column DOM element by its column Id or index\r\n * @param {Number|String} columnIdOrIdx - column Id or index\r\n */\r\n getHeaderColumn(columnIdOrIdx: number | string) {\r\n const idx = (typeof columnIdOrIdx === 'number' ? columnIdOrIdx : this.getColumnIndex(columnIdOrIdx));\r\n const targetHeader = this.hasFrozenColumns() ? ((idx <= this._options.frozenColumn!) ? this._headerL : this._headerR) : this._headerL;\r\n const targetIndex = this.hasFrozenColumns() ? ((idx <= this._options.frozenColumn!) ? idx : idx - this._options.frozenColumn! - 1) : idx;\r\n\r\n return targetHeader.children[targetIndex] as HTMLDivElement;\r\n }\r\n\r\n /** Get the Header Row DOM element */\r\n getHeaderRow() {\r\n return this.hasFrozenColumns() ? this._headerRows : this._headerRows[0];\r\n }\r\n\r\n /** Get the Footer DOM element */\r\n getFooterRow() {\r\n return this.hasFrozenColumns() ? this._footerRow : this._footerRow[0];\r\n }\r\n\r\n /** @alias `getPreHeaderPanelLeft` */\r\n getPreHeaderPanel() {\r\n return this._preHeaderPanel;\r\n }\r\n\r\n /** Get the Pre-Header Panel Left DOM node element */\r\n getPreHeaderPanelLeft() {\r\n return this._preHeaderPanel;\r\n }\r\n\r\n /** Get the Pre-Header Panel Right DOM node element */\r\n getPreHeaderPanelRight() {\r\n return this._preHeaderPanelR;\r\n }\r\n\r\n /** Get the Top-Header Panel DOM node element */\r\n getTopHeaderPanel() {\r\n return this._topHeaderPanel;\r\n }\r\n\r\n /**\r\n * Get Header Row Column DOM element by its column Id or index\r\n * @param {Number|String} columnIdOrIdx - column Id or index\r\n */\r\n getHeaderRowColumn(columnIdOrIdx: number | string) {\r\n let idx = (typeof columnIdOrIdx === 'number' ? columnIdOrIdx : this.getColumnIndex(columnIdOrIdx));\r\n let headerRowTarget: HTMLDivElement;\r\n\r\n if (this.hasFrozenColumns()) {\r\n if (idx <= this._options.frozenColumn!) {\r\n headerRowTarget = this._headerRowL;\r\n } else {\r\n headerRowTarget = this._headerRowR;\r\n idx -= this._options.frozenColumn! + 1;\r\n }\r\n } else {\r\n headerRowTarget = this._headerRowL;\r\n }\r\n\r\n return headerRowTarget.children[idx] as HTMLDivElement;\r\n }\r\n\r\n /**\r\n * Get the Footer Row Column DOM element by its column Id or index\r\n * @param {Number|String} columnIdOrIdx - column Id or index\r\n */\r\n getFooterRowColumn(columnIdOrIdx: number | string) {\r\n let idx = (typeof columnIdOrIdx === 'number' ? columnIdOrIdx : this.getColumnIndex(columnIdOrIdx));\r\n let footerRowTarget: HTMLDivElement;\r\n\r\n if (this.hasFrozenColumns()) {\r\n if (idx <= this._options.frozenColumn!) {\r\n footerRowTarget = this._footerRowL;\r\n } else {\r\n footerRowTarget = this._footerRowR;\r\n\r\n idx -= this._options.frozenColumn! + 1;\r\n }\r\n } else {\r\n footerRowTarget = this._footerRowL;\r\n }\r\n\r\n return footerRowTarget.children[idx] as HTMLDivElement;\r\n }\r\n\r\n protected createColumnFooter() {\r\n if (this._options.createFooterRow) {\r\n this._footerRow.forEach((footer) => {\r\n const columnElements = footer.querySelectorAll('.slick-footerrow-column');\r\n columnElements.forEach((column) => {\r\n const columnDef = Utils.storage.get(column, 'column');\r\n this.trigger(this.onBeforeFooterRowCellDestroy, {\r\n node: column,\r\n column: columnDef,\r\n grid: this\r\n });\r\n });\r\n });\r\n\r\n Utils.emptyElement(this._footerRowL);\r\n Utils.emptyElement(this._footerRowR);\r\n\r\n for (let i = 0; i < this.columns.length; i++) {\r\n const m = this.columns[i];\r\n if (!m || m.hidden) { continue; }\r\n\r\n const footerRowCell = Utils.createDomElement('div', { className: `ui-state-default slick-state-default slick-footerrow-column l${i} r${i}` }, this.hasFrozenColumns() && (i > this._options.frozenColumn!) ? this._footerRowR : this._footerRowL);\r\n const className = this.hasFrozenColumns() && i <= this._options.frozenColumn! ? 'frozen' : null;\r\n if (className) {\r\n footerRowCell.classList.add(className);\r\n }\r\n\r\n Utils.storage.put(footerRowCell, 'column', m);\r\n\r\n this.trigger(this.onFooterRowCellRendered, {\r\n node: footerRowCell,\r\n column: m,\r\n grid: this\r\n });\r\n }\r\n }\r\n }\r\n\r\n protected handleHeaderMouseHoverOn(e: Event | SlickEventData_) {\r\n (e as any)?.target.classList.add('ui-state-hover', 'slick-state-hover');\r\n }\r\n\r\n protected handleHeaderMouseHoverOff(e: Event | SlickEventData_) {\r\n (e as any)?.target.classList.remove('ui-state-hover', 'slick-state-hover');\r\n }\r\n\r\n protected createColumnHeaders() {\r\n this._headers.forEach((header) => {\r\n const columnElements = header.querySelectorAll('.slick-header-column');\r\n columnElements.forEach((column) => {\r\n const columnDef = Utils.storage.get(column, 'column');\r\n if (columnDef) {\r\n this.trigger(this.onBeforeHeaderCellDestroy, {\r\n node: column,\r\n column: columnDef,\r\n grid: this\r\n });\r\n }\r\n });\r\n });\r\n\r\n Utils.emptyElement(this._headerL);\r\n Utils.emptyElement(this._headerR);\r\n\r\n this.getHeadersWidth();\r\n\r\n Utils.width(this._headerL, this.headersWidthL);\r\n Utils.width(this._headerR, this.headersWidthR);\r\n\r\n this._headerRows.forEach((row) => {\r\n const columnElements = row.querySelectorAll('.slick-headerrow-column');\r\n columnElements.forEach((column) => {\r\n const columnDef = Utils.storage.get(column, 'column');\r\n if (columnDef) {\r\n this.trigger(this.onBeforeHeaderRowCellDestroy, {\r\n node: this,\r\n column: columnDef,\r\n grid: this\r\n });\r\n }\r\n });\r\n });\r\n\r\n Utils.emptyElement(this._headerRowL);\r\n Utils.emptyElement(this._headerRowR);\r\n\r\n if (this._options.createFooterRow) {\r\n const footerRowLColumnElements = this._footerRowL.querySelectorAll('.slick-footerrow-column');\r\n footerRowLColumnElements.forEach((column) => {\r\n const columnDef = Utils.storage.get(column, 'column');\r\n if (columnDef) {\r\n this.trigger(this.onBeforeFooterRowCellDestroy, {\r\n node: this,\r\n column: columnDef,\r\n grid: this\r\n });\r\n }\r\n });\r\n Utils.emptyElement(this._footerRowL);\r\n\r\n if (this.hasFrozenColumns()) {\r\n const footerRowRColumnElements = this._footerRowR.querySelectorAll('.slick-footerrow-column');\r\n footerRowRColumnElements.forEach((column) => {\r\n const columnDef = Utils.storage.get(column, 'column');\r\n if (columnDef) {\r\n this.trigger(this.onBeforeFooterRowCellDestroy, {\r\n node: this,\r\n column: columnDef,\r\n grid: this\r\n });\r\n }\r\n });\r\n Utils.emptyElement(this._footerRowR);\r\n }\r\n }\r\n\r\n for (let i = 0; i < this.columns.length; i++) {\r\n const m: C = this.columns[i];\r\n if (m.hidden) { continue; }\r\n\r\n const headerTarget = this.hasFrozenColumns() ? ((i <= this._options.frozenColumn!) ? this._headerL : this._headerR) : this._headerL;\r\n const headerRowTarget = this.hasFrozenColumns() ? ((i <= this._options.frozenColumn!) ? this._headerRowL : this._headerRowR) : this._headerRowL;\r\n\r\n const header = Utils.createDomElement('div', { id: `${this.uid + m.id}`, dataset: { id: String(m.id) }, role: 'columnheader', className: 'ui-state-default slick-state-default slick-header-column' }, headerTarget);\r\n if (m.toolTip) {\r\n header.title = m.toolTip;\r\n }\r\n if (!m.reorderable) {\r\n header.classList.add(this._options.unorderableColumnCssClass!);\r\n }\r\n const colNameElm = Utils.createDomElement('span', { className: 'slick-column-name' }, header);\r\n this.applyHtmlCode(colNameElm, m.name as string);\r\n\r\n Utils.width(header, m.width! - this.headerColumnWidthDiff);\r\n\r\n let classname = m.headerCssClass || null;\r\n if (classname) {\r\n header.classList.add(...Utils.classNameToList(classname));\r\n }\r\n classname = this.hasFrozenColumns() && i <= this._options.frozenColumn! ? 'frozen' : null;\r\n if (classname) {\r\n header.classList.add(classname);\r\n }\r\n\r\n this._bindingEventService.bind(header, 'mouseenter', this.handleHeaderMouseEnter.bind(this) as EventListener);\r\n this._bindingEventService.bind(header, 'mouseleave', this.handleHeaderMouseLeave.bind(this) as EventListener);\r\n\r\n Utils.storage.put(header, 'column', m);\r\n\r\n if (this._options.enableColumnReorder || m.sortable) {\r\n this._bindingEventService.bind(header, 'mouseenter', this.handleHeaderMouseHoverOn.bind(this) as EventListener);\r\n this._bindingEventService.bind(header, 'mouseleave', this.handleHeaderMouseHoverOff.bind(this) as EventListener);\r\n }\r\n\r\n if (m.hasOwnProperty('headerCellAttrs') && m.headerCellAttrs instanceof Object) {\r\n Object.keys(m.headerCellAttrs).forEach(key => {\r\n if (m.headerCellAttrs.hasOwnProperty(key)) {\r\n header.setAttribute(key, m.headerCellAttrs[key]);\r\n }\r\n });\r\n }\r\n\r\n if (m.sortable) {\r\n header.classList.add('slick-header-sortable');\r\n Utils.createDomElement('div', { className: `slick-sort-indicator ${this._options.numberedMultiColumnSort && !this._options.sortColNumberInSeparateSpan ? ' slick-sort-indicator-numbered' : ''}` }, header);\r\n if (this._options.numberedMultiColumnSort && this._options.sortColNumberInSeparateSpan) {\r\n Utils.createDomElement('div', { className: 'slick-sort-indicator-numbered' }, header);\r\n }\r\n }\r\n\r\n this.trigger(this.onHeaderCellRendered, {\r\n node: header,\r\n column: m,\r\n grid: this\r\n });\r\n\r\n if (this._options.showHeaderRow) {\r\n const headerRowCell = Utils.createDomElement('div', { className: `ui-state-default slick-state-default slick-headerrow-column l${i} r${i}` }, headerRowTarget);\r\n const frozenClasses = this.hasFrozenColumns() && i <= this._options.frozenColumn! ? 'frozen' : null;\r\n if (frozenClasses) {\r\n headerRowCell.classList.add(frozenClasses);\r\n }\r\n\r\n this._bindingEventService.bind(headerRowCell, 'mouseenter', this.handleHeaderRowMouseEnter.bind(this) as EventListener);\r\n this._bindingEventService.bind(headerRowCell, 'mouseleave', this.handleHeaderRowMouseLeave.bind(this) as EventListener);\r\n\r\n Utils.storage.put(headerRowCell, 'column', m);\r\n\r\n this.trigger(this.onHeaderRowCellRendered, {\r\n node: headerRowCell,\r\n column: m,\r\n grid: this\r\n });\r\n }\r\n if (this._options.createFooterRow && this._options.showFooterRow) {\r\n const footerRowTarget = this.hasFrozenColumns() ? ((i <= this._options.frozenColumn!) ? this._footerRow[0] : this._footerRow[1]) : this._footerRow[0];\r\n const footerRowCell = Utils.createDomElement('div', { className: `ui-state-default slick-state-default slick-footerrow-column l${i} r${i}` }, footerRowTarget);\r\n Utils.storage.put(footerRowCell, 'column', m);\r\n\r\n this.trigger(this.onFooterRowCellRendered, {\r\n node: footerRowCell,\r\n column: m,\r\n grid: this\r\n });\r\n }\r\n }\r\n\r\n this.setSortColumns(this.sortColumns);\r\n this.setupColumnResize();\r\n if (this._options.enableColumnReorder) {\r\n if (typeof this._options.enableColumnReorder === 'function') {\r\n this._options.enableColumnReorder(this as unknown as SlickGridModel, this._headers, this.headerColumnWidthDiff, this.setColumns as any, this.setupColumnResize, this.columns, this.getColumnIndex, this.uid, this.trigger);\r\n } else {\r\n this.setupColumnReorder();\r\n }\r\n }\r\n }\r\n\r\n protected setupColumnSort() {\r\n this._headers.forEach((header) => {\r\n this._bindingEventService.bind(header, 'click', (e: any) => {\r\n if (this.columnResizeDragging) {\r\n return;\r\n }\r\n\r\n if (e.target.classList.contains('slick-resizable-handle')) {\r\n return;\r\n }\r\n\r\n const coll = e.target.closest('.slick-header-column');\r\n if (!coll) {\r\n return;\r\n }\r\n\r\n const column = Utils.storage.get(coll, 'column');\r\n if (column.sortable) {\r\n if (!this.getEditorLock()?.commitCurrentEdit()) {\r\n return;\r\n }\r\n\r\n const previousSortColumns = this.sortColumns.slice();\r\n let sortColumn: ColumnSort | null = null;\r\n let i = 0;\r\n for (; i < this.sortColumns.length; i++) {\r\n if (this.sortColumns[i].columnId === column.id) {\r\n sortColumn = this.sortColumns[i];\r\n sortColumn.sortAsc = !sortColumn.sortAsc;\r\n break;\r\n }\r\n }\r\n const hadSortCol = !!sortColumn;\r\n\r\n if (this._options.tristateMultiColumnSort) {\r\n if (!sortColumn) {\r\n sortColumn = { columnId: column.id, sortAsc: column.defaultSortAsc, sortCol: column };\r\n }\r\n if (hadSortCol && sortColumn.sortAsc) {\r\n // three state: remove sort rather than go back to ASC\r\n this.sortColumns.splice(i, 1);\r\n sortColumn = null;\r\n }\r\n if (!this._options.multiColumnSort) {\r\n this.sortColumns = [];\r\n }\r\n if (sortColumn && (!hadSortCol || !this._options.multiColumnSort)) {\r\n this.sortColumns.push(sortColumn);\r\n }\r\n } else {\r\n // legacy behaviour\r\n if (e.metaKey && this._options.multiColumnSort) {\r\n if (sortColumn) {\r\n this.sortColumns.splice(i, 1);\r\n }\r\n } else {\r\n if ((!e.shiftKey && !e.metaKey) || !this._options.multiColumnSort) {\r\n this.sortColumns = [];\r\n }\r\n\r\n if (!sortColumn) {\r\n sortColumn = { columnId: column.id, sortAsc: column.defaultSortAsc, sortCol: column };\r\n this.sortColumns.push(sortColumn);\r\n } else if (this.sortColumns.length === 0) {\r\n this.sortColumns.push(sortColumn);\r\n }\r\n }\r\n }\r\n\r\n let onSortArgs;\r\n if (!this._options.multiColumnSort) {\r\n onSortArgs = {\r\n multiColumnSort: false,\r\n previousSortColumns,\r\n columnId: (this.sortColumns.length > 0 ? column.id : null),\r\n sortCol: (this.sortColumns.length > 0 ? column : null),\r\n sortAsc: (this.sortColumns.length > 0 ? this.sortColumns[0].sortAsc : true)\r\n };\r\n } else {\r\n onSortArgs = {\r\n multiColumnSort: true,\r\n previousSortColumns,\r\n sortCols: this.sortColumns.map((col) => {\r\n const tempCol = this.columns[this.getColumnIndex(col.columnId)];\r\n return !tempCol || tempCol.hidden ? null : { columnId: tempCol.id, sortCol: tempCol, sortAsc: col.sortAsc };\r\n }).filter((el) => el)\r\n };\r\n }\r\n\r\n if (this.trigger(this.onBeforeSort, onSortArgs, e).getReturnValue() !== false) {\r\n this.setSortColumns(this.sortColumns);\r\n this.trigger(this.onSort, onSortArgs, e);\r\n }\r\n }\r\n });\r\n });\r\n }\r\n\r\n protected setupColumnReorder() {\r\n this.sortableSideLeftInstance?.destroy();\r\n this.sortableSideRightInstance?.destroy();\r\n\r\n let columnScrollTimer: any = null;\r\n\r\n const scrollColumnsRight = () => this._viewportScrollContainerX.scrollLeft = this._viewportScrollContainerX.scrollLeft + 10;\r\n const scrollColumnsLeft = () => this._viewportScrollContainerX.scrollLeft = this._viewportScrollContainerX.scrollLeft - 10;\r\n\r\n let canDragScroll = false;\r\n const sortableOptions = {\r\n animation: 50,\r\n direction: 'horizontal',\r\n chosenClass: 'slick-header-column-active',\r\n ghostClass: 'slick-sortable-placeholder',\r\n draggable: '.slick-header-column',\r\n dragoverBubble: false,\r\n revertClone: true,\r\n scroll: !this.hasFrozenColumns(), // enable auto-scroll\r\n // lock unorderable columns by using a combo of filter + onMove\r\n filter: `.${this._options.unorderableColumnCssClass}`,\r\n onMove: (event: MouseEvent & { related: HTMLElement; }) => {\r\n return !event.related.classList.contains(this._options.unorderableColumnCssClass as string);\r\n },\r\n onStart: (e: { item: any; originalEvent: MouseEvent; }) => {\r\n canDragScroll = !this.hasFrozenColumns() ||\r\n Utils.offset(e.item)!.left > Utils.offset(this._viewportScrollContainerX)!.left;\r\n\r\n if (canDragScroll && e.originalEvent.pageX > this._container.clientWidth) {\r\n if (!(columnScrollTimer)) {\r\n columnScrollTimer = setInterval(scrollColumnsRight, 100);\r\n }\r\n } else if (canDragScroll && e.originalEvent.pageX < Utils.offset(this._viewportScrollContainerX)!.left) {\r\n if (!(columnScrollTimer)) {\r\n columnScrollTimer = setInterval(scrollColumnsLeft, 100);\r\n }\r\n } else {\r\n clearInterval(columnScrollTimer);\r\n columnScrollTimer = null;\r\n }\r\n },\r\n onEnd: (e: MouseEvent & { item: any; originalEvent: MouseEvent; }) => {\r\n clearInterval(columnScrollTimer);\r\n columnScrollTimer = null;\r\n\r\n if (!this.getEditorLock()?.commitCurrentEdit()) {\r\n return;\r\n }\r\n\r\n let reorderedIds = this.sortableSideLeftInstance?.toArray() ?? [];\r\n reorderedIds = reorderedIds.concat(this.sortableSideRightInstance?.toArray() ?? []);\r\n\r\n const reorderedColumns: C[] = [];\r\n for (let i = 0; i < reorderedIds.length; i++) {\r\n reorderedColumns.push(this.columns[this.getColumnIndex(reorderedIds[i])]);\r\n }\r\n this.setColumns(reorderedColumns);\r\n\r\n this.trigger(this.onColumnsReordered, { impactedColumns: this.columns });\r\n e.stopPropagation();\r\n this.setupColumnResize();\r\n if (this.activeCellNode) {\r\n this.setFocus(); // refocus on active cell\r\n }\r\n }\r\n };\r\n\r\n this.sortableSideLeftInstance = Sortable.create(this._headerL, sortableOptions);\r\n this.sortableSideRightInstance = Sortable.create(this._headerR, sortableOptions);\r\n }\r\n\r\n protected getHeaderChildren() {\r\n const a = Array.from(this._headers[0].children);\r\n const b = Array.from(this._headers[1].children);\r\n return a.concat(b) as HTMLElement[];\r\n }\r\n\r\n protected handleResizeableDoubleClick(evt: MouseEvent & { target: HTMLDivElement; }) {\r\n const triggeredByColumn = evt.target.parentElement!.id.replace(this.uid, '');\r\n this.trigger(this.onColumnsResizeDblClick, { triggeredByColumn });\r\n }\r\n\r\n protected setupColumnResize() {\r\n if (typeof Resizable === 'undefined') {\r\n throw new Error(`Slick.Resizable is undefined, make sure to import \"slick.interactions.js\"`);\r\n }\r\n\r\n let j: number;\r\n let k: number;\r\n let c: C;\r\n let pageX: number;\r\n let minPageX: number;\r\n let maxPageX: number;\r\n let firstResizable: number | undefined;\r\n let lastResizable = -1;\r\n let frozenLeftColMaxWidth = 0;\r\n\r\n const children: HTMLElement[] = this.getHeaderChildren();\r\n const vc = this.getVisibleColumns();\r\n for (let i = 0; i < children.length; i++) {\r\n const child = children[i];\r\n const handles = child.querySelectorAll('.slick-resizable-handle');\r\n handles.forEach((handle) => handle.remove());\r\n\r\n if (i >= vc.length || !vc[i]) {\r\n continue;\r\n }\r\n\r\n if (vc[i].resizable) {\r\n if (firstResizable === undefined) {\r\n firstResizable = i;\r\n }\r\n lastResizable = i;\r\n }\r\n }\r\n\r\n if (firstResizable === undefined) {\r\n return;\r\n }\r\n\r\n for (let i = 0; i < children.length; i++) {\r\n const colElm = children[i];\r\n\r\n if (i >= vc.length || !vc[i]) {\r\n continue;\r\n }\r\n if (i < firstResizable || (this._options.forceFitColumns && i >= lastResizable)) {\r\n continue;\r\n }\r\n\r\n const resizeableHandle = Utils.createDomElement('div', { className: 'slick-resizable-handle', role: 'separator', ariaOrientation: 'horizontal' }, colElm);\r\n this._bindingEventService.bind(resizeableHandle, 'dblclick', this.handleResizeableDoubleClick.bind(this) as EventListener);\r\n\r\n this.slickResizableInstances.push(\r\n Resizable({\r\n resizeableElement: colElm as HTMLElement,\r\n resizeableHandleElement: resizeableHandle,\r\n onResizeStart: (e, resizeElms): boolean | void => {\r\n const targetEvent = (e as TouchEvent).touches ? (e as TouchEvent).changedTouches[0] : e;\r\n if (!this.getEditorLock()?.commitCurrentEdit()) {\r\n return false;\r\n }\r\n pageX = (targetEvent as MouseEvent).pageX;\r\n frozenLeftColMaxWidth = 0;\r\n resizeElms.resizeableElement.classList.add('slick-header-column-active');\r\n let shrinkLeewayOnRight: number | null = null;\r\n let stretchLeewayOnRight: number | null = null;\r\n // lock each column's width option to current width\r\n for (let pw = 0; pw < children.length; pw++) {\r\n if (pw >= vc.length || !vc[pw]) {\r\n continue;\r\n }\r\n vc[pw].previousWidth = children[pw].offsetWidth;\r\n }\r\n if (this._options.forceFitColumns) {\r\n shrinkLeewayOnRight = 0;\r\n stretchLeewayOnRight = 0;\r\n // colums on right affect maxPageX/minPageX\r\n for (j = i + 1; j < vc.length; j++) {\r\n c = vc[j];\r\n if (c?.resizable) {\r\n if (stretchLeewayOnRight !== null) {\r\n if (c.maxWidth) {\r\n stretchLeewayOnRight += c.maxWidth - (c.previousWidth || 0);\r\n } else {\r\n stretchLeewayOnRight = null;\r\n }\r\n }\r\n shrinkLeewayOnRight += (c.previousWidth || 0) - Math.max(c.minWidth || 0, this.absoluteColumnMinWidth);\r\n }\r\n }\r\n }\r\n let shrinkLeewayOnLeft = 0;\r\n let stretchLeewayOnLeft: number | null = 0;\r\n for (j = 0; j <= i; j++) {\r\n // columns on left only affect minPageX\r\n c = vc[j];\r\n if (c?.resizable) {\r\n if (stretchLeewayOnLeft !== null) {\r\n if (c.maxWidth) {\r\n stretchLeewayOnLeft += c.maxWidth - (c.previousWidth || 0);\r\n } else {\r\n stretchLeewayOnLeft = null;\r\n }\r\n }\r\n shrinkLeewayOnLeft += (c.previousWidth || 0) - Math.max(c.minWidth || 0, this.absoluteColumnMinWidth);\r\n }\r\n }\r\n if (shrinkLeewayOnRight === null) {\r\n shrinkLeewayOnRight = 100000;\r\n }\r\n if (shrinkLeewayOnLeft === null) {\r\n shrinkLeewayOnLeft = 100000;\r\n }\r\n if (stretchLeewayOnRight === null) {\r\n stretchLeewayOnRight = 100000;\r\n }\r\n if (stretchLeewayOnLeft === null) {\r\n stretchLeewayOnLeft = 100000;\r\n }\r\n maxPageX = pageX + Math.min(shrinkLeewayOnRight, stretchLeewayOnLeft);\r\n minPageX = pageX - Math.min(shrinkLeewayOnLeft, stretchLeewayOnRight);\r\n },\r\n onResize: (e, resizeElms) => {\r\n const targetEvent = (e as TouchEvent).touches ? (e as TouchEvent).changedTouches[0] : e;\r\n this.columnResizeDragging = true;\r\n let actualMinWidth;\r\n const d = Math.min(maxPageX, Math.max(minPageX, (targetEvent as MouseEvent).pageX)) - pageX;\r\n let x;\r\n let newCanvasWidthL = 0;\r\n let newCanvasWidthR = 0;\r\n const viewportWidth = this.viewportHasVScroll ? this.viewportW - (this.scrollbarDimensions?.width ?? 0) : this.viewportW;\r\n\r\n if (d < 0) { // shrink column\r\n x = d;\r\n\r\n for (j = i; j >= 0; j--) {\r\n c = vc[j];\r\n if (c?.resizable && !c.hidden) {\r\n actualMinWidth = Math.max(c.minWidth || 0, this.absoluteColumnMinWidth);\r\n if (x && (c.previousWidth || 0) + x < actualMinWidth) {\r\n x += (c.previousWidth || 0) - actualMinWidth;\r\n c.width = actualMinWidth;\r\n } else {\r\n c.width = (c.previousWidth || 0) + x;\r\n x = 0;\r\n }\r\n }\r\n }\r\n\r\n for (k = 0; k <= i; k++) {\r\n c = vc[k];\r\n if (!c || c.hidden) { continue; }\r\n\r\n if (this.hasFrozenColumns() && (k > this._options.frozenColumn!)) {\r\n newCanvasWidthR += c.width || 0;\r\n } else {\r\n newCanvasWidthL += c.width || 0;\r\n }\r\n }\r\n\r\n if (this._options.forceFitColumns) {\r\n x = -d;\r\n for (j = i + 1; j < vc.length; j++) {\r\n c = vc[j];\r\n if (!c || c.hidden) { continue; }\r\n if (c.resizable) {\r\n if (x && c.maxWidth && (c.maxWidth - (c.previousWidth || 0) < x)) {\r\n x -= c.maxWidth - (c.previousWidth || 0);\r\n c.width = c.maxWidth;\r\n } else {\r\n c.width = (c.previousWidth || 0) + x;\r\n x = 0;\r\n }\r\n\r\n if (this.hasFrozenColumns() && (j > this._options.frozenColumn!)) {\r\n newCanvasWidthR += c.width || 0;\r\n } else {\r\n newCanvasWidthL += c.width || 0;\r\n }\r\n }\r\n }\r\n } else {\r\n for (j = i + 1; j < vc.length; j++) {\r\n c = vc[j];\r\n if (!c || c.hidden) { continue; }\r\n\r\n if (this.hasFrozenColumns() && (j > this._options.frozenColumn!)) {\r\n newCanvasWidthR += c.width || 0;\r\n } else {\r\n newCanvasWidthL += c.width || 0;\r\n }\r\n }\r\n }\r\n\r\n if (this._options.forceFitColumns) {\r\n x = -d;\r\n for (j = i + 1; j < vc.length; j++) {\r\n c = vc[j];\r\n if (!c || c.hidden) { continue; }\r\n if (c.resizable) {\r\n if (x && c.maxWidth && (c.maxWidth - (c.previousWidth || 0) < x)) {\r\n x -= c.maxWidth - (c.previousWidth || 0);\r\n c.width = c.maxWidth;\r\n } else {\r\n c.width = (c.previousWidth || 0) + x;\r\n x = 0;\r\n }\r\n }\r\n }\r\n }\r\n } else { // stretch column\r\n x = d;\r\n\r\n newCanvasWidthL = 0;\r\n newCanvasWidthR = 0;\r\n\r\n for (j = i; j >= 0; j--) {\r\n c = vc[j];\r\n if (!c || c.hidden) { continue; }\r\n if (c.resizable) {\r\n if (x && c.maxWidth && (c.maxWidth - (c.previousWidth || 0) < x)) {\r\n x -= c.maxWidth - (c.previousWidth || 0);\r\n c.width = c.maxWidth;\r\n } else {\r\n const newWidth = (c.previousWidth || 0) + x;\r\n const resizedCanvasWidthL = this.canvasWidthL + x;\r\n\r\n if (this.hasFrozenColumns() && (j <= this._options.frozenColumn!)) {\r\n // if we're on the left frozen side, we need to make sure that our left section width never goes over the total viewport width\r\n if (newWidth > frozenLeftColMaxWidth && resizedCanvasWidthL < (viewportWidth - this._options.frozenRightViewportMinWidth!)) {\r\n frozenLeftColMaxWidth = newWidth; // keep max column width ref, if we go over the limit this number will stop increasing\r\n }\r\n c.width = ((resizedCanvasWidthL + this._options.frozenRightViewportMinWidth!) > viewportWidth) ? frozenLeftColMaxWidth : newWidth;\r\n } else {\r\n c.width = newWidth;\r\n }\r\n x = 0;\r\n }\r\n }\r\n }\r\n\r\n for (k = 0; k <= i; k++) {\r\n c = vc[k];\r\n if (!c || c.hidden) { continue; }\r\n\r\n if (this.hasFrozenColumns() && (k > this._options.frozenColumn!)) {\r\n newCanvasWidthR += c.width || 0;\r\n } else {\r\n newCanvasWidthL += c.width || 0;\r\n }\r\n }\r\n\r\n if (this._options.forceFitColumns) {\r\n x = -d;\r\n for (j = i + 1; j < vc.length; j++) {\r\n c = vc[j];\r\n if (!c || c.hidden) { continue; }\r\n if (c.resizable) {\r\n actualMinWidth = Math.max(c.minWidth || 0, this.absoluteColumnMinWidth);\r\n if (x && (c.previousWidth || 0) + x < actualMinWidth) {\r\n x += (c.previousWidth || 0) - actualMinWidth;\r\n c.width = actualMinWidth;\r\n } else {\r\n c.width = (c.previousWidth || 0) + x;\r\n x = 0;\r\n }\r\n\r\n if (this.hasFrozenColumns() && (j > this._options.frozenColumn!)) {\r\n newCanvasWidthR += c.width || 0;\r\n } else {\r\n newCanvasWidthL += c.width || 0;\r\n }\r\n }\r\n }\r\n } else {\r\n for (j = i + 1; j < vc.length; j++) {\r\n c = vc[j];\r\n if (!c || c.hidden) { continue; }\r\n\r\n if (this.hasFrozenColumns() && (j > this._options.frozenColumn!)) {\r\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n newCanvasWidthR += c.width || 0;\r\n } else {\r\n newCanvasWidthL += c.width || 0;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (this.hasFrozenColumns() && newCanvasWidthL !== this.canvasWidthL) {\r\n Utils.width(this._headerL, newCanvasWidthL + 1000);\r\n Utils.setStyleSize(this._paneHeaderR, 'left', newCanvasWidthL);\r\n }\r\n\r\n this.applyColumnHeaderWidths();\r\n if (this._options.syncColumnCellResize) {\r\n this.applyColumnWidths();\r\n }\r\n this.trigger(this.onColumnsDrag, {\r\n triggeredByColumn: resizeElms.resizeableElement,\r\n resizeHandle: resizeElms.resizeableHandleElement\r\n });\r\n },\r\n onResizeEnd: (_e, resizeElms) => {\r\n resizeElms.resizeableElement.classList.remove('slick-header-column-active');\r\n\r\n const triggeredByColumn = resizeElms.resizeableElement.id.replace(this.uid, '');\r\n if (this.trigger(this.onBeforeColumnsResize, { triggeredByColumn }).getReturnValue() === true) {\r\n this.applyColumnHeaderWidths();\r\n }\r\n let newWidth;\r\n for (j = 0; j < vc.length; j++) {\r\n c = vc[j];\r\n if (!c || c.hidden) { continue; }\r\n newWidth = children[j].offsetWidth;\r\n\r\n if (c.previousWidth !== newWidth && c.rerenderOnResize) {\r\n this.invalidateAllRows();\r\n }\r\n }\r\n this.updateCanvasWidth(true);\r\n this.render();\r\n this.trigger(this.onColumnsResized, { triggeredByColumn });\r\n clearTimeout(this._columnResizeTimer);\r\n this._columnResizeTimer = setTimeout(() => { this.columnResizeDragging = false; }, 300);\r\n }\r\n })\r\n );\r\n }\r\n }\r\n\r\n protected getVBoxDelta(el: HTMLElement) {\r\n const p = ['borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom'];\r\n const styles = getComputedStyle(el);\r\n let delta = 0;\r\n p.forEach((val) => delta += Utils.toFloat(styles[val as any]));\r\n return delta;\r\n }\r\n\r\n protected setFrozenOptions() {\r\n this._options.frozenColumn = (this._options.frozenColumn! >= 0 && this._options.frozenColumn! < this.columns.length)\r\n ? parseInt(this._options.frozenColumn as unknown as string, 10)\r\n : -1;\r\n\r\n if (this._options.frozenRow! > -1) {\r\n this.hasFrozenRows = true;\r\n this.frozenRowsHeight = (this._options.frozenRow!) * this._options.rowHeight!;\r\n const dataLength = this.getDataLength();\r\n\r\n this.actualFrozenRow = (this._options.frozenBottom)\r\n ? (dataLength - this._options.frozenRow!)\r\n : this._options.frozenRow!;\r\n } else {\r\n this.hasFrozenRows = false;\r\n }\r\n }\r\n\r\n protected setPaneVisibility() {\r\n if (this.hasFrozenColumns()) {\r\n Utils.show(this._paneHeaderR);\r\n Utils.show(this._paneTopR);\r\n\r\n if (this.hasFrozenRows) {\r\n Utils.show(this._paneBottomL);\r\n Utils.show(this._paneBottomR);\r\n } else {\r\n Utils.hide(this._paneBottomR);\r\n Utils.hide(this._paneBottomL);\r\n }\r\n } else {\r\n Utils.hide(this._paneHeaderR);\r\n Utils.hide(this._paneTopR);\r\n Utils.hide(this._paneBottomR);\r\n\r\n if (this.hasFrozenRows) {\r\n Utils.show(this._paneBottomL);\r\n } else {\r\n Utils.hide(this._paneBottomR);\r\n Utils.hide(this._paneBottomL);\r\n }\r\n }\r\n }\r\n\r\n protected setOverflow() {\r\n this._viewportTopL.style.overflowX = (this.hasFrozenColumns()) ? (this.hasFrozenRows && !this._options.alwaysAllowHorizontalScroll ? 'hidden' : 'scroll') : (this.hasFrozenRows && !this._options.alwaysAllowHorizontalScroll ? 'hidden' : 'auto');\r\n this._viewportTopL.style.overflowY = (!this.hasFrozenColumns() && this._options.alwaysShowVerticalScroll) ? 'scroll' : ((this.hasFrozenColumns()) ? (this.hasFrozenRows ? 'hidden' : 'hidden') : (this.hasFrozenRows ? 'scroll' : 'auto'));\r\n\r\n this._viewportTopR.style.overflowX = (this.hasFrozenColumns()) ? (this.hasFrozenRows && !this._options.alwaysAllowHorizontalScroll ? 'hidden' : 'scroll') : (this.hasFrozenRows && !this._options.alwaysAllowHorizontalScroll ? 'hidden' : 'auto');\r\n this._viewportTopR.style.overflowY = this._options.alwaysShowVerticalScroll ? 'scroll' : ((this.hasFrozenColumns()) ? (this.hasFrozenRows ? 'scroll' : 'auto') : (this.hasFrozenRows ? 'scroll' : 'auto'));\r\n\r\n this._viewportBottomL.style.overflowX = (this.hasFrozenColumns()) ? (this.hasFrozenRows && !this._options.alwaysAllowHorizontalScroll ? 'scroll' : 'auto') : (this.hasFrozenRows && !this._options.alwaysAllowHorizontalScroll ? 'auto' : 'auto');\r\n this._viewportBottomL.style.overflowY = (!this.hasFrozenColumns() && this._options.alwaysShowVerticalScroll) ? 'scroll' : ((this.hasFrozenColumns()) ? (this.hasFrozenRows ? 'hidden' : 'hidden') : (this.hasFrozenRows ? 'scroll' : 'auto'));\r\n\r\n this._viewportBottomR.style.overflowX = (this.hasFrozenColumns()) ? (this.hasFrozenRows && !this._options.alwaysAllowHorizontalScroll ? 'scroll' : 'auto') : (this.hasFrozenRows && !this._options.alwaysAllowHorizontalScroll ? 'auto' : 'auto');\r\n this._viewportBottomR.style.overflowY = this._options.alwaysShowVerticalScroll ? 'scroll' : ((this.hasFrozenColumns()) ? (this.hasFrozenRows ? 'auto' : 'auto') : (this.hasFrozenRows ? 'auto' : 'auto'));\r\n\r\n if (this._options.viewportClass) {\r\n const viewportClassList = Utils.classNameToList(this._options.viewportClass);\r\n this._viewportTopL.classList.add(...viewportClassList);\r\n this._viewportTopR.classList.add(...viewportClassList);\r\n this._viewportBottomL.classList.add(...viewportClassList);\r\n this._viewportBottomR.classList.add(...viewportClassList);\r\n }\r\n }\r\n\r\n protected setScroller() {\r\n if (this.hasFrozenColumns()) {\r\n this._headerScrollContainer = this._headerScrollerR;\r\n this._headerRowScrollContainer = this._headerRowScrollerR;\r\n this._footerRowScrollContainer = this._footerRowScrollerR;\r\n\r\n if (this.hasFrozenRows) {\r\n if (this._options.frozenBottom) {\r\n this._viewportScrollContainerX = this._viewportBottomR;\r\n this._viewportScrollContainerY = this._viewportTopR;\r\n } else {\r\n this._viewportScrollContainerX = this._viewportScrollContainerY = this._viewportBottomR;\r\n }\r\n } else {\r\n this._viewportScrollContainerX = this._viewportScrollContainerY = this._viewportTopR;\r\n }\r\n } else {\r\n this._headerScrollContainer = this._headerScrollerL;\r\n this._headerRowScrollContainer = this._headerRowScrollerL;\r\n this._footerRowScrollContainer = this._footerRowScrollerL;\r\n\r\n if (this.hasFrozenRows) {\r\n if (this._options.frozenBottom) {\r\n this._viewportScrollContainerX = this._viewportBottomL;\r\n this._viewportScrollContainerY = this._viewportTopL;\r\n } else {\r\n this._viewportScrollContainerX = this._viewportScrollContainerY = this._viewportBottomL;\r\n }\r\n } else {\r\n this._viewportScrollContainerX = this._viewportScrollContainerY = this._viewportTopL;\r\n }\r\n }\r\n }\r\n\r\n protected measureCellPaddingAndBorder() {\r\n const h = ['borderLeftWidth', 'borderRightWidth', 'paddingLeft', 'paddingRight'];\r\n const v = ['borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom'];\r\n const header = this._headers[0];\r\n\r\n this.headerColumnWidthDiff = this.headerColumnHeightDiff = 0;\r\n this.cellWidthDiff = this.cellHeightDiff = 0;\r\n\r\n let el = Utils.createDomElement('div', { className: 'ui-state-default slick-state-default slick-header-column', style: { visibility: 'hidden' }, textContent: '-' }, header);\r\n let style = getComputedStyle(el);\r\n if (style.boxSizing !== 'border-box') {\r\n h.forEach((val) => this.headerColumnWidthDiff += Utils.toFloat(style[val as any]));\r\n v.forEach((val) => this.headerColumnHeightDiff += Utils.toFloat(style[val as any]));\r\n }\r\n el.remove();\r\n\r\n const r = Utils.createDomElement('div', { className: 'slick-row' }, this._canvas[0]);\r\n el = Utils.createDomElement('div', { className: 'slick-cell', id: '', style: { visibility: 'hidden' }, textContent: '-' }, r);\r\n style = getComputedStyle(el);\r\n if (style.boxSizing !== 'border-box') {\r\n h.forEach((val) => this.cellWidthDiff += Utils.toFloat(style[val as any]));\r\n v.forEach((val) => this.cellHeightDiff += Utils.toFloat(style[val as any]));\r\n }\r\n r.remove();\r\n\r\n this.absoluteColumnMinWidth = Math.max(this.headerColumnWidthDiff, this.cellWidthDiff);\r\n }\r\n\r\n protected createCssRules() {\r\n this._style = document.createElement('style');\r\n this._style.nonce = this._options.nonce || '';\r\n (this._options.shadowRoot || document.head).appendChild(this._style);\r\n\r\n const rowHeight = (this._options.rowHeight! - this.cellHeightDiff);\r\n const rules = [\r\n `.${this.uid} .slick-group-header-column { left: 1000px; }`,\r\n `.${this.uid} .slick-header-column { left: 1000px; }`,\r\n `.${this.uid} .slick-top-panel { height: ${this._options.topPanelHeight}px; }`,\r\n `.${this.uid} .slick-preheader-panel { height: ${this._options.preHeaderPanelHeight}px; }`,\r\n `.${this.uid} .slick-topheader-panel { height: ${this._options.topHeaderPanelHeight}px; }`,\r\n `.${this.uid} .slick-headerrow-columns { height: ${this._options.headerRowHeight}px; }`,\r\n `.${this.uid} .slick-footerrow-columns { height: ${this._options.footerRowHeight}px; }`,\r\n `.${this.uid} .slick-cell { height: ${rowHeight}px; }`,\r\n `.${this.uid} .slick-row { height: ${this._options.rowHeight}px; }`,\r\n ];\r\n\r\n const sheet = this._style.sheet;\r\n if (sheet) {\r\n rules.forEach(rule => {\r\n sheet.insertRule(rule);\r\n });\r\n\r\n for (let i = 0; i < this.columns.length; i++) {\r\n if (!this.columns[i] || this.columns[i].hidden) { continue; }\r\n\r\n sheet.insertRule(`.${this.uid} .l${i} { }`);\r\n sheet.insertRule(`.${this.uid} .r${i} { }`);\r\n }\r\n } else {\r\n // fallback in case the 1st approach doesn't work, let's use our previous way of creating the css rules which is what works in Salesforce :(\r\n this.createCssRulesAlternative(rules);\r\n }\r\n }\r\n\r\n /** Create CSS rules via template in case the first approach with createElement('style') doesn't work */\r\n protected createCssRulesAlternative(rules: string[]) {\r\n const template = document.createElement('template');\r\n template.innerHTML = '