diff --git a/README.md b/README.md index 2c79049..d368831 100644 --- a/README.md +++ b/README.md @@ -444,6 +444,7 @@ Changes - fix `setStatic` method - add `setAnimation` method to API - add `setGridWidth` method ([#227](https://github.com/troolee/gridstack.js/issues/227)) +- add `removable`/`removeTimeout` #### v0.2.4 (2016-02-15) diff --git a/demo/two.html b/demo/two.html index 7219455..320c1f3 100644 --- a/demo/two.html +++ b/demo/two.html @@ -35,6 +35,14 @@ text-align: center; background-color: #18bc9c; } + + #grid2 .grid-stack-item-content { + background-color: #9caabc; + } + + .grid-stack-item-removing { + opacity: 0.5; + } @@ -58,7 +66,8 @@ $(function () { var options = { width: 6, - float: true + float: true, + removable: true }; $('#grid1').gridstack(options); $('#grid2').gridstack(options); diff --git a/doc/README.md b/doc/README.md index b51a62b..ecb86be 100644 --- a/doc/README.md +++ b/doc/README.md @@ -75,6 +75,8 @@ gridstack.js API - `placeholderClass` - class for placeholder (default: `'grid-stack-placeholder'`) - `placeholderText` - placeholder default content (default: `''`) - `resizable` - allows to override jQuery UI resizable options. (default: `{autoHide: true, handles: 'se'}`) +- `removable` - if `true` widgets could be removed by dragging outside of the grid (default: `false`) +- `removeTimeout` - time in milliseconds before widget is being removed while dragging outside of the grid. (default: `2000`) - `rtl` - if `true` turns grid to RTL. Possible values are `true`, `false`, `'auto'` (default: `'auto'`) See [example](http://troolee.github.io/gridstack.js/demo/rtl.html) - `staticGrid` - makes grid static (default `false`). If true widgets are not movable/resizable. You don't even need jQueryUI draggable/resizable. A CSS class `grid-stack-static` is also added to the container. - `verticalMargin` - vertical gap size (default: `20`). Can be: diff --git a/src/gridstack.js b/src/gridstack.js index e27de5a..752dda6 100644 --- a/src/gridstack.js +++ b/src/gridstack.js @@ -534,7 +534,9 @@ }), disableDrag: opts.disableDrag || false, disableResize: opts.disableResize || false, - rtl: 'auto' + rtl: 'auto', + removable: false, + removeTimeout: 2000 }); if (this.opts.rtl === 'auto') { @@ -805,17 +807,73 @@ var cellWidth; var cellHeight; + var removeTimeout; + + var setupRemovingTimeout = function() { + if (removeTimeout || !self.opts.removable) { + return; + } + removeTimeout = setTimeout(function() { + el.addClass('grid-stack-item-removing'); + node._isAboutToRemove = true; + }, self.opts.removeTimeout); + }; + var clearRemovingTimeout = function() { + if (!removeTimeout) { + return; + } + clearTimeout(removeTimeout); + removeTimeout = null; + el.removeClass('grid-stack-item-removing'); + node._isAboutToRemove = false; + }; var dragOrResize = function(event, ui) { var x = Math.round(ui.position.left / cellWidth); var y = Math.floor((ui.position.top + cellHeight / 2) / cellHeight); var width; var height; + if (event.type != 'drag') { width = Math.round(ui.size.width / cellWidth); height = Math.round(ui.size.height / cellHeight); } + if (event.type == 'drag') { + if (x < 0 || x >= self.grid.width || y < 0) { + setupRemovingTimeout(); + + x = node._beforeDragX; + y = node._beforeDragY; + + self.placeholder.detach(); + self.placeholder.hide(); + self.grid.removeNode(node); + self._updateContainerHeight(); + + node._temporaryRemoved = true; + } else { + clearRemovingTimeout(); + + if (node._temporaryRemoved) { + self.grid.addNode(node); + self.placeholder + .attr('data-gs-x', x) + .attr('data-gs-y', y) + .attr('data-gs-width', width) + .attr('data-gs-height', height) + .show(); + self.container.append(self.placeholder); + node.el = self.placeholder; + node._temporaryRemoved = false; + } + } + } else if (event.type == 'resize') { + if (x < 0) { + return; + } + } + if (!self.grid.canMoveNode(node, x, y, width, height)) { return; } @@ -838,6 +896,8 @@ .attr('data-gs-height', o.attr('data-gs-height')) .show(); node.el = self.placeholder; + node._beforeDragX = node.x; + node._beforeDragY = node.y; el.resizable('option', 'minWidth', cellWidth * (node.minWidth || 1)); el.resizable('option', 'minHeight', strictCellHeight * (node.minHeight || 1)); @@ -848,18 +908,39 @@ }; var onEndMoving = function(event, ui) { + var forceNotify = false; self.placeholder.detach(); var o = $(this); node.el = o; self.placeholder.hide(); - o - .attr('data-gs-x', node.x) - .attr('data-gs-y', node.y) - .attr('data-gs-width', node.width) - .attr('data-gs-height', node.height) - .removeAttr('style'); + + if (node._isAboutToRemove) { + forceNotify = true; + el.removeData('_gridstack_node'); + el.remove(); + } else { + clearRemovingTimeout(); + if (!node._temporaryRemoved) { + o + .attr('data-gs-x', node.x) + .attr('data-gs-y', node.y) + .attr('data-gs-width', node.width) + .attr('data-gs-height', node.height) + .removeAttr('style'); + } else { + o + .attr('data-gs-x', node._beforeDragX) + .attr('data-gs-y', node._beforeDragY) + .attr('data-gs-width', node.width) + .attr('data-gs-height', node.height) + .removeAttr('style'); + node.x = node._beforeDragX; + node.y = node._beforeDragY; + self.grid.addNode(node); + } + } self._updateContainerHeight(); - self._triggerChangeEvent(); + self._triggerChangeEvent(forceNotify); self.grid.endUpdate();