* @internal Called to scale the widget width & position up/down based on the column change. * Note we store previous layouts (especially original ones) to make it possible to go * from say 12 -> 1 -> 12 and get back to where we were. * * @param prevColumn previous number of columns *
(prevColumn: number, column: number, layout: ColumnOptions = 'moveScale')
| 1091 | * Note: items will never be outside of the current column boundaries. default (moveScale). Ignored for 1 column |
| 1092 | */ |
| 1093 | public columnChanged(prevColumn: number, column: number, layout: ColumnOptions = 'moveScale'): GridStackEngine { |
| 1094 | if (!this.nodes.length || !column || prevColumn === column) return this; |
| 1095 | |
| 1096 | // simpler shortcuts layouts |
| 1097 | const doCompact = layout === 'compact' || layout === 'list'; |
| 1098 | if (doCompact) { |
| 1099 | this.sortNodes(1); // sort with original layout once and only once (new column will affect order otherwise) |
| 1100 | } |
| 1101 | |
| 1102 | // cache the current layout in case they want to go back (like 12 -> 1 -> 12) as it requires original data IFF we're sizing down (see below) |
| 1103 | if (column < prevColumn) this.cacheLayout(this.nodes, prevColumn); |
| 1104 | this.batchUpdate(); // do this EARLY as it will call saveInitial() so we can detect where we started for _dirty and collision |
| 1105 | let newNodes: GridStackNode[] = []; |
| 1106 | let nodes = doCompact ? this.nodes : Utils.sort(this.nodes, -1); // current column reverse sorting so we can insert last to front (limit collision) |
| 1107 | |
| 1108 | // see if we have cached previous layout IFF we are going up in size (restore) otherwise always |
| 1109 | // generate next size down from where we are (looks more natural as you gradually size down). |
| 1110 | if (column > prevColumn && this._layouts) { |
| 1111 | const cacheNodes = this._layouts[column] || []; |
| 1112 | // ...if not, start with the largest layout (if not already there) as down-scaling is more accurate |
| 1113 | // by pretending we came from that larger column by assigning those values as starting point |
| 1114 | const lastIndex = this._layouts.length - 1; |
| 1115 | if (!cacheNodes.length && prevColumn !== lastIndex && this._layouts[lastIndex]?.length) { |
| 1116 | prevColumn = lastIndex; |
| 1117 | this._layouts[lastIndex].forEach(cacheNode => { |
| 1118 | const n = nodes.find(n => n._id === cacheNode._id); |
| 1119 | if (n) { |
| 1120 | // still current, use cache info positions |
| 1121 | if (!doCompact && !cacheNode.autoPosition) { |
| 1122 | n.x = cacheNode.x ?? n.x; |
| 1123 | n.y = cacheNode.y ?? n.y; |
| 1124 | } |
| 1125 | n.w = cacheNode.w ?? n.w; |
| 1126 | if (cacheNode.x == undefined || cacheNode.y === undefined) n.autoPosition = true; |
| 1127 | } |
| 1128 | }); |
| 1129 | } |
| 1130 | |
| 1131 | // if we found cache re-use those nodes that are still current |
| 1132 | cacheNodes.forEach(cacheNode => { |
| 1133 | const j = nodes.findIndex(n => n._id === cacheNode._id); |
| 1134 | if (j !== -1) { |
| 1135 | const n = nodes[j]; |
| 1136 | // still current, use cache info positions |
| 1137 | if (doCompact) { |
| 1138 | n.w = cacheNode.w; // only w is used, and don't trim the list |
| 1139 | return; |
| 1140 | } |
| 1141 | if (cacheNode.autoPosition || isNaN(cacheNode.x) || isNaN(cacheNode.y)) { |
| 1142 | this.findEmptyPosition(cacheNode, newNodes); |
| 1143 | } |
| 1144 | if (!cacheNode.autoPosition) { |
| 1145 | n.x = cacheNode.x ?? n.x; |
| 1146 | n.y = cacheNode.y ?? n.y; |
| 1147 | n.w = cacheNode.w ?? n.w; |
| 1148 | newNodes.push(n); |
| 1149 | } |
| 1150 | nodes.splice(j, 1); |
no test coverage detected