Skip to content

Commit 50558cf

Browse files
author
Alain Dumesny
authored
Merge pull request #1331 from adumesny/typescript
TS: drag&drop fixes
2 parents be7f0d6 + 20c1943 commit 50558cf

File tree

12 files changed

+118
-63
lines changed

12 files changed

+118
-63
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ v2.x is a Typescript rewrite of 1.x, removing all jquery events, using classes a
373373
'verticalMargin()` to get value --> `getMargin()`
374374
```
375375

376-
2. event signatures are generic and not jquery-ui dependent anymore. `gsresizestop` has been removed as `resizestop|dragstop` are now called **after** the DOm attributes have been updated.
376+
2. event signatures are generic and not jquery-ui dependent anymore. `gsresizestop` has been removed as `resizestop|dragstop` are now called **after** the DOM attributes have been updated.
377377

378378
3. `oneColumnMode` would trigger when `window.width` < 768px by default. We now check for grid width instead (more correct and supports nesting). You might need to adjust grid `minWidth` or `disableOneColumnMode`.
379379

demo/advance.html

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,21 @@
3131
<h1>Advanced Demo</h1>
3232
<div class="row">
3333
<div class="col-md-2 d-none d-md-block">
34-
<div id="trash" style="padding: 15px; margin-bottom: 15px;" class="text-center">
34+
<div id="trash" style="padding: 5px; margin-bottom: 15px;" class="text-center">
3535
<div>
36-
<ion-icon name="trash" style="font-size: 400%"></ion-icon>
36+
<ion-icon name="trash" style="font-size: 300%"></ion-icon>
3737
</div>
3838
<div>
3939
<span>Drop here to remove!</span>
4040
</div>
4141
</div>
4242
<div class="newWidget grid-stack-item">
43-
<div class="card-body grid-stack-item-content">
43+
<div class="grid-stack-item-content" style="padding: 5px;">
4444
<div>
45-
<ion-icon name="add-circle" style="font-size: 400%"></ion-icon>
45+
<ion-icon name="add-circle" style="font-size: 300%"></ion-icon>
4646
</div>
4747
<div>
48-
<span>Drag me in into the dashboard!</span>
48+
<span>Drag me in the dashboard!</span>
4949
</div>
5050
</div>
5151
</div>
@@ -109,11 +109,11 @@ <h1>Advanced Demo</h1>
109109
resizable: {
110110
handles: 'e, se, s, sw, w'
111111
},
112-
removable: '#trash',
113-
removeTimeout: 100,
114-
dragIn: '.newWidget',
112+
acceptWidgets: true,
113+
dragIn: '.newWidget', // class that can be dragged from outside
115114
dragInOptions: { revert: 'invalid', scroll: false, appendTo: 'body', helper: 'clone' },
116-
acceptWidgets: '.newWidget'
115+
removable: '#trash', // drag-out delete class
116+
removeTimeout: 100,
117117
});
118118

119119
grid.on('added removed change', function(e, items) {

demo/events.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@ function addEvents(grid, id) {
2727
});
2828

2929
grid.on('dropped', function(event, previousWidget, newWidget) {
30-
console.log(g + 'dropped - Removed widget that was dragged out of grid:', previousWidget);
31-
console.log(g + 'dropped - Added widget in dropped grid:', newWidget);
30+
if (previousWidget) {
31+
console.log(g + 'dropped - Removed widget from grid:', previousWidget);
32+
}
33+
if (newWidget) {
34+
console.log(g + 'dropped - Added widget in grid:', newWidget);
35+
}
3236
});
3337

3438
grid.on('enable', function(event) {

demo/two.html

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,6 @@
1313
<script src="../dist/gridstack.all.js"></script>
1414

1515
<style type="text/css">
16-
.grid-stack {
17-
min-height: 50px;
18-
}
19-
#grid2 {
20-
background: lightcyan;
21-
}
22-
#grid2 .grid-stack-item-content {
23-
background-color: #9caabc;
24-
}
2516
.grid-stack-item-removing {
2617
opacity: 0.5;
2718
}
@@ -37,11 +28,11 @@
3728
text-align: center;
3829
}
3930
.sidebar .grid-stack-item {
40-
width: 200px;
41-
height: 100px;
31+
width: 120px;
32+
height: 50px;
4233
border: 2px dashed green;
4334
text-align: center;
44-
line-height: 100px;
35+
line-height: 35px;
4536
z-index: 10;
4637
background: rgba(0, 255, 0, 0.1);
4738
cursor: default;
@@ -60,7 +51,7 @@ <h1>Two grids demo</h1>
6051
<div class="col-md-3">
6152
<div class="sidebar">
6253

63-
<!-- will size to fit content -->
54+
<!-- will size to match content -->
6455
<div class="grid-stack-item">
6556
<div class="grid-stack-item-content">Drag me</div>
6657
</div>
@@ -94,12 +85,14 @@ <h1>Two grids demo</h1>
9485
<script type="text/javascript">
9586
let options = {
9687
column: 6,
88+
minRow: 1, // don't collapse when empty
9789
cellHeight: 70,
9890
disableOneColumnMode: true,
9991
float: false,
100-
removable: '.trash',
92+
dragIn: '.sidebar .grid-stack-item', // class that can be dragged from outside
93+
dragInOptions: { revert: 'invalid', scroll: false, appendTo: 'body', helper: 'clone' }, // clone
94+
removable: '.trash', // drag-out delete class
10195
removeTimeout: 100,
102-
dragIn: '.sidebar .grid-stack-item',
10396
acceptWidgets: function(el) { return true; } // function example, else can be simple: true | false | '.someClass' value
10497
};
10598
let grids = GridStack.initAll(options);
@@ -117,8 +110,7 @@ <h1>Two grids demo</h1>
117110
addEvents(grid, i);
118111
grid.batchUpdate();
119112
items.forEach(function (node) {
120-
grid.addWidget('<div><div class="grid-stack-item-content">'
121-
+ (node.text? node.text : '') + '</div></div>', node);
113+
grid.addWidget('<div><div class="grid-stack-item-content">' + (node.text? node.text : '') + '</div></div>', node);
122114
});
123115
grid.commit();
124116
});

doc/CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Change log
4444
- add `margin` to replace `verticalMargin` which affects both dimensions in code, rather than one in code the other in CSS.
4545
You can now have perfect square cells (default) [723](https://github.com/gridstack/gridstack.js/issues/723)
4646
- fix [1299](https://github.com/gridstack/gridstack.js/pull/1299) many columns round-off error
47+
- fix [1102](https://github.com/gridstack/gridstack.js/issues/1102) lose functionality when they are moved to a new grid
4748

4849
## 1.2.0 (2020-08-01)
4950

doc/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,9 @@ Extras:
127127
options you can pass when calling `addWidget()`
128128

129129
- `autoPosition` - tells to ignore `x` and `y` attributes and to place element to the first available position. Having either one missing will also do that.
130-
- `x`, `y` - (number) element position in row/column. Note: if one is missing this will `autoPosition` the item
131-
- `width`, `height` - (number) element size in row/column (default 1x1)
132-
- `maxWidth`, `minWidth`, `maxHeight`, `minHeight` - element constraints in row/column (default none)
130+
- `x`, `y` - (number) element position in column/row. Note: if one is missing this will `autoPosition` the item
131+
- `width`, `height` - (number) element size in column/row (default 1x1)
132+
- `maxWidth`, `minWidth`, `maxHeight`, `minHeight` - element constraints in column/row (default none)
133133
- `locked` - means another widget wouldn't be able to move it during dragging or resizing.
134134
The widget can still be dragged or resized by the user.
135135
You need to add `noResize` and `noMove` attributes to completely lock the widget.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<title>lose functionality</title>
8+
9+
<link rel="stylesheet" href="../../../demo/demo.css"/>
10+
11+
<script src="../../../dist/gridstack.all.js"></script>
12+
</head>
13+
<body>
14+
<div class="container-fluid">
15+
<h1>lose functionality when dragged</h1>
16+
<br/>
17+
<div class="grid-stack" id="right-grid">
18+
<div class="grid-stack-item">
19+
<div class="grid-stack-item-content" id="button1">button1</div>
20+
</div>
21+
</div>
22+
<br/>
23+
<br/>
24+
<div class="grid-stack" id="left-grid">
25+
<div class="grid-stack-item">
26+
<div class="grid-stack-item-content" id="button2">button2</div>
27+
</div>
28+
</div>
29+
</div>
30+
31+
<script type="text/javascript">
32+
GridStack.initAll({acceptWidgets: true});
33+
34+
function pressed1(){
35+
$('.container-fluid').append("button 1 pressed ");
36+
}
37+
38+
function pressed2(){
39+
$('.container-fluid').append("button 2 pressed ");
40+
}
41+
$('#button1').click(pressed1);
42+
$('#button2').click(pressed2);
43+
</script>
44+
</body>
45+
</html>

src/gridstack-dd.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export type DDKey = 'minWidth' | 'minHeight' | string;
2323
export type DDValue = number | string;
2424

2525
/** drag&drop events callbacks */
26-
export type DDCallback = (event: Event, arg2: GridItemHTMLElement) => void;
26+
export type DDCallback = (event: Event, arg2: GridItemHTMLElement, helper?: GridItemHTMLElement) => void;
2727

2828
/**
2929
* Base class for drag'n'drop plugin.

src/gridstack-engine.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ export class GridStackEngine {
320320
}
321321

322322
public removeNode(node: GridStackNode, removeDOM = true, triggerRemoveEvent = false): GridStackEngine {
323-
if (triggerRemoveEvent) {
323+
if (triggerRemoveEvent) { // we wait until final drop to manually track removed items (rather than during drag)
324324
this.removedNodes.push(node);
325325
}
326326
node._id = null; // hint that node is being removed

src/gridstack.ts

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,11 +1322,12 @@ export class GridStack {
13221322

13231323
/** called when the item stops moving/resizing */
13241324
let onEndMoving = (event: Event) => {
1325+
if (this.placeholder.parentNode === this.el) { this.el.removeChild(this.placeholder) }
1326+
1327+
// if the item has moved to another grid, we're done here
13251328
let target: GridItemHTMLElement = event.target as GridItemHTMLElement;
1326-
if (!target.gridstackNode) return;
1329+
if (!target.gridstackNode || target.gridstackNode.grid !== this) return;
13271330

1328-
// let forceNotify = false; what is the point of calling 'change' event with no data, when the 'removed' event is already called ?
1329-
if (this.placeholder.parentNode === this.el) { this.el.removeChild(this.placeholder) }
13301331
node.el = target;
13311332

13321333
if (node._isAboutToRemove) {
@@ -1623,8 +1624,8 @@ export class GridStack {
16231624
// if not calculate the grid size based on element outer size
16241625
let cellWidth = this.cellWidth();
16251626
let cellHeight = this.getCellHeight();
1626-
width = node && node.width ? node.width : Math.ceil(el.offsetWidth / cellWidth);
1627-
height = node && node.height ? node.height : Math.round(el.offsetHeight / cellHeight);
1627+
width = node && node.width ? node.width : Math.round(el.offsetWidth / cellWidth) || 1;
1628+
height = node && node.height ? node.height : Math.round(el.offsetHeight / cellHeight) || 1;
16281629

16291630
let newNode = this.engine.prepareNode({width, height, _added: false, _temporary: true});
16301631
newNode._isOutOfGrid = true;
@@ -1651,43 +1652,55 @@ export class GridStack {
16511652
el.gridstackNode = el._gridstackNodeOrig;
16521653
return false; // prevent parent from receiving msg (which may be grid as well)
16531654
})
1654-
.on(this.el, 'drop', (event, _el: GridItemHTMLElement) => {
1655-
if (this.placeholder.parentNode === this.el) {
1656-
this.el.removeChild(this.placeholder);
1655+
.on(this.el, 'drop', (event, el: GridItemHTMLElement, helper: GridItemHTMLElement) => {
1656+
this.placeholder.remove();
1657+
1658+
// notify of removal from prev grid...
1659+
let origNode = el._gridstackNodeOrig;
1660+
delete el._gridstackNodeOrig;
1661+
if (origNode && origNode.grid && origNode.grid !== this) {
1662+
let oGrid = origNode.grid;
1663+
oGrid.placeholder.remove();
1664+
origNode.el = el; // was using placeholder, have it point to node we've moved instead
1665+
oGrid.engine.removedNodes.push(origNode);
1666+
oGrid._triggerRemoveEvent();
16571667
}
1658-
let node: GridStackNode = _el.gridstackNode;
1659-
this.engine.cleanupNode(node);
1660-
node.grid = this;
1661-
let originalNode = _el._gridstackNodeOrig;
1662-
delete _el.gridstackNode;
1663-
delete _el._gridstackNodeOrig;
1664-
this.dd
1665-
.off(_el, 'drag')
1666-
.draggable(_el, 'destroy')
1667-
.resizable(_el, 'destroy');
16681668

1669-
let el = _el.cloneNode(true) as GridItemHTMLElement;
1670-
1671-
el.gridstackNode = node;
1672-
if (originalNode && originalNode.grid) {
1673-
originalNode.grid._triggerRemoveEvent();
1669+
let node: GridStackNode = el.gridstackNode; // use existing placeholder node as it's already in our list with drop location
1670+
this.engine.cleanupNode(node); // remove all internal _xyz values
1671+
node.grid = this;
1672+
this.dd.off(el, 'drag');
1673+
// if we made a copy ('helper' which is temp) of the original node then insert a copy, else we move the original node (#1102)
1674+
// as the helper will be nuked by default (by jqueryui and here to make it the same)
1675+
if (helper !== el) {
1676+
helper.remove();
1677+
el.gridstackNode = origNode; // original item (left behind) is re-stored to pre dragging as the node now has drop info
1678+
el = el.cloneNode(true) as GridItemHTMLElement;
1679+
} else {
1680+
el.remove(); // reduce flicker as we change depth here, and size further down
1681+
this.dd
1682+
.draggable(el, 'destroy')
1683+
.resizable(el, 'destroy');
16741684
}
1675-
_el.remove();
1685+
el.gridstackNode = node;
16761686
node.el = el;
1677-
Utils.removePositioningStyles(el);
16781687

1688+
Utils.removePositioningStyles(el);
16791689
this._writeAttr(el, node);
16801690
this.el.appendChild(el);
1681-
this._prepareElementsByNode(el, node);
16821691
this._updateContainerHeight();
16831692
this.engine.addedNodes.push(node);
16841693
this._triggerAddEvent();
16851694
this._triggerChangeEvent();
16861695

16871696
this.engine.endUpdate();
16881697
if (this._gsEventHandler['dropped']) {
1689-
this._gsEventHandler['dropped']({type: 'dropped'}, originalNode, node);
1698+
this._gsEventHandler['dropped']({type: 'dropped'}, origNode && origNode.grid ? origNode : undefined, node);
16901699
}
1700+
1701+
// wait till we return out of the drag callback to set the new drag&resize handler or they may get messed up
1702+
window.setTimeout(() => this._prepareElementsByNode(el, node));
1703+
16911704
return false; // prevent parent from receiving msg (which may be grid as well)
16921705
});
16931706
return this;

0 commit comments

Comments
 (0)