From d6a3d3e71a6db0ea4dd376ba3bb3aa403f3897f6 Mon Sep 17 00:00:00 2001 From: Alain Dumesny Date: Tue, 1 Mar 2022 08:49:57 -0800 Subject: [PATCH] private --> protected * changed private to protected so subclasses can access full implementation of base classes. * more cleanup on the engine (_notify() second param was removed as never used, Layout per column uses Node types instead), doc tweaks, etc... --- spec/gridstack-engine-spec.ts | 39 +++++------------ src/gridstack-engine.ts | 80 ++++++++++++++++------------------- src/gridstack.ts | 55 ++++++++++++------------ src/h5/dd-base-impl.ts | 6 +-- src/h5/dd-draggable.ts | 44 +++++++++---------- src/h5/dd-droppable.ts | 22 +++++----- src/h5/dd-resizable-handle.ts | 26 ++++++------ src/h5/dd-resizable.ts | 50 +++++++++++----------- src/h5/gridstack-dd-native.ts | 4 +- 9 files changed, 152 insertions(+), 174 deletions(-) diff --git a/spec/gridstack-engine-spec.ts b/spec/gridstack-engine-spec.ts index 478f8b78d..034489400 100644 --- a/spec/gridstack-engine-spec.ts +++ b/spec/gridstack-engine-spec.ts @@ -25,8 +25,8 @@ describe('gridstack engine', function() { expect(engine.float).toEqual(false); expect(engine.maxRow).toEqual(undefined); expect(engine.nodes).toEqual([]); - expect(engine.onChange).toEqual(undefined); expect(engine.batchMode).toEqual(undefined); + expect((engine as any).onChange).toEqual(undefined); }); it('should set params correctly.', function() { @@ -37,8 +37,8 @@ describe('gridstack engine', function() { expect(engine.float).toBe(true); expect(engine.maxRow).toEqual(2); expect(engine.nodes).toEqual(arr); - expect(engine.onChange).toEqual(fkt); expect(engine.batchMode).toEqual(undefined); + expect((engine as any).onChange).toEqual(fkt); }); }); @@ -80,42 +80,42 @@ describe('gridstack engine', function() { it('should sort ascending with 12 columns.', function() { w.column = 12; w.nodes = [{x: 7, y: 0}, {x: 4, y: 4}, {x: 9, y: 0}, {x: 0, y: 1}]; - e.prototype._sortNodes.call(w, 1); + engine.sortNodes.call(w, 1); expect(w.nodes).toEqual([{x: 7, y: 0}, {x: 9, y: 0}, {x: 0, y: 1}, {x: 4, y: 4}]); }); it('should sort descending with 12 columns.', function() { w.column = 12; w.nodes = [{x: 7, y: 0}, {x: 4, y: 4}, {x: 9, y: 0}, {x: 0, y: 1}]; - e.prototype._sortNodes.call(w, -1); + engine.sortNodes.call(w, -1); expect(w.nodes).toEqual([{x: 4, y: 4}, {x: 0, y: 1}, {x: 9, y: 0}, {x: 7, y: 0}]); }); it('should sort ascending with 1 columns.', function() { w.column = 1; w.nodes = [{x: 7, y: 0}, {x: 4, y: 4}, {x: 9, y: 0}, {x: 0, y: 1}]; - e.prototype._sortNodes.call(w, 1); + engine.sortNodes.call(w, 1); expect(w.nodes).toEqual([{x: 0, y: 1}, {x: 7, y: 0}, {x: 4, y: 4}, {x: 9, y: 0}]); }); it('should sort descending with 1 columns.', function() { w.column = 1; w.nodes = [{x: 7, y: 0}, {x: 4, y: 4}, {x: 9, y: 0}, {x: 0, y: 1}]; - e.prototype._sortNodes.call(w, -1); + engine.sortNodes.call(w, -1); expect(w.nodes).toEqual([{x: 9, y: 0}, {x: 4, y: 4}, {x: 7, y: 0}, {x: 0, y: 1}]); }); it('should sort ascending without columns.', function() { w.column = undefined; w.nodes = [{x: 7, y: 0, w: 1}, {x: 4, y: 4, w: 1}, {x: 9, y: 0, w: 1}, {x: 0, y: 1, w: 1}]; - e.prototype._sortNodes.call(w, 1); + engine.sortNodes.call(w, 1); expect(w.nodes).toEqual([{x: 7, y: 0, w: 1}, {x: 9, y: 0, w: 1}, {x: 0, y: 1, w: 1}, {x: 4, y: 4, w: 1}]); }); it('should sort descending without columns.', function() { w.column = undefined; w.nodes = [{x: 7, y: 0, w: 1}, {x: 4, y: 4, w: 1}, {x: 9, y: 0, w: 1}, {x: 0, y: 1, w: 1}]; - e.prototype._sortNodes.call(w, -1); + engine.sortNodes.call(w, -1); expect(w.nodes).toEqual([{x: 4, y: 4, w: 1}, {x: 0, y: 1, w: 1}, {x: 9, y: 0, w: 1}, {x: 7, y: 0, w: 1}]); }); @@ -244,30 +244,13 @@ describe('gridstack engine', function() { it('should by called with dirty nodes', function() { (engine as any)._notify(); - expect(spy.callback).toHaveBeenCalledWith([ - engine.nodes[0], - engine.nodes[1] - ], true); + expect(spy.callback).toHaveBeenCalledWith([engine.nodes[0], engine.nodes[1]]); }); it('should by called with extra passed node to be removed', function() { let n1 = {id: -1}; - (engine as any)._notify(n1); - expect(spy.callback).toHaveBeenCalledWith([ - n1, - engine.nodes[0], - engine.nodes[1] - ], true); - }); - - it('should by called with extra passed node to be removed and should maintain false parameter', function() { - let n1 = {id: -1}; - (engine as any)._notify(n1, false); - expect(spy.callback).toHaveBeenCalledWith([ - n1, - engine.nodes[0], - engine.nodes[1] - ], false); + (engine as any)._notify([n1]); + expect(spy.callback).toHaveBeenCalledWith([n1, engine.nodes[0], engine.nodes[1]]); }); }); diff --git a/src/gridstack-engine.ts b/src/gridstack-engine.ts index 30cf730aa..5f4ba816f 100644 --- a/src/gridstack-engine.ts +++ b/src/gridstack-engine.ts @@ -1,19 +1,21 @@ /** * gridstack-engine.ts 5.0.0-dev - * Copyright (c) 2021 Alain Dumesny - see GridStack root license + * Copyright (c) 2021-2022 Alain Dumesny - see GridStack root license */ import { Utils } from './utils'; import { GridStackNode, ColumnOptions, GridStackPosition, GridStackMoveOpts } from './types'; -export type onChangeCB = (nodes: GridStackNode[], removeDOM?: boolean) => void; -/** options used for creations - similar to GridStackOptions */ +/** callback to update the DOM attributes since this class is generic (no HTML or other info) for items that changed - see _notify() */ +type OnChangeCB = (nodes: GridStackNode[]) => void; + +/** options used during creation - similar to GridStackOptions */ export interface GridStackEngineOptions { column?: number; maxRow?: number; float?: boolean; nodes?: GridStackNode[]; - onChange?: onChangeCB; + onChange?: OnChangeCB; } /** @@ -26,29 +28,30 @@ export class GridStackEngine { public column: number; public maxRow: number; public nodes: GridStackNode[]; - public onChange: onChangeCB; public addedNodes: GridStackNode[] = []; public removedNodes: GridStackNode[] = []; public batchMode: boolean; + /** @internal callback to update the DOM attributes */ + protected onChange: OnChangeCB; /** @internal */ - private _float: boolean; + protected _float: boolean; /** @internal */ - private _prevFloat: boolean; + protected _prevFloat: boolean; /** @internal cached layouts of difference column count so we can restore ack (eg 12 -> 1 -> 12) */ - private _layouts?: Layout[][]; // maps column # to array of values nodes + protected _layouts?: GridStackNode[][]; // maps column # to array of values nodes /** @internal true while we are resizing widgets during column resize to skip certain parts */ - private _inColumnResize: boolean; + protected _inColumnResize: boolean; /** @internal true if we have some items locked */ - private _hasLocked: boolean; + protected _hasLocked: boolean; /** @internal unique global internal _id counter NOT starting at 0 */ - private static _idSeq = 1; + protected static _idSeq = 1; public constructor(opts: GridStackEngineOptions = {}) { this.column = opts.column || 12; - this.onChange = opts.onChange; - this._float = opts.float; this.maxRow = opts.maxRow; + this._float = opts.float; this.nodes = opts.nodes || []; + this.onChange = opts.onChange; } public batchUpdate(): GridStackEngine { @@ -56,8 +59,7 @@ export class GridStackEngine { this.batchMode = true; this._prevFloat = this._float; this._float = true; // let things go anywhere for now... commit() will restore and possibly reposition - this.saveInitial(); // since begin update (which is called multiple times) won't do this - return this; + return this.saveInitial(); // since begin update (which is called multiple times) won't do this } public commit(): GridStackEngine { @@ -70,14 +72,14 @@ export class GridStackEngine { } // use entire row for hitting area (will use bottom reverse sorted first) if we not actively moving DOWN and didn't already skip - private _useEntireRowArea(node: GridStackNode, nn: GridStackPosition): boolean { + protected _useEntireRowArea(node: GridStackNode, nn: GridStackPosition): boolean { return !this.float && !this._hasLocked && (!node._moving || node._skipDown || nn.y <= node.y); } /** @internal fix collision on given 'node', going to given new location 'nn', with optional 'collide' node already found. * return true if we moved. */ - private _fixCollisions(node: GridStackNode, nn = node, collide?: GridStackNode, opt: GridStackMoveOpts = {}): boolean { - this._sortNodes(-1); // from last to first, so recursive collision move items in the right order + protected _fixCollisions(node: GridStackNode, nn = node, collide?: GridStackNode, opt: GridStackMoveOpts = {}): boolean { + this.sortNodes(-1); // from last to first, so recursive collision move items in the right order collide = collide || this.collide(node, nn); // REAL area collide for swap and skip if none... if (!collide) return false; @@ -240,7 +242,7 @@ export class GridStackEngine { public compact(): GridStackEngine { if (this.nodes.length === 0) return this; this.batchUpdate() - ._sortNodes(); + .sortNodes(); let copyNodes = this.nodes; this.nodes = []; // pretend we have no nodes to conflict layout to start with... copyNodes.forEach(node => { @@ -265,16 +267,16 @@ export class GridStackEngine { /** float getter method */ public get float(): boolean { return this._float || false; } - /** @internal */ - private _sortNodes(dir?: -1 | 1): GridStackEngine { + /** sort the nodes array from first to last, or reverse. Called during collision/placement to force an order */ + public sortNodes(dir?: -1 | 1): GridStackEngine { this.nodes = Utils.sort(this.nodes, dir, this.column); return this; } /** @internal called to top gravity pack the items back OR revert back to original Y positions when floating */ - private _packNodes(): GridStackEngine { + protected _packNodes(): GridStackEngine { if (this.batchMode) { return this; } - this._sortNodes(); // first to last + this.sortNodes(); // first to last if (this.float) { // restore original Y pos @@ -402,6 +404,7 @@ export class GridStackEngine { return node; } + /** returns a list of modified nodes from their original values */ public getDirtyNodes(verify?: boolean): GridStackNode[] { // compare original x,y,w,h instead as _dirty can be a temporary state if (verify) { @@ -410,12 +413,11 @@ export class GridStackEngine { return this.nodes.filter(n => n._dirty); } - /** @internal call this to call onChange CB with dirty nodes */ - private _notify(nodes?: GridStackNode | GridStackNode[], removeDOM = true): GridStackEngine { - if (this.batchMode) return this; - nodes = (nodes === undefined ? [] : (Array.isArray(nodes) ? nodes : [nodes]) ); - let dirtyNodes = nodes.concat(this.getDirtyNodes()); - this.onChange && this.onChange(dirtyNodes, removeDOM); + /** @internal call this to call onChange callback with dirty nodes so DOM can be updated */ + protected _notify(removedNodes?: GridStackNode[]): GridStackEngine { + if (this.batchMode || !this.onChange) return this; + let dirtyNodes = (removedNodes || []).concat(this.getDirtyNodes()); + this.onChange(dirtyNodes); return this; } @@ -463,7 +465,7 @@ export class GridStackEngine { delete node._removeDOM; if (node.autoPosition) { - this._sortNodes(); + this.sortNodes(); for (let i = 0;; ++i) { let x = i % this.column; @@ -501,7 +503,7 @@ export class GridStackEngine { // don't use 'faster' .splice(findIndex(),1) in case node isn't in our list, or in multiple times. this.nodes = this.nodes.filter(n => n !== node); return this._packNodes() - ._notify(node); + ._notify([node]); } public removeAll(removeDOM = true): GridStackEngine { @@ -676,7 +678,7 @@ export class GridStackEngine { let len = this._layouts?.length; let layout = len && this.column !== (len - 1) ? this._layouts[len - 1] : null; let list: GridStackNode[] = []; - this._sortNodes(); + this.sortNodes(); this.nodes.forEach(n => { let wl = layout?.find(l => l._id === n._id); let w: GridStackNode = {...n}; @@ -771,7 +773,7 @@ export class GridStackEngine { // see if we have cached previous layout IFF we are going up in size (restore) otherwise always // generate next size down from where we are (looks more natural as you gradually size down). - let cacheNodes: Layout[] = []; + let cacheNodes: GridStackNode[] = []; if (column > prevColumn) { cacheNodes = this._layouts[column] || []; // ...if not, start with the largest layout (if not already there) as down-scaling is more accurate @@ -842,7 +844,7 @@ export class GridStackEngine { * @param clear if true, will force other caches to be removed (default false) */ public cacheLayout(nodes: GridStackNode[], column: number, clear = false): GridStackEngine { - let copy: Layout[] = []; + let copy: GridStackNode[] = []; nodes.forEach((n, i) => { n._id = n._id || GridStackEngine._idSeq++; // make sure we have an id in case this is new layout, else re-use id already set copy[i] = {x: n.x, y: n.y, w: n.w, _id: n._id} // only thing we change is x,y,w and id to find it back @@ -859,7 +861,7 @@ export class GridStackEngine { */ public cacheOneLayout(n: GridStackNode, column: number): GridStackEngine { n._id = n._id || GridStackEngine._idSeq++; - let layout: Layout = {x: n.x, y: n.y, w: n.w, _id: n._id} + let layout: GridStackNode = {x: n.x, y: n.y, w: n.w, _id: n._id} this._layouts = this._layouts || []; this._layouts[column] = this._layouts[column] || []; let index = this._layouts[column].findIndex(l => l._id === n._id); @@ -876,11 +878,3 @@ export class GridStackEngine { return this; } } - -/** @internal class to store per column layout bare minimal info (subset of GridStackWidget) */ -interface Layout { - x: number; - y: number; - w: number; - _id: number; // so we can find full node back -} diff --git a/src/gridstack.ts b/src/gridstack.ts index 1dbcaf19b..6ed884db9 100644 --- a/src/gridstack.ts +++ b/src/gridstack.ts @@ -2,7 +2,7 @@ * GridStack 5.0.0-dev * https://gridstackjs.com/ * - * Copyright (c) 2021 Alain Dumesny + * Copyright (c) 2021-2022 Alain Dumesny * see root license https://github.com/gridstack/gridstack.js/tree/master/LICENSE */ import { GridStackEngine } from './gridstack-engine'; @@ -219,27 +219,27 @@ export class GridStack { return this._placeholder; } /** @internal */ - private _placeholder: HTMLElement; + protected _placeholder: HTMLElement; /** @internal */ - private _prevColumn: number; + protected _prevColumn: number; /** @internal */ - private _ignoreLayoutsNodeChange: boolean; + protected _ignoreLayoutsNodeChange: boolean; /** @internal */ public _gsEventHandler = {}; /** @internal */ - private _styles: GridCSSStyleSheet; + protected _styles: GridCSSStyleSheet; /** @internal flag to keep cells square during resize */ - private _isAutoCellHeight: boolean; + protected _isAutoCellHeight: boolean; /** @internal track event binding to window resize so we can remove */ - private _windowResizeBind: () => void; + protected _windowResizeBind: () => void; /** @internal limit auto cell resizing method */ - private _cellHeightThrottle: () => void; + protected _cellHeightThrottle: () => void; /** @internal true when loading items to insert first rather than append */ - private _insertNotAppend: boolean; + protected _insertNotAppend: boolean; /** @internal extra row added when dragging at the bottom of the grid */ - private _extraDragRow = 0; + protected _extraDragRow = 0; /** @internal true if nested grid should get column count from our width */ - private _autoColumn?: boolean; + protected _autoColumn?: boolean; /** * Construct a grid item from the given element and options @@ -262,6 +262,7 @@ export class GridStack { delete opts.column; } // 'minWidth' legacy support in 5.1 + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ let anyOpts = opts as any; if (anyOpts.minWidth !== undefined) { opts.oneColumnSize = opts.oneColumnSize || anyOpts.minWidth; @@ -295,7 +296,7 @@ export class GridStack { this.opts = Utils.defaults(opts, defaults); opts = null; // make sure we use this.opts instead - this.initMargin(); // part of settings defaults... + this._initMargin(); // part of settings defaults... // Now check if we're loading into 1 column mode FIRST so we don't do un-necessary work (like cellHeight = width / 12 then go 1 column) if (this.opts.column !== 1 && !this.opts.disableOneColumnMode && this._widthOrContainer() <= this.opts.oneColumnSize) { @@ -678,7 +679,7 @@ export class GridStack { return this._widthOrContainer() / this.getColumn(); } /** return our expected width (or parent) for 1 column check */ - private _widthOrContainer(): number { + protected _widthOrContainer(): number { // use `offsetWidth` or `clientWidth` (no scrollbar) ? // https://stackoverflow.com/questions/21064101/understanding-offsetwidth-clientwidth-scrollwidth-and-height-respectively return (this.el.clientWidth || this.el.parentElement.clientWidth || window.innerWidth); @@ -1099,7 +1100,7 @@ export class GridStack { // re-use existing margin handling this.opts.margin = value; this.opts.marginTop = this.opts.marginBottom = this.opts.marginLeft = this.opts.marginRight = undefined; - this.initMargin(); + this._initMargin(); this._updateStyles(true); // true = force re-create @@ -1134,7 +1135,7 @@ export class GridStack { } /** @internal */ - private _triggerChangeEvent(): GridStack { + protected _triggerChangeEvent(): GridStack { if (this.engine.batchMode) return this; let elements = this.engine.getDirtyNodes(true); // verify they really changed if (elements && elements.length) { @@ -1148,7 +1149,7 @@ export class GridStack { } /** @internal */ - private _triggerAddEvent(): GridStack { + protected _triggerAddEvent(): GridStack { if (this.engine.batchMode) return this; if (this.engine.addedNodes && this.engine.addedNodes.length > 0) { if (!this._ignoreLayoutsNodeChange) { @@ -1173,14 +1174,14 @@ export class GridStack { } /** @internal */ - private _triggerEvent(name: string, data?: GridStackNode[]): GridStack { + protected _triggerEvent(name: string, data?: GridStackNode[]): GridStack { let event = data ? new CustomEvent(name, {bubbles: false, detail: data}) : new Event(name); this.el.dispatchEvent(event); return this; } /** @internal called to delete the current dynamic style sheet used for our layout */ - private _removeStylesheet(): GridStack { + protected _removeStylesheet(): GridStack { if (this._styles) { Utils.removeStylesheet(this._styles._id); @@ -1190,7 +1191,7 @@ export class GridStack { } /** @internal updated/create the CSS styles for row based layout and initial margin setting */ - private _updateStyles(forceUpdate = false, maxH?: number): GridStack { + protected _updateStyles(forceUpdate = false, maxH?: number): GridStack { // call to delete existing one if we change cellHeight / margin if (forceUpdate) { this._removeStylesheet(); @@ -1254,7 +1255,7 @@ export class GridStack { } /** @internal */ - private _updateContainerHeight(): GridStack { + protected _updateContainerHeight(): GridStack { if (!this.engine || this.engine.batchMode) return this; let row = this.getRow() + this._extraDragRow; // checks for minRow already // check for css min height @@ -1280,7 +1281,7 @@ export class GridStack { } /** @internal */ - private _prepareElement(el: GridItemHTMLElement, triggerAddEvent = false, node?: GridStackNode): GridStack { + protected _prepareElement(el: GridItemHTMLElement, triggerAddEvent = false, node?: GridStackNode): GridStack { if (!node) { el.classList.add(this.opts.itemClass); node = this._readAttr(el); @@ -1299,7 +1300,7 @@ export class GridStack { } /** @internal call to write position x,y,w,h attributes back to element */ - private _writePosAttr(el: HTMLElement, n: GridStackPosition): GridStack { + protected _writePosAttr(el: HTMLElement, n: GridStackPosition): GridStack { if (n.x !== undefined && n.x !== null) { el.setAttribute('gs-x', String(n.x)); } if (n.y !== undefined && n.y !== null) { el.setAttribute('gs-y', String(n.y)); } if (n.w) { el.setAttribute('gs-w', String(n.w)); } @@ -1308,7 +1309,7 @@ export class GridStack { } /** @internal call to write any default attributes back to element */ - private _writeAttr(el: HTMLElement, node: GridStackWidget): GridStack { + protected _writeAttr(el: HTMLElement, node: GridStackWidget): GridStack { if (!node) return this; this._writePosAttr(el, node); @@ -1335,7 +1336,7 @@ export class GridStack { } /** @internal call to read any default attributes from element */ - private _readAttr(el: HTMLElement): GridStackWidget { + protected _readAttr(el: HTMLElement): GridStackWidget { let node: GridStackNode = {}; node.x = Utils.toNumber(el.getAttribute('gs-x')); node.y = Utils.toNumber(el.getAttribute('gs-y')); @@ -1364,7 +1365,7 @@ export class GridStack { } /** @internal */ - private _setStaticClass(): GridStack { + protected _setStaticClass(): GridStack { let classes = ['grid-stack-static']; if (this.opts.staticGrid) { @@ -1425,7 +1426,7 @@ export class GridStack { } /** add or remove the window size event handler */ - private _updateWindowResizeEvent(forceRemove = false): GridStack { + protected _updateWindowResizeEvent(forceRemove = false): GridStack { // only add event if we're not nested (parent will call us) and we're auto sizing cells or supporting oneColumn (i.e. doing work) const workTodo = (this._isAutoCellHeight || !this.opts.disableOneColumnMode) && !this.opts._isNested; @@ -1450,7 +1451,7 @@ export class GridStack { public static getGridElements(els: string): GridHTMLElement[] { return Utils.getElements(els) } /** @internal initialize margin top/bottom/left/right and units */ - private initMargin(): GridStack { + protected _initMargin(): GridStack { let data: HeightData; let margin = 0; diff --git a/src/h5/dd-base-impl.ts b/src/h5/dd-base-impl.ts index 3105f6049..deff4ab48 100644 --- a/src/h5/dd-base-impl.ts +++ b/src/h5/dd-base-impl.ts @@ -1,6 +1,6 @@ /** * dd-base-impl.ts 5.0.0-dev - * Copyright (c) 2021 Alain Dumesny - see GridStack root license + * Copyright (c) 2021-2022 Alain Dumesny - see GridStack root license */ export type EventCallback = (event: Event) => boolean|void; @@ -9,9 +9,9 @@ export abstract class DDBaseImplement { public get disabled(): boolean { return this._disabled; } /** @internal */ - private _disabled = false; + protected _disabled = false; /** @internal */ - private _eventRegister: { + protected _eventRegister: { [eventName: string]: EventCallback; } = {}; diff --git a/src/h5/dd-draggable.ts b/src/h5/dd-draggable.ts index 3cd7a9a65..a8d0605e1 100644 --- a/src/h5/dd-draggable.ts +++ b/src/h5/dd-draggable.ts @@ -1,6 +1,6 @@ /** * dd-draggable.ts 5.0.0-dev - * Copyright (c) 2021 Alain Dumesny - see GridStack root license + * Copyright (c) 2021-2022 Alain Dumesny - see GridStack root license */ import { DDManager } from './dd-manager'; @@ -36,25 +36,25 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt public helper: HTMLElement; // used by GridStackDDNative /** @internal */ - private dragOffset: DragOffset; + protected dragOffset: DragOffset; /** @internal */ - private dragElementOriginStyle: Array; + protected dragElementOriginStyle: Array; /** @internal */ - private dragFollowTimer: number; + protected dragFollowTimer: number; /** @internal */ - private dragEl: HTMLElement; + protected dragEl: HTMLElement; /** @internal */ - private dragging = false; + protected dragging = false; /** @internal */ - private paintTimer: number; + protected paintTimer: number; /** @internal */ - private parentOriginStylePosition: string; + protected parentOriginStylePosition: string; /** @internal */ - private helperContainment: HTMLElement; + protected helperContainment: HTMLElement; /** @internal #1541 can't have {passive: true} on Safari as otherwise it reverts animate back to old location on drop */ - private static dragEventListenerOption = true; // DDUtils.isEventSupportPassiveOption ? { capture: true, passive: true } : true; + protected static dragEventListenerOption = true; // DDUtils.isEventSupportPassiveOption ? { capture: true, passive: true } : true; /** @internal */ - private static originStyleProp = ['transition', 'pointerEvents', 'position', + protected static originStyleProp = ['transition', 'pointerEvents', 'position', 'left', 'top', 'opacity', 'zIndex', 'width', 'height', 'willChange', 'min-width']; constructor(el: HTMLElement, option: DDDraggableOpt = {}) { @@ -115,7 +115,7 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _dragStart(event: DragEvent): void { + protected _dragStart(event: DragEvent): void { DDManager.dragElement = this; this.helper = this._createHelper(event); this._setupHelperContainmentStyle(); @@ -135,7 +135,7 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _setupDragFollowNodeNotifyStart(ev: Event): DDDraggable { + protected _setupDragFollowNodeNotifyStart(ev: Event): DDDraggable { this._setupHelperStyle(); document.addEventListener('dragover', this._drag, DDDraggable.dragEventListenerOption); this.dragEl.addEventListener('dragend', this._dragEnd); @@ -149,7 +149,7 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _drag(event: DragEvent): void { + protected _drag(event: DragEvent): void { // Safari: prevent default to allow drop to happen instead of reverting back (with animation) and delaying dragend #1541 // https://stackoverflow.com/questions/61760755/how-to-fire-dragend-event-immediately event.preventDefault(); @@ -162,7 +162,7 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _dragEnd(event: DragEvent): void { + protected _dragEnd(event: DragEvent): void { if (this.dragFollowTimer) { clearTimeout(this.dragFollowTimer); delete this.dragFollowTimer; @@ -192,7 +192,7 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal create a clone copy (or user defined method) of the original drag item if set */ - private _createHelper(event: DragEvent): HTMLElement { + protected _createHelper(event: DragEvent): HTMLElement { let helper = this.el; if (typeof this.option.helper === 'function') { helper = this.option.helper(event); @@ -209,7 +209,7 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _setupHelperStyle(): DDDraggable { + protected _setupHelperStyle(): DDDraggable { // TODO: set all at once with style.cssText += ... ? https://stackoverflow.com/questions/3968593 const rec = this.helper.getBoundingClientRect(); const style = this.helper.style; @@ -231,7 +231,7 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _removeHelperStyle(): DDDraggable { + protected _removeHelperStyle(): DDDraggable { // don't bother restoring styles if we're gonna remove anyway... let node = this.helper ? (this.helper as GridItemHTMLElement).gridstackNode : undefined; if (this.dragElementOriginStyle && (!node || !node._isAboutToRemove)) { @@ -251,7 +251,7 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _dragFollow(event: DragEvent): void { + protected _dragFollow(event: DragEvent): void { if (this.paintTimer) { cancelAnimationFrame(this.paintTimer); } @@ -269,7 +269,7 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _setupHelperContainmentStyle(): DDDraggable { + protected _setupHelperContainmentStyle(): DDDraggable { this.helperContainment = this.helper.parentElement; if (this.helper.style.position !== 'fixed') { this.parentOriginStylePosition = this.helperContainment.style.position; @@ -285,7 +285,7 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt * TODO: maybe use mouse event instead of HTML5 drag as we have to work around it anyway, or change code to not update * the actual grid-item but move the ghost image around (and special case jq version) ? **/ - private _cancelDragGhost(e: DragEvent): DDDraggable { + protected _cancelDragGhost(e: DragEvent): DDDraggable { /* doesn't seem to do anything... let t = e.dataTransfer; t.effectAllowed = 'none'; @@ -307,7 +307,7 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _getDragOffset(event: DragEvent, el: HTMLElement, parent: HTMLElement): DragOffset { + protected _getDragOffset(event: DragEvent, el: HTMLElement, parent: HTMLElement): DragOffset { // in case ancestor has transform/perspective css properties that change the viewpoint let xformOffsetX = 0; diff --git a/src/h5/dd-droppable.ts b/src/h5/dd-droppable.ts index 5846edd5f..2ac68fe3c 100644 --- a/src/h5/dd-droppable.ts +++ b/src/h5/dd-droppable.ts @@ -1,6 +1,6 @@ /** * dd-droppable.ts 5.0.0-dev - * Copyright (c) 2021 Alain Dumesny - see GridStack root license + * Copyright (c) 2021-2022 Alain Dumesny - see GridStack root license */ import { DDDraggable } from './dd-draggable'; @@ -26,8 +26,8 @@ export class DDDroppable extends DDBaseImplement implements HTMLElementExtendOpt public option: DDDroppableOpt; /** @internal */ - private moving: boolean; - private static lastActive: DDDroppable; + protected moving: boolean; + protected static lastActive: DDDroppable; constructor(el: HTMLElement, opts: DDDroppableOpt = {}) { super(); @@ -81,7 +81,7 @@ export class DDDroppable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal called when the cursor enters our area - prepare for a possible drop and track leaving */ - private _dragEnter(event: DragEvent): void { + protected _dragEnter(event: DragEvent): void { // TEST console.log(`${count++} Enter ${(this.el as GridHTMLElement).gridstack.opts.id}`); if (!this._canDrop()) return; event.preventDefault(); @@ -110,13 +110,13 @@ export class DDDroppable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal called when an moving to drop item is being dragged over - do nothing but eat the event */ - private _dragOver(event: DragEvent): void { + protected _dragOver(event: DragEvent): void { event.preventDefault(); event.stopPropagation(); } /** @internal called when the item is leaving our area, stop tracking if we had moving item */ - private _dragLeave(event: DragEvent, forceLeave?: boolean): void { + protected _dragLeave(event: DragEvent, forceLeave?: boolean): void { // TEST console.log(`${count++} Leave ${(this.el as GridHTMLElement).gridstack.opts.id}`); event.preventDefault(); event.stopPropagation(); @@ -149,7 +149,7 @@ export class DDDroppable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal item is being dropped on us - call the client drop event */ - private _drop(event: DragEvent): void { + protected _drop(event: DragEvent): void { if (!this.moving) return; // should not have received event... event.preventDefault(); const ev = DDUtils.initEvent(event, { target: this.el, type: 'drop' }); @@ -161,7 +161,7 @@ export class DDDroppable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal called to remove callbacks when leaving or dropping */ - private _removeLeaveCallbacks() { + protected _removeLeaveCallbacks() { if (!this.moving) { return; } delete this.moving; this.el.removeEventListener('dragover', this._dragOver); @@ -172,12 +172,12 @@ export class DDDroppable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _canDrop(): boolean { + protected _canDrop(): boolean { return DDManager.dragElement && (!this.accept || this.accept(DDManager.dragElement.el)); } /** @internal */ - private _setupAccept(): DDDroppable { + protected _setupAccept(): DDDroppable { if (this.option.accept && typeof this.option.accept === 'string') { this.accept = (el: HTMLElement) => { return el.matches(this.option.accept as string) @@ -189,7 +189,7 @@ export class DDDroppable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _ui(drag: DDDraggable) { + protected _ui(drag: DDDraggable) { return { draggable: drag.el, ...drag.ui() diff --git a/src/h5/dd-resizable-handle.ts b/src/h5/dd-resizable-handle.ts index cd9e5322c..39aeb439a 100644 --- a/src/h5/dd-resizable-handle.ts +++ b/src/h5/dd-resizable-handle.ts @@ -1,6 +1,6 @@ /** * dd-resizable-handle.ts 5.0.0-dev - * Copyright (c) 2021 Alain Dumesny - see GridStack root license + * Copyright (c) 2021-2022 Alain Dumesny - see GridStack root license */ export interface DDResizableHandleOpt { @@ -11,19 +11,19 @@ export interface DDResizableHandleOpt { export class DDResizableHandle { /** @internal */ - private el: HTMLElement; + protected el: HTMLElement; /** @internal */ - private host: HTMLElement; + protected host: HTMLElement; /** @internal */ - private option: DDResizableHandleOpt; + protected option: DDResizableHandleOpt; /** @internal */ - private dir: string; + protected dir: string; /** @internal true after we've moved enough pixels to start a resize */ - private moving = false; + protected moving = false; /** @internal */ - private mouseDownEvent: MouseEvent; + protected mouseDownEvent: MouseEvent; /** @internal */ - private static prefix = 'ui-resizable-'; + protected static prefix = 'ui-resizable-'; constructor(host: HTMLElement, direction: string, option: DDResizableHandleOpt) { this.host = host; @@ -38,7 +38,7 @@ export class DDResizableHandle { } /** @internal */ - private _init(): DDResizableHandle { + protected _init(): DDResizableHandle { const el = document.createElement('div'); el.classList.add('ui-resizable-handle'); el.classList.add(`${DDResizableHandle.prefix}${this.dir}`); @@ -61,7 +61,7 @@ export class DDResizableHandle { } /** @internal called on mouse down on us: capture move on the entire document (mouse might not stay on us) until we release the mouse */ - private _mouseDown(e: MouseEvent): void { + protected _mouseDown(e: MouseEvent): void { e.preventDefault(); this.mouseDownEvent = e; document.addEventListener('mousemove', this._mouseMove, true); // capture, not bubble @@ -69,7 +69,7 @@ export class DDResizableHandle { } /** @internal */ - private _mouseMove(e: MouseEvent): void { + protected _mouseMove(e: MouseEvent): void { let s = this.mouseDownEvent; // don't start unless we've moved at least 3 pixels if (!this.moving && Math.abs(e.x - s.x) + Math.abs(e.y - s.y) > 2) { @@ -81,7 +81,7 @@ export class DDResizableHandle { } /** @internal */ - private _mouseUp(e: MouseEvent): void { + protected _mouseUp(e: MouseEvent): void { if (this.moving) { this._triggerEvent('stop', e); } @@ -92,7 +92,7 @@ export class DDResizableHandle { } /** @internal */ - private _triggerEvent(name: string, event: MouseEvent): DDResizableHandle { + protected _triggerEvent(name: string, event: MouseEvent): DDResizableHandle { if (this.option[name]) this.option[name](event); return this; } diff --git a/src/h5/dd-resizable.ts b/src/h5/dd-resizable.ts index 226242237..a5def720a 100644 --- a/src/h5/dd-resizable.ts +++ b/src/h5/dd-resizable.ts @@ -1,6 +1,6 @@ /** * dd-resizable.ts 5.0.0-dev - * Copyright (c) 2021 Alain Dumesny - see GridStack root license + * Copyright (c) 2021-2022 Alain Dumesny - see GridStack root license */ import { DDResizableHandle } from './dd-resizable-handle'; @@ -29,25 +29,25 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt public option: DDResizableOpt; /** @internal */ - private handlers: DDResizableHandle[]; + protected handlers: DDResizableHandle[]; /** @internal */ - private originalRect: Rect; + protected originalRect: Rect; /** @internal */ - private temporalRect: Rect; + protected temporalRect: Rect; /** @internal */ - private scrollY: number; + protected scrollY: number; /** @internal */ - private scrolled: number; + protected scrolled: number; /** @internal */ - private scrollEl: HTMLElement; + protected scrollEl: HTMLElement; /** @internal */ - private startEvent: MouseEvent; + protected startEvent: MouseEvent; /** @internal value saved in the same order as _originStyleProp[] */ - private elOriginStyleVal: string[]; + protected elOriginStyleVal: string[]; /** @internal */ - private parentOriginStylePosition: string; + protected parentOriginStylePosition: string; /** @internal */ - private static _originStyleProp = ['width', 'height', 'position', 'left', 'top', 'opacity', 'zIndex']; + protected static _originStyleProp = ['width', 'height', 'position', 'left', 'top', 'opacity', 'zIndex']; constructor(el: HTMLElement, opts: DDResizableOpt = {}) { super(); @@ -104,7 +104,7 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _setupAutoHide(): DDResizable { + protected _setupAutoHide(): DDResizable { if (this.option.autoHide) { this.el.classList.add('ui-resizable-autohide'); // use mouseover/mouseout instead of mouseenter/mouseleave to get better performance; @@ -119,17 +119,17 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _showHandlers = () => { + protected _showHandlers = () => { this.el.classList.remove('ui-resizable-autohide'); } /** @internal */ - private _hideHandlers = () => { + protected _hideHandlers = () => { this.el.classList.add('ui-resizable-autohide'); } /** @internal */ - private _setupHandlers(): DDResizable { + protected _setupHandlers(): DDResizable { let handlerDirection = this.option.handles || 'e,s,se'; if (handlerDirection === 'all') { handlerDirection = 'n,e,s,w,se,sw,ne,nw'; @@ -151,7 +151,7 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _resizeStart(event: MouseEvent): DDResizable { + protected _resizeStart(event: MouseEvent): DDResizable { this.originalRect = this.el.getBoundingClientRect(); this.scrollEl = Utils.getScrollElement(this.el); this.scrollY = this.scrollEl.scrollTop; @@ -169,7 +169,7 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _resizing(event: MouseEvent, dir: string): DDResizable { + protected _resizing(event: MouseEvent, dir: string): DDResizable { this.scrolled = this.scrollEl.scrollTop - this.scrollY; this.temporalRect = this._getChange(event, dir); this._applyChange(); @@ -182,7 +182,7 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _resizeStop(event: MouseEvent): DDResizable { + protected _resizeStop(event: MouseEvent): DDResizable { const ev = DDUtils.initEvent(event, { type: 'resizestop', target: this.el }); if (this.option.stop) { this.option.stop(ev); // Note: ui() not used by gridstack so don't pass @@ -199,7 +199,7 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _setupHelper(): DDResizable { + protected _setupHelper(): DDResizable { this.elOriginStyleVal = DDResizable._originStyleProp.map(prop => this.el.style[prop]); this.parentOriginStylePosition = this.el.parentElement.style.position; if (window.getComputedStyle(this.el.parentElement).position.match(/static/)) { @@ -211,7 +211,7 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _cleanHelper(): DDResizable { + protected _cleanHelper(): DDResizable { DDResizable._originStyleProp.forEach((prop, i) => { this.el.style[prop] = this.elOriginStyleVal[i] || null; }); @@ -220,7 +220,7 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _getChange(event: MouseEvent, dir: string): Rect { + protected _getChange(event: MouseEvent, dir: string): Rect { const oEvent = this.startEvent; const newRect = { // Note: originalRect is a complex object, not a simple Rect, so copy out. width: this.originalRect.width, @@ -261,7 +261,7 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal constrain the size to the set min/max values */ - private _constrainSize(oWidth: number, oHeight: number): Size { + protected _constrainSize(oWidth: number, oHeight: number): Size { const maxWidth = this.option.maxWidth || Number.MAX_SAFE_INTEGER; const minWidth = this.option.minWidth || oWidth; const maxHeight = this.option.maxHeight || Number.MAX_SAFE_INTEGER; @@ -272,7 +272,7 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _applyChange(): DDResizable { + protected _applyChange(): DDResizable { let containmentRect = { left: 0, top: 0, width: 0, height: 0 }; if (this.el.style.position === 'absolute') { const containmentEl = this.el.parentElement; @@ -288,14 +288,14 @@ export class DDResizable extends DDBaseImplement implements HTMLElementExtendOpt } /** @internal */ - private _removeHandlers(): DDResizable { + protected _removeHandlers(): DDResizable { this.handlers.forEach(handle => handle.destroy()); delete this.handlers; return this; } /** @internal */ - private _ui = (): DDUIData => { + protected _ui = (): DDUIData => { const containmentEl = this.el.parentElement; const containmentRect = containmentEl.getBoundingClientRect(); const newRect = { // Note: originalRect is a complex object, not a simple Rect, so copy out. diff --git a/src/h5/gridstack-dd-native.ts b/src/h5/gridstack-dd-native.ts index 4441c5429..072c90387 100644 --- a/src/h5/gridstack-dd-native.ts +++ b/src/h5/gridstack-dd-native.ts @@ -1,6 +1,6 @@ /** * gridstack-dd-native.ts 5.0.0-dev - * Copyright (c) 2021 Alain Dumesny - see GridStack root license + * Copyright (c) 2021-2022 Alain Dumesny - see GridStack root license */ import { DDManager } from './dd-manager'; @@ -129,7 +129,7 @@ export class GridStackDDNative extends GridStackDD { } /** @internal returns a list of DD elements, creating them on the fly by default */ - private _getDDElements(els: GridStackElement, create = true): DDElement[] { + protected _getDDElements(els: GridStackElement, create = true): DDElement[] { let hosts = Utils.getElements(els) as DDElementHost[]; if (!hosts.length) return []; let list = hosts.map(e => e.ddElement || (create ? DDElement.init(e) : null));