Skip to content

Commit d6a3d3e

Browse files
committed
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...
1 parent c14aaa2 commit d6a3d3e

File tree

9 files changed

+152
-174
lines changed

9 files changed

+152
-174
lines changed

spec/gridstack-engine-spec.ts

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ describe('gridstack engine', function() {
2525
expect(engine.float).toEqual(false);
2626
expect(engine.maxRow).toEqual(undefined);
2727
expect(engine.nodes).toEqual([]);
28-
expect(engine.onChange).toEqual(undefined);
2928
expect(engine.batchMode).toEqual(undefined);
29+
expect((engine as any).onChange).toEqual(undefined);
3030
});
3131

3232
it('should set params correctly.', function() {
@@ -37,8 +37,8 @@ describe('gridstack engine', function() {
3737
expect(engine.float).toBe(true);
3838
expect(engine.maxRow).toEqual(2);
3939
expect(engine.nodes).toEqual(arr);
40-
expect(engine.onChange).toEqual(fkt);
4140
expect(engine.batchMode).toEqual(undefined);
41+
expect((engine as any).onChange).toEqual(fkt);
4242
});
4343
});
4444

@@ -80,42 +80,42 @@ describe('gridstack engine', function() {
8080
it('should sort ascending with 12 columns.', function() {
8181
w.column = 12;
8282
w.nodes = [{x: 7, y: 0}, {x: 4, y: 4}, {x: 9, y: 0}, {x: 0, y: 1}];
83-
e.prototype._sortNodes.call(w, 1);
83+
engine.sortNodes.call(w, 1);
8484
expect(w.nodes).toEqual([{x: 7, y: 0}, {x: 9, y: 0}, {x: 0, y: 1}, {x: 4, y: 4}]);
8585
});
8686

8787
it('should sort descending with 12 columns.', function() {
8888
w.column = 12;
8989
w.nodes = [{x: 7, y: 0}, {x: 4, y: 4}, {x: 9, y: 0}, {x: 0, y: 1}];
90-
e.prototype._sortNodes.call(w, -1);
90+
engine.sortNodes.call(w, -1);
9191
expect(w.nodes).toEqual([{x: 4, y: 4}, {x: 0, y: 1}, {x: 9, y: 0}, {x: 7, y: 0}]);
9292
});
9393

9494
it('should sort ascending with 1 columns.', function() {
9595
w.column = 1;
9696
w.nodes = [{x: 7, y: 0}, {x: 4, y: 4}, {x: 9, y: 0}, {x: 0, y: 1}];
97-
e.prototype._sortNodes.call(w, 1);
97+
engine.sortNodes.call(w, 1);
9898
expect(w.nodes).toEqual([{x: 0, y: 1}, {x: 7, y: 0}, {x: 4, y: 4}, {x: 9, y: 0}]);
9999
});
100100

101101
it('should sort descending with 1 columns.', function() {
102102
w.column = 1;
103103
w.nodes = [{x: 7, y: 0}, {x: 4, y: 4}, {x: 9, y: 0}, {x: 0, y: 1}];
104-
e.prototype._sortNodes.call(w, -1);
104+
engine.sortNodes.call(w, -1);
105105
expect(w.nodes).toEqual([{x: 9, y: 0}, {x: 4, y: 4}, {x: 7, y: 0}, {x: 0, y: 1}]);
106106
});
107107

108108
it('should sort ascending without columns.', function() {
109109
w.column = undefined;
110110
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}];
111-
e.prototype._sortNodes.call(w, 1);
111+
engine.sortNodes.call(w, 1);
112112
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}]);
113113
});
114114

115115
it('should sort descending without columns.', function() {
116116
w.column = undefined;
117117
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}];
118-
e.prototype._sortNodes.call(w, -1);
118+
engine.sortNodes.call(w, -1);
119119
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}]);
120120
});
121121

