diff --git a/src/gridstack-engine.ts b/src/gridstack-engine.ts index 233e851e2..6ed335b29 100644 --- a/src/gridstack-engine.ts +++ b/src/gridstack-engine.ts @@ -670,7 +670,7 @@ export class GridStackEngine { nn = this.nodeBoundFix(nn, resizing); Utils.copyPos(o, nn); - if (Utils.samePos(node, o)) return false; + if (!o.forceCollide && Utils.samePos(node, o)) return false; let prevPos: GridStackPosition = Utils.copyPos({}, node); // check if we will need to fix collision at our new location diff --git a/src/gridstack.ts b/src/gridstack.ts index 8d947b564..5e986a1dc 100644 --- a/src/gridstack.ts +++ b/src/gridstack.ts @@ -658,6 +658,7 @@ export class GridStack { * see http://gridstackjs.com/demo/serialization.html */ public load(items: GridStackWidget[], addRemove: boolean | AddRemoveFcn = GridStack.addRemoveCB || true): GridStack { + items = Utils.cloneDeep(items); // so we can mod // if passed list has coordinates, use them (insert from end to beginning for conflict resolution) else force widget same order const haveCoord = items.some(w => w.x !== undefined || w.y !== undefined); if (haveCoord) items = Utils.sort(items, -1, this._prevColumn || this.getColumn()); @@ -692,11 +693,19 @@ export class GridStack { }); } - // now add/update the widgets + // now add/update the widgets - starting with removing items in the new layout we will reposition + // to reduce collision and add no-coord ones at next available spot + let updateNodes: GridStackWidget[] = []; + this.engine.nodes = this.engine.nodes.filter(n => { + if (Utils.find(items, n.id)) { updateNodes.push(n); return false; } // remove if found from list + return true; + }); let widthChanged = false; items.forEach(w => { - let item = Utils.find(this.engine.nodes, w.id); + let item = Utils.find(updateNodes, w.id); if (item) { + // if item sizes to content, re-use the exiting height so it's a better guess at the final size 9same if width doesn't change) + if (Utils.shouldSizeToContent(item)) w.h = item.h; // 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; @@ -704,6 +713,14 @@ export class GridStack { this.engine.findEmptyPosition(w); } widthChanged = widthChanged || (w.w !== undefined && w.w !== item.w); + + // add back to current list BUT force a collision check if it 'appears' we didn't change to make sure we don't overlap others now + this.engine.nodes.push(item); + if (Utils.samePos(item, w)) { + this.moveNode(item, {...w, forceCollide: true}); + Utils.copyPos(w, item, true); + } + 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/types.ts b/src/types.ts index 3a09d069b..ef2dfd57d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -284,6 +284,8 @@ export interface GridStackMoveOpts extends GridStackPosition { resizing?: boolean; /** best node (most coverage) we collied with */ collide?: GridStackNode; + /** for collision check even if we don't move */ + forceCollide?: boolean; } export interface GridStackPosition { diff --git a/src/utils.ts b/src/utils.ts index 60b8a1e9f..b56bc2c6a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -279,7 +279,7 @@ export class Utils { /** true if a and b has same size & position */ static samePos(a: GridStackPosition, b: GridStackPosition): boolean { - return a && b && a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h; + return a && b && a.x === b.x && a.y === b.y && (a.w || 1) === (b.w || 1) && (a.h || 1) === (b.h || 1); } /** given a node, makes sure it's min/max are valid */