* Load widgets from a list. This will call update() on each (matching by id) or add/remove widgets that are not there. * Used to restore a grid layout for a saved layout list (see `save()`). * * @param items list of widgets definition to update/create * @param addRemove boolean (default
(items: GridStackWidget[], addRemove: boolean | AddRemoveFcn = GridStack.addRemoveCB || true)
| 720 | * @see {@link http://gridstackjs.com/demo/serialization.html} for complete example |
| 721 | */ |
| 722 | public load(items: GridStackWidget[], addRemove: boolean | AddRemoveFcn = GridStack.addRemoveCB || true): GridStack { |
| 723 | // items = Utils.cloneDeep(items); // TODO: let callee decide by using directly instead of copy we can modify ? |
| 724 | |
| 725 | // make sure size 1x1 (default) is present as it may need to override current sizes |
| 726 | items.forEach(n => { n.w = n.w || n.minW || 1; n.h = n.h || n.minH || 1 }); |
| 727 | |
| 728 | // sort items. those without coord will be appended last |
| 729 | items = Utils.sort(items); |
| 730 | |
| 731 | this.engine.skipCacheUpdate = this._ignoreLayoutsNodeChange = true; // skip layout update |
| 732 | |
| 733 | // if we're loading a layout into for example 1 column and items don't fit, make sure to save |
| 734 | // the original wanted layout so we can scale back up correctly #1471 |
| 735 | let maxColumn = 0; |
| 736 | items.forEach(n => { maxColumn = Math.max(maxColumn, (n.x || 0) + n.w) }); |
| 737 | if (maxColumn > this.engine.defaultColumn) this.engine.defaultColumn = maxColumn; |
| 738 | const column = this.getColumn(); |
| 739 | if (maxColumn > column) { |
| 740 | // if we're loading (from empty) into a smaller column, check for special responsive layout |
| 741 | if (this.engine.nodes.length === 0 && this.responseLayout) { |
| 742 | this.engine.nodes = items; |
| 743 | this.engine.columnChanged(maxColumn, column, this.responseLayout); |
| 744 | items = this.engine.nodes; |
| 745 | this.engine.nodes = []; |
| 746 | delete this.responseLayout; |
| 747 | } else this.engine.cacheLayout(items, maxColumn, true); |
| 748 | } |
| 749 | |
| 750 | // if given a different callback, temporally set it as global option so creating will use it |
| 751 | const prevCB = GridStack.addRemoveCB; |
| 752 | if (typeof (addRemove) === 'function') GridStack.addRemoveCB = addRemove as AddRemoveFcn; |
| 753 | |
| 754 | const removed: GridStackNode[] = []; |
| 755 | this.batchUpdate(); |
| 756 | |
| 757 | // if we are loading from empty temporarily remove animation |
| 758 | const blank = !this.engine.nodes.length; |
| 759 | const noAnim = blank && this.opts.animate; |
| 760 | if (noAnim) this.setAnimation(false); |
| 761 | |
| 762 | // see if any items are missing from new layout and need to be removed first |
| 763 | if (!blank && addRemove) { |
| 764 | const copyNodes = [...this.engine.nodes]; // don't loop through array you modify |
| 765 | copyNodes.forEach(n => { |
| 766 | if (!n.id) return; |
| 767 | const item = Utils.find(items, n.id); |
| 768 | if (!item) { |
| 769 | if (GridStack.addRemoveCB) GridStack.addRemoveCB(this.el, n, false, false); |
| 770 | removed.push(n); // batch keep track |
| 771 | this.removeWidget(n.el, true, false); |
| 772 | } |
| 773 | }); |
| 774 | } |
| 775 | |
| 776 | // now add/update the widgets - starting with removing items in the new layout we will reposition |
| 777 | // to reduce collision and add no-coord ones at next available spot |
| 778 | this.engine._loading = true; // help with collision |
| 779 | const updateNodes: GridStackWidget[] = []; |
no test coverage detected