@@ -244,30 +244,13 @@ describe('gridstack engine', function() {
244244

245245
it('should by called with dirty nodes', function() {
246246
(engine as any)._notify();
247-
expect(spy.callback).toHaveBeenCalledWith([
248-
engine.nodes[0],
249-
engine.nodes[1]
250-
], true);
247+
expect(spy.callback).toHaveBeenCalledWith([engine.nodes[0], engine.nodes[1]]);
251248
});
252249

253250
it('should by called with extra passed node to be removed', function() {
254251
let n1 = {id: -1};
255-
(engine as any)._notify(n1);
256-
expect(spy.callback).toHaveBeenCalledWith([
257-
n1,
258-
engine.nodes[0],
259-
engine.nodes[1]
260-
], true);
261-
});
262-
263-
it('should by called with extra passed node to be removed and should maintain false parameter', function() {
264-
let n1 = {id: -1};
265-
(engine as any)._notify(n1, false);
266-
expect(spy.callback).toHaveBeenCalledWith([
267-
n1,
268-
engine.nodes[0],
269-
engine.nodes[1]
270-
], false);
252+
(engine as any)._notify([n1]);
253+
expect(spy.callback).toHaveBeenCalledWith([n1, engine.nodes[0], engine.nodes[1]]);
271254
});
272255
});
273256

src/gridstack-engine.ts

Lines changed: 37 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
/**
22
* gridstack-engine.ts 5.0.0-dev
3-
* Copyright (c) 2021 Alain Dumesny - see GridStack root license
3+
* Copyright (c) 2021-2022 Alain Dumesny - see GridStack root license
44
*/
55

66
import { Utils } from './utils';
77
import { GridStackNode, ColumnOptions, GridStackPosition, GridStackMoveOpts } from './types';
88

9-
export type onChangeCB = (nodes: GridStackNode[], removeDOM?: boolean) => void;
10-
/** options used for creations - similar to GridStackOptions */
9+
/** callback to update the DOM attributes since this class is generic (no HTML or other info) for items that changed - see _notify() */
10+
type OnChangeCB = (nodes: GridStackNode[]) => void;
11+
12+
/** options used during creation - similar to GridStackOptions */
1113
export interface GridStackEngineOptions {
1214
column?: number;
1315
maxRow?: number;
1416
float?: boolean;
1517
nodes?: GridStackNode[];
16-
onChange?: onChangeCB;
18+
onChange?: OnChangeCB;
1719
}
1820

1921
/**
@@ -26,38 +28,38 @@ export class GridStackEngine {
2628
public column: number;
2729
public maxRow: number;
2830
public nodes: GridStackNode[];
29-
public onChange: onChangeCB;
3031
public addedNodes: GridStackNode[] = [];
3132
public removedNodes: GridStackNode[] = [];
3233
public batchMode: boolean;
34+
/** @internal callback to update the DOM attributes */
35+
protected onChange: OnChangeCB;
3336
/** @internal */
34-
private _float: boolean;
37+
protected _float: boolean;
3538
/** @internal */
36-
private _prevFloat: boolean;
39+
protected _prevFloat: boolean;
3740
/** @internal cached layouts of difference column count so we can restore ack (eg 12 -> 1 -> 12) */
38-
private _layouts?: Layout[][]; // maps column # to array of values nodes
41+
protected _layouts?: GridStackNode[][]; // maps column # to array of values nodes
3942
/** @internal true while we are resizing widgets during column resize to skip certain parts */
40-
private _inColumnResize: boolean;
43+
protected _inColumnResize: boolean;
4144
/** @internal true if we have some items locked */
42-
private _hasLocked: boolean;
45+
protected _hasLocked: boolean;
4346
/** @internal unique global internal _id counter NOT starting at 0 */
44-
private static _idSeq = 1;
47+
protected static _idSeq = 1;
4548

