diff --git a/CHANGELOG.md b/CHANGELOG.md index 38fc38ee..488a5cb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.0.0](https://github.com/6pac/SlickGrid/compare/4.0.1...5.0.0) (2023-09-19) + +### Reverts + +* fix auto-scroll issue by reverting commit 5ff56e3 ([2b40409](https://github.com/6pac/SlickGrid/commit/2b4040943d451366da92d22fed1adba3d8a2e017)) + # [5.0.0-alpha.9](https://github.com/6pac/SlickGrid/compare/5.0.0-alpha.8...5.0.0-alpha.9) (2023-09-19) # [5.0.0-alpha.8](https://github.com/6pac/SlickGrid/compare/5.0.0-alpha.7...5.0.0-alpha.8) (2023-09-19) diff --git a/dist/browser/slick.grid.js b/dist/browser/slick.grid.js index af56ef69..3ed047d3 100644 --- a/dist/browser/slick.grid.js +++ b/dist/browser/slick.grid.js @@ -23,7 +23,7 @@ this.options = options; ////////////////////////////////////////////////////////////////////////////////////////////// // Public API - __publicField(this, "slickGridVersion", "5.0.0-alpha.9"); + __publicField(this, "slickGridVersion", "5.0.0"); /** optional grid state clientId */ __publicField(this, "cid", ""); // Events @@ -2958,7 +2958,7 @@ * Distributed under MIT license. * All rights reserved. * - * SlickGrid v5.0.0-alpha.9 + * SlickGrid v5.0.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 f76830bc..761b850a 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\nimport type SortableInstance from 'sortablejs';\n\nimport type {\n AutoSize,\n CellViewportRange,\n Column,\n ColumnSort,\n CssStyleHash,\n CSSStyleDeclarationWritable,\n CustomDataView,\n DOMEvent,\n DOMMouseOrTouchEvent,\n DragPosition,\n DragRowMove,\n Editor,\n EditController,\n Formatter,\n FormatterOverrideCallback,\n FormatterResultObject,\n GridOption as BaseGridOption,\n InteractionBase,\n ItemMetadata,\n MultiColumnSort,\n OnActiveCellChangedEventArgs,\n OnAddNewRowEventArgs,\n OnAutosizeColumnsEventArgs,\n OnBeforeUpdateColumnsEventArgs,\n OnBeforeAppendCellEventArgs,\n OnBeforeCellEditorDestroyEventArgs,\n OnBeforeColumnsResizeEventArgs,\n OnBeforeEditCellEventArgs,\n OnBeforeHeaderCellDestroyEventArgs,\n OnBeforeHeaderRowCellDestroyEventArgs,\n OnBeforeFooterRowCellDestroyEventArgs,\n OnBeforeSetColumnsEventArgs,\n OnCellChangeEventArgs,\n OnCellCssStylesChangedEventArgs,\n OnColumnsDragEventArgs,\n OnColumnsReorderedEventArgs,\n OnColumnsResizedEventArgs,\n OnColumnsResizeDblClickEventArgs,\n OnCompositeEditorChangeEventArgs,\n OnClickEventArgs,\n OnDblClickEventArgs,\n OnFooterContextMenuEventArgs,\n OnFooterRowCellRenderedEventArgs,\n OnHeaderCellRenderedEventArgs,\n OnFooterClickEventArgs,\n OnHeaderClickEventArgs,\n OnHeaderContextMenuEventArgs,\n OnHeaderMouseEventArgs,\n OnHeaderRowCellRenderedEventArgs,\n OnKeyDownEventArgs,\n OnValidationErrorEventArgs,\n OnRenderedEventArgs,\n OnSelectedRowsChangedEventArgs,\n OnSetOptionsEventArgs,\n OnActivateChangedOptionsEventArgs,\n OnScrollEventArgs,\n PagingInfo,\n Plugin,\n RowInfo,\n SelectionModel,\n SingleColumnSort,\n SlickGridEventData,\n SlickGridModel,\n} from './models/index';\nimport {\n BindingEventService as BindingEventService_,\n ColAutosizeMode as ColAutosizeMode_,\n GlobalEditorLock as GlobalEditorLock_,\n GridAutosizeColsMode as GridAutosizeColsMode_,\n keyCode as keyCode_,\n preClickClassName as preClickClassName_,\n RowSelectionMode as RowSelectionMode_,\n type SlickEditorLock,\n SlickEvent as SlickEvent_,\n SlickEventData as SlickEventData_,\n SlickRange as SlickRange_,\n Utils as Utils_,\n ValueFilterMode as ValueFilterMode_,\n WidthEvalMode as WidthEvalMode_,\n} from './slick.core';\nimport { Draggable as Draggable_, MouseWheel as MouseWheel_, Resizable as Resizable_ } from './slick.interactions';\n\n// for (iife) load Slick methods from global Slick object, or use imports for (esm)\nconst BindingEventService = IIFE_ONLY ? Slick.BindingEventService : BindingEventService_;\nconst ColAutosizeMode = IIFE_ONLY ? Slick.ColAutosizeMode : ColAutosizeMode_;\nconst SlickEvent = IIFE_ONLY ? Slick.Event : SlickEvent_;\nconst SlickEventData = IIFE_ONLY ? Slick.EventData : SlickEventData_;\nconst GlobalEditorLock = IIFE_ONLY ? Slick.GlobalEditorLock : GlobalEditorLock_;\nconst GridAutosizeColsMode = IIFE_ONLY ? Slick.GridAutosizeColsMode : GridAutosizeColsMode_;\nconst keyCode = IIFE_ONLY ? Slick.keyCode : keyCode_;\nconst preClickClassName = IIFE_ONLY ? Slick.preClickClassName : preClickClassName_;\nconst SlickRange = IIFE_ONLY ? Slick.Range : SlickRange_;\nconst RowSelectionMode = IIFE_ONLY ? Slick.RowSelectionMode : RowSelectionMode_;\nconst ValueFilterMode = IIFE_ONLY ? Slick.ValueFilterMode : ValueFilterMode_;\nconst Utils = IIFE_ONLY ? Slick.Utils : Utils_;\nconst WidthEvalMode = IIFE_ONLY ? Slick.WidthEvalMode : WidthEvalMode_;\nconst Draggable = IIFE_ONLY ? Slick.Draggable : Draggable_;\nconst MouseWheel = IIFE_ONLY ? Slick.MouseWheel : MouseWheel_;\nconst Resizable = IIFE_ONLY ? Slick.Resizable : Resizable_;\n\n/**\n * @license\n * (c) 2009-present Michael Leibman\n * michael{dot}leibman{at}gmail{dot}com\n * http://github.com/mleibman/slickgrid\n *\n * Distributed under MIT license.\n * All rights reserved.\n *\n * SlickGrid v5.0.0-alpha.9\n *\n * NOTES:\n * Cell/row DOM manipulations are done directly bypassing JS DOM manipulation methods.\n * This increases the speed dramatically, but can only be done safely because there are no event handlers\n * or data associated with any cell/row DOM nodes. Cell editors must make sure they implement .destroy()\n * and do proper cleanup.\n */\n\n//////////////////////////////////////////////////////////////////////////////////////////////\n// SlickGrid class implementation (available as SlickGrid)\n\ninterface RowCaching {\n rowNode: HTMLElement[] | null,\n cellColSpans: Array;\n cellNodesByColumnIdx: HTMLElement[];\n cellRenderQueue: any[];\n}\n\nexport class SlickGrid = Column, O extends BaseGridOption = BaseGridOption> {\n //////////////////////////////////////////////////////////////////////////////////////////////\n // Public API\n slickGridVersion = '5.0.0-alpha.9';\n\n /** optional grid state clientId */\n cid = '';\n\n // Events\n onActiveCellChanged = new SlickEvent();\n onActiveCellPositionChanged = new SlickEvent();\n onAddNewRow = new SlickEvent();\n onAutosizeColumns = new SlickEvent();\n onBeforeAppendCell = new SlickEvent();\n onBeforeCellEditorDestroy = new SlickEvent();\n onBeforeColumnsResize = new SlickEvent();\n onBeforeDestroy = new SlickEvent();\n onBeforeEditCell = new SlickEvent();\n onBeforeFooterRowCellDestroy = new SlickEvent();\n onBeforeHeaderCellDestroy = new SlickEvent();\n onBeforeHeaderRowCellDestroy = new SlickEvent();\n onBeforeSetColumns = new SlickEvent();\n onBeforeSort = new SlickEvent();\n onBeforeUpdateColumns = new SlickEvent();\n onCellChange = new SlickEvent();\n onCellCssStylesChanged = new SlickEvent();\n onClick = new SlickEvent();\n onColumnsReordered = new SlickEvent();\n onColumnsDrag = new SlickEvent();\n onColumnsResized = new SlickEvent();\n onColumnsResizeDblClick = new SlickEvent();\n onCompositeEditorChange = new SlickEvent();\n onContextMenu = new SlickEvent();\n onDrag = new SlickEvent();\n onDblClick = new SlickEvent();\n onDragInit = new SlickEvent();\n onDragStart = new SlickEvent();\n onDragEnd = new SlickEvent();\n onFooterClick = new SlickEvent();\n onFooterContextMenu = new SlickEvent();\n onFooterRowCellRendered = new SlickEvent();\n onHeaderCellRendered = new SlickEvent();\n onHeaderClick = new SlickEvent();\n onHeaderContextMenu = new SlickEvent();\n onHeaderMouseEnter = new SlickEvent();\n onHeaderMouseLeave = new SlickEvent();\n onHeaderRowCellRendered = new SlickEvent();\n onHeaderRowMouseEnter = new SlickEvent();\n onHeaderRowMouseLeave = new SlickEvent();\n onKeyDown = new SlickEvent();\n onMouseEnter = new SlickEvent();\n onMouseLeave = new SlickEvent();\n onRendered = new SlickEvent();\n onScroll = new SlickEvent();\n onSelectedRowsChanged = new SlickEvent();\n onSetOptions = new SlickEvent();\n onActivateChangedOptions = new SlickEvent();\n onSort = new SlickEvent();\n onValidationError = new SlickEvent();\n onViewportChanged = new SlickEvent();\n\n // ---\n // protected variables\n\n // shared across all grids on the page\n protected scrollbarDimensions?: { height: number; width: number; };\n protected maxSupportedCssHeight!: number; // browser's breaking point\n\n protected canvas: HTMLCanvasElement | null = null;\n protected canvas_context: CanvasRenderingContext2D | null = null;\n\n // settings\n protected _options!: O;\n protected _defaults: BaseGridOption = {\n alwaysShowVerticalScroll: false,\n alwaysAllowHorizontalScroll: false,\n explicitInitialization: false,\n rowHeight: 25,\n defaultColumnWidth: 80,\n enableAddRow: false,\n leaveSpaceForNewRows: false,\n editable: false,\n autoEdit: true,\n autoCommitEdit: false,\n suppressActiveCellChangeOnEdit: false,\n enableCellNavigation: true,\n enableColumnReorder: true,\n asyncEditorLoading: false,\n asyncEditorLoadDelay: 100,\n forceFitColumns: false,\n enableAsyncPostRender: false,\n asyncPostRenderDelay: 50,\n enableAsyncPostRenderCleanup: false,\n asyncPostRenderCleanupDelay: 40,\n auto: false,\n editorLock: GlobalEditorLock,\n showColumnHeader: true,\n showHeaderRow: false,\n headerRowHeight: 25,\n createFooterRow: false,\n showFooterRow: false,\n footerRowHeight: 25,\n createPreHeaderPanel: false,\n showPreHeaderPanel: false,\n preHeaderPanelHeight: 25,\n showTopPanel: false,\n topPanelHeight: 25,\n formatterFactory: null,\n editorFactory: null,\n cellFlashingCssClass: 'flashing',\n selectedCellCssClass: 'selected',\n multiSelect: true,\n enableTextSelectionOnCells: false,\n dataItemColumnValueExtractor: null,\n frozenBottom: false,\n frozenColumn: -1,\n frozenRow: -1,\n frozenRightViewportMinWidth: 100,\n fullWidthRows: false,\n multiColumnSort: false,\n numberedMultiColumnSort: false,\n tristateMultiColumnSort: false,\n sortColNumberInSeparateSpan: false,\n defaultFormatter: this.defaultFormatter,\n forceSyncScrolling: false,\n addNewRowCssClass: 'new-row',\n preserveCopiedSelectionOnPaste: false,\n showCellSelection: true,\n viewportClass: undefined,\n minRowBuffer: 3,\n emulatePagingWhenScrolling: true, // when scrolling off bottom of viewport, place new row at top of viewport\n editorCellNavOnLRKeys: false,\n enableMouseWheelScrollHandler: true,\n doPaging: true,\n autosizeColsMode: GridAutosizeColsMode.LegacyOff,\n autosizeColPaddingPx: 4,\n scrollRenderThrottling: 50,\n autosizeTextAvgToMWidthRatio: 0.75,\n viewportSwitchToScrollModeWidthPercent: undefined,\n viewportMinWidthPx: undefined,\n viewportMaxWidthPx: undefined,\n suppressCssChangesOnHiddenInit: false,\n ffMaxSupportedCssHeight: 6000000,\n maxSupportedCssHeight: 1000000000,\n sanitizer: undefined, // sanitize function, built in basic sanitizer is: Slick.RegexSanitizer(dirtyHtml)\n logSanitizedHtml: false, // log to console when sanitised - recommend true for testing of dev and production\n mixinDefaults: true\n };\n\n protected _columnDefaults = {\n name: '',\n resizable: true,\n sortable: false,\n minWidth: 30,\n maxWidth: undefined,\n rerenderOnResize: false,\n headerCssClass: null,\n defaultSortAsc: true,\n focusable: true,\n selectable: true,\n hidden: false\n } as Partial;\n\n protected _columnAutosizeDefaults: AutoSize = {\n ignoreHeaderText: false,\n colValueArray: undefined,\n allowAddlPercent: undefined,\n formatterOverride: undefined,\n autosizeMode: ColAutosizeMode.ContentIntelligent,\n rowSelectionModeOnInit: undefined,\n rowSelectionMode: RowSelectionMode.FirstNRows,\n rowSelectionCount: 100,\n valueFilterMode: ValueFilterMode.None,\n widthEvalMode: WidthEvalMode.Auto,\n sizeToRemaining: undefined,\n widthPx: undefined,\n contentSizePx: 0,\n headerWidthPx: 0,\n colDataTypeOf: undefined\n };\n\n // scroller\n protected th!: number; // virtual height\n protected h!: number; // real scrollable height\n protected ph!: number; // page height\n protected n!: number; // number of pages\n protected cj!: number; // \"jumpiness\" coefficient\n\n protected page = 0; // current page\n protected offset = 0; // current page offset\n protected vScrollDir = 1;\n protected _bindingEventService = new BindingEventService();\n protected initialized = false;\n protected _container!: HTMLElement;\n protected uid = `slickgrid_${Math.round(1000000 * Math.random())}`;\n protected _focusSink!: HTMLDivElement;\n protected _focusSink2!: HTMLDivElement;\n protected _groupHeaders: HTMLDivElement[] = [];\n protected _headerScroller: HTMLDivElement[] = [];\n protected _headers: HTMLDivElement[] = [];\n protected _headerRows!: HTMLDivElement[];\n protected _headerRowScroller!: HTMLDivElement[];\n protected _headerRowSpacerL!: HTMLDivElement;\n protected _headerRowSpacerR!: HTMLDivElement;\n protected _footerRow!: HTMLDivElement[];\n protected _footerRowScroller!: HTMLDivElement[];\n protected _footerRowSpacerL!: HTMLDivElement;\n protected _footerRowSpacerR!: HTMLDivElement;\n protected _preHeaderPanel!: HTMLDivElement;\n protected _preHeaderPanelScroller!: HTMLDivElement;\n protected _preHeaderPanelSpacer!: HTMLDivElement;\n protected _preHeaderPanelR!: HTMLDivElement;\n protected _preHeaderPanelScrollerR!: HTMLDivElement;\n protected _preHeaderPanelSpacerR!: HTMLDivElement;\n protected _topPanelScrollers!: HTMLDivElement[];\n protected _topPanels!: HTMLDivElement[];\n protected _viewport!: HTMLDivElement[];\n protected _canvas!: HTMLDivElement[];\n protected _style: any;\n protected _boundAncestors: HTMLElement[] = [];\n protected stylesheet?: { cssRules: Array<{ selectorText: string; }>; rules: Array<{ selectorText: string; }>; } | null;\n protected columnCssRulesL?: Array<{ selectorText: string; }>;\n protected columnCssRulesR?: Array<{ selectorText: string; }>;\n protected viewportH = 0;\n protected viewportW = 0;\n protected canvasWidth = 0;\n protected canvasWidthL = 0;\n protected canvasWidthR = 0;\n protected headersWidth = 0;\n protected headersWidthL = 0;\n protected headersWidthR = 0;\n protected viewportHasHScroll = false;\n protected viewportHasVScroll = false;\n protected headerColumnWidthDiff = 0;\n protected headerColumnHeightDiff = 0; // border+padding\n protected cellWidthDiff = 0;\n protected cellHeightDiff = 0;\n protected absoluteColumnMinWidth!: number;\n protected hasFrozenRows = false;\n protected frozenRowsHeight = 0;\n protected actualFrozenRow = -1;\n protected paneTopH = 0;\n protected paneBottomH = 0;\n protected viewportTopH = 0;\n protected viewportBottomH = 0;\n protected topPanelH = 0;\n protected headerRowH = 0;\n protected footerRowH = 0;\n\n protected tabbingDirection = 1;\n protected _activeCanvasNode!: HTMLDivElement;\n protected _activeViewportNode!: HTMLDivElement;\n protected activePosX!: number;\n protected activeRow!: number;\n protected activeCell!: number;\n protected activeCellNode: HTMLDivElement | null = null;\n protected currentEditor: Editor | null = null;\n protected serializedEditorValue: any;\n protected editController?: EditController;\n\n protected rowsCache: Array = {} as any;\n protected renderedRows = 0;\n protected numVisibleRows = 0;\n protected prevScrollTop = 0;\n protected scrollTop = 0;\n protected lastRenderedScrollTop = 0;\n protected lastRenderedScrollLeft = 0;\n protected prevScrollLeft = 0;\n protected scrollLeft = 0;\n\n protected selectionModel?: SelectionModel;\n protected selectedRows: number[] = [];\n\n protected plugins: Plugin[] = [];\n protected cellCssClasses: CssStyleHash = {};\n\n protected columnsById: Record = {};\n protected sortColumns: ColumnSort[] = [];\n protected columnPosLeft: number[] = [];\n protected columnPosRight: number[] = [];\n\n protected pagingActive = false;\n protected pagingIsLastPage = false;\n\n protected scrollThrottle!: { enqueue: () => void; dequeue: () => void; };\n\n // async call handles\n protected h_editorLoader: any = null;\n protected h_render = null;\n protected h_postrender: any = null;\n protected h_postrenderCleanup: any = null;\n protected postProcessedRows: any = {};\n protected postProcessToRow: number = null as any;\n protected postProcessFromRow: number = null as any;\n protected postProcessedCleanupQueue: Array<{\n actionType: string;\n groupId: number;\n node: HTMLElement | HTMLElement[];\n columnIdx?: number;\n rowIdx?: number;\n }> = [];\n protected postProcessgroupId = 0;\n\n // perf counters\n protected counter_rows_rendered = 0;\n protected counter_rows_removed = 0;\n\n protected _paneHeaderL!: HTMLDivElement;\n protected _paneHeaderR!: HTMLDivElement;\n protected _paneTopL!: HTMLDivElement;\n protected _paneTopR!: HTMLDivElement;\n protected _paneBottomL!: HTMLDivElement;\n protected _paneBottomR!: HTMLDivElement;\n protected _headerScrollerL!: HTMLDivElement;\n protected _headerScrollerR!: HTMLDivElement;\n protected _headerL!: HTMLDivElement;\n protected _headerR!: HTMLDivElement;\n protected _groupHeadersL!: HTMLDivElement;\n protected _groupHeadersR!: HTMLDivElement;\n protected _headerRowScrollerL!: HTMLDivElement;\n protected _headerRowScrollerR!: HTMLDivElement;\n protected _footerRowScrollerL!: HTMLDivElement;\n protected _footerRowScrollerR!: HTMLDivElement;\n protected _headerRowL!: HTMLDivElement;\n protected _headerRowR!: HTMLDivElement;\n protected _footerRowL!: HTMLDivElement;\n protected _footerRowR!: HTMLDivElement;\n protected _topPanelScrollerL!: HTMLDivElement;\n protected _topPanelScrollerR!: HTMLDivElement;\n protected _topPanelL!: HTMLDivElement;\n protected _topPanelR!: HTMLDivElement;\n protected _viewportTopL!: HTMLDivElement;\n protected _viewportTopR!: HTMLDivElement;\n protected _viewportBottomL!: HTMLDivElement;\n protected _viewportBottomR!: HTMLDivElement;\n protected _canvasTopL!: HTMLDivElement;\n protected _canvasTopR!: HTMLDivElement;\n protected _canvasBottomL!: HTMLDivElement;\n protected _canvasBottomR!: HTMLDivElement;\n protected _viewportScrollContainerX!: HTMLDivElement;\n protected _viewportScrollContainerY!: HTMLDivElement;\n protected _headerScrollContainer!: HTMLDivElement;\n protected _headerRowScrollContainer!: HTMLDivElement;\n protected _footerRowScrollContainer!: HTMLDivElement;\n\n // store css attributes if display:none is active in container or parent\n protected cssShow = { position: 'absolute', visibility: 'hidden', display: 'block' };\n protected _hiddenParents: HTMLElement[] = [];\n protected oldProps: Array> = [];\n protected enforceFrozenRowHeightRecalc = false;\n protected columnResizeDragging = false;\n protected slickDraggableInstance: InteractionBase | null = null;\n protected slickMouseWheelInstances: Array = [];\n protected slickResizableInstances: Array = [];\n protected sortableSideLeftInstance: SortableInstance;\n protected sortableSideRightInstance: SortableInstance;\n protected logMessageCount = 0;\n protected logMessageMaxCount = 30;\n\n /**\n * Creates a new instance of the grid.\n * @class SlickGrid\n * @constructor\n * @param {Node} container - Container node to create the grid in.\n * @param {Array|Object} data - An array of objects for databinding.\n * @param {Array} columns - An array of column definitions.\n * @param {Object} [options] - Grid this._options.\n **/\n constructor(protected container: HTMLElement | string, protected data: CustomDataView | TData[], protected columns: C[], protected options: Partial) {\n this.initialize();\n }\n\n //////////////////////////////////////////////////////////////////////////////////////////////\n // Initialization\n\n /** Initializes the grid. */\n init() {\n this.finishInitialization();\n }\n\n protected initialize() {\n if (typeof this.container === 'string') {\n this._container = document.querySelector(this.container) as HTMLDivElement;\n } else {\n this._container = this.container;\n }\n\n if (!this._container) {\n throw new Error(`SlickGrid requires a valid container, ${this.container} does not exist in the DOM.`);\n }\n\n // calculate these only once and share between grid instances\n if (this.options.mixinDefaults) {\n if (!this.options) { this.options = {}; }\n Utils.applyDefaults(this.options, this._defaults);\n } else {\n this._options = Utils.extend(true, {}, this._defaults, this.options);\n }\n this.scrollThrottle = this.actionThrottle(this.render.bind(this), this._options.scrollRenderThrottling as number);\n this.maxSupportedCssHeight = this.maxSupportedCssHeight || this.getMaxSupportedCssHeight();\n this.validateAndEnforceOptions();\n this._columnDefaults.width = this._options.defaultColumnWidth;\n\n if (!this._options.suppressCssChangesOnHiddenInit) {\n this.cacheCssForHiddenInit();\n }\n\n this.updateColumnProps();\n\n // validate loaded JavaScript modules against requested options\n if (this._options.enableColumnReorder && (!Sortable || !Sortable.create)) {\n throw new Error('SlickGrid requires Sortable.js module to be loaded');\n }\n\n this.editController = {\n commitCurrentEdit: this.commitCurrentEdit.bind(this),\n cancelCurrentEdit: this.cancelCurrentEdit.bind(this),\n };\n\n Utils.emptyElement(this._container);\n this._container.style.overflow = 'hidden';\n this._container.style.outline = String(0);\n this._container.classList.add(this.uid);\n this._container.classList.add('ui-widget');\n\n const containerStyles = window.getComputedStyle(this._container);\n if (!(/relative|absolute|fixed/).test(containerStyles.position)) {\n this._container.style.position = 'relative';\n }\n\n this._focusSink = Utils.createDomElement('div', { tabIndex: 0, style: { position: 'fixed', width: '0px', height: '0px', top: '0px', left: '0px', outline: '0px' } }, this._container);\n\n // Containers used for scrolling frozen columns and rows\n this._paneHeaderL = Utils.createDomElement('div', { className: 'slick-pane slick-pane-header slick-pane-left', tabIndex: 0 }, this._container);\n this._paneHeaderR = Utils.createDomElement('div', { className: 'slick-pane slick-pane-header slick-pane-right', tabIndex: 0 }, this._container);\n this._paneTopL = Utils.createDomElement('div', { className: 'slick-pane slick-pane-top slick-pane-left', tabIndex: 0 }, this._container);\n this._paneTopR = Utils.createDomElement('div', { className: 'slick-pane slick-pane-top slick-pane-right', tabIndex: 0 }, this._container);\n this._paneBottomL = Utils.createDomElement('div', { className: 'slick-pane slick-pane-bottom slick-pane-left', tabIndex: 0 }, this._container);\n this._paneBottomR = Utils.createDomElement('div', { className: 'slick-pane slick-pane-bottom slick-pane-right', tabIndex: 0 }, this._container);\n\n if (this._options.createPreHeaderPanel) {\n this._preHeaderPanelScroller = Utils.createDomElement('div', { className: 'slick-preheader-panel ui-state-default slick-state-default', style: { overflow: 'hidden', position: 'relative' } }, this._paneHeaderL);\n this._preHeaderPanelScroller.appendChild(document.createElement('div'));\n this._preHeaderPanel = Utils.createDomElement('div', null, this._preHeaderPanelScroller);\n this._preHeaderPanelSpacer = Utils.createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._preHeaderPanelScroller);\n\n this._preHeaderPanelScrollerR = Utils.createDomElement('div', { className: 'slick-preheader-panel ui-state-default slick-state-default', style: { overflow: 'hidden', position: 'relative' } }, this._paneHeaderR);\n this._preHeaderPanelR = Utils.createDomElement('div', null, this._preHeaderPanelScrollerR);\n this._preHeaderPanelSpacerR = Utils.createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._preHeaderPanelScrollerR);\n\n if (!this._options.showPreHeaderPanel) {\n Utils.hide(this._preHeaderPanelScroller);\n Utils.hide(this._preHeaderPanelScrollerR);\n }\n }\n\n // Append the header scroller containers\n this._headerScrollerL = Utils.createDomElement('div', { className: 'slick-header ui-state-default slick-state-default slick-header-left' }, this._paneHeaderL);\n this._headerScrollerR = Utils.createDomElement('div', { className: 'slick-header ui-state-default slick-state-default slick-header-right' }, this._paneHeaderR);\n\n // Cache the header scroller containers\n this._headerScroller.push(this._headerScrollerL);\n this._headerScroller.push(this._headerScrollerR);\n\n // Append the columnn containers to the headers\n this._headerL = Utils.createDomElement('div', { className: 'slick-header-columns slick-header-columns-left', style: { left: '-1000px' } }, this._headerScrollerL);\n this._headerR = Utils.createDomElement('div', { className: 'slick-header-columns slick-header-columns-right', style: { left: '-1000px' } }, this._headerScrollerR);\n\n // Cache the header columns\n this._headers = [this._headerL, this._headerR];\n\n this._headerRowScrollerL = Utils.createDomElement('div', { className: 'slick-headerrow ui-state-default slick-state-default' }, this._paneTopL);\n this._headerRowScrollerR = Utils.createDomElement('div', { className: 'slick-headerrow ui-state-default slick-state-default' }, this._paneTopR);\n\n this._headerRowScroller = [this._headerRowScrollerL, this._headerRowScrollerR];\n\n this._headerRowSpacerL = Utils.createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._headerRowScrollerL);\n this._headerRowSpacerR = Utils.createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._headerRowScrollerR);\n\n this._headerRowL = Utils.createDomElement('div', { className: 'slick-headerrow-columns slick-headerrow-columns-left' }, this._headerRowScrollerL);\n this._headerRowR = Utils.createDomElement('div', { className: 'slick-headerrow-columns slick-headerrow-columns-right' }, this._headerRowScrollerR);\n\n this._headerRows = [this._headerRowL, this._headerRowR];\n\n // Append the top panel scroller\n this._topPanelScrollerL = Utils.createDomElement('div', { className: 'slick-top-panel-scroller ui-state-default slick-state-default' }, this._paneTopL);\n this._topPanelScrollerR = Utils.createDomElement('div', { className: 'slick-top-panel-scroller ui-state-default slick-state-default' }, this._paneTopR);\n\n this._topPanelScrollers = [this._topPanelScrollerL, this._topPanelScrollerR];\n\n // Append the top panel\n this._topPanelL = Utils.createDomElement('div', { className: 'slick-top-panel', style: { width: '10000px' } }, this._topPanelScrollerL);\n this._topPanelR = Utils.createDomElement('div', { className: 'slick-top-panel', style: { width: '10000px' } }, this._topPanelScrollerR);\n\n this._topPanels = [this._topPanelL, this._topPanelR];\n\n if (!this._options.showColumnHeader) {\n this._headerScroller.forEach((el) => {\n Utils.hide(el);\n });\n }\n\n if (!this._options.showTopPanel) {\n this._topPanelScrollers.forEach((scroller) => {\n Utils.hide(scroller);\n })\n }\n\n if (!this._options.showHeaderRow) {\n this._headerRowScroller.forEach((scroller) => {\n Utils.hide(scroller);\n })\n }\n\n // Append the viewport containers\n this._viewportTopL = Utils.createDomElement('div', { className: 'slick-viewport slick-viewport-top slick-viewport-left', tabIndex: 0 }, this._paneTopL);\n this._viewportTopR = Utils.createDomElement('div', { className: 'slick-viewport slick-viewport-top slick-viewport-right', tabIndex: 0 }, this._paneTopR);\n this._viewportBottomL = Utils.createDomElement('div', { className: 'slick-viewport slick-viewport-bottom slick-viewport-left', tabIndex: 0 }, this._paneBottomL);\n this._viewportBottomR = Utils.createDomElement('div', { className: 'slick-viewport slick-viewport-bottom slick-viewport-right', tabIndex: 0 }, this._paneBottomR);\n\n // Cache the viewports\n this._viewport = [this._viewportTopL, this._viewportTopR, this._viewportBottomL, this._viewportBottomR];\n if (this._options.viewportClass) {\n this._viewport.forEach((view) => {\n view.classList.add(...(this._options.viewportClass || '').split(' '));\n });\n }\n\n // Default the active viewport to the top left\n this._activeViewportNode = this._viewportTopL;\n\n // Append the canvas containers\n this._canvasTopL = Utils.createDomElement('div', { className: 'grid-canvas grid-canvas-top grid-canvas-left', tabIndex: 0 }, this._viewportTopL);\n this._canvasTopR = Utils.createDomElement('div', { className: 'grid-canvas grid-canvas-top grid-canvas-right', tabIndex: 0 }, this._viewportTopR);\n this._canvasBottomL = Utils.createDomElement('div', { className: 'grid-canvas grid-canvas-bottom grid-canvas-left', tabIndex: 0 }, this._viewportBottomL);\n this._canvasBottomR = Utils.createDomElement('div', { className: 'grid-canvas grid-canvas-bottom grid-canvas-right', tabIndex: 0 }, this._viewportBottomR);\n\n // Cache the canvases\n this._canvas = [this._canvasTopL, this._canvasTopR, this._canvasBottomL, this._canvasBottomR];\n\n this.scrollbarDimensions = this.scrollbarDimensions || this.measureScrollbar();\n\n // Default the active canvas to the top left\n this._activeCanvasNode = this._canvasTopL;\n\n // pre-header\n if (this._preHeaderPanelSpacer) {\n Utils.width(this._preHeaderPanelSpacer, this.getCanvasWidth() + this.scrollbarDimensions.width);\n }\n\n this._headers.forEach((el) => {\n Utils.width(el, this.getHeadersWidth());\n })\n\n Utils.width(this._headerRowSpacerL, this.getCanvasWidth() + this.scrollbarDimensions.width);\n Utils.width(this._headerRowSpacerR, this.getCanvasWidth() + this.scrollbarDimensions.width);\n\n // footer Row\n if (this._options.createFooterRow) {\n this._footerRowScrollerR = Utils.createDomElement('div', { className: 'slick-footerrow ui-state-default slick-state-default' }, this._paneTopR);\n this._footerRowScrollerL = Utils.createDomElement('div', { className: 'slick-footerrow ui-state-default slick-state-default' }, this._paneTopL);\n\n this._footerRowScroller = [this._footerRowScrollerL, this._footerRowScrollerR];\n\n this._footerRowSpacerL = Utils.createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._footerRowScrollerL);\n Utils.width(this._footerRowSpacerL, this.getCanvasWidth() + this.scrollbarDimensions.width);\n this._footerRowSpacerR = Utils.createDomElement('div', { style: { display: 'block', height: '1px', position: 'absolute', top: '0px', left: '0px' } }, this._footerRowScrollerR);\n Utils.width(this._footerRowSpacerR, this.getCanvasWidth() + this.scrollbarDimensions.width);\n\n\n this._footerRowL = Utils.createDomElement('div', { className: 'slick-footerrow-columns slick-footerrow-columns-left' }, this._footerRowScrollerL);\n this._footerRowR = Utils.createDomElement('div', { className: 'slick-footerrow-columns slick-footerrow-columns-right' }, this._footerRowScrollerR);\n\n this._footerRow = [this._footerRowL, this._footerRowR];\n\n if (!this._options.showFooterRow) {\n this._footerRowScroller.forEach((scroller) => {\n Utils.hide(scroller);\n });\n }\n }\n\n this._focusSink2 = this._focusSink.cloneNode(true) as HTMLDivElement;\n this._container.appendChild(this._focusSink2);\n\n if (!this._options.explicitInitialization) {\n this.finishInitialization();\n }\n }\n\n protected finishInitialization() {\n if (!this.initialized) {\n this.initialized = true;\n\n this.getViewportWidth();\n this.getViewportHeight();\n\n // header columns and cells may have different padding/border skewing width calculations (box-sizing, hello?)\n // calculate the diff so we can set consistent sizes\n this.measureCellPaddingAndBorder();\n\n // for usability reasons, all text selection in SlickGrid is disabled\n // with the exception of input and textarea elements (selection must\n // be enabled there so that editors work as expected); note that\n // selection in grid cells (grid body) is already unavailable in\n // all browsers except IE\n this.disableSelection(this._headers); // disable all text selection in header (including input and textarea)\n\n if (!this._options.enableTextSelectionOnCells) {\n // disable text selection in grid cells except in input and textarea elements\n // (this is IE-specific, because selectstart event will only fire in IE)\n this._viewport.forEach((view) => {\n this._bindingEventService.bind(view, 'selectstart', (event) => {\n if (event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement) {\n return;\n }\n });\n })\n }\n\n this.setFrozenOptions();\n this.setPaneVisibility();\n this.setScroller();\n this.setOverflow();\n\n this.updateColumnCaches();\n this.createColumnHeaders();\n this.createColumnFooter();\n this.setupColumnSort();\n this.createCssRules();\n this.resizeCanvas();\n this.bindAncestorScrollEvents();\n\n this._bindingEventService.bind(this._container, 'resize', this.resizeCanvas.bind(this));\n this._viewport.forEach((view) => {\n this._bindingEventService.bind(view, 'scroll', this.handleScroll.bind(this));\n });\n\n if (this._options.enableMouseWheelScrollHandler) {\n this._viewport.forEach((view) => {\n this.slickMouseWheelInstances.push(MouseWheel({\n element: view,\n onMouseWheel: this.handleMouseWheel.bind(this)\n }));\n });\n }\n\n this._headerScroller.forEach((el) => {\n this._bindingEventService.bind(el, 'contextmenu', this.handleHeaderContextMenu.bind(this) as EventListener);\n this._bindingEventService.bind(el, 'click', this.handleHeaderClick.bind(this) as EventListener);\n });\n\n this._headerRowScroller.forEach((scroller) => {\n this._bindingEventService.bind(scroller, 'scroll', this.handleHeaderRowScroll.bind(this) as EventListener);\n });\n\n if (this._options.createFooterRow) {\n this._footerRow.forEach((footer) => {\n this._bindingEventService.bind(footer, 'contextmenu', this.handleFooterContextMenu.bind(this) as EventListener);\n this._bindingEventService.bind(footer, 'click', this.handleFooterClick.bind(this) as EventListener);\n });\n\n this._footerRowScroller.forEach((scroller) => {\n this._bindingEventService.bind(scroller, 'scroll', this.handleFooterRowScroll.bind(this) as EventListener);\n });\n }\n\n if (this._options.createPreHeaderPanel) {\n this._bindingEventService.bind(this._preHeaderPanelScroller, 'scroll', this.handlePreHeaderPanelScroll.bind(this) as EventListener);\n }\n\n this._bindingEventService.bind(this._focusSink, 'keydown', this.handleKeyDown.bind(this) as EventListener);\n this._bindingEventService.bind(this._focusSink2, 'keydown', this.handleKeyDown.bind(this) as EventListener);\n\n this._canvas.forEach((element) => {\n this._bindingEventService.bind(element, 'keydown', this.handleKeyDown.bind(this) as EventListener);\n this._bindingEventService.bind(element, 'click', this.handleClick.bind(this) as EventListener);\n this._bindingEventService.bind(element, 'dblclick', this.handleDblClick.bind(this) as EventListener);\n this._bindingEventService.bind(element, 'contextmenu', this.handleContextMenu.bind(this) as EventListener);\n this._bindingEventService.bind(element, 'mouseover', this.handleCellMouseOver.bind(this) as EventListener);\n this._bindingEventService.bind(element, 'mouseout', this.handleCellMouseOut.bind(this) as EventListener);\n });\n\n if (Draggable) {\n this.slickDraggableInstance = Draggable({\n containerElement: this._container,\n allowDragFrom: 'div.slick-cell',\n onDragInit: this.handleDragInit.bind(this),\n onDragStart: this.handleDragStart.bind(this),\n onDrag: this.handleDrag.bind(this),\n onDragEnd: this.handleDragEnd.bind(this)\n });\n }\n\n if (!this._options.suppressCssChangesOnHiddenInit) {\n this.restoreCssFromHiddenInit();\n }\n }\n }\n\n cacheCssForHiddenInit() {\n // handle display:none on container or container parents\n this._hiddenParents = Utils.parents(this._container, ':hidden') as HTMLElement[];\n for (const el of this._hiddenParents) {\n const old: Partial = {};\n for (const name in this.cssShow) {\n old[name as any] = el.style[name as 'position' | 'visibility' | 'display'];\n el.style[name as any] = this.cssShow[name as 'position' | 'visibility' | 'display'];\n }\n this.oldProps.push(old);\n }\n }\n\n restoreCssFromHiddenInit() {\n // finish handle display:none on container or container parents\n // - put values back the way they were\n let i = 0;\n for (const el of this._hiddenParents) {\n const old = this.oldProps[i++];\n for (const name in this.cssShow) {\n el.style[name as CSSStyleDeclarationWritable] = (old as any)[name];\n }\n }\n }\n\n protected hasFrozenColumns() {\n return this._options.frozenColumn! > -1;\n }\n\n /** Register an external Plugin */\n registerPlugin(plugin: T) {\n this.plugins.unshift(plugin);\n plugin.init(this as unknown as SlickGridModel);\n }\n\n /** Unregister (destroy) an external Plugin */\n unregisterPlugin(plugin: Plugin) {\n for (let i = this.plugins.length; i >= 0; i--) {\n if (this.plugins[i] === plugin) {\n this.plugins[i]?.destroy();\n this.plugins.splice(i, 1);\n break;\n }\n }\n }\n\n /** Get a Plugin (addon) by its name */\n getPluginByName

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