Skip to content

Commit ea442d1

Browse files
committed
drag between grids
1 parent d010ddd commit ea442d1

File tree

6 files changed

+161
-34
lines changed

6 files changed

+161
-34
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,11 +479,12 @@ Changes
479479
- fix `setStatic` method
480480
- add `setAnimation` method to API
481481
- add `setGridWidth` method ([#227](https://github.com/troolee/gridstack.js/issues/227))
482-
- add `removable`/`removeTimeout`
482+
- add `removable`/`removeTimeout` *(experimental)*
483483
- add `detachGrid` parameter to `destroy` method ([#216](https://github.com/troolee/gridstack.js/issues/216)) (thanks @jhpedemonte)
484484
- add `useOffset` parameter to `getCellFromPixel` method ([#237](https://github.com/troolee/gridstack.js/issues/237))
485485
- add `minWidth`, `maxWidth`, `minHeight`, `maxHeight`, `id` parameters to `addWidget` ([#188](https://github.com/troolee/gridstack.js/issues/188))
486486
- add `added` and `removed` events for when a widget is added or removed, respectively. ([#54](https://github.com/troolee/gridstack.js/issues/54))
487+
- add `acceptWidgets` parameter. Widgets can now be draggable between grids or from outside *(experimental)*
487488

488489
#### v0.2.4 (2016-02-15)
489490

dist/gridstack.js

Lines changed: 148 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,9 @@
576576
var maxHeight = 0;
577577
_.each(nodes, function(n) {
578578
if (n._id === null) {
579-
n.el.remove();
579+
if (n.el) {
580+
n.el.remove();
581+
}
580582
} else {
581583
n.el
582584
.attr('data-gs-x', n.x)
@@ -671,7 +673,9 @@
671673
if (typeof self.opts.removable === 'string') {
672674
var trashZone = $(self.opts.removable);
673675
if (!trashZone.data('droppable')) {
674-
trashZone.droppable({});
676+
trashZone.droppable({
677+
accept: '.' + self.opts.itemClass
678+
});
675679
}
676680
trashZone
677681
.on('dropover', function(event, ui) {
@@ -691,6 +695,114 @@
691695
self._clearRemovingTimeout(el);
692696
});
693697
}
698+
699+
if (self.opts.acceptWidgets) {
700+
var draggingElement = null;
701+
702+
var onDrag = function(event, ui) {
703+
var el = draggingElement;
704+
var node = el.data('_gridstack_node');
705+
var pos = self.getCellFromPixel(ui.offset, true);
706+
var x = Math.max(0, pos.x);
707+
var y = Math.max(0, pos.y);
708+
if (!node._added) {
709+
node._added = true;
710+
711+
node.el = el;
712+
node.x = x;
713+
node.y = y;
714+
self.grid.cleanNodes();
715+
self.grid.beginUpdate(node);
716+
self.grid.addNode(node);
717+
718+
self.container.append(self.placeholder);
719+
self.placeholder
720+
.attr('data-gs-x', node.x)
721+
.attr('data-gs-y', node.y)
722+
.attr('data-gs-width', node.width)
723+
.attr('data-gs-height', node.height)
724+
.show();
725+
node.el = self.placeholder;
726+
node._beforeDragX = node.x;
727+
node._beforeDragY = node.y;
728+
729+
self._updateContainerHeight();
730+
} else {
731+
if (!self.grid.canMoveNode(node, x, y)) {
732+
return;
733+
}
734+
self.grid.moveNode(node, x, y);
735+
self._updateContainerHeight();
736+
}
737+
};
738+
739+
$(self.container).droppable({
740+
accept: function(el) {
741+
el = $(el);
742+
var node = el.data('_gridstack_node');
743+
if (node && node._grid === self) {
744+
return false;
745+
}
746+
return el.is(self.opts.acceptWidgets === true ? '.grid-stack-item' : self.opts.acceptWidgets);
747+
},
748+
over: function(event, ui) {
749+
var offset = self.container.offset();
750+
var el = $(ui.draggable);
751+
var cellWidth = self.cellWidth();
752+
var cellHeight = self.cellHeight();
753+
var origNode = el.data('_gridstack_node');
754+
755+
var width = origNode ? origNode.width : (Math.ceil(el.outerWidth() / cellWidth));
756+
var height = origNode ? origNode.height : (Math.ceil(el.outerHeight() / cellHeight));
757+
758+
draggingElement = el;
759+
760+
var node = self.grid._prepareNode({width: width, height: height, _added: false, _temporary: true});
761+
el.data('_gridstack_node', node);
762+
el.data('_gridstack_node_orig', origNode);
763+
764+
el.on('drag', onDrag);
765+
},
766+
out: function(event, ui) {
767+
var el = $(ui.draggable);
768+
el.unbind('drag', onDrag);
769+
var node = el.data('_gridstack_node');
770+
node.el = null;
771+
self.grid.removeNode(node);
772+
self.placeholder.detach();
773+
self._updateContainerHeight();
774+
el.data('_gridstack_node', el.data('_gridstack_node_orig'));
775+
},
776+
drop: function(event, ui) {
777+
self.placeholder.detach();
778+
779+
var node = $(ui.draggable).data('_gridstack_node');
780+
node._grid = self;
781+
var el = $(ui.draggable).clone(false);
782+
el.data('_gridstack_node', node);
783+
$(ui.draggable).remove();
784+
node.el = el;
785+
self.placeholder.hide();
786+
el
787+
.attr('data-gs-x', node.x)
788+
.attr('data-gs-y', node.y)
789+
.attr('data-gs-width', node.width)
790+
.attr('data-gs-height', node.height)
791+
.addClass(self.opts.itemClass)
792+
.removeAttr('style')
793+
.enableSelection()
794+
.removeData('draggable')
795+
.removeClass('ui-draggable ui-draggable-dragging ui-draggable-disabled')
796+
.unbind('drag', onDrag);
797+
self.container.append(el);
798+
self._prepareElementByNode(el, node);
799+
self._updateContainerHeight();
800+
self._triggerChangeEvent();
801+
802+
self.grid.endUpdate();
803+
}
804+
});
805+
}
694806
};
695807

696808
GridStack.prototype._triggerChangeEvent = function(forceTrigger) {
@@ -840,7 +952,6 @@
840952
};
841953

842954
GridStack.prototype._clearRemovingTimeout = function(el) {
843-
var self = this;
844955
var node = $(el).data('_gridstack_node');
845956

846957
if (!node._removeTimeout) {
@@ -852,30 +963,8 @@
852963
node._isAboutToRemove = false;
853964
};
854965

855-
GridStack.prototype._prepareElement = function(el, triggerAddEvent) {
856-
triggerAddEvent = typeof triggerAddEvent != 'undefined' ? triggerAddEvent : false;
966+
GridStack.prototype._prepareElementByNode = function(el, node) {
857967
var self = this;
858-
el = $(el);
859-
860-
el.addClass(this.opts.itemClass);
861-
var node = self.grid.addNode({
862-
x: el.attr('data-gs-x'),
863-
y: el.attr('data-gs-y'),
864-
width: el.attr('data-gs-width'),
865-
height: el.attr('data-gs-height'),
866-
maxWidth: el.attr('data-gs-max-width'),
867-
minWidth: el.attr('data-gs-min-width'),
868-
maxHeight: el.attr('data-gs-max-height'),
869-
minHeight: el.attr('data-gs-min-height'),
870-
autoPosition: Utils.toBool(el.attr('data-gs-auto-position')),
871-
noResize: Utils.toBool(el.attr('data-gs-no-resize')),
872-
noMove: Utils.toBool(el.attr('data-gs-no-move')),
873-
locked: Utils.toBool(el.attr('data-gs-locked')),
874-
el: el,
875-
id: el.attr('data-gs-id'),
876-
_grid: self
877-
}, triggerAddEvent);
878-
el.data('_gridstack_node', node);
879968

880969
var cellWidth;
881970
var cellHeight;
@@ -962,9 +1051,13 @@
9621051
};
9631052

9641053
var onEndMoving = function(event, ui) {
1054+
var o = $(this);
1055+
if (!o.data('_gridstack_node')) {
1056+
return;
1057+
}
1058+
9651059
var forceNotify = false;
9661060
self.placeholder.detach();
967-
var o = $(this);
9681061
node.el = o;
9691062
self.placeholder.hide();
9701063

@@ -1031,6 +1124,34 @@
10311124
el.attr('data-gs-locked', node.locked ? 'yes' : null);
10321125
};
10331126

1127+
GridStack.prototype._prepareElement = function(el, triggerAddEvent) {
1128+
triggerAddEvent = typeof triggerAddEvent != 'undefined' ? triggerAddEvent : false;
1129+
var self = this;
1130+
el = $(el);
1131+
1132+
el.addClass(this.opts.itemClass);
1133+
var node = self.grid.addNode({
1134+
x: el.attr('data-gs-x'),
1135+
y: el.attr('data-gs-y'),
1136+
width: el.attr('data-gs-width'),
1137+
height: el.attr('data-gs-height'),
1138+
maxWidth: el.attr('data-gs-max-width'),
1139+
minWidth: el.attr('data-gs-min-width'),
1140+
maxHeight: el.attr('data-gs-max-height'),
1141+
minHeight: el.attr('data-gs-min-height'),
1142+
autoPosition: Utils.toBool(el.attr('data-gs-auto-position')),
1143+
noResize: Utils.toBool(el.attr('data-gs-no-resize')),
1144+
noMove: Utils.toBool(el.attr('data-gs-no-move')),
1145+
locked: Utils.toBool(el.attr('data-gs-locked')),
1146+
el: el,
1147+
id: el.attr('data-gs-id'),
1148+
_grid: self
1149+
}, triggerAddEvent);
1150+
el.data('_gridstack_node', node);
1151+
1152+
this._prepareElementByNode(el, node);
1153+
};
1154+
10341155
GridStack.prototype.setAnimation = function(enable) {
10351156
if (enable) {
10361157
this.container.addClass('grid-stack-animate');

dist/gridstack.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/gridstack.min.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

doc/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ gridstack.js API
5656

5757
## Options
5858

59+
- `acceptWidgets` - if `true` of jquery selector the grid will accept widgets dragged from other grids or from
60+
outside (default: `false`) See [example](http://troolee.github.io/gridstack.js/demo/two.html)
5961
- `alwaysShowResizeHandle` - if `true` the resizing handles are shown even if the user is not hovering over the widget
6062
(default: `false`)
6163
- `animate` - turns animation on (default: `false`)

src/gridstack.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,7 @@
771771
self.grid.removeNode(node);
772772
self.placeholder.detach();
773773
self._updateContainerHeight();
774+
el.data('_gridstack_node', el.data('_gridstack_node_orig'));
774775
},
775776
drop: function(event, ui) {
776777
self.placeholder.detach();
@@ -791,7 +792,6 @@
791792
.removeAttr('style')
792793
.enableSelection()
793794
.removeData('draggable')
794-
// .unbind('.draggable')
795795
.removeClass('ui-draggable ui-draggable-dragging ui-draggable-disabled')
796796
.unbind('drag', onDrag);
797797
self.container.append(el);
@@ -952,7 +952,6 @@
952952
};
953953

954954
GridStack.prototype._clearRemovingTimeout = function(el) {
955-
var self = this;
956955
var node = $(el).data('_gridstack_node');
957956

958957
if (!node._removeTimeout) {
@@ -1052,9 +1051,13 @@
10521051
};
10531052

10541053
var onEndMoving = function(event, ui) {
1054+
var o = $(this);
1055+
if (!o.data('_gridstack_node')) {
1056+
return;
1057+
}
1058+
10551059
var forceNotify = false;
10561060
self.placeholder.detach();
1057-
var o = $(this);
10581061
node.el = o;
10591062
self.placeholder.hide();
10601063

0 commit comments

Comments
 (0)