From 784ad10929426ee50b74df94d94c5a0d423017ab Mon Sep 17 00:00:00 2001 From: Alain Dumesny Date: Thu, 20 Jul 2023 15:44:52 -0700 Subject: [PATCH] `load()` support re-order loading with autoPosition * you can now re-order widgets during load() using autoPosition:true --- doc/CHANGES.md | 1 + src/gridstack.ts | 21 ++++++++++++++++----- src/utils.ts | 4 ++-- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/doc/CHANGES.md b/doc/CHANGES.md index 9269c0e51..a8f8a0bd7 100644 --- a/doc/CHANGES.md +++ b/doc/CHANGES.md @@ -95,6 +95,7 @@ Change log ## 8.3.0-dev (TBD) * feat [#2378](https://github.com/gridstack/gridstack.js/pull/2378) attribute `DDRemoveOpt.decline` to deny the removal of a specific class. * fix: dragging onto trash now calls removeWidget() and therefore `GridStack.addRemoveCB` (for component cleanup) +* feat: make `load()` support re-order loading without explicit coordinates (`autoPosition` or missing `x,y`) uses passed order. ## 8.3.0 (2023-06-13) * feat [#2358](https://github.com/gridstack/gridstack.js/issues/2358) column(N, 'list'|'compact'|...) resizing now support reflowing content as list diff --git a/src/gridstack.ts b/src/gridstack.ts index 0ca0d0749..564ffbba8 100644 --- a/src/gridstack.ts +++ b/src/gridstack.ts @@ -650,12 +650,14 @@ export class GridStack { * see http://gridstackjs.com/demo/serialization.html **/ public load(layout: GridStackWidget[], addRemove: boolean | AddRemoveFcn = GridStack.addRemoveCB || true): GridStack { - let items = GridStack.Utils.sort([...layout], -1, this._prevColumn || this.getColumn()); // make copy before we mod/sort - this._insertNotAppend = true; // since create in reverse order... + // if passed list has coordinates, use them (insert from end to beginning for conflict resolution) else force widget same order + const haveCoord = layout.some(w => w.x !== undefined || w.y !== undefined); + let items = haveCoord ? Utils.sort(layout, -1, this._prevColumn || this.getColumn()) : layout; + this._insertNotAppend = haveCoord; // if we create in reverse order... // 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 // the original wanted layout so we can scale back up correctly #1471 - if (this._prevColumn && this._prevColumn !== this.opts.column && items.some(n => (n.x + n.w) > (this.opts.column as number))) { + if (this._prevColumn && this._prevColumn !== this.opts.column && items.some(n => ((n.x || 0) + n.w) > (this.opts.column as number))) { this._ignoreLayoutsNodeChange = true; // skip layout update this.engine.cacheLayout(items, this._prevColumn, true); } @@ -681,10 +683,19 @@ export class GridStack { }); } - // now add/update the widgets + // now add/update the widgets - starting with an empty list to reduce collision and add no-coord ones at next available spot + let copyNodes = this.engine.nodes; + this.engine.nodes = []; items.forEach(w => { - let item = (w.id !== undefined) ? this.engine.nodes.find(n => n.id === w.id) : undefined; + let item = (w.id !== undefined) ? copyNodes.find(n => n.id === w.id) : undefined; if (item) { + // check if missing coord, in which case find next empty slot with new (or old if missing) sizes + if (w.autoPosition || w.x === undefined || w.y === undefined) { + w.w = w.w || item.w; + w.h = w.h || item.h; + this.engine.findEmptyPosition(w); + } + this.engine.nodes.push(item); // now back to current list... this.update(item.el, w); if (w.subGridOpts?.children) { // update any sub grid as well let sub = item.el.querySelector('.grid-stack') as GridHTMLElement; diff --git a/src/utils.ts b/src/utils.ts index dcb3732a1..89e4f1af5 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -137,9 +137,9 @@ export class Utils { static sort(nodes: GridStackNode[], dir: 1 | -1 = 1, column?: number): GridStackNode[] { column = column || nodes.reduce((col, n) => Math.max(n.x + n.w, col), 0) || 12; if (dir === -1) - return nodes.sort((a, b) => (b.x + b.y * column)-(a.x + a.y * column)); + return nodes.sort((a, b) => ((b.x ?? 1000) + (b.y ?? 1000) * column)-((a.x ?? 1000) + (a.y ?? 1000) * column)); else - return nodes.sort((b, a) => (b.x + b.y * column)-(a.x + a.y * column)); + return nodes.sort((b, a) => ((b.x ?? 1000) + (b.y ?? 1000) * column)-((a.x ?? 1000) + (a.y ?? 1000) * column)); } /**