Skip to content

Commit 3131015

Browse files
authored
Merge pull request #2412 from adumesny/master
2 parents fcf8401 + b92f840 commit 3131015

File tree

6 files changed

+62
-21
lines changed

6 files changed

+62
-21
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,15 +175,15 @@ grid.printCount();
175175

176176
## Extend Engine
177177

178-
You can now (5.1+) easily create your own layout engine to further customize you usage. Here is a typescript example
178+
You can now (5.1+) easily create your own layout engine to further customize your usage. Here is a typescript example
179179

180180
```ts
181181
import { GridStack, GridStackEngine, GridStackNod, GridStackMoveOpts } from 'gridstack';
182182

183183
class CustomEngine extends GridStackEngine {
184184

185185
/** refined this to move the node to the given new location */
186-
public moveNode(node: GridStackNode, o: GridStackMoveOpts): boolean {
186+
public override moveNode(node: GridStackNode, o: GridStackMoveOpts): boolean {
187187
// keep the same original X and Width and let base do it all...
188188
o.x = node.x;
189189
o.w = node.w;

demo/fitToContent.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<title>FitToContent demo</title>
88

99
<link rel="stylesheet" href="demo.css"/>
10+
<link rel="stylesheet" href="../dist/gridstack-extra.css"/>
1011
<script src="../dist/gridstack-all.js"></script>
1112
<style type="text/css">
1213
.grid-stack-item-content {
@@ -18,6 +19,11 @@
1819
<div class="container">
1920
<h1>Cell FitToContent options demo</h1>
2021
<p>new 9.x feature that size the items to fit their content height as to not have scroll bars (unless `fitToContent:false` in C: case) </p>
22+
<div>
23+
column:
24+
<a onClick="column(8)" class="btn btn-primary" href="#">8</a>
25+
<a onClick="column(12)" class="btn btn-primary" href="#">12</a>
26+
</div>
2127
<br>
2228
<div class="grid-stack"></div>
2329
</div>
@@ -38,6 +44,10 @@ <h1>Cell FitToContent options demo</h1>
3844
{x:0, y:1, w:3, content: `<div>D: ${text} ${text}</div>`},
3945
];
4046
grid.load(items);
47+
48+
function column(n) {
49+
grid.column(n, 'none');
50+
}
4151
</script>
4252
</body>
4353
</html>

doc/CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ Change log
9595

9696
## 8.4.0-dev (TBD)
9797
- feat [#404](https://github.com/gridstack/gridstack.js/issues/404) added `GridStackOptions.fitToContent` and `GridStackWidget.fitToContent` to make gridItems size themselves to their content (no scroll bar), calling `GridStack.resizeToContent(el)` whenever the grid or item is resized.
98+
- also added new `'resizecontent'` event, and `resizeToContentCB` and `resizeToContentParent` vars.
9899
- fix [#2406](https://github.com/gridstack/gridstack.js/issues/2406) inf loop when autoPosition after loading into 1 column, then 2.
99100

100101
## 8.4.0 (2023-07-20)

src/gridstack-engine.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -385,10 +385,10 @@ export class GridStackEngine {
385385
if (node.minW && node.minW <= this.column) { node.w = Math.max(node.w, node.minW); }
386386
if (node.minH) { node.h = Math.max(node.h, node.minH); }
387387

388-
// if user loaded a larger than allowed widget for current # of columns (or force 1 column mode),
388+
// if user loaded a larger than allowed widget for current # of columns,
389389
// remember it's position & width so we can restore back (1 -> 12 column) #1655 #1985
390390
// IFF we're not in the middle of column resizing!
391-
const saveOrig = this.column === 1 || node.x + node.w > this.column;
391+
const saveOrig = (node.x || 0) + (node.w || 1) > this.column;
392392
if (saveOrig && this.column < 12 && !this._inColumnResize && node._id && this.findCacheLayout(node, 12) === -1) {
393393
let copy = {...node}; // need _id + positions
394394
if (copy.autoPosition) { delete copy.x; delete copy.y; }
@@ -771,7 +771,7 @@ export class GridStackEngine {
771771
if (!n) return; // no cache for new nodes. Will use those values.
772772
// Y changed, push down same amount
773773
// TODO: detect doing item 'swaps' will help instead of move (especially in 1 column mode)
774-
if (node.y !== node._orig.y) {
774+
if (n.y >= 0 && node.y !== node._orig.y) {
775775
n.y += (node.y - node._orig.y);
776776
}
777777
// X changed, scale from new position

src/gridstack.ts

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { GridStackEngine } from './gridstack-engine';
99
import { Utils, HeightData, obsolete } from './utils';
1010
import { gridDefaults, ColumnOptions, GridItemHTMLElement, GridStackElement, GridStackEventHandlerCallback,
1111
GridStackNode, GridStackWidget, numberOrString, DDUIData, DDDragInOpt, GridStackPosition, GridStackOptions,
12-
dragInDefaultOptions, GridStackEventHandler, GridStackNodesHandler, AddRemoveFcn, SaveFcn, CompactOptions, GridStackMoveOpts } from './types';
12+
dragInDefaultOptions, GridStackEventHandler, GridStackNodesHandler, AddRemoveFcn, SaveFcn, CompactOptions, GridStackMoveOpts, ResizeToContentFcn } from './types';
1313

1414
/*
1515
* and include D&D by default
@@ -35,7 +35,7 @@ export interface GridHTMLElement extends HTMLElement {
3535
}
3636
/** list of possible events, or space separated list of them */
3737
export type GridStackEvent = 'added' | 'change' | 'disable' | 'drag' | 'dragstart' | 'dragstop' | 'dropped' |
38-
'enable' | 'removed' | 'resize' | 'resizestart' | 'resizestop' | string;
38+
'enable' | 'removed' | 'resize' | 'resizestart' | 'resizestop' | 'resizecontent' | string;
3939

4040
/** Defines the coordinates of an object */
4141
export interface MousePosition {
@@ -184,6 +184,11 @@ export class GridStack {
184184
*/
185185
public static saveCB?: SaveFcn;
186186

187+
/** callback to use for resizeToContent instead of the built in one */
188+
public static resizeToContentCB?: ResizeToContentFcn;
189+
/** parent class for sizing content. defaults to '.grid-stack-item-content' */
190+
public static resizeToContentParent = '.grid-stack-item-content';
191+
187192
/** scoping so users can call GridStack.Utils.sort() for example */
188193
public static Utils = Utils;
189194

@@ -859,9 +864,8 @@ export class GridStack {
859864
}
860865
this.engine.columnChanged(oldColumn, column, domNodes, layout);
861866
if (this._isAutoCellHeight) this.cellHeight();
862-
// this.engine.nodes.forEach(n => {
863-
// if (Utils.shouldFitToContent(n)) this.resizeToContent(n.el);
864-
// });
867+
868+
this.doContentResize();
865869

866870
// and trigger our event last...
867871
this._ignoreLayoutsNodeChange = true; // skip layout update
@@ -1045,7 +1049,8 @@ export class GridStack {
10451049
this._gsEventHandler[name] = (event: CustomEvent) => (callback as GridStackNodesHandler)(event, event.detail);
10461050
}
10471051
this.el.addEventListener(name, this._gsEventHandler[name]);
1048-
} else if (name === 'drag' || name === 'dragstart' || name === 'dragstop' || name === 'resizestart' || name === 'resize' || name === 'resizestop' || name === 'dropped') {
1052+
} else if (name === 'drag' || name === 'dragstart' || name === 'dragstop' || name === 'resizestart' || name === 'resize'
1053+
|| name === 'resizestop' || name === 'dropped' || name === 'resizecontent') {
10491054
// drag&drop stop events NEED to be call them AFTER we update node attributes so handle them ourself.
10501055
// do same for start event to make it easier...
10511056
this._gsEventHandler[name] = callback;
@@ -1258,21 +1263,32 @@ export class GridStack {
12581263
GridStack.getElements(els).forEach(el => {
12591264
let n = el?.gridstackNode;
12601265
if (!n) return;
1261-
let height = el.clientHeight;
1266+
if (el.parentElement !== n.grid.el) return; // skip if we are not inside a grid
1267+
let height = el.clientHeight; // getBoundingClientRect().height seem to flicker back and forth
12621268
if (!height) return; // 0 when hidden, skip
1263-
const item = el.querySelector('.grid-stack-item-content');
1269+
const item = el.querySelector(GridStack.resizeToContentParent);
12641270
if (!item) return;
1265-
const itemH = item.clientHeight;
1266-
const wantedH = (item.firstChild as Element)?.clientHeight || itemH; // NOTE: clientHeight & getBoundingClientRect() is undefined for text and other leaf nodes. use <div> container!
1271+
const itemH = item.clientHeight; // available height to our child (minus border, padding...)
1272+
const wantedH = (item.firstChild as Element)?.getBoundingClientRect().height || itemH; // NOTE: clientHeight & getBoundingClientRect() is undefined for text and other leaf nodes. use <div> container!
12671273
if (itemH === wantedH) return;
12681274
height += wantedH - itemH;
12691275
const cell = this.getCellHeight();
12701276
if (!cell) return;
12711277
let h = Math.ceil(height / cell);
12721278
if (n.maxH && h > n.maxH) h = n.maxH;
1273-
if (h !== n.h) this.moveNode(n, {h});
1279+
if (h !== n.h) {
1280+
this._ignoreLayoutsNodeChange = true;
1281+
this.moveNode(n, {h});
1282+
delete this._ignoreLayoutsNodeChange;
1283+
}
12741284
});
12751285
}
1286+
1287+
/** call the user resize (so we can do extra work) else our build in version */
1288+
protected resizeToContentCheck(el: GridItemHTMLElement) {
1289+
if (GridStack.resizeToContentCB) GridStack.resizeToContentCB(el);
1290+
else this.resizeToContent(el);
1291+
}
12761292

12771293
/**
12781294
* Updates the margins which will set all 4 sides at once - see `GridStackOptions.margin` for format options (CSS string format of 1,2,4 values or single number).
@@ -1608,18 +1624,29 @@ export class GridStack {
16081624
// update any nested grids, or items size
16091625
this.engine.nodes.forEach(n => {
16101626
if (n.subGrid) n.subGrid.onResize()
1611-
// update any gridItem height with fitToContent, but wait for DOM $animation_speed to settle if we changed column count
1612-
// TODO: is there a way to know what the final (post animation) size of the content will be so we can animate the column width and height together rather than sequentially ?
1613-
if (Utils.shouldFitToContent(n)) {
1614-
columnChanged ? setTimeout(() => this.resizeToContent(n.el), 300 + 10) : this.resizeToContent(n.el);
1615-
}
16161627
});
1628+
this.doContentResize(columnChanged);
16171629

16181630
this.batchUpdate(false);
16191631

16201632
return this;
16211633
}
16221634

1635+
private doContentResize(delay = true, n: GridStackNode = undefined) {
1636+
// update any gridItem height with fitToContent, but wait for DOM $animation_speed to settle if we changed column count
1637+
// TODO: is there a way to know what the final (post animation) size of the content will be so we can animate the column width and height together rather than sequentially ?
1638+
setTimeout(() => {
1639+
if (n) {
1640+
if (Utils.shouldFitToContent(n)) this.resizeToContentCheck(n.el);
1641+
} else {
1642+
this.engine.nodes.forEach(n => {
1643+
if (Utils.shouldFitToContent(n)) this.resizeToContentCheck(n.el);
1644+
});
1645+
}
1646+
if (this._gsEventHandler['resizeContent']) this._gsEventHandler['resizeContent'](null, n ? [n] : this.engine.nodes);
1647+
}, delay ? 300 + 10 : 0);
1648+
}
1649+
16231650
/** add or remove the grid element size event handler */
16241651
protected _updateResizeEvent(forceRemove = false): GridStack {
16251652
// only add event if we're not nested (parent will call us) and we're auto sizing cells or supporting oneColumn (i.e. doing work)
@@ -2192,6 +2219,8 @@ export class GridStack {
21922219
this._triggerChangeEvent();
21932220

21942221
this.engine.endUpdate();
2222+
2223+
if (event.type === 'resizestop') this.doContentResize(false, node);
21952224
}
21962225

21972226
dd.draggable(el, {

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ export type AddRemoveFcn = (parent: HTMLElement, w: GridStackWidget, add: boolea
8686
/** optional function called during save() to let the caller add additional custom data to the GridStackWidget structure that will get returned */
8787
export type SaveFcn = (node: GridStackNode, w: GridStackWidget) => void;
8888

89+
export type ResizeToContentFcn = (els: GridItemHTMLElement) => void;
8990

9091
/**
9192
* Defines the options for a Grid

0 commit comments

Comments
 (0)