4649
public constructor(opts: GridStackEngineOptions = {}) {
4750
this.column = opts.column || 12;
48-
this.onChange = opts.onChange;
49-
this._float = opts.float;
5051
this.maxRow = opts.maxRow;
52+
this._float = opts.float;
5153
this.nodes = opts.nodes || [];
54+
this.onChange = opts.onChange;
5255
}
5356

5457
public batchUpdate(): GridStackEngine {
5558
if (this.batchMode) return this;
5659
this.batchMode = true;
5760
this._prevFloat = this._float;
5861
this._float = true; // let things go anywhere for now... commit() will restore and possibly reposition
59-
this.saveInitial(); // since begin update (which is called multiple times) won't do this
60-
return this;
62+
return this.saveInitial(); // since begin update (which is called multiple times) won't do this
6163
}
6264

6365
public commit(): GridStackEngine {
@@ -70,14 +72,14 @@ export class GridStackEngine {
7072
}
7173

7274
// use entire row for hitting area (will use bottom reverse sorted first) if we not actively moving DOWN and didn't already skip
73-
private _useEntireRowArea(node: GridStackNode, nn: GridStackPosition): boolean {
75+
protected _useEntireRowArea(node: GridStackNode, nn: GridStackPosition): boolean {
7476
return !this.float && !this._hasLocked && (!node._moving || node._skipDown || nn.y <= node.y);
7577
}
7678

7779
/** @internal fix collision on given 'node', going to given new location 'nn', with optional 'collide' node already found.
7880
* return true if we moved. */
79-
private _fixCollisions(node: GridStackNode, nn = node, collide?: GridStackNode, opt: GridStackMoveOpts = {}): boolean {
80-
this._sortNodes(-1); // from last to first, so recursive collision move items in the right order
81+
protected _fixCollisions(node: GridStackNode, nn = node, collide?: GridStackNode, opt: GridStackMoveOpts = {}): boolean {
82+
this.sortNodes(-1); // from last to first, so recursive collision move items in the right order
8183

8284
collide = collide || this.collide(node, nn); // REAL area collide for swap and skip if none...
8385
if (!collide) return false;
@@ -240,7 +242,7 @@ export class GridStackEngine {
240242
public compact(): GridStackEngine {
241243
if (this.nodes.length === 0) return this;
242244
this.batchUpdate()
243-
._sortNodes();
245+
.sortNodes();
244246
let copyNodes = this.nodes;
245247
this.nodes = []; // pretend we have no nodes to conflict layout to start with...
246248
copyNodes.forEach(node => {
@@ -265,16 +267,16 @@ export class GridStackEngine {
265267
/** float getter method */
266268
public get float(): boolean { return this._float || false; }
267269

268-
/** @internal */
269-
private _sortNodes(dir?: -1 | 1): GridStackEngine {
270+
/** sort the nodes array from first to last, or reverse. Called during collision/placement to force an order */
271+
public sortNodes(dir?: -1 | 1): GridStackEngine {
270272
this.nodes = Utils.sort(this.nodes, dir, this.column);
271273
return this;
272274
}
273275

274276
/** @internal called to top gravity pack the items back OR revert back to original Y positions when floating */
275-
private _packNodes(): GridStackEngine {
277+
protected _packNodes(): GridStackEngine {
276278
if (this.batchMode) { return this; }
277-
this._sortNodes(); // first to last
279+
this.sortNodes(); // first to last
278280

279281
if (this.float) {
280282
// restore original Y pos
@@ -402,6 +404,7 @@ export class GridStackEngine {
402404
return node;
403405
}
404406

407+
/** returns a list of modified nodes from their original values */
405408
public getDirtyNodes(verify?: boolean): GridStackNode[] {
406409
// compare original x,y,w,h instead as _dirty can be a temporary state
407410
if (verify) {
@@ -410,12 +413,11 @@ export class GridStackEngine {
410413
return this.nodes.filter(n => n._dirty);
411414
}
412415

413-
/** @internal call this to call onChange CB with dirty nodes */
414-
private _notify(nodes?: GridStackNode | GridStackNode[], removeDOM = true): GridStackEngine {
415-
if (this.batchMode) return this;
416-
nodes = (nodes === undefined ? [] : (Array.isArray(nodes) ? nodes : [nodes]) );
417-
let dirtyNodes = nodes.concat(this.getDirtyNodes());
418-
this.onChange && this.onChange(dirtyNodes, removeDOM);
416+
/** @internal call this to call onChange callback with dirty nodes so DOM can be updated */
417+
protected _notify(removedNodes?: GridStackNode[]): GridStackEngine {
418+
if (this.batchMode || !this.onChange) return this;
419+
let dirtyNodes = (removedNodes || []).concat(this.getDirtyNodes());
420+
this.onChange(dirtyNodes);
419421
return this;
420422
}
421423

@@ -463,7 +465,7 @@ export class GridStackEngine {
463465
delete node._removeDOM;
464466

465467
if (node.autoPosition) {
466-
this._sortNodes();
468+
this.sortNodes();
467469

468470
for (let i = 0;; ++i) {
469471
let x = i % this.column;
@@ -501,7 +503,7 @@ export class GridStackEngine {
501503
// don't use 'faster' .splice(findIndex(),1) in case node isn't in our list, or in multiple times.
502504
this.nodes = this.nodes.filter(n => n !== node);
503505
return this._packNodes()
504-
._notify(node);
506+
._notify([node]);
505507
}
506508

507509
public removeAll(removeDOM = true): GridStackEngine {
@@ -676,7 +678,7 @@ export class GridStackEngine {
676678
let len = this._layouts?.length;
677679
let layout = len && this.column !== (len - 1) ? this._layouts[len - 1] : null;
678680
let list: GridStackNode[] = [];
679-
this._sortNodes();
681+
this.sortNodes();
680682
this.nodes.forEach(n => {
681683
let wl = layout?.find(l => l._id === n._id);
682684
let w: GridStackNode = {...n};
@@ -771,7 +773,7 @@ export class GridStackEngine {
771773

772774
// see if we have cached previous layout IFF we are going up in size (restore) otherwise always
773775
// generate next size down from where we are (looks more natural as you gradually size down).
774-
let cacheNodes: Layout[] = [];
776+
let cacheNodes: GridStackNode[] = [];
775777
if (column > prevColumn) {
776778
cacheNodes = this._layouts[column] || [];
777779
// ...if not, start with the largest layout (if not already there) as down-scaling is more accurate
@@ -842,7 +844,7 @@ export class GridStackEngine {
842844
* @param clear if true, will force other caches to be removed (default false)
843845
*/
844846
public cacheLayout(nodes: GridStackNode[], column: number, clear = false): GridStackEngine {
845-
let copy: Layout[] = [];
847+
let copy: GridStackNode[] = [];
846848
nodes.forEach((n, i) => {
847849
n._id = n._id || GridStackEngine._idSeq++; // make sure we have an id in case this is new layout, else re-use id already set
848850
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 {
859861
*/
860862
public cacheOneLayout(n: GridStackNode, column: number): GridStackEngine {
861863
n._id = n._id || GridStackEngine._idSeq++;
862-
let layout: Layout = {x: n.x, y: n.y, w: n.w, _id: n._id}
864+
let layout: GridStackNode = {x: n.x, y: n.y, w: n.w, _id: n._id}
863865
this._layouts = this._layouts || [];
864866
this._layouts[column] = this._layouts[column] || [];
865867
let index = this._layouts[column].findIndex(l => l._id === n._id);
@@ -876,11 +878,3 @@ export class GridStackEngine {
876878
return this;
877879
}
878880
}
879-
880-
/** @internal class to store per column layout bare minimal info (subset of GridStackWidget) */
881-
interface Layout {
882-
x: number;
883-
y: number;
884-
w: number;
885-
_id: number; // so we can find full node back
886-
}

0 commit comments

Comments
 (0)