From 2cbd04d8ecd2ced0188a013cb501491df4e414ba Mon Sep 17 00:00:00 2001 From: "Dan G. Switzer, II" Date: Wed, 29 Nov 2017 14:41:36 -0500 Subject: [PATCH] Improved item placement in _updateNodeWidths() There are several issues in the GridStack.prototype._updateNodeWidths method. 1) Not all the items are guaranteed to be processed. This is because the update() method can change the this.grid.nodes array. This can lead to items being ignored. The code now processes each item in the grid. 2) The code does not correctly confine items to the grid's width. This code adds sanity checks to make sure that an item is always placed inside the grid and that it's width does not overlap the grid's width. --- src/gridstack.js | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/src/gridstack.js b/src/gridstack.js index 518942def..5b4c56a05 100644 --- a/src/gridstack.js +++ b/src/gridstack.js @@ -1672,10 +1672,41 @@ this.grid._sortNodes(); this.grid.batchUpdate(); var node = {}; - for (var i = 0; i < this.grid.nodes.length; i++) { - node = this.grid.nodes[i]; - this.update(node.el, Math.round(node.x * newWidth / oldWidth), undefined, - Math.round(node.width * newWidth / oldWidth), undefined); + + // We need an array of the elements to update so that we make sure that + // each item in the grid gets processed. We need to get a fixed list of + // array items, because the this.update() can shift items in the this.grid.nodes + // array which can lead to elements not being processed. + var nodes = _.map(this.grid.nodes, 'el') + , columnPos, columnWidth; + + for (var i = 0; i < nodes.length; i++) { + // get the current live node data, in case a previous update has changed anything + node = this.grid.getNodeDataByDOMEl(nodes[i]); + /* + * Calculate the new column position for the item, but make sure it fits inside the + * grid range. If the calculated position is outside the range, then it will move + * it to the last column (newWidth-1). + */ + columnPos = Math.min(Math.round(node.x * newWidth / oldWidth), newWidth-1); + // calculate the new width of the item + columnWidth = Math.round(node.width * newWidth / oldWidth); + + // if the item is too wide, we need to adjust our calculations + if( columnPos + columnWidth > newWidth ){ + /* + * To keep the original calculated width, we could just move the item to the left to + * fit within the width of the grid, but this would cause other items to shift: + * + * columnPos = newWidth - columnWidth; + * + * Instead of shifting other items around, we will just make sure the item's + * width is resized to fit inside the width of the grid. + */ + columnWidth = (columnPos + columnWidth) - newWidth; + } + + this.update(node.el, columnPos, undefined, columnWidth, undefined); } this.grid.commit(); };