Release v0.2.0

This commit is contained in:
vieron
2013-10-26 19:54:50 +02:00
parent 21f53a7bd4
commit 277d8a7753
8 changed files with 1001 additions and 253 deletions
+25
View File
@@ -0,0 +1,25 @@
<a name="v0.2.0"></a>
## v0.2.0 (2013-10-26)
#### Bug Fixes
* fixes and improvements in widget-resizing. ([ae02b32b](http://github.com/ducksboard/gridster.js/commit/ae02b32b9210c6328f4acc339e215ae50c134f77), closes [#32](http://github.com/ducksboard/gridster.js/issues/32))
* **gridster:**
* the preview holder should not always use `li` ([1ade74e2](http://github.com/ducksboard/gridster.js/commit/1ade74e239485b07e870fca44e1eafb3ff1ae283))
* overlapping widget problem ([31fd8d6b](http://github.com/ducksboard/gridster.js/commit/31fd8d6ba893e4c39b91ba30d429e37f3da30b24))
* Orphan preview holder when dragging is interrupted ([1b13617d](http://github.com/ducksboard/gridster.js/commit/1b13617df2ce53235bdf3a1e38f1555f529663c3))
* remove_widget Returns the instance of the Gridster Class ([5bfbc5c0](http://github.com/ducksboard/gridster.js/commit/5bfbc5c0b5ab49c2a7c651327ce2e0f30f594985))
#### Features
* **draggable:**
* new config option to move or not the dragged element ([4d9b2a84](http://github.com/ducksboard/gridster.js/commit/4d9b2a84f11cb7cb2ddad51c158d92b82e7bc447))
* CSS selectors support in `ignore_dragging` config opt ([0f956249](http://github.com/ducksboard/gridster.js/commit/0f95624925be97aee7a8450707e04e887e4dac58))
* pass previous position to the drag callback ([055cc0e4](http://github.com/ducksboard/gridster.js/commit/055cc0e4f6f9de5721986515656ac894855f9e02))
* Don't start new drag if previous one hasn't stopped ([91ca6572](http://github.com/ducksboard/gridster.js/commit/91ca65721c2eb32b5dec82cdc5e5e7f81dac329e))
* pass useful data to all drag callbacks ([8dda2410](http://github.com/ducksboard/gridster.js/commit/8dda2410f300592706985c05141ca6b702977dc0))
* **gridster:** drag-and-drop widget resizing ([e1924053](http://github.com/ducksboard/gridster.js/commit/e19240532de0bad35ffe6e5fc63934819390adc5))
* **utils:** add delay helper to utils ([faa6c5db](http://github.com/ducksboard/gridster.js/commit/faa6c5db0002feccf681e9f919ed583eef152773))
+63 -6
View File
@@ -1,4 +1,4 @@
/*! gridster.js - v0.1.0 - 2013-06-14
/*! gridster.js - v0.2.0 - 2013-10-26
* http://gridster.net/
* Copyright (c) 2013 ducksboard; Licensed MIT */
@@ -15,19 +15,20 @@
transition: height .4s;
}
.gridster .gs_w{
.gridster .gs-w {
z-index: 2;
position: absolute;
}
.ready .gs_w:not(.preview-holder) {
.ready .gs-w:not(.preview-holder) {
-webkit-transition: opacity .3s, left .3s, top .3s;
-moz-transition: opacity .3s, left .3s, top .3s;
-o-transition: opacity .3s, left .3s, top .3s;
transition: opacity .3s, left .3s, top .3s;
}
.ready .gs_w:not(.preview-holder) {
.ready .gs-w:not(.preview-holder),
.ready .resize-preview-holder {
-webkit-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
-moz-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
-o-transition: opacity .3s, left .3s, top .3s, width .3s, height .3s;
@@ -50,7 +51,8 @@
transition: left .3s, top .3s!important;
}
.gridster .dragging {
.gridster .dragging,
.gridster .resizing {
z-index: 10!important;
-webkit-transition: all 0s !important;
-moz-transition: all 0s !important;
@@ -58,7 +60,62 @@
transition: all 0s !important;
}
.gs-resize-handle {
position: absolute;
z-index: 1;
}
.gs-resize-handle-both {
width: 20px;
height: 20px;
bottom: -8px;
right: -8px;
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4=');
background-position: top left;
background-repeat: no-repeat;
cursor: se-resize;
z-index: 20;
}
.gs-resize-handle-x {
top: 0;
bottom: 13px;
right: -5px;
width: 10px;
cursor: e-resize;
}
.gs-resize-handle-y {
left: 0;
right: 13px;
bottom: -5px;
height: 10px;
cursor: s-resize;
}
.gs-w:hover .gs-resize-handle,
.resizing .gs-resize-handle {
opacity: 1;
}
.gs-resize-handle,
.gs-w.dragging .gs-resize-handle {
opacity: 0;
}
.gs-resize-disabled .gs-resize-handle {
display: none!important;
}
[data-max-sizex="1"] .gs-resize-handle-x,
[data-max-sizey="1"] .gs-resize-handle-y,
[data-max-sizey="1"][data-max-sizex="1"] .gs-resize-handle {
display: none !important;
}
/* Uncomment this if you set helper : "clone" in draggable options */
/*.gridster .player {
opacity:0;
}*/
}
*/
+453 -120
View File
@@ -1,4 +1,4 @@
/*! gridster.js - v0.1.0 - 2013-06-14
/*! gridster.js - v0.2.0 - 2013-10-26
* http://gridster.net/
* Copyright (c) 2013 ducksboard; Licensed MIT */
@@ -317,6 +317,14 @@
}(jQuery, window, document));
;(function(window, undefined) {
window.delay = function(func, wait) {
var args = Array.prototype.slice.call(arguments, 2);
return setTimeout(function(){ return func.apply(null, args); }, wait);
};
/* Debounce and throttle functions taken from underscore.js */
window.debounce = function(func, wait, immediate) {
var timeout;
@@ -358,20 +366,22 @@
})(window);
;(function($, window, document, undefined){
;(function($, window, document, undefined) {
var defaults = {
items: '.gs_w',
items: 'li',
distance: 1,
limit: true,
offset_left: 0,
autoscroll: true,
ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'],
handle: null,
container_width: 0 // 0 == auto
// drag: function(e){},
// start : function(e, ui){},
// stop : function(e){}
container_width: 0, // 0 == auto
move_element: true,
helper: false // or 'clone'
// drag: function(e) {},
// start : function(e, ui) {},
// stop : function(e) {}
};
var $window = $(window);
@@ -480,21 +490,36 @@
if (this.options.limit) {
if (left > this.player_max_left) {
left = this.player_max_left;
}else if(left < this.player_min_left) {
} else if(left < this.player_min_left) {
left = this.player_min_left;
}
}
return {
left: left,
top: top,
mouse_left: mouse_actual_pos.left,
mouse_top: mouse_actual_pos.top
position: {
left: left,
top: top
},
pointer: {
left: mouse_actual_pos.left,
top: mouse_actual_pos.top,
diff_left: diff_x,
diff_top: diff_y + this.scrollOffset
}
};
};
fn.manage_scroll = function(offset) {
fn.get_drag_data = function(e) {
var offset = this.get_offset(e);
offset.$player = this.$player;
offset.$helper = this.helper ? this.$helper : this.$player;
return offset;
};
fn.manage_scroll = function(data) {
/* scroll document */
var nextScrollTop;
var scrollTop = $window.scrollTop();
@@ -504,8 +529,8 @@
var mouse_down_zone = max_window_y - 50;
var mouse_up_zone = min_window_y + 50;
var abs_mouse_left = offset.mouse_left;
var abs_mouse_top = min_window_y + offset.mouse_top;
var abs_mouse_left = data.pointer.left;
var abs_mouse_top = min_window_y + data.pointer.top;
var max_player_y = (this.doc_height - this.window_height +
this.player_height);
@@ -551,7 +576,7 @@
this.mouse_init_pos = this.get_mouse_pos(e);
this.offsetY = this.mouse_init_pos.top - this.el_init_pos.top;
this.$body.on(pointer_events.move, function(mme){
this.$body.on(pointer_events.move, function(mme) {
var mouse_actual_pos = self.get_mouse_pos(mme);
var diff_x = Math.abs(
mouse_actual_pos.left - self.mouse_init_pos.left);
@@ -582,8 +607,10 @@
fn.on_dragstart = function(e) {
e.preventDefault();
this.drag_start = true;
this.is_dragging = true;
if (this.is_dragging) { return this; }
this.drag_start = this.is_dragging = true;
var offset = this.$container.offset();
this.baseX = Math.round(offset.left);
this.baseY = Math.round(offset.top);
@@ -593,9 +620,10 @@
this.$helper = this.$player.clone()
.appendTo(this.$container).addClass('helper');
this.helper = true;
}else{
} else {
this.helper = false;
}
this.scrollOffset = 0;
this.el_init_offset = this.$player.offset();
this.player_width = this.$player.width();
@@ -606,52 +634,43 @@
this.options.offset_left);
if (this.options.start) {
this.options.start.call(this.$player, e, {
helper: this.helper ? this.$helper : this.$player
});
this.options.start.call(this.$player, e, this.get_drag_data(e));
}
return false;
};
fn.on_dragmove = function(e) {
var offset = this.get_offset(e);
var data = this.get_drag_data(e);
this.options.autoscroll && this.manage_scroll(offset);
this.options.autoscroll && this.manage_scroll(data);
(this.helper ? this.$helper : this.$player).css({
'position': 'absolute',
'left' : offset.left,
'top' : offset.top
});
if (this.options.move_element) {
(this.helper ? this.$helper : this.$player).css({
'position': 'absolute',
'left' : data.position.left,
'top' : data.position.top
});
}
var ui = {
'position': {
'left': offset.left,
'top': offset.top
}
};
var last_position = this.last_position || data.position;
data.prev_position = last_position;
if (this.options.drag) {
this.options.drag.call(this.$player, e, ui);
this.options.drag.call(this.$player, e, data);
}
this.last_position = data.position;
return false;
};
fn.on_dragstop = function(e) {
var offset = this.get_offset(e);
var data = this.get_drag_data(e);
this.drag_start = false;
var ui = {
'position': {
'left': offset.left,
'top': offset.top
}
};
if (this.options.stop) {
this.options.stop.call(this.$player, e, ui);
this.options.stop.call(this.$player, e, data);
}
if (this.helper) {
@@ -679,8 +698,7 @@
this.disabled = true;
};
fn.destroy = function(){
fn.destroy = function() {
this.disable();
this.$container.off('.gridster-draggable');
@@ -695,16 +713,12 @@
return !$(event.target).is(this.options.handle);
}
return $.inArray(event.target.nodeName, this.options.ignore_dragging) >= 0;
return $(event.target).is(this.options.ignore_dragging.join(', '));
};
//jQuery adapter
$.fn.drag = function ( options ) {
return this.each(function () {
if (!$.data(this, 'drag')) {
$.data(this, 'drag', new Draggable( this, options ));
}
});
return new Draggable(this, options);
};
@@ -722,7 +736,7 @@
min_cols: 1,
max_cols: null,
min_rows: 15,
max_size_x: 6,
max_size_x: false,
autogenerate_stylesheet: true,
avoid_overlapped_widgets: true,
serialize_params: function($w, wgd) {
@@ -735,7 +749,15 @@
},
collision: {},
draggable: {
items: '.gs-w',
distance: 4
},
resize: {
enabled: false,
axes: ['x', 'y', 'both'],
handle_append_to: '',
handle_class: 'gs-resize-handle',
max_size: [Infinity, Infinity]
}
};
@@ -784,6 +806,19 @@
* @param {Object} [options.draggable] An Object with all options for
* Draggable class you want to overwrite. See Draggable docs for more
* info.
* @param {Object} [options.resize] An Object with resize config
* options.
* @param {Boolean} [options.resize.enabled] Set to true to enable
* resizing.
* @param {Array} [options.resize.axes] Axes in which widgets can be
* resized. Possible values: ['x', 'y', 'both'].
* @param {String} [options.resize.handle_append_to] Set a valid CSS
* selector to append resize handles to.
* @param {String} [options.resize.handle_class] CSS class name used
* by resize handles.
* @param {Array} [options.resize.max_size] Limit widget dimensions
* when resizing. Array values should be integers:
* `[max_cols_occupied, max_rows_occupied]`
*
* @constructor
*/
@@ -791,7 +826,8 @@
this.options = $.extend(true, defaults, options);
this.$el = $(el);
this.$wrapper = this.$el.parent();
this.$widgets = this.$el.children(this.options.widget_selector).addClass('gs_w');
this.$widgets = this.$el.children(
this.options.widget_selector).addClass('gs-w');
this.widgets = [];
this.$changed = $([]);
this.wrapper_width = this.$wrapper.width();
@@ -810,13 +846,16 @@
var fn = Gridster.prototype;
fn.init = function() {
this.options.resize.enabled && this.setup_resize();
this.generate_grid_and_stylesheet();
this.get_widgets_from_DOM();
this.set_dom_grid_height();
this.$wrapper.addClass('ready');
this.draggable();
this.options.resize.enabled && this.resizable();
$(window).bind('resize.gridster', throttle($.proxy(this.recalculate_faux_grid, this), 200));
$(window).bind('resize.gridster', throttle(
$.proxy(this.recalculate_faux_grid, this), 200));
};
@@ -845,6 +884,33 @@
};
/**
* Disables drag-and-drop widget resizing.
*
* @method disable
* @return {Class} Returns instance of gridster Class.
*/
fn.disable_resize = function() {
this.$el.addClass('gs-resize-disabled');
this.resize_api.disable();
return this;
};
/**
* Enables drag-and-drop widget resizing.
*
* @method enable
* @return {Class} Returns instance of gridster Class.
*/
fn.enable_resize = function() {
this.$el.removeClass('gs-resize-disabled');
this.resize_api.enable();
return this;
};
/**
* Add a new widget to the grid.
*
@@ -855,10 +921,11 @@
* @param {Number} [size_y] The nº of columns the widget occupies vertically.
* @param {Number} [col] The column the widget should start in.
* @param {Number} [row] The row the widget should start in.
* @param {Array} [max_size] max_size Maximun size (in units) for width and height.
* @return {HTMLElement} Returns the jQuery wrapped HTMLElement representing.
* the widget that was just created.
*/
fn.add_widget = function(html, size_x, size_y, col, row) {
fn.add_widget = function(html, size_x, size_y, col, row, max_size) {
var pos;
size_x || (size_x = 1);
size_y || (size_y = 1);
@@ -879,7 +946,7 @@
'data-row': pos.row,
'data-sizex' : size_x,
'data-sizey' : size_y
}).addClass('gs_w').appendTo(this.$el).hide();
}).addClass('gs-w').appendTo(this.$el).hide();
this.$widgets = this.$widgets.add($w);
@@ -888,26 +955,73 @@
this.add_faux_rows(pos.size_y);
//this.add_faux_cols(pos.size_x);
if (max_size) {
this.set_widget_max_size($w, max_size);
}
this.set_dom_grid_height();
return $w.fadeIn();
};
/**
* Change widget size limits.
*
* @method set_widget_max_size
* @param {HTMLElement|Number} $widget The jQuery wrapped HTMLElement
* representing the widget or an index representing the desired widget.
* @param {Array} max_size Maximun size (in units) for width and height.
* @return {HTMLElement} Returns instance of gridster Class.
*/
fn.set_widget_max_size = function($widget, max_size) {
$widget = typeof $widget === 'number' ?
this.$widgets.eq($widget) : $widget;
/**
* Change the size of a widget.
if (!$widget.length) { return this; }
var wgd = $widget.data('coords').grid;
wgd.max_size_x = max_size[0];
wgd.max_size_y = max_size[1];
return this;
};
/**
* Append the resize handle into a widget.
*
* @method add_resize_handle
* @param {HTMLElement} $widget The jQuery wrapped HTMLElement
* representing the widget.
* @return {HTMLElement} Returns instance of gridster Class.
*/
fn.add_resize_handle = function($w) {
var append_to = this.options.resize.handle_append_to;
$(this.resize_handle_tpl).appendTo( append_to ? $(append_to, $w) : $w);
return this;
};
/**
* Change the size of a widget. Width is limited to the current grid width.
*
* @method resize_widget
* @param {HTMLElement} $widget The jQuery wrapped HTMLElement
* representing the widget.
* @param {Number} size_x The number of columns that will occupy the widget.
* @param {Number} size_y The number of rows that will occupy the widget.
* @param {Function} callback Function executed when the widget is removed.
* @param {Boolean} [reposition] Set to false to not move the widget to
* the left if there is insufficient space on the right.
* By default <code>size_x</code> is limited to the space available from
* the column where the widget begins, until the last column to the right.
* @param {Function} [callback] Function executed when the widget is removed.
* @return {HTMLElement} Returns $widget.
*/
fn.resize_widget = function($widget, size_x, size_y, callback) {
fn.resize_widget = function($widget, size_x, size_y, reposition, callback) {
var wgd = $widget.coords().grid;
reposition !== false && (reposition = true);
size_x || (size_x = wgd.size_x);
size_y || (size_y = wgd.size_y);
@@ -915,20 +1029,20 @@
size_x = this.cols;
}
var old_cells_occupied = this.get_cells_occupied(wgd);
var old_size_x = wgd.size_x;
var old_size_y = wgd.size_y;
var old_col = wgd.col;
var new_col = old_col;
var wider = size_x > old_size_x;
var taller = size_y > old_size_y;
if (old_col + size_x - 1 > this.cols) {
if (reposition && old_col + size_x - 1 > this.cols) {
var diff = old_col + (size_x - 1) - this.cols;
var c = old_col - diff;
new_col = Math.max(1, c);
}
if (size_y > old_size_y) {
this.add_faux_rows(Math.max(size_y - old_size_y, 0));
}
var new_grid_data = {
col: new_col,
row: wgd.row,
@@ -936,7 +1050,34 @@
size_y: size_y
};
var new_cells_occupied = this.get_cells_occupied(new_grid_data);
this.mutate_widget_in_gridmap($widget, wgd, new_grid_data);
this.set_dom_grid_height();
if (callback) {
callback.call(this, new_grid_data.size_x, new_grid_data.size_y);
}
return $widget;
};
/**
* Mutate widget dimensions and position in the grid map.
*
* @method mutate_widget_in_gridmap
* @param {HTMLElement} $widget The jQuery wrapped HTMLElement
* representing the widget to mutate.
* @param {Object} wgd Current widget grid data (col, row, size_x, size_y).
* @param {Object} new_wgd New widget grid data.
* @return {HTMLElement} Returns instance of gridster Class.
*/
fn.mutate_widget_in_gridmap = function($widget, wgd, new_wgd) {
var old_size_x = wgd.size_x;
var old_size_y = wgd.size_y;
var old_cells_occupied = this.get_cells_occupied(wgd);
var new_cells_occupied = this.get_cells_occupied(new_wgd);
var empty_cols = [];
$.each(old_cells_occupied.cols, function(i, col) {
@@ -970,48 +1111,46 @@
if (occupied_cols.length) {
var cols_to_empty = [
new_col, wgd.row, size_x, Math.min(old_size_y, size_y), $widget
new_wgd.col, new_wgd.row, new_wgd.size_x, Math.min(old_size_y, new_wgd.size_y), $widget
];
this.empty_cells.apply(this, cols_to_empty);
}
if (occupied_rows.length) {
var rows_to_empty = [new_col, wgd.row, size_x, size_y, $widget];
var rows_to_empty = [new_wgd.col, new_wgd.row, new_wgd.size_x, new_wgd.size_y, $widget];
this.empty_cells.apply(this, rows_to_empty);
}
wgd.col = new_col;
wgd.size_x = size_x;
wgd.size_y = size_y;
this.add_to_gridmap(new_grid_data, $widget);
// not the same that wgd = new_wgd;
wgd.col = new_wgd.col;
wgd.row = new_wgd.row;
wgd.size_x = new_wgd.size_x;
wgd.size_y = new_wgd.size_y;
this.add_to_gridmap(new_wgd, $widget);
$widget.removeClass('player-revert');
//update coords instance attributes
$widget.data('coords').update({
width: (size_x * this.options.widget_base_dimensions[0] +
((size_x - 1) * this.options.widget_margins[0]) * 2),
height: (size_y * this.options.widget_base_dimensions[1] +
((size_y - 1) * this.options.widget_margins[1]) * 2)
width: (new_wgd.size_x * this.options.widget_base_dimensions[0] +
((new_wgd.size_x - 1) * this.options.widget_margins[0]) * 2),
height: (new_wgd.size_y * this.options.widget_base_dimensions[1] +
((new_wgd.size_y - 1) * this.options.widget_margins[1]) * 2)
});
if (size_y > old_size_y) {
this.add_faux_rows(size_y - old_size_y);
}
if (size_x > old_size_x) {
this.add_faux_cols(size_x - old_size_x);
}
$widget.attr({
'data-col': new_col,
'data-sizex': size_x,
'data-sizey': size_y
'data-col': new_wgd.col,
'data-row': new_wgd.row,
'data-sizex': new_wgd.size_x,
'data-sizey': new_wgd.size_y
});
if (empty_cols.length) {
var cols_to_remove_holes = [
empty_cols[0], wgd.row,
empty_cols[0], new_wgd.row,
empty_cols.length,
Math.min(old_size_y, size_y),
Math.min(old_size_y, new_wgd.size_y),
$widget
];
@@ -1020,18 +1159,17 @@
if (empty_rows.length) {
var rows_to_remove_holes = [
new_col, wgd.row, size_x, size_y, $widget
new_wgd.col, new_wgd.row, new_wgd.size_x, new_wgd.size_y, $widget
];
this.remove_empty_cells.apply(this, rows_to_remove_holes);
}
if (callback) {
callback.call(this, size_x, size_y);
}
this.move_widget_up($widget);
return $widget;
return this;
};
/**
* Move down widgets in cells represented by the arguments col, row, size_x,
* size_y
@@ -1184,6 +1322,8 @@
callback.call(this, el);
}
}, this));
return this;
};
@@ -1246,12 +1386,13 @@
* @return {Array} Returns the instance of the Gridster class.
*/
fn.register_widget = function($el) {
var wgd = {
'col': parseInt($el.attr('data-col'), 10),
'row': parseInt($el.attr('data-row'), 10),
'size_x': parseInt($el.attr('data-sizex'), 10),
'size_y': parseInt($el.attr('data-sizey'), 10),
'max_size_x': parseInt($el.attr('data-max-sizex'), 10) || false,
'max_size_y': parseInt($el.attr('data-max-sizey'), 10) || false,
'el': $el
};
@@ -1259,8 +1400,7 @@
!this.can_move_to(
{size_x: wgd.size_x, size_y: wgd.size_y}, wgd.col, wgd.row)
) {
wgd = this.next_position(wgd.size_x, wgd.size_y);
wgd.el = $el;
$.extend(wgd, this.next_position(wgd.size_x, wgd.size_y));
$el.attr({
'data-col': wgd.col,
'data-row': wgd.row,
@@ -1271,12 +1411,13 @@
// attach Coord object to player data-coord attribute
$el.data('coords', $el.coords());
// Extend Coord object with grid position info
$el.data('coords').grid = wgd;
this.add_to_gridmap(wgd, $el);
this.options.resize.enabled && this.add_resize_handle($el);
return this;
};
@@ -1349,13 +1490,15 @@
var draggable_options = $.extend(true, {}, this.options.draggable, {
offset_left: this.options.widget_margins[0],
container_width: this.container_width,
ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON',
'.' + this.options.resize.handle_class],
start: function(event, ui) {
self.$widgets.filter('.player-revert')
.removeClass('player-revert');
self.$player = $(this);
self.$helper = self.options.draggable.helper === 'clone' ?
$(ui.helper) : self.$player;
self.$helper = $(ui.$helper);
self.helper = !self.$helper.is(self.$player);
self.on_start_drag.call(self, event, ui);
@@ -1371,7 +1514,51 @@
}, 60)
});
this.drag_api = this.$el.drag(draggable_options).data('drag');
this.drag_api = this.$el.drag(draggable_options);
return this;
};
/**
* Bind resize events to get resize working.
*
* @method resizable
* @return {Class} Returns instance of gridster Class.
*/
fn.resizable = function() {
this.resize_api = this.$el.drag({
items: '.' + this.options.resize.handle_class,
offset_left: this.options.widget_margins[0],
container_width: this.container_width,
move_element: false,
start: $.proxy(this.on_start_resize, this),
stop: $.proxy(function(event, ui) {
delay($.proxy(function() {
this.on_stop_resize(event, ui);
}, this), 120);
}, this),
drag: throttle($.proxy(this.on_resize, this), 60)
});
return this;
};
/**
* Setup things required for resizing. Like build templates for drag handles.
*
* @method setup_resize
* @return {Class} Returns instance of gridster Class.
*/
fn.setup_resize = function() {
this.resize_handle_class = this.options.resize.handle_class;
var axes = this.options.resize.axes;
var handle_tpl = '<span class="' + this.resize_handle_class + ' ' +
this.resize_handle_class + '-{type}" />';
this.resize_handle_tpl = $.map(axes, function(type) {
return handle_tpl.replace('{type}', type);
}).join('');
return this;
};
@@ -1381,10 +1568,9 @@
*
* @method on_start_drag
* @param {Event} event The original browser event
* @param {Object} ui A prepared ui object.
* @param {Object} ui A prepared ui object with useful drag-related data
*/
fn.on_start_drag = function(event, ui) {
this.$helper.add(this.$player).add(this.$wrapper).addClass('dragging');
this.$player.addClass('player');
@@ -1406,12 +1592,11 @@
this.last_cols = [];
this.last_rows = [];
// see jquery.collision.js
this.collision_api = this.$helper.collision(
colliders, this.options.collision);
this.$preview_holder = $('<li />', {
this.$preview_holder = $('<' + this.$player.get(0).tagName + ' />', {
'class': 'preview-holder',
'data-row': this.$player.attr('data-row'),
'data-col': this.$player.attr('data-col'),
@@ -1432,7 +1617,7 @@
*
* @method on_drag
* @param {Event} event The original browser event
* @param {Object} ui A prepared ui object.
* @param {Object} ui A prepared ui object with useful drag-related data
*/
fn.on_drag = function(event, ui) {
//break if dragstop has been fired
@@ -1475,7 +1660,7 @@
*
* @method on_stop_drag
* @param {Event} event The original browser event
* @param {Object} ui A prepared ui object.
* @param {Object} ui A prepared ui object with useful drag-related data
*/
fn.on_stop_drag = function(event, ui) {
this.$helper.add(this.$player).add(this.$wrapper)
@@ -1483,7 +1668,8 @@
ui.position.left = ui.position.left + this.baseX;
ui.position.top = ui.position.top + this.baseY;
this.colliders_data = this.collision_api.get_closest_colliders(ui.position);
this.colliders_data = this.collision_api.get_closest_colliders(
ui.position);
this.on_overlapped_column_change(
this.on_start_overlapping_column,
@@ -1531,6 +1717,148 @@
};
/**
* This function is executed every time a widget starts to be resized.
*
* @method on_start_resize
* @param {Event} event The original browser event
* @param {Object} ui A prepared ui object with useful drag-related data
*/
fn.on_start_resize = function(event, ui) {
this.$resized_widget = ui.$player.closest('.gs-w');
this.resize_coords = this.$resized_widget.coords();
this.resize_wgd = this.resize_coords.grid;
this.resize_initial_width = this.resize_coords.coords.width;
this.resize_initial_height = this.resize_coords.coords.height;
this.resize_initial_sizex = this.resize_coords.grid.size_x;
this.resize_initial_sizey = this.resize_coords.grid.size_y;
this.resize_last_sizex = this.resize_initial_sizex;
this.resize_last_sizey = this.resize_initial_sizey;
this.resize_max_size_x = Math.min(this.resize_wgd.max_size_x ||
this.options.resize.max_size[0], this.cols - this.resize_wgd.col + 1);
this.resize_max_size_y = this.resize_wgd.max_size_y ||
this.options.resize.max_size[1];
this.resize_dir = {
right: ui.$player.is('.' + this.resize_handle_class + '-x'),
bottom: ui.$player.is('.' + this.resize_handle_class + '-y')
};
this.$resized_widget.css({
'min-width': this.options.widget_base_dimensions[0],
'min-height': this.options.widget_base_dimensions[1]
});
var nodeName = this.$resized_widget.get(0).tagName;
this.$resize_preview_holder = $('<' + nodeName + ' />', {
'class': 'preview-holder resize-preview-holder',
'data-row': this.$resized_widget.attr('data-row'),
'data-col': this.$resized_widget.attr('data-col'),
'css': {
'width': this.resize_initial_width,
'height': this.resize_initial_height
}
}).appendTo(this.$el);
this.$resized_widget.addClass('resizing');
};
/**
* This function is executed every time a widget stops being resized.
*
* @method on_stop_resize
* @param {Event} event The original browser event
* @param {Object} ui A prepared ui object with useful drag-related data
*/
fn.on_stop_resize = function(event, ui) {
this.$resized_widget
.removeClass('resizing')
.css({
'width': '',
'height': ''
});
delay($.proxy(function() {
this.$resize_preview_holder
.remove()
.css({
'min-width': '',
'min-height': ''
});
}, this), 300);
};
/**
* This function is executed when a widget is being resized.
*
* @method on_resize
* @param {Event} event The original browser event
* @param {Object} ui A prepared ui object with useful drag-related data
*/
fn.on_resize = function(event, ui) {
var rel_x = (ui.pointer.diff_left);
var rel_y = (ui.pointer.diff_top);
var wbd_x = this.options.widget_base_dimensions[0];
var wbd_y = this.options.widget_base_dimensions[1];
var max_width = Infinity;
var max_height = Infinity;
var inc_units_x = Math.ceil((rel_x /
(this.options.widget_base_dimensions[0] +
this.options.widget_margins[0] * 2)) - 0.2);
var inc_units_y = Math.ceil((rel_y /
(this.options.widget_base_dimensions[1] +
this.options.widget_margins[1] * 2)) - 0.2);
var size_x = Math.max(1, this.resize_initial_sizex + inc_units_x);
var size_y = Math.max(1, this.resize_initial_sizey + inc_units_y);
size_x = Math.min(size_x, this.resize_max_size_x);
max_width = (this.resize_max_size_x * wbd_x) +
((size_x - 1) * this.options.widget_margins[0] * 2);
size_y = Math.min(size_y, this.resize_max_size_y);
max_height = (this.resize_max_size_y * wbd_y) +
((size_y - 1) * this.options.widget_margins[1] * 2);
if (this.resize_dir.right) {
size_y = this.resize_initial_sizey;
} else if (this.resize_dir.bottom) {
size_x = this.resize_initial_sizex;
}
var css_props = {};
!this.resize_dir.bottom && (css_props.width = Math.min(
this.resize_initial_width + rel_x, max_width));
!this.resize_dir.right && (css_props.height = Math.min(
this.resize_initial_height + rel_y, max_height));
this.$resized_widget.css(css_props);
if (size_x !== this.resize_last_sizex ||
size_y !== this.resize_last_sizey) {
this.resize_widget(this.$resized_widget, size_x, size_y, false);
this.$resize_preview_holder.css({
'width': '',
'height': ''
}).attr({
'data-row': this.$resized_widget.attr('data-row'),
'data-sizex': size_x,
'data-sizey': size_y
});
}
this.resize_last_sizex = size_x;
this.resize_last_sizey = size_y;
};
/**
* Executes the callbacks passed as arguments when a column begins to be
* overlapped or stops being overlapped.
@@ -2036,8 +2364,9 @@
}, this));
}
var $widgets_under_ph = this.get_widgets_under_player(
this.cells_occupied_by_placeholder);
var $widgets_under_ph = this.get_widgets_under_player(this.cells_occupied_by_placeholder);
if ($widgets_under_ph.length) {
$widgets_under_ph.each($.proxy(function(i, widget) {
var $w = $(widget);
@@ -2429,10 +2758,14 @@
* @return {Class} Returns the instance of the Gridster Class.
*/
fn.move_widget_down = function($widget, y_units) {
var el_grid_data = $widget.coords().grid;
var actual_row = el_grid_data.row;
var moved = [];
var y_diff = y_units;
var el_grid_data, actual_row, moved, y_diff;
if (y_units <= 0) { return false; }
el_grid_data = $widget.coords().grid;
actual_row = el_grid_data.row;
moved = [];
y_diff = y_units;
if (!$widget) { return false; }
@@ -2971,7 +3304,7 @@
*/
fn.generate_stylesheet = function(opts) {
var styles = '';
var max_size_x = this.options.max_size_x;
var max_size_x = this.options.max_size_x || this.cols;
var max_rows = 0;
var max_cols = 0;
var i;
@@ -3003,7 +3336,7 @@
styles += (opts.namespace + ' [data-col="'+ (i + 1) + '"] { left:' +
((i * opts.widget_base_dimensions[0]) +
(i * opts.widget_margins[0]) +
((i + 1) * opts.widget_margins[0])) + 'px;} ');
((i + 1) * opts.widget_margins[0])) + 'px; }\n');
}
/* generate CSS styles for rows */
@@ -3011,19 +3344,19 @@
styles += (opts.namespace + ' [data-row="' + (i + 1) + '"] { top:' +
((i * opts.widget_base_dimensions[1]) +
(i * opts.widget_margins[1]) +
((i + 1) * opts.widget_margins[1]) ) + 'px;} ');
((i + 1) * opts.widget_margins[1]) ) + 'px; }\n');
}
for (var y = 1; y <= opts.rows; y++) {
styles += (opts.namespace + ' [data-sizey="' + y + '"] { height:' +
(y * opts.widget_base_dimensions[1] +
(y - 1) * (opts.widget_margins[1] * 2)) + 'px;}');
(y - 1) * (opts.widget_margins[1] * 2)) + 'px; }\n');
}
for (var x = 1; x <= max_size_x; x++) {
styles += (opts.namespace + ' [data-sizex="' + x + '"] { width:' +
(x * opts.widget_base_dimensions[0] +
(x - 1) * (opts.widget_margins[0] * 2)) + 'px;}');
(x - 1) * (opts.widget_margins[0] * 2)) + 'px; }\n');
}
return this.add_style_tag(styles);
+2 -2
View File
@@ -1,2 +1,2 @@
/*! gridster.js - v0.1.0 - 2013-06-14 - * http://gridster.net/ - Copyright (c) 2013 ducksboard; Licensed MIT */
.gridster{position:relative}.gridster>*{margin:0 auto;-webkit-transition:height .4s;-moz-transition:height .4s;-o-transition:height .4s;-ms-transition:height .4s;transition:height .4s}.gridster .gs_w{z-index:2;position:absolute}.ready .gs_w:not(.preview-holder){-webkit-transition:opacity .3s,left .3s,top .3s;-moz-transition:opacity .3s,left .3s,top .3s;-o-transition:opacity .3s,left .3s,top .3s;transition:opacity .3s,left .3s,top .3s}.ready .gs_w:not(.preview-holder){-webkit-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-moz-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-o-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;transition:opacity .3s,left .3s,top .3s,width .3s,height .3s}.gridster .preview-holder{z-index:1;position:absolute;background-color:#fff;border-color:#fff;opacity:.3}.gridster .player-revert{z-index:10!important;-webkit-transition:left .3s,top .3s!important;-moz-transition:left .3s,top .3s!important;-o-transition:left .3s,top .3s!important;transition:left .3s,top .3s!important}.gridster .dragging{z-index:10!important;-webkit-transition:all 0s!important;-moz-transition:all 0s!important;-o-transition:all 0s!important;transition:all 0s!important}
/*! gridster.js - v0.2.0 - 2013-10-26 - * http://gridster.net/ - Copyright (c) 2013 ducksboard; Licensed MIT */
.gridster{position:relative}.gridster>*{margin:0 auto;-webkit-transition:height .4s;-moz-transition:height .4s;-o-transition:height .4s;-ms-transition:height .4s;transition:height .4s}.gridster .gs-w{z-index:2;position:absolute}.ready .gs-w:not(.preview-holder){-webkit-transition:opacity .3s,left .3s,top .3s;-moz-transition:opacity .3s,left .3s,top .3s;-o-transition:opacity .3s,left .3s,top .3s;transition:opacity .3s,left .3s,top .3s}.ready .gs-w:not(.preview-holder),.ready .resize-preview-holder{-webkit-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-moz-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-o-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;transition:opacity .3s,left .3s,top .3s,width .3s,height .3s}.gridster .preview-holder{z-index:1;position:absolute;background-color:#fff;border-color:#fff;opacity:.3}.gridster .player-revert{z-index:10!important;-webkit-transition:left .3s,top .3s!important;-moz-transition:left .3s,top .3s!important;-o-transition:left .3s,top .3s!important;transition:left .3s,top .3s!important}.gridster .dragging,.gridster .resizing{z-index:10!important;-webkit-transition:all 0s!important;-moz-transition:all 0s!important;-o-transition:all 0s!important;transition:all 0s!important}.gs-resize-handle{position:absolute;z-index:1}.gs-resize-handle-both{width:20px;height:20px;bottom:-8px;right:-8px;background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4=);background-position:top left;background-repeat:no-repeat;cursor:se-resize;z-index:20}.gs-resize-handle-x{top:0;bottom:13px;right:-5px;width:10px;cursor:e-resize}.gs-resize-handle-y{left:0;right:13px;bottom:-5px;height:10px;cursor:s-resize}.gs-w:hover .gs-resize-handle,.resizing .gs-resize-handle{opacity:1}.gs-resize-handle,.gs-w.dragging .gs-resize-handle{opacity:0}.gs-resize-disabled .gs-resize-handle{display:none!important}[data-max-sizex="1"] .gs-resize-handle-x,[data-max-sizey="1"] .gs-resize-handle-y,[data-max-sizey="1"][data-max-sizex="1"] .gs-resize-handle{display:none!important}
+2 -2
View File
File diff suppressed because one or more lines are too long
+453 -120
View File
@@ -1,4 +1,4 @@
/*! gridster.js - v0.1.0 - 2013-06-14
/*! gridster.js - v0.2.0 - 2013-10-26
* http://gridster.net/
* Copyright (c) 2013 ducksboard; Licensed MIT */
@@ -317,6 +317,14 @@
}(jQuery, window, document));
;(function(window, undefined) {
window.delay = function(func, wait) {
var args = Array.prototype.slice.call(arguments, 2);
return setTimeout(function(){ return func.apply(null, args); }, wait);
};
/* Debounce and throttle functions taken from underscore.js */
window.debounce = function(func, wait, immediate) {
var timeout;
@@ -358,20 +366,22 @@
})(window);
;(function($, window, document, undefined){
;(function($, window, document, undefined) {
var defaults = {
items: '.gs_w',
items: 'li',
distance: 1,
limit: true,
offset_left: 0,
autoscroll: true,
ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'],
handle: null,
container_width: 0 // 0 == auto
// drag: function(e){},
// start : function(e, ui){},
// stop : function(e){}
container_width: 0, // 0 == auto
move_element: true,
helper: false // or 'clone'
// drag: function(e) {},
// start : function(e, ui) {},
// stop : function(e) {}
};
var $window = $(window);
@@ -480,21 +490,36 @@
if (this.options.limit) {
if (left > this.player_max_left) {
left = this.player_max_left;
}else if(left < this.player_min_left) {
} else if(left < this.player_min_left) {
left = this.player_min_left;
}
}
return {
left: left,
top: top,
mouse_left: mouse_actual_pos.left,
mouse_top: mouse_actual_pos.top
position: {
left: left,
top: top
},
pointer: {
left: mouse_actual_pos.left,
top: mouse_actual_pos.top,
diff_left: diff_x,
diff_top: diff_y + this.scrollOffset
}
};
};
fn.manage_scroll = function(offset) {
fn.get_drag_data = function(e) {
var offset = this.get_offset(e);
offset.$player = this.$player;
offset.$helper = this.helper ? this.$helper : this.$player;
return offset;
};
fn.manage_scroll = function(data) {
/* scroll document */
var nextScrollTop;
var scrollTop = $window.scrollTop();
@@ -504,8 +529,8 @@
var mouse_down_zone = max_window_y - 50;
var mouse_up_zone = min_window_y + 50;
var abs_mouse_left = offset.mouse_left;
var abs_mouse_top = min_window_y + offset.mouse_top;
var abs_mouse_left = data.pointer.left;
var abs_mouse_top = min_window_y + data.pointer.top;
var max_player_y = (this.doc_height - this.window_height +
this.player_height);
@@ -551,7 +576,7 @@
this.mouse_init_pos = this.get_mouse_pos(e);
this.offsetY = this.mouse_init_pos.top - this.el_init_pos.top;
this.$body.on(pointer_events.move, function(mme){
this.$body.on(pointer_events.move, function(mme) {
var mouse_actual_pos = self.get_mouse_pos(mme);
var diff_x = Math.abs(
mouse_actual_pos.left - self.mouse_init_pos.left);
@@ -582,8 +607,10 @@
fn.on_dragstart = function(e) {
e.preventDefault();
this.drag_start = true;
this.is_dragging = true;
if (this.is_dragging) { return this; }
this.drag_start = this.is_dragging = true;
var offset = this.$container.offset();
this.baseX = Math.round(offset.left);
this.baseY = Math.round(offset.top);
@@ -593,9 +620,10 @@
this.$helper = this.$player.clone()
.appendTo(this.$container).addClass('helper');
this.helper = true;
}else{
} else {
this.helper = false;
}
this.scrollOffset = 0;
this.el_init_offset = this.$player.offset();
this.player_width = this.$player.width();
@@ -606,52 +634,43 @@
this.options.offset_left);
if (this.options.start) {
this.options.start.call(this.$player, e, {
helper: this.helper ? this.$helper : this.$player
});
this.options.start.call(this.$player, e, this.get_drag_data(e));
}
return false;
};
fn.on_dragmove = function(e) {
var offset = this.get_offset(e);
var data = this.get_drag_data(e);
this.options.autoscroll && this.manage_scroll(offset);
this.options.autoscroll && this.manage_scroll(data);
(this.helper ? this.$helper : this.$player).css({
'position': 'absolute',
'left' : offset.left,
'top' : offset.top
});
if (this.options.move_element) {
(this.helper ? this.$helper : this.$player).css({
'position': 'absolute',
'left' : data.position.left,
'top' : data.position.top
});
}
var ui = {
'position': {
'left': offset.left,
'top': offset.top
}
};
var last_position = this.last_position || data.position;
data.prev_position = last_position;
if (this.options.drag) {
this.options.drag.call(this.$player, e, ui);
this.options.drag.call(this.$player, e, data);
}
this.last_position = data.position;
return false;
};
fn.on_dragstop = function(e) {
var offset = this.get_offset(e);
var data = this.get_drag_data(e);
this.drag_start = false;
var ui = {
'position': {
'left': offset.left,
'top': offset.top
}
};
if (this.options.stop) {
this.options.stop.call(this.$player, e, ui);
this.options.stop.call(this.$player, e, data);
}
if (this.helper) {
@@ -679,8 +698,7 @@
this.disabled = true;
};
fn.destroy = function(){
fn.destroy = function() {
this.disable();
this.$container.off('.gridster-draggable');
@@ -695,16 +713,12 @@
return !$(event.target).is(this.options.handle);
}
return $.inArray(event.target.nodeName, this.options.ignore_dragging) >= 0;
return $(event.target).is(this.options.ignore_dragging.join(', '));
};
//jQuery adapter
$.fn.drag = function ( options ) {
return this.each(function () {
if (!$.data(this, 'drag')) {
$.data(this, 'drag', new Draggable( this, options ));
}
});
return new Draggable(this, options);
};
@@ -722,7 +736,7 @@
min_cols: 1,
max_cols: null,
min_rows: 15,
max_size_x: 6,
max_size_x: false,
autogenerate_stylesheet: true,
avoid_overlapped_widgets: true,
serialize_params: function($w, wgd) {
@@ -735,7 +749,15 @@
},
collision: {},
draggable: {
items: '.gs-w',
distance: 4
},
resize: {
enabled: false,
axes: ['x', 'y', 'both'],
handle_append_to: '',
handle_class: 'gs-resize-handle',
max_size: [Infinity, Infinity]
}
};
@@ -784,6 +806,19 @@
* @param {Object} [options.draggable] An Object with all options for
* Draggable class you want to overwrite. See Draggable docs for more
* info.
* @param {Object} [options.resize] An Object with resize config
* options.
* @param {Boolean} [options.resize.enabled] Set to true to enable
* resizing.
* @param {Array} [options.resize.axes] Axes in which widgets can be
* resized. Possible values: ['x', 'y', 'both'].
* @param {String} [options.resize.handle_append_to] Set a valid CSS
* selector to append resize handles to.
* @param {String} [options.resize.handle_class] CSS class name used
* by resize handles.
* @param {Array} [options.resize.max_size] Limit widget dimensions
* when resizing. Array values should be integers:
* `[max_cols_occupied, max_rows_occupied]`
*
* @constructor
*/
@@ -791,7 +826,8 @@
this.options = $.extend(true, defaults, options);
this.$el = $(el);
this.$wrapper = this.$el.parent();
this.$widgets = this.$el.children(this.options.widget_selector).addClass('gs_w');
this.$widgets = this.$el.children(
this.options.widget_selector).addClass('gs-w');
this.widgets = [];
this.$changed = $([]);
this.wrapper_width = this.$wrapper.width();
@@ -810,13 +846,16 @@
var fn = Gridster.prototype;
fn.init = function() {
this.options.resize.enabled && this.setup_resize();
this.generate_grid_and_stylesheet();
this.get_widgets_from_DOM();
this.set_dom_grid_height();
this.$wrapper.addClass('ready');
this.draggable();
this.options.resize.enabled && this.resizable();
$(window).bind('resize.gridster', throttle($.proxy(this.recalculate_faux_grid, this), 200));
$(window).bind('resize.gridster', throttle(
$.proxy(this.recalculate_faux_grid, this), 200));
};
@@ -845,6 +884,33 @@
};
/**
* Disables drag-and-drop widget resizing.
*
* @method disable
* @return {Class} Returns instance of gridster Class.
*/
fn.disable_resize = function() {
this.$el.addClass('gs-resize-disabled');
this.resize_api.disable();
return this;
};
/**
* Enables drag-and-drop widget resizing.
*
* @method enable
* @return {Class} Returns instance of gridster Class.
*/
fn.enable_resize = function() {
this.$el.removeClass('gs-resize-disabled');
this.resize_api.enable();
return this;
};
/**
* Add a new widget to the grid.
*
@@ -855,10 +921,11 @@
* @param {Number} [size_y] The of columns the widget occupies vertically.
* @param {Number} [col] The column the widget should start in.
* @param {Number} [row] The row the widget should start in.
* @param {Array} [max_size] max_size Maximun size (in units) for width and height.
* @return {HTMLElement} Returns the jQuery wrapped HTMLElement representing.
* the widget that was just created.
*/
fn.add_widget = function(html, size_x, size_y, col, row) {
fn.add_widget = function(html, size_x, size_y, col, row, max_size) {
var pos;
size_x || (size_x = 1);
size_y || (size_y = 1);
@@ -879,7 +946,7 @@
'data-row': pos.row,
'data-sizex' : size_x,
'data-sizey' : size_y
}).addClass('gs_w').appendTo(this.$el).hide();
}).addClass('gs-w').appendTo(this.$el).hide();
this.$widgets = this.$widgets.add($w);
@@ -888,26 +955,73 @@
this.add_faux_rows(pos.size_y);
//this.add_faux_cols(pos.size_x);
if (max_size) {
this.set_widget_max_size($w, max_size);
}
this.set_dom_grid_height();
return $w.fadeIn();
};
/**
* Change widget size limits.
*
* @method set_widget_max_size
* @param {HTMLElement|Number} $widget The jQuery wrapped HTMLElement
* representing the widget or an index representing the desired widget.
* @param {Array} max_size Maximun size (in units) for width and height.
* @return {HTMLElement} Returns instance of gridster Class.
*/
fn.set_widget_max_size = function($widget, max_size) {
$widget = typeof $widget === 'number' ?
this.$widgets.eq($widget) : $widget;
/**
* Change the size of a widget.
if (!$widget.length) { return this; }
var wgd = $widget.data('coords').grid;
wgd.max_size_x = max_size[0];
wgd.max_size_y = max_size[1];
return this;
};
/**
* Append the resize handle into a widget.
*
* @method add_resize_handle
* @param {HTMLElement} $widget The jQuery wrapped HTMLElement
* representing the widget.
* @return {HTMLElement} Returns instance of gridster Class.
*/
fn.add_resize_handle = function($w) {
var append_to = this.options.resize.handle_append_to;
$(this.resize_handle_tpl).appendTo( append_to ? $(append_to, $w) : $w);
return this;
};
/**
* Change the size of a widget. Width is limited to the current grid width.
*
* @method resize_widget
* @param {HTMLElement} $widget The jQuery wrapped HTMLElement
* representing the widget.
* @param {Number} size_x The number of columns that will occupy the widget.
* @param {Number} size_y The number of rows that will occupy the widget.
* @param {Function} callback Function executed when the widget is removed.
* @param {Boolean} [reposition] Set to false to not move the widget to
* the left if there is insufficient space on the right.
* By default <code>size_x</code> is limited to the space available from
* the column where the widget begins, until the last column to the right.
* @param {Function} [callback] Function executed when the widget is removed.
* @return {HTMLElement} Returns $widget.
*/
fn.resize_widget = function($widget, size_x, size_y, callback) {
fn.resize_widget = function($widget, size_x, size_y, reposition, callback) {
var wgd = $widget.coords().grid;
reposition !== false && (reposition = true);
size_x || (size_x = wgd.size_x);
size_y || (size_y = wgd.size_y);
@@ -915,20 +1029,20 @@
size_x = this.cols;
}
var old_cells_occupied = this.get_cells_occupied(wgd);
var old_size_x = wgd.size_x;
var old_size_y = wgd.size_y;
var old_col = wgd.col;
var new_col = old_col;
var wider = size_x > old_size_x;
var taller = size_y > old_size_y;
if (old_col + size_x - 1 > this.cols) {
if (reposition && old_col + size_x - 1 > this.cols) {
var diff = old_col + (size_x - 1) - this.cols;
var c = old_col - diff;
new_col = Math.max(1, c);
}
if (size_y > old_size_y) {
this.add_faux_rows(Math.max(size_y - old_size_y, 0));
}
var new_grid_data = {
col: new_col,
row: wgd.row,
@@ -936,7 +1050,34 @@
size_y: size_y
};
var new_cells_occupied = this.get_cells_occupied(new_grid_data);
this.mutate_widget_in_gridmap($widget, wgd, new_grid_data);
this.set_dom_grid_height();
if (callback) {
callback.call(this, new_grid_data.size_x, new_grid_data.size_y);
}
return $widget;
};
/**
* Mutate widget dimensions and position in the grid map.
*
* @method mutate_widget_in_gridmap
* @param {HTMLElement} $widget The jQuery wrapped HTMLElement
* representing the widget to mutate.
* @param {Object} wgd Current widget grid data (col, row, size_x, size_y).
* @param {Object} new_wgd New widget grid data.
* @return {HTMLElement} Returns instance of gridster Class.
*/
fn.mutate_widget_in_gridmap = function($widget, wgd, new_wgd) {
var old_size_x = wgd.size_x;
var old_size_y = wgd.size_y;
var old_cells_occupied = this.get_cells_occupied(wgd);
var new_cells_occupied = this.get_cells_occupied(new_wgd);
var empty_cols = [];
$.each(old_cells_occupied.cols, function(i, col) {
@@ -970,48 +1111,46 @@
if (occupied_cols.length) {
var cols_to_empty = [
new_col, wgd.row, size_x, Math.min(old_size_y, size_y), $widget
new_wgd.col, new_wgd.row, new_wgd.size_x, Math.min(old_size_y, new_wgd.size_y), $widget
];
this.empty_cells.apply(this, cols_to_empty);
}
if (occupied_rows.length) {
var rows_to_empty = [new_col, wgd.row, size_x, size_y, $widget];
var rows_to_empty = [new_wgd.col, new_wgd.row, new_wgd.size_x, new_wgd.size_y, $widget];
this.empty_cells.apply(this, rows_to_empty);
}
wgd.col = new_col;
wgd.size_x = size_x;
wgd.size_y = size_y;
this.add_to_gridmap(new_grid_data, $widget);
// not the same that wgd = new_wgd;
wgd.col = new_wgd.col;
wgd.row = new_wgd.row;
wgd.size_x = new_wgd.size_x;
wgd.size_y = new_wgd.size_y;
this.add_to_gridmap(new_wgd, $widget);
$widget.removeClass('player-revert');
//update coords instance attributes
$widget.data('coords').update({
width: (size_x * this.options.widget_base_dimensions[0] +
((size_x - 1) * this.options.widget_margins[0]) * 2),
height: (size_y * this.options.widget_base_dimensions[1] +
((size_y - 1) * this.options.widget_margins[1]) * 2)
width: (new_wgd.size_x * this.options.widget_base_dimensions[0] +
((new_wgd.size_x - 1) * this.options.widget_margins[0]) * 2),
height: (new_wgd.size_y * this.options.widget_base_dimensions[1] +
((new_wgd.size_y - 1) * this.options.widget_margins[1]) * 2)
});
if (size_y > old_size_y) {
this.add_faux_rows(size_y - old_size_y);
}
if (size_x > old_size_x) {
this.add_faux_cols(size_x - old_size_x);
}
$widget.attr({
'data-col': new_col,
'data-sizex': size_x,
'data-sizey': size_y
'data-col': new_wgd.col,
'data-row': new_wgd.row,
'data-sizex': new_wgd.size_x,
'data-sizey': new_wgd.size_y
});
if (empty_cols.length) {
var cols_to_remove_holes = [
empty_cols[0], wgd.row,
empty_cols[0], new_wgd.row,
empty_cols.length,
Math.min(old_size_y, size_y),
Math.min(old_size_y, new_wgd.size_y),
$widget
];
@@ -1020,18 +1159,17 @@
if (empty_rows.length) {
var rows_to_remove_holes = [
new_col, wgd.row, size_x, size_y, $widget
new_wgd.col, new_wgd.row, new_wgd.size_x, new_wgd.size_y, $widget
];
this.remove_empty_cells.apply(this, rows_to_remove_holes);
}
if (callback) {
callback.call(this, size_x, size_y);
}
this.move_widget_up($widget);
return $widget;
return this;
};
/**
* Move down widgets in cells represented by the arguments col, row, size_x,
* size_y
@@ -1184,6 +1322,8 @@
callback.call(this, el);
}
}, this));
return this;
};
@@ -1246,12 +1386,13 @@
* @return {Array} Returns the instance of the Gridster class.
*/
fn.register_widget = function($el) {
var wgd = {
'col': parseInt($el.attr('data-col'), 10),
'row': parseInt($el.attr('data-row'), 10),
'size_x': parseInt($el.attr('data-sizex'), 10),
'size_y': parseInt($el.attr('data-sizey'), 10),
'max_size_x': parseInt($el.attr('data-max-sizex'), 10) || false,
'max_size_y': parseInt($el.attr('data-max-sizey'), 10) || false,
'el': $el
};
@@ -1259,8 +1400,7 @@
!this.can_move_to(
{size_x: wgd.size_x, size_y: wgd.size_y}, wgd.col, wgd.row)
) {
wgd = this.next_position(wgd.size_x, wgd.size_y);
wgd.el = $el;
$.extend(wgd, this.next_position(wgd.size_x, wgd.size_y));
$el.attr({
'data-col': wgd.col,
'data-row': wgd.row,
@@ -1271,12 +1411,13 @@
// attach Coord object to player data-coord attribute
$el.data('coords', $el.coords());
// Extend Coord object with grid position info
$el.data('coords').grid = wgd;
this.add_to_gridmap(wgd, $el);
this.options.resize.enabled && this.add_resize_handle($el);
return this;
};
@@ -1349,13 +1490,15 @@
var draggable_options = $.extend(true, {}, this.options.draggable, {
offset_left: this.options.widget_margins[0],
container_width: this.container_width,
ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON',
'.' + this.options.resize.handle_class],
start: function(event, ui) {
self.$widgets.filter('.player-revert')
.removeClass('player-revert');
self.$player = $(this);
self.$helper = self.options.draggable.helper === 'clone' ?
$(ui.helper) : self.$player;
self.$helper = $(ui.$helper);
self.helper = !self.$helper.is(self.$player);
self.on_start_drag.call(self, event, ui);
@@ -1371,7 +1514,51 @@
}, 60)
});
this.drag_api = this.$el.drag(draggable_options).data('drag');
this.drag_api = this.$el.drag(draggable_options);
return this;
};
/**
* Bind resize events to get resize working.
*
* @method resizable
* @return {Class} Returns instance of gridster Class.
*/
fn.resizable = function() {
this.resize_api = this.$el.drag({
items: '.' + this.options.resize.handle_class,
offset_left: this.options.widget_margins[0],
container_width: this.container_width,
move_element: false,
start: $.proxy(this.on_start_resize, this),
stop: $.proxy(function(event, ui) {
delay($.proxy(function() {
this.on_stop_resize(event, ui);
}, this), 120);
}, this),
drag: throttle($.proxy(this.on_resize, this), 60)
});
return this;
};
/**
* Setup things required for resizing. Like build templates for drag handles.
*
* @method setup_resize
* @return {Class} Returns instance of gridster Class.
*/
fn.setup_resize = function() {
this.resize_handle_class = this.options.resize.handle_class;
var axes = this.options.resize.axes;
var handle_tpl = '<span class="' + this.resize_handle_class + ' ' +
this.resize_handle_class + '-{type}" />';
this.resize_handle_tpl = $.map(axes, function(type) {
return handle_tpl.replace('{type}', type);
}).join('');
return this;
};
@@ -1381,10 +1568,9 @@
*
* @method on_start_drag
* @param {Event} event The original browser event
* @param {Object} ui A prepared ui object.
* @param {Object} ui A prepared ui object with useful drag-related data
*/
fn.on_start_drag = function(event, ui) {
this.$helper.add(this.$player).add(this.$wrapper).addClass('dragging');
this.$player.addClass('player');
@@ -1406,12 +1592,11 @@
this.last_cols = [];
this.last_rows = [];
// see jquery.collision.js
this.collision_api = this.$helper.collision(
colliders, this.options.collision);
this.$preview_holder = $('<li />', {
this.$preview_holder = $('<' + this.$player.get(0).tagName + ' />', {
'class': 'preview-holder',
'data-row': this.$player.attr('data-row'),
'data-col': this.$player.attr('data-col'),
@@ -1432,7 +1617,7 @@
*
* @method on_drag
* @param {Event} event The original browser event
* @param {Object} ui A prepared ui object.
* @param {Object} ui A prepared ui object with useful drag-related data
*/
fn.on_drag = function(event, ui) {
//break if dragstop has been fired
@@ -1475,7 +1660,7 @@
*
* @method on_stop_drag
* @param {Event} event The original browser event
* @param {Object} ui A prepared ui object.
* @param {Object} ui A prepared ui object with useful drag-related data
*/
fn.on_stop_drag = function(event, ui) {
this.$helper.add(this.$player).add(this.$wrapper)
@@ -1483,7 +1668,8 @@
ui.position.left = ui.position.left + this.baseX;
ui.position.top = ui.position.top + this.baseY;
this.colliders_data = this.collision_api.get_closest_colliders(ui.position);
this.colliders_data = this.collision_api.get_closest_colliders(
ui.position);
this.on_overlapped_column_change(
this.on_start_overlapping_column,
@@ -1531,6 +1717,148 @@
};
/**
* This function is executed every time a widget starts to be resized.
*
* @method on_start_resize
* @param {Event} event The original browser event
* @param {Object} ui A prepared ui object with useful drag-related data
*/
fn.on_start_resize = function(event, ui) {
this.$resized_widget = ui.$player.closest('.gs-w');
this.resize_coords = this.$resized_widget.coords();
this.resize_wgd = this.resize_coords.grid;
this.resize_initial_width = this.resize_coords.coords.width;
this.resize_initial_height = this.resize_coords.coords.height;
this.resize_initial_sizex = this.resize_coords.grid.size_x;
this.resize_initial_sizey = this.resize_coords.grid.size_y;
this.resize_last_sizex = this.resize_initial_sizex;
this.resize_last_sizey = this.resize_initial_sizey;
this.resize_max_size_x = Math.min(this.resize_wgd.max_size_x ||
this.options.resize.max_size[0], this.cols - this.resize_wgd.col + 1);
this.resize_max_size_y = this.resize_wgd.max_size_y ||
this.options.resize.max_size[1];
this.resize_dir = {
right: ui.$player.is('.' + this.resize_handle_class + '-x'),
bottom: ui.$player.is('.' + this.resize_handle_class + '-y')
};
this.$resized_widget.css({
'min-width': this.options.widget_base_dimensions[0],
'min-height': this.options.widget_base_dimensions[1]
});
var nodeName = this.$resized_widget.get(0).tagName;
this.$resize_preview_holder = $('<' + nodeName + ' />', {
'class': 'preview-holder resize-preview-holder',
'data-row': this.$resized_widget.attr('data-row'),
'data-col': this.$resized_widget.attr('data-col'),
'css': {
'width': this.resize_initial_width,
'height': this.resize_initial_height
}
}).appendTo(this.$el);
this.$resized_widget.addClass('resizing');
};
/**
* This function is executed every time a widget stops being resized.
*
* @method on_stop_resize
* @param {Event} event The original browser event
* @param {Object} ui A prepared ui object with useful drag-related data
*/
fn.on_stop_resize = function(event, ui) {
this.$resized_widget
.removeClass('resizing')
.css({
'width': '',
'height': ''
});
delay($.proxy(function() {
this.$resize_preview_holder
.remove()
.css({
'min-width': '',
'min-height': ''
});
}, this), 300);
};
/**
* This function is executed when a widget is being resized.
*
* @method on_resize
* @param {Event} event The original browser event
* @param {Object} ui A prepared ui object with useful drag-related data
*/
fn.on_resize = function(event, ui) {
var rel_x = (ui.pointer.diff_left);
var rel_y = (ui.pointer.diff_top);
var wbd_x = this.options.widget_base_dimensions[0];
var wbd_y = this.options.widget_base_dimensions[1];
var max_width = Infinity;
var max_height = Infinity;
var inc_units_x = Math.ceil((rel_x /
(this.options.widget_base_dimensions[0] +
this.options.widget_margins[0] * 2)) - 0.2);
var inc_units_y = Math.ceil((rel_y /
(this.options.widget_base_dimensions[1] +
this.options.widget_margins[1] * 2)) - 0.2);
var size_x = Math.max(1, this.resize_initial_sizex + inc_units_x);
var size_y = Math.max(1, this.resize_initial_sizey + inc_units_y);
size_x = Math.min(size_x, this.resize_max_size_x);
max_width = (this.resize_max_size_x * wbd_x) +
((size_x - 1) * this.options.widget_margins[0] * 2);
size_y = Math.min(size_y, this.resize_max_size_y);
max_height = (this.resize_max_size_y * wbd_y) +
((size_y - 1) * this.options.widget_margins[1] * 2);
if (this.resize_dir.right) {
size_y = this.resize_initial_sizey;
} else if (this.resize_dir.bottom) {
size_x = this.resize_initial_sizex;
}
var css_props = {};
!this.resize_dir.bottom && (css_props.width = Math.min(
this.resize_initial_width + rel_x, max_width));
!this.resize_dir.right && (css_props.height = Math.min(
this.resize_initial_height + rel_y, max_height));
this.$resized_widget.css(css_props);
if (size_x !== this.resize_last_sizex ||
size_y !== this.resize_last_sizey) {
this.resize_widget(this.$resized_widget, size_x, size_y, false);
this.$resize_preview_holder.css({
'width': '',
'height': ''
}).attr({
'data-row': this.$resized_widget.attr('data-row'),
'data-sizex': size_x,
'data-sizey': size_y
});
}
this.resize_last_sizex = size_x;
this.resize_last_sizey = size_y;
};
/**
* Executes the callbacks passed as arguments when a column begins to be
* overlapped or stops being overlapped.
@@ -2036,8 +2364,9 @@
}, this));
}
var $widgets_under_ph = this.get_widgets_under_player(
this.cells_occupied_by_placeholder);
var $widgets_under_ph = this.get_widgets_under_player(this.cells_occupied_by_placeholder);
if ($widgets_under_ph.length) {
$widgets_under_ph.each($.proxy(function(i, widget) {
var $w = $(widget);
@@ -2429,10 +2758,14 @@
* @return {Class} Returns the instance of the Gridster Class.
*/
fn.move_widget_down = function($widget, y_units) {
var el_grid_data = $widget.coords().grid;
var actual_row = el_grid_data.row;
var moved = [];
var y_diff = y_units;
var el_grid_data, actual_row, moved, y_diff;
if (y_units <= 0) { return false; }
el_grid_data = $widget.coords().grid;
actual_row = el_grid_data.row;
moved = [];
y_diff = y_units;
if (!$widget) { return false; }
@@ -2971,7 +3304,7 @@
*/
fn.generate_stylesheet = function(opts) {
var styles = '';
var max_size_x = this.options.max_size_x;
var max_size_x = this.options.max_size_x || this.cols;
var max_rows = 0;
var max_cols = 0;
var i;
@@ -3003,7 +3336,7 @@
styles += (opts.namespace + ' [data-col="'+ (i + 1) + '"] { left:' +
((i * opts.widget_base_dimensions[0]) +
(i * opts.widget_margins[0]) +
((i + 1) * opts.widget_margins[0])) + 'px;} ');
((i + 1) * opts.widget_margins[0])) + 'px; }\n');
}
/* generate CSS styles for rows */
@@ -3011,19 +3344,19 @@
styles += (opts.namespace + ' [data-row="' + (i + 1) + '"] { top:' +
((i * opts.widget_base_dimensions[1]) +
(i * opts.widget_margins[1]) +
((i + 1) * opts.widget_margins[1]) ) + 'px;} ');
((i + 1) * opts.widget_margins[1]) ) + 'px; }\n');
}
for (var y = 1; y <= opts.rows; y++) {
styles += (opts.namespace + ' [data-sizey="' + y + '"] { height:' +
(y * opts.widget_base_dimensions[1] +
(y - 1) * (opts.widget_margins[1] * 2)) + 'px;}');
(y - 1) * (opts.widget_margins[1] * 2)) + 'px; }\n');
}
for (var x = 1; x <= max_size_x; x++) {
styles += (opts.namespace + ' [data-sizex="' + x + '"] { width:' +
(x * opts.widget_base_dimensions[0] +
(x - 1) * (opts.widget_margins[0] * 2)) + 'px;}');
(x - 1) * (opts.widget_margins[0] * 2)) + 'px; }\n');
}
return this.add_style_tag(styles);
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "gridster",
"title": "gridster.js",
"description": "a drag-and-drop multi-column jQuery grid plugin",
"version": "0.1.0",
"version": "0.2.0",
"homepage": "http://gridster.net/",
"author": {
"name": "ducksboard",