slickgrid
Version:
A lightning fast JavaScript grid/spreadsheet
106 lines (90 loc) • 3.46 kB
text/typescript
import type { CSSStyleDeclarationWritable, CellRangeDecoratorOption, SlickPlugin } from '../models/index.js';
import { Utils as Utils_, type SlickRange } from '../slick.core.js';
import type { SlickGrid } from '../slick.grid.js';
// for (iife) load Slick methods from global Slick object, or use imports for (esm)
const Utils = IIFE_ONLY ? Slick.Utils : Utils_;
/***
* Displays an overlay on top of a given cell range.
*
* TODO:
* Currently, it blocks mouse events to DOM nodes behind it.
* Use FF and WebKit-specific "pointer-events" CSS style, or some kind of event forwarding.
* Could also construct the borders separately using 4 individual DIVs.
*
* @param {Grid} grid
* @param {Object} options
*/
export class SlickCellRangeDecorator implements SlickPlugin {
// --
// public API
pluginName = 'CellRangeDecorator' as const;
// --
// protected props
protected _options: CellRangeDecoratorOption;
protected _elem?: HTMLDivElement | null;
protected _selectionCss: CSSStyleDeclaration;
protected _defaults = {
selectionCssClass: 'slick-range-decorator',
selectionCss: {
zIndex: '9999',
border: '2px dashed red'
},
copyToSelectionCss : {
"zIndex": "9999",
"border": "2px dashed blue"
},
offset: { top: -1, left: -1, height: -2, width: -2 }
} as CellRangeDecoratorOption;
constructor(protected readonly grid: SlickGrid, options?: Partial<CellRangeDecoratorOption>) {
this._options = Utils.extend(true, {}, this._defaults, options);
this._selectionCss = options?.selectionCss || {} as CSSStyleDeclaration;
}
destroy() {
this.hide();
}
getSelectionCss() {
return this._selectionCss;
}
setSelectionCss(cssProps: CSSStyleDeclaration) {
this._selectionCss = cssProps;
}
init() { }
hide() {
this._elem?.remove();
this._elem = null;
}
show(range: SlickRange, isCopyTo?: boolean) {
if (!this._elem) {
this._elem = document.createElement('div');
this._elem.className = this._options.selectionCssClass;
this._elem.style.position = 'absolute';
const canvasNode = this.grid.getActiveCanvasNode();
if (canvasNode) {
canvasNode.appendChild(this._elem);
}
}
const css = isCopyTo && this._options.copyToSelectionCss ? this._options.copyToSelectionCss :this._options.selectionCss;
Object.keys(css).forEach((cssStyleKey) => {
if (this._elem!.style[cssStyleKey as CSSStyleDeclarationWritable] !== css[cssStyleKey as CSSStyleDeclarationWritable]) {
this._elem!.style[cssStyleKey as CSSStyleDeclarationWritable] = css[cssStyleKey as CSSStyleDeclarationWritable];
}
});
const from = this.grid.getCellNodeBox(range.fromRow, range.fromCell);
const to = this.grid.getCellNodeBox(range.toRow, range.toCell);
if (from && to && this._options?.offset) {
this._elem.style.top = `${from.top + this._options.offset.top}px`;
this._elem.style.left = `${from.left + this._options.offset.left}px`;
this._elem.style.height = `${to.bottom - from.top + this._options.offset.height}px`;
this._elem.style.width = `${to.right - from.left + this._options.offset.width}px`;
}
return this._elem;
}
}
// extend Slick namespace on window object when building as iife
if (IIFE_ONLY && window.Slick) {
Utils.extend(true, window, {
Slick: {
CellRangeDecorator: SlickCellRangeDecorator
}
});
}