Skip to content

Commit 9ca815c

Browse files
committed
1 column mode loading, saving 12 column layout
fix #1985 fix #1975 (oneColumnModeDomSort case) * we now handle DOM and addWidget() when temporally into 1 column mode better to save the full 12 column mode * also DOM reading will reverse-sort entries to lay them in 1 column mode correctly (like if you had started with 12 and scaled down)
1 parent 43625f5 commit 9ca815c

File tree

6 files changed

+86
-23
lines changed

6 files changed

+86
-23
lines changed

doc/CHANGES.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Change log
55
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
66
**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)*
77

8-
- [7.0.2 (TBD)](#702-tbd)
8+
- [7.0.1-dev (TBD)](#701-dev-tbd)
99
- [7.0.1 (2022-10-14)](#701-2022-10-14)
1010
- [7.0.0 (2022-10-09)](#700-2022-10-09)
1111
- [6.0.3 (2022-10-08)](#603-2022-10-08)
@@ -75,9 +75,12 @@ Change log
7575

7676
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
7777

78-
## 7.0.2 (TBD)
78+
## 7.0.1-dev (TBD)
79+
* add `GridStackEngine.findEmptyPosition()`
7980
* fixed [#2081](https://github.com/gridstack/gridstack.js/issues/2081) removeWidget() after it's gone from DOM
80-
* add GridStackEngine.findEmptyPosition()
81+
* fixed [#1985](https://github.com/gridstack/gridstack.js/issues/1985) addWidget() or DOM read in single column mode will not adjust to multi column mode
82+
* fixed [#1975](https://github.com/gridstack/gridstack.js/issues/1975) oneColumnModeDomSort not respected when loading in 1 column
83+
8184
## 7.0.1 (2022-10-14)
8285
* fixed [#2073](https://github.com/gridstack/gridstack.js/issues/2073) SSR (server side rendering) isTouch issue (introduced in v6)
8386
* fixed - removing last item delete sub-grid that are not auto-generated (nested.html vs nested_advanced.html)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "gridstack",
33
"version": "7.0.1-dev",
4-
"description": "TypeScript/JS lib for dashboard layout and creation, mobile support, no external dependencies, with many wrappers (React, Angular, Vue, Ember, knockout...)",
4+
"description": "TypeScript/JS lib for dashboard layout and creation, responsive, mobile support, no external dependencies, with many wrappers (React, Angular, Vue, Ember, knockout...)",
55
"main": "./dist/gridstack.js",
66
"types": "./dist/gridstack.d.ts",
77
"repository": {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<title>read 1 column</title>
8+
9+
<link rel="stylesheet" href="../../../demo/demo.css"/>
10+
<script src="../../../dist/gridstack-all.js"></script>
11+
12+
</head>
13+
<body>
14+
<div class="container-fluid">
15+
<h1>read from dom into 1 column has wrong order and 12 column layout</h1>
16+
<div class="grid-stack">
17+
<div class="grid-stack-item" gs-x="4" gs-y="0"><div class="grid-stack-item-content">1</div></div>
18+
<div class="grid-stack-item" gs-x="0" gs-y="0"><div class="grid-stack-item-content">0</div></div>
19+
<div class="grid-stack-item" gs-x="1" gs-y="1"><div class="grid-stack-item-content">2</div></div>
20+
</div>
21+
</div>
22+
<script type="text/javascript">
23+
let grid = GridStack.init({
24+
cellHeight: 70,
25+
float: true,
26+
});
27+
28+
var items = [
29+
{x: 0, y: 0, content: '0'},
30+
{x: 2, y: 0, content: '1'},
31+
];
32+
// grid.addWidget(items[1]); // need to be reverse sort-order to be correct (otherwise DOM above is wrong)
33+
// grid.addWidget(items[0]);
34+
// grid.load(items); // or this work (code reverse sort)
35+
36+
</script>
37+
</body>
38+
</html>

src/gridstack-engine.ts

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export class GridStackEngine {
3737
protected _float: boolean;
3838
/** @internal */
3939
protected _prevFloat: boolean;
40-
/** @internal cached layouts of difference column count so we can restore ack (eg 12 -> 1 -> 12) */
40+
/** @internal cached layouts of difference column count so we can restore back (eg 12 -> 1 -> 12) */
4141
protected _layouts?: GridStackNode[][]; // maps column # to array of values nodes
4242
/** @internal true while we are resizing widgets during column resize to skip certain parts */
4343
protected _inColumnResize: boolean;
@@ -362,7 +362,7 @@ export class GridStackEngine {
362362
return this.nodeBoundFix(node, resizing);
363363
}
364364

365-
/** part2 of preparing a node to fit inside our grid - checks for x,y from grid dimensions */
365+
/** part2 of preparing a node to fit inside our grid - checks for x,y,w from grid dimensions */
366366
public nodeBoundFix(node: GridStackNode, resizing?: boolean): GridStackNode {
367367

368368
let before = node._orig || Utils.copyPos({}, node);
@@ -372,14 +372,18 @@ export class GridStackEngine {
372372
if (node.minW && node.minW <= this.column) { node.w = Math.max(node.w, node.minW); }
373373
if (node.minH) { node.h = Math.max(node.h, node.minH); }
374374

375+
// if user loaded a larger than allowed widget for current # of columns (or force 1 column mode),
376+
// remember it's position & width so we can restore back (1 -> 12 column) #1655 #1985
377+
// IFF we're not in the middle of column resizing!
378+
const saveOrig = this.column === 1 || node.x + node.w > this.column;
379+
if (saveOrig && this.column < 12 && !this._inColumnResize && !node.autoPosition && node._id && this.findCacheLayout(node, 12) === -1) {
380+
let copy = {...node}; // need _id + positions
381+
copy.x = Math.min(11, copy.x);
382+
copy.w = Math.min(12, copy.w);
383+
this.cacheOneLayout(copy, 12);
384+
}
385+
375386
if (node.w > this.column) {
376-
// if user loaded a larger than allowed widget for current # of columns,
377-
// remember it's full width so we can restore back (1 -> 12 column) #1655
378-
// IFF we're not in the middle of column resizing!
379-
if (this.column < 12 && !this._inColumnResize) {
380-
node.w = Math.min(12, node.w);
381-
this.cacheOneLayout(node, 12);
382-
}
383387
node.w = this.column;
384388
} else if (node.w < 1) {
385389
node.w = 1;
@@ -706,7 +710,7 @@ export class GridStackEngine {
706710
return this;
707711
}
708712

709-
/** saves a copy of the largest column layout (eg 12 even when rendering oneColumnMode, so we don't loose orig layout),
713+
/** saves a copy of the largest column layout (eg 12 even when rendering oneColumnMode) so we don't loose orig layout,
710714
* returning a list of widgets for serialization */
711715
public save(saveElement = true): GridStackNode[] {
712716
// use the highest layout for any saved info so we can have full detail on reload #1849
@@ -852,7 +856,7 @@ export class GridStackEngine {
852856
}
853857

854858
// finally re-layout them in reverse order (to get correct placement)
855-
newNodes = Utils.sort(newNodes, -1, column);
859+
if (!domOrder) newNodes = Utils.sort(newNodes, -1, column);
856860
this._inColumnResize = true; // prevent cache update
857861
this.nodes = []; // pretend we have no nodes to start with (add() will use same structures) to simplify layout
858862
newNodes.forEach(node => {
@@ -891,11 +895,18 @@ export class GridStackEngine {
891895
let layout: GridStackNode = {x: n.x, y: n.y, w: n.w, _id: n._id}
892896
this._layouts = this._layouts || [];
893897
this._layouts[column] = this._layouts[column] || [];
894-
let index = this._layouts[column].findIndex(l => l._id === n._id);
895-
index === -1 ? this._layouts[column].push(layout) : this._layouts[column][index] = layout;
898+
let index = this.findCacheLayout(n, column);
899+
if (index === -1)
900+
this._layouts[column].push(layout);
901+
else
902+
this._layouts[column][index] = layout;
896903
return this;
897904
}
898905

906+
protected findCacheLayout(n: GridStackNode, column: number): number {
907+
return this._layouts?.[column]?.findIndex(l => l._id === n._id) ?? -1;
908+
}
909+
899910

900911
/** called to remove all internal values but the _id */
901912
public cleanupNode(node: GridStackNode): GridStackEngine {

src/gridstack.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ export interface CellPosition {
3434
y: number;
3535
}
3636

37+
/** optional function called during load() to callback the user on new added/remove items */
38+
export type AddRemoveFcn = (g: GridStack, w: GridStackWidget, add: boolean) => GridItemHTMLElement;
39+
3740
interface GridCSSStyleSheet extends CSSStyleSheet {
3841
_max?: number; // internal tracker of the max # of rows we created
3942
}
@@ -186,7 +189,7 @@ export class GridStack {
186189
protected _placeholder: HTMLElement;
187190
/** @internal */
188191
protected _prevColumn: number;
189-
/** @internal */
192+
/** @internal prevent cached layouts from being updated when loading into small column layouts */
190193
protected _ignoreLayoutsNodeChange: boolean;
191194
/** @internal */
192195
public _gsEventHandler = {};
@@ -328,16 +331,18 @@ export class GridStack {
328331
if (this.opts.auto) {
329332
this.batchUpdate(); // prevent in between re-layout #1535 TODO: this only set float=true, need to prevent collision check...
330333
let elements: {el: HTMLElement; i: number}[] = [];
334+
let column = this.getColumn();
335+
if (column === 1 && this._prevColumn) column = this._prevColumn; // do 12 column when reading into 1 column mode
331336
this.getGridItems().forEach(el => { // get dom elements (not nodes yet)
332337
let x = parseInt(el.getAttribute('gs-x'));
333338
let y = parseInt(el.getAttribute('gs-y'));
334339
elements.push({
335340
el,
336341
// if x,y are missing (autoPosition) add them to end of list - but keep their respective DOM order
337-
i: (Number.isNaN(x) ? 1000 : x) + (Number.isNaN(y) ? 1000 : y) * this.getColumn()
342+
i: (Number.isNaN(x) ? 1000 : x) + (Number.isNaN(y) ? 1000 : y) * column
338343
});
339344
});
340-
elements.sort((a, b) => a.i - b.i).forEach(e => this._prepareElement(e.el));
345+
elements.sort((a, b) => b.i - a.i).forEach(e => this._prepareElement(e.el)); // revert sort so lowest item wins
341346
this.batchUpdate(false);
342347
}
343348

@@ -421,8 +426,14 @@ export class GridStack {
421426
this.makeSubGrid(node.el, undefined, undefined, false);
422427
}
423428

429+
// if we're adding an item into 1 column (_prevColumn is set only when going to 1) make sure
430+
// we don't override the larger 12 column layout that was already saved. #1985
431+
if (this._prevColumn && this.opts.column === 1) {
432+
this._ignoreLayoutsNodeChange = true;
433+
}
424434
this._triggerAddEvent();
425435
this._triggerChangeEvent();
436+
delete this._ignoreLayoutsNodeChange;
426437

427438
return el;
428439
}
@@ -603,11 +614,11 @@ export class GridStack {
603614
* @example
604615
* see http://gridstackjs.com/demo/serialization.html
605616
**/
606-
public load(layout: GridStackWidget[], addAndRemove: boolean | ((g: GridStack, w: GridStackWidget, add: boolean) => GridItemHTMLElement) = true): GridStack {
617+
public load(layout: GridStackWidget[], addAndRemove: boolean | AddRemoveFcn = true): GridStack {
607618
let items = GridStack.Utils.sort([...layout], -1, this._prevColumn || this.getColumn()); // make copy before we mod/sort
608619
this._insertNotAppend = true; // since create in reverse order...
609620

610-
// if we're loading a layout into 1 column (_prevColumn is set only when going to 1) and items don't fit, make sure to save
621+
// if we're loading a layout into for example 1 column (_prevColumn is set only when going to 1) and items don't fit, make sure to save
611622
// the original wanted layout so we can scale back up correctly #1471
612623
if (this._prevColumn && this._prevColumn !== this.opts.column && items.some(n => (n.x + n.w) > this.opts.column)) {
613624
this._ignoreLayoutsNodeChange = true; // skip layout update

src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ export class Utils {
236236
return true;
237237
}
238238

239-
/** copies over b size & position (GridStackPosition), and possibly min/max as well */
239+
/** copies over b size & position (GridStackPosition), and optionally min/max as well */
240240
static copyPos(a: GridStackWidget, b: GridStackWidget, doMinMax = false): GridStackWidget {
241241
a.x = b.x;
242242
a.y = b.y;

0 commit comments

Comments
 (0)