diff --git a/demo/column.html b/demo/column.html index 40c6f5c2f..01448f335 100644 --- a/demo/column.html +++ b/demo/column.html @@ -53,6 +53,11 @@

setColumn() grid demo

} var items = [ + /* match karma testing + {x: 0, y: 0, width: 4, height: 2}, + {x: 4, y: 0, width: 4, height: 4}, + {text: ' auto'}, + */ {x: 0, y: 0, width: 2, height: 2}, {x: 2, y: 0, width: 2, height: 1}, {x: 5, y: 1, width: 1, height: 1}, @@ -63,22 +68,21 @@

setColumn() grid demo

]; var count = 0; grid.batchUpdate(); - for (count=0; count<4;) { - var n = items[count]; - grid.addWidget($('
' + count++ + (n.text ? n.text : '') + '
'), n); - }; + addWidget(); addWidget(); addWidget(); addWidget(); grid.commit(); - $('#add-widget').click(function() { + function addWidget() { var n = items[count] || { x: Math.round(12 * Math.random()), y: Math.round(5 * Math.random()), width: Math.round(1 + 3 * Math.random()), height: Math.round(1 + 3 * Math.random()) }; - grid.addWidget($('
' + count++ + (n.text ? n.text : '') + '
'), n); - }); + grid.addWidget($('

' + + count++ + (n.text ? n.text : '') + '
'), n); + }; + $('#add-widget').click(function() { addWidget() }); $('#1column').click(function() { delete grid.opts.oneColumnModeDomSort; grid.setColumn(1); $text.text(1);}); $('#1columnDOM').click(function() { grid.opts.oneColumnModeDomSort = true; grid.setColumn(1); $text.text('1 DOM');}); $('#2column').click(function() { grid.setColumn(2); $text.text(2);}); diff --git a/doc/CHANGES.md b/doc/CHANGES.md index 0d27e40f4..113707bb3 100644 --- a/doc/CHANGES.md +++ b/doc/CHANGES.md @@ -31,6 +31,8 @@ Change log - add `oneColumnModeDomSort` true|false to let you specify a custom layout (use dom order instead of x,y) for oneColumnMode `setColumn(1)` [#713](https://github.com/gridstack/gridstack.js/issues/713) - fix oneColumnMode to only restore if we auto went to it as window sizes up [#1125](https://github.com/gridstack/gridstack.js/pull/1125) +- editing in 1 column (or few columns) does a better job updating higher layout (track before and after and move items accordingly). +Tracking item swap would be even better still. [#1127](https://github.com/gridstack/gridstack.js/pull/1127) ## v0.6.1 (2020-02-02) diff --git a/spec/gridstack-spec.js b/spec/gridstack-spec.js index 19170776f..6f317278e 100644 --- a/spec/gridstack-spec.js +++ b/spec/gridstack-spec.js @@ -383,7 +383,7 @@ describe('gridstack', function() { expect(parseInt(el2.attr('data-gs-height'))).toBe(4); expect(parseInt(el3.attr('data-gs-x'))).toBe(0); - expect(parseInt(el3.attr('data-gs-y'))).toBe(6); + expect(parseInt(el3.attr('data-gs-y'))).toBe(6); // ??? keep same row, but might more intuitive higher expect(parseInt(el3.attr('data-gs-width'))).toBe(1); // ??? could take entire width if it did above expect(parseInt(el3.attr('data-gs-height'))).toBe(1); @@ -397,6 +397,7 @@ describe('gridstack', function() { expect(parseInt(el3.attr('data-gs-width'))).toBe(1); expect(parseInt(el3.attr('data-gs-height'))).toBe(1); + expect(parseInt(el1.attr('data-gs-x'))).toBe(0); expect(parseInt(el1.attr('data-gs-y'))).toBe(1); expect(parseInt(el1.attr('data-gs-width'))).toBe(1); expect(parseInt(el1.attr('data-gs-height'))).toBe(2); @@ -420,8 +421,8 @@ describe('gridstack', function() { expect(parseInt(el1.attr('data-gs-width'))).toBe(4); expect(parseInt(el1.attr('data-gs-height'))).toBe(2); - expect(parseInt(el2.attr('data-gs-x'))).toBe(0); - expect(parseInt(el2.attr('data-gs-y'))).toBe(3); + expect(parseInt(el2.attr('data-gs-x'))).toBe(4); + expect(parseInt(el2.attr('data-gs-y'))).toBe(1); expect(parseInt(el2.attr('data-gs-width'))).toBe(4); expect(parseInt(el2.attr('data-gs-height'))).toBe(4); @@ -440,8 +441,8 @@ describe('gridstack', function() { expect(parseInt(el1.attr('data-gs-width'))).toBe(1); expect(parseInt(el1.attr('data-gs-height'))).toBe(2); - expect(parseInt(el2.attr('data-gs-x'))).toBe(0); - expect(parseInt(el2.attr('data-gs-y'))).toBe(3); + expect(parseInt(el2.attr('data-gs-x'))).toBe(1); + expect(parseInt(el2.attr('data-gs-y'))).toBe(1); expect(parseInt(el2.attr('data-gs-width'))).toBe(1); expect(parseInt(el2.attr('data-gs-height'))).toBe(4); }); diff --git a/src/gridstack.js b/src/gridstack.js index 1e06a8aff..88cef7bf1 100644 --- a/src/gridstack.js +++ b/src/gridstack.js @@ -355,12 +355,12 @@ if (this.float) { this.nodes.forEach(function(n, i) { - if (n._updating || n._origY === undefined || n.y === n._origY) { + if (n._updating || n._packY === undefined || n.y === n._packY) { return; } var newY = n.y; - while (newY >= n._origY) { + while (newY >= n._packY) { var collisionNode = this.nodes .slice(0, i) .find(Utils._didCollide, {n: n, newY: newY}); @@ -653,14 +653,14 @@ GridStackEngine.prototype.beginUpdate = function(node) { if (node._updating) return; node._updating = true; - this.nodes.forEach(function(n) { n._origY = n.y; }); + this.nodes.forEach(function(n) { n._packY = n.y; }); }; GridStackEngine.prototype.endUpdate = function() { var n = this.nodes.find(function(n) { return n._updating; }); if (n) { n._updating = false; - this.nodes.forEach(function(n) { delete n._origY; }); + this.nodes.forEach(function(n) { delete n._packY; }); } }; @@ -1801,23 +1801,37 @@ GridStackEngine.prototype._layoutsNodesChange = function(nodes) { if (!this._layouts || this._ignoreLayoutsNodeChange) return; // remove smaller layouts - we will re-generate those on the fly... larger ones need to update - this._layouts.forEach(function(layout, i) { - if (!layout || i === this.column) return; - if (i < this.column) { - this._layouts[i] = undefined; + this._layouts.forEach(function(layout, column) { + if (!layout || column === this.column) return; + if (column < this.column) { + this._layouts[column] = undefined; } else { - // TODO: save the original x,y,w (h isn't cached) and see what actually changed to propagate correctly ? + // we save the original x,y,w (h isn't cached) to see what actually changed to propagate better. + // Note: we don't need to check against out of bound scaling/moving as that will be done when using those cache values. nodes.forEach(function(node) { var n = layout.find(function(l) { return l._id === node._id }); - if (!n) return; - var ratio = i / this.column; - n.y = node.y; - n.x = Math.round(node.x * ratio); - // width ??? + if (!n) return; // no cache for new nodes. Will use those values. + var ratio = column / this.column; + // Y changed, push down same amount + // TODO: detect doing item 'swaps' will help instead of move (especially in 1 column mode) + if (node.y !== node._origY) { + n.y += (node.y - node._origY); + } + // X changed, scale from new position + if (node.x !== node._origX) { + n.x = Math.round(node.x * ratio); + } + // width changed, scale from new width + if (node.width !== node._origW) { + n.width = Math.round(node.width * ratio); + } + // ...height always carries over from cache }, this); } }, this); + + this._saveInitial(); // reset current value now that we diffed. } /** @@ -1906,6 +1920,19 @@ }, this); this.commit(); delete this._ignoreLayoutsNodeChange; + + // save this initial layout so we can see what changed and apply changes to other layouts better (diff) + this._saveInitial(); + } + + /** called to save initial position/size */ + GridStackEngine.prototype._saveInitial = function() { + this.nodes.forEach(function(n) { + n._origX = n.x; + n._origY = n.y; + n._origW = n.width; + n._origH = n.height; + }); } /**