gridster-rails 0.2.1 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 674696cba3853465f747492df84085e31e5468d7
4
- data.tar.gz: 35e4e3ef41c060e809e8251e66bf486e8cdbba02
3
+ metadata.gz: e0261906757a321a7e11caeb6d7ac0fe7723c15d
4
+ data.tar.gz: 6e579dbf8f89f425e6daf6b81e228b251e315bf8
5
5
  SHA512:
6
- metadata.gz: 072213c1adade7c2f507dfc95b8f7bd6185c2d11a44377abe6b6aebde174090fa076b423ee2742859388e0d62dda311a798a7c17fa64728a08bdd8a41a266d59
7
- data.tar.gz: fc8736e205c589d16bd04e0f3cb5e2c921630fa363f0c86f579b647e1d21ad572c34278e78f9605eaeb54a912f2a551e772c98712c94537ce8394000ce6c26fc
6
+ metadata.gz: b779e93128b9468e6b506d95fe450accec0ac670026d118ecb7d5e92f1bd38556ec25c1d228fa5e80aa3e59cb3fb62877ebde0c4410d4708423d098372ffba83
7
+ data.tar.gz: 8c7d9f1b7663ec3cc4526d059a5e821b0297cbd5f2903d87d3f4b75aedd9cc13735251465234733d482a6d44d09a62b35bf745b6119abdb1196f2ba13ff344dd
data/README.md CHANGED
@@ -18,7 +18,7 @@ This is [gridster.js](http://gridster.net) GEMified for the Rails >= 3.1 asset p
18
18
 
19
19
  * modify **lib/gridster-rails/version.rb** to match gridster.js version
20
20
 
21
- VERSION = "0.2.1"
21
+ VERSION = "0.5.6"
22
22
 
23
23
  * modify **lib/gridster-rails.rb** to subclass Rails::Engine
24
24
 
@@ -1,5 +1,5 @@
1
1
  module Gridster
2
2
  module Rails
3
- VERSION = "0.2.1"
3
+ VERSION = "0.5.6"
4
4
  end
5
5
  end
@@ -1,8 +1,16 @@
1
- /*! gridster.js - v0.2.1 - 2013-10-28
1
+ /*! gridster.js - v0.5.6 - 2014-09-25
2
2
  * http://gridster.net/
3
- * Copyright (c) 2013 ducksboard; Licensed MIT */
3
+ * Copyright (c) 2014 ducksboard; Licensed MIT */
4
4
 
5
- ;(function($, window, document, undefined){
5
+ ;(function(root, factory) {
6
+
7
+ if (typeof define === 'function' && define.amd) {
8
+ define('gridster-coords', ['jquery'], factory);
9
+ } else {
10
+ root.GridsterCoords = factory(root.$ || root.jQuery);
11
+ }
12
+
13
+ }(this, function($) {
6
14
  /**
7
15
  * Creates objects with coordinates (x1, y1, x2, y2, cx, cy, width, height)
8
16
  * to simulate DOM elements on the screen.
@@ -55,6 +63,9 @@
55
63
 
56
64
  var d = this.data;
57
65
 
66
+ typeof d.left === 'undefined' && (d.left = d.x1);
67
+ typeof d.top === 'undefined' && (d.top = d.y1);
68
+
58
69
  this.coords.x1 = d.left;
59
70
  this.coords.y1 = d.top;
60
71
  this.coords.x2 = d.left + d.width;
@@ -89,6 +100,10 @@
89
100
  return this.coords;
90
101
  };
91
102
 
103
+ fn.destroy = function() {
104
+ this.el.removeData('coords');
105
+ delete this.el;
106
+ };
92
107
 
93
108
  //jQuery adapter
94
109
  $.fn.coords = function() {
@@ -101,12 +116,24 @@
101
116
  return ins;
102
117
  };
103
118
 
104
- }(jQuery, window, document));
119
+ return Coords;
120
+
121
+ }));
105
122
 
106
- ;(function($, window, document, undefined){
123
+ ;(function(root, factory) {
124
+
125
+ if (typeof define === 'function' && define.amd) {
126
+ define('gridster-collision', ['jquery', 'gridster-coords'], factory);
127
+ } else {
128
+ root.GridsterCollision = factory(root.$ || root.jQuery,
129
+ root.GridsterCoords);
130
+ }
131
+
132
+ }(this, function($, Coords) {
107
133
 
108
134
  var defaults = {
109
- colliders_context: document.body
135
+ colliders_context: document.body,
136
+ overlapping_region: 'C'
110
137
  // ,on_overlap: function(collider_data){},
111
138
  // on_overlap_start : function(collider_data){},
112
139
  // on_overlap_stop : function(collider_data){}
@@ -124,6 +151,9 @@
124
151
  * of HTMLElements or an Array of Coords instances.
125
152
  * @param {Object} [options] An Object with all options you want to
126
153
  * overwrite:
154
+ * @param {String} [options.overlapping_region] Determines when collision
155
+ * is valid, depending on the overlapped area. Values can be: 'N', 'S',
156
+ * 'W', 'E', 'C' or 'all'. Default is 'C'.
127
157
  * @param {Function} [options.on_overlap_start] Executes a function the first
128
158
  * time each `collider ` is overlapped.
129
159
  * @param {Function} [options.on_overlap_stop] Executes a function when a
@@ -138,16 +168,12 @@
138
168
  this.$element = el;
139
169
  this.last_colliders = [];
140
170
  this.last_colliders_coords = [];
141
- if (typeof colliders === 'string' || colliders instanceof jQuery) {
142
- this.$colliders = $(colliders,
143
- this.options.colliders_context).not(this.$element);
144
- }else{
145
- this.colliders = $(colliders);
146
- }
171
+ this.set_colliders(colliders);
147
172
 
148
173
  this.init();
149
174
  }
150
175
 
176
+ Collision.defaults = defaults;
151
177
 
152
178
  var fn = Collision.prototype;
153
179
 
@@ -228,6 +254,7 @@
228
254
 
229
255
  fn.find_collisions = function(player_data_coords){
230
256
  var self = this;
257
+ var overlapping_region = this.options.overlapping_region;
231
258
  var colliders_coords = [];
232
259
  var colliders_data = [];
233
260
  var $colliders = (this.colliders || this.$colliders);
@@ -251,7 +278,8 @@
251
278
  player_coords, collider_coords);
252
279
 
253
280
  //todo: make this an option
254
- if (region === 'C'){
281
+ if (region === overlapping_region || overlapping_region === 'all') {
282
+
255
283
  var area_coords = self.calculate_overlapped_area_coords(
256
284
  player_coords, collider_coords);
257
285
  var area = self.calculate_overlapped_area(area_coords);
@@ -308,24 +336,59 @@
308
336
  };
309
337
 
310
338
 
339
+ fn.set_colliders = function(colliders) {
340
+ if (typeof colliders === 'string' || colliders instanceof $) {
341
+ this.$colliders = $(colliders,
342
+ this.options.colliders_context).not(this.$element);
343
+ }else{
344
+ this.colliders = $(colliders);
345
+ }
346
+ };
347
+
348
+
311
349
  //jQuery adapter
312
350
  $.fn.collision = function(collider, options) {
313
351
  return new Collision( this, collider, options );
314
352
  };
315
353
 
354
+ return Collision;
316
355
 
317
- }(jQuery, window, document));
356
+ }));
318
357
 
319
358
  ;(function(window, undefined) {
320
359
 
360
+ /* Delay, debounce and throttle functions taken from underscore.js
361
+ *
362
+ * Copyright (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and
363
+ * Investigative Reporters & Editors
364
+ *
365
+ * Permission is hereby granted, free of charge, to any person
366
+ * obtaining a copy of this software and associated documentation
367
+ * files (the "Software"), to deal in the Software without
368
+ * restriction, including without limitation the rights to use,
369
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
370
+ * copies of the Software, and to permit persons to whom the
371
+ * Software is furnished to do so, subject to the following
372
+ * conditions:
373
+ *
374
+ * The above copyright notice and this permission notice shall be
375
+ * included in all copies or substantial portions of the Software.
376
+ *
377
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
378
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
379
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
380
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
381
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
382
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
383
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
384
+ * OTHER DEALINGS IN THE SOFTWARE.
385
+ */
321
386
 
322
387
  window.delay = function(func, wait) {
323
388
  var args = Array.prototype.slice.call(arguments, 2);
324
389
  return setTimeout(function(){ return func.apply(null, args); }, wait);
325
390
  };
326
391
 
327
-
328
- /* Debounce and throttle functions taken from underscore.js */
329
392
  window.debounce = function(func, wait, immediate) {
330
393
  var timeout;
331
394
  return function() {
@@ -340,7 +403,6 @@
340
403
  };
341
404
  };
342
405
 
343
-
344
406
  window.throttle = function(func, wait) {
345
407
  var context, args, timeout, throttling, more, result;
346
408
  var whenDone = debounce(
@@ -366,7 +428,15 @@
366
428
 
367
429
  })(window);
368
430
 
369
- ;(function($, window, document, undefined) {
431
+ ;(function(root, factory) {
432
+
433
+ if (typeof define === 'function' && define.amd) {
434
+ define('gridster-draggable', ['jquery'], factory);
435
+ } else {
436
+ root.GridsterDraggable = factory(root.$ || root.jQuery);
437
+ }
438
+
439
+ }(this, function($) {
370
440
 
371
441
  var defaults = {
372
442
  items: 'li',
@@ -374,24 +444,30 @@
374
444
  limit: true,
375
445
  offset_left: 0,
376
446
  autoscroll: true,
377
- ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'],
447
+ ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'], // or function
378
448
  handle: null,
379
449
  container_width: 0, // 0 == auto
380
450
  move_element: true,
381
- helper: false // or 'clone'
451
+ helper: false, // or 'clone'
452
+ remove_helper: true
382
453
  // drag: function(e) {},
383
454
  // start : function(e, ui) {},
384
455
  // stop : function(e) {}
385
456
  };
386
457
 
387
458
  var $window = $(window);
459
+ var dir_map = { x : 'left', y : 'top' };
388
460
  var isTouch = !!('ontouchstart' in window);
389
- var pointer_events = {
390
- start: isTouch ? 'touchstart.gridster-draggable' : 'mousedown.gridster-draggable',
391
- move: isTouch ? 'touchmove.gridster-draggable' : 'mousemove.gridster-draggable',
392
- end: isTouch ? 'touchend.gridster-draggable' : 'mouseup.gridster-draggable'
461
+
462
+ var capitalize = function(str) {
463
+ return str.charAt(0).toUpperCase() + str.slice(1);
393
464
  };
394
465
 
466
+ var idCounter = 0;
467
+ var uniqId = function() {
468
+ return ++idCounter + '';
469
+ }
470
+
395
471
  /**
396
472
  * Basic drag implementation for DOM elements inside a container.
397
473
  * Provide start/stop/drag callbacks.
@@ -408,6 +484,9 @@
408
484
  * the mouse must move before dragging should start.
409
485
  * @param {Boolean} [options.limit] Constrains dragging to the width of
410
486
  * the container
487
+ * @param {Object|Function} [options.ignore_dragging] Array of node names
488
+ * that sould not trigger dragging, by default is `['INPUT', 'TEXTAREA',
489
+ * 'SELECT', 'BUTTON']`. If a function is used return true to ignore dragging.
411
490
  * @param {offset_left} [options.offset_left] Offset added to the item
412
491
  * that is being dragged.
413
492
  * @param {Number} [options.drag] Executes a callback when the mouse is
@@ -420,37 +499,52 @@
420
499
  */
421
500
  function Draggable(el, options) {
422
501
  this.options = $.extend({}, defaults, options);
423
- this.$body = $(document.body);
502
+ this.$document = $(document);
424
503
  this.$container = $(el);
425
504
  this.$dragitems = $(this.options.items, this.$container);
426
505
  this.is_dragging = false;
427
506
  this.player_min_left = 0 + this.options.offset_left;
507
+ this.id = uniqId();
508
+ this.ns = '.gridster-draggable-' + this.id;
428
509
  this.init();
429
510
  }
430
511
 
512
+ Draggable.defaults = defaults;
513
+
431
514
  var fn = Draggable.prototype;
432
515
 
433
516
  fn.init = function() {
434
- this.calculate_positions();
435
- this.$container.css('position', 'relative');
517
+ var pos = this.$container.css('position');
518
+ this.calculate_dimensions();
519
+ this.$container.css('position', pos === 'static' ? 'relative' : pos);
436
520
  this.disabled = false;
437
521
  this.events();
438
522
 
439
- $(window).bind('resize.gridster-draggable',
440
- throttle($.proxy(this.calculate_positions, this), 200));
523
+ $(window).bind(this.nsEvent('resize'),
524
+ throttle($.proxy(this.calculate_dimensions, this), 200));
525
+ };
526
+
527
+ fn.nsEvent = function(ev) {
528
+ return (ev || '') + this.ns;
441
529
  };
442
530
 
443
531
  fn.events = function() {
444
- this.$container.on('selectstart.gridster-draggable',
532
+ this.pointer_events = {
533
+ start: this.nsEvent('touchstart') + ' ' + this.nsEvent('mousedown'),
534
+ move: this.nsEvent('touchmove') + ' ' + this.nsEvent('mousemove'),
535
+ end: this.nsEvent('touchend') + ' ' + this.nsEvent('mouseup'),
536
+ };
537
+
538
+ this.$container.on(this.nsEvent('selectstart'),
445
539
  $.proxy(this.on_select_start, this));
446
540
 
447
- this.$container.on(pointer_events.start, this.options.items,
541
+ this.$container.on(this.pointer_events.start, this.options.items,
448
542
  $.proxy(this.drag_handler, this));
449
543
 
450
- this.$body.on(pointer_events.end, $.proxy(function(e) {
544
+ this.$document.on(this.pointer_events.end, $.proxy(function(e) {
451
545
  this.is_dragging = false;
452
546
  if (this.disabled) { return; }
453
- this.$body.off(pointer_events.move);
547
+ this.$document.off(this.pointer_events.move);
454
548
  if (this.drag_start) {
455
549
  this.on_dragstop(e);
456
550
  }
@@ -464,7 +558,7 @@
464
558
 
465
559
 
466
560
  fn.get_mouse_pos = function(e) {
467
- if (isTouch) {
561
+ if (e.originalEvent && e.originalEvent.touches) {
468
562
  var oe = e.originalEvent;
469
563
  e = oe.touches.length ? oe.touches[0] : oe.changedTouches[0];
470
564
  }
@@ -483,9 +577,10 @@
483
577
  mouse_actual_pos.left - this.mouse_init_pos.left);
484
578
  var diff_y = Math.round(mouse_actual_pos.top - this.mouse_init_pos.top);
485
579
 
486
- var left = Math.round(this.el_init_offset.left + diff_x - this.baseX);
487
- var top = Math.round(
488
- this.el_init_offset.top + diff_y - this.baseY + this.scrollOffset);
580
+ var left = Math.round(this.el_init_offset.left +
581
+ diff_x - this.baseX + $(window).scrollLeft() - this.win_offset_x);
582
+ var top = Math.round(this.el_init_offset.top +
583
+ diff_y - this.baseY + $(window).scrollTop() - this.win_offset_y);
489
584
 
490
585
  if (this.options.limit) {
491
586
  if (left > this.player_max_left) {
@@ -503,8 +598,8 @@
503
598
  pointer: {
504
599
  left: mouse_actual_pos.left,
505
600
  top: mouse_actual_pos.top,
506
- diff_left: diff_x,
507
- diff_top: diff_y + this.scrollOffset
601
+ diff_left: diff_x + ($(window).scrollLeft() - this.win_offset_x),
602
+ diff_top: diff_y + ($(window).scrollTop() - this.win_offset_y)
508
603
  }
509
604
  };
510
605
  };
@@ -519,47 +614,75 @@
519
614
  };
520
615
 
521
616
 
522
- fn.manage_scroll = function(data) {
523
- /* scroll document */
524
- var nextScrollTop;
525
- var scrollTop = $window.scrollTop();
526
- var min_window_y = scrollTop;
527
- var max_window_y = min_window_y + this.window_height;
528
-
529
- var mouse_down_zone = max_window_y - 50;
530
- var mouse_up_zone = min_window_y + 50;
531
-
532
- var abs_mouse_left = data.pointer.left;
533
- var abs_mouse_top = min_window_y + data.pointer.top;
534
-
535
- var max_player_y = (this.doc_height - this.window_height +
536
- this.player_height);
537
-
538
- if (abs_mouse_top >= mouse_down_zone) {
539
- nextScrollTop = scrollTop + 30;
540
- if (nextScrollTop < max_player_y) {
541
- $window.scrollTop(nextScrollTop);
542
- this.scrollOffset = this.scrollOffset + 30;
617
+ fn.set_limits = function(container_width) {
618
+ container_width || (container_width = this.$container.width());
619
+ this.player_max_left = (container_width - this.player_width +
620
+ - this.options.offset_left);
621
+
622
+ this.options.container_width = container_width;
623
+
624
+ return this;
625
+ };
626
+
627
+
628
+ fn.scroll_in = function(axis, data) {
629
+ var dir_prop = dir_map[axis];
630
+
631
+ var area_size = 50;
632
+ var scroll_inc = 30;
633
+
634
+ var is_x = axis === 'x';
635
+ var window_size = is_x ? this.window_width : this.window_height;
636
+ var doc_size = is_x ? $(document).width() : $(document).height();
637
+ var player_size = is_x ? this.$player.width() : this.$player.height();
638
+
639
+ var next_scroll;
640
+ var scroll_offset = $window['scroll' + capitalize(dir_prop)]();
641
+ var min_window_pos = scroll_offset;
642
+ var max_window_pos = min_window_pos + window_size;
643
+
644
+ var mouse_next_zone = max_window_pos - area_size; // down/right
645
+ var mouse_prev_zone = min_window_pos + area_size; // up/left
646
+
647
+ var abs_mouse_pos = min_window_pos + data.pointer[dir_prop];
648
+
649
+ var max_player_pos = (doc_size - window_size + player_size);
650
+
651
+ if (abs_mouse_pos >= mouse_next_zone) {
652
+ next_scroll = scroll_offset + scroll_inc;
653
+ if (next_scroll < max_player_pos) {
654
+ $window['scroll' + capitalize(dir_prop)](next_scroll);
655
+ this['scroll_offset_' + axis] += scroll_inc;
543
656
  }
544
657
  }
545
658
 
546
- if (abs_mouse_top <= mouse_up_zone) {
547
- nextScrollTop = scrollTop - 30;
548
- if (nextScrollTop > 0) {
549
- $window.scrollTop(nextScrollTop);
550
- this.scrollOffset = this.scrollOffset - 30;
659
+ if (abs_mouse_pos <= mouse_prev_zone) {
660
+ next_scroll = scroll_offset - scroll_inc;
661
+ if (next_scroll > 0) {
662
+ $window['scroll' + capitalize(dir_prop)](next_scroll);
663
+ this['scroll_offset_' + axis] -= scroll_inc;
551
664
  }
552
665
  }
666
+
667
+ return this;
668
+ };
669
+
670
+
671
+ fn.manage_scroll = function(data) {
672
+ this.scroll_in('x', data);
673
+ this.scroll_in('y', data);
553
674
  };
554
675
 
555
676
 
556
- fn.calculate_positions = function(e) {
677
+ fn.calculate_dimensions = function(e) {
557
678
  this.window_height = $window.height();
679
+ this.window_width = $window.width();
558
680
  };
559
681
 
560
682
 
561
683
  fn.drag_handler = function(e) {
562
684
  var node = e.target.nodeName;
685
+ // skip if drag is disabled, or click was not done with the mouse primary button
563
686
  if (this.disabled || e.which !== 1 && !isTouch) {
564
687
  return;
565
688
  }
@@ -576,7 +699,7 @@
576
699
  this.mouse_init_pos = this.get_mouse_pos(e);
577
700
  this.offsetY = this.mouse_init_pos.top - this.el_init_pos.top;
578
701
 
579
- this.$body.on(pointer_events.move, function(mme) {
702
+ this.$document.on(this.pointer_events.move, function(mme) {
580
703
  var mouse_actual_pos = self.get_mouse_pos(mme);
581
704
  var diff_x = Math.abs(
582
705
  mouse_actual_pos.left - self.mouse_init_pos.left);
@@ -614,7 +737,7 @@
614
737
  var offset = this.$container.offset();
615
738
  this.baseX = Math.round(offset.left);
616
739
  this.baseY = Math.round(offset.top);
617
- this.doc_height = $(document).height();
740
+ this.initial_container_width = this.options.container_width || this.$container.width();
618
741
 
619
742
  if (this.options.helper === 'clone') {
620
743
  this.$helper = this.$player.clone()
@@ -624,14 +747,15 @@
624
747
  this.helper = false;
625
748
  }
626
749
 
627
- this.scrollOffset = 0;
750
+ this.win_offset_y = $(window).scrollTop();
751
+ this.win_offset_x = $(window).scrollLeft();
752
+ this.scroll_offset_y = 0;
753
+ this.scroll_offset_x = 0;
628
754
  this.el_init_offset = this.$player.offset();
629
755
  this.player_width = this.$player.width();
630
756
  this.player_height = this.$player.height();
631
757
 
632
- var container_width = this.options.container_width || this.$container.width();
633
- this.player_max_left = (container_width - this.player_width +
634
- this.options.offset_left);
758
+ this.set_limits(this.options.container_width);
635
759
 
636
760
  if (this.options.start) {
637
761
  this.options.start.call(this.$player, e, this.get_drag_data(e));
@@ -673,7 +797,7 @@
673
797
  this.options.stop.call(this.$player, e, data);
674
798
  }
675
799
 
676
- if (this.helper) {
800
+ if (this.helper && this.options.remove_helper) {
677
801
  this.$helper.remove();
678
802
  }
679
803
 
@@ -701,9 +825,9 @@
701
825
  fn.destroy = function() {
702
826
  this.disable();
703
827
 
704
- this.$container.off('.gridster-draggable');
705
- this.$body.off('.gridster-draggable');
706
- $(window).off('.gridster-draggable');
828
+ this.$container.off(this.ns);
829
+ this.$document.off(this.ns);
830
+ $(window).off(this.ns);
707
831
 
708
832
  $.removeData(this.$container, 'drag');
709
833
  };
@@ -713,6 +837,10 @@
713
837
  return !$(event.target).is(this.options.handle);
714
838
  }
715
839
 
840
+ if ($.isFunction(this.options.ignore_dragging)) {
841
+ return this.options.ignore_dragging(event);
842
+ }
843
+
716
844
  return $(event.target).is(this.options.ignore_dragging.join(', '));
717
845
  };
718
846
 
@@ -721,10 +849,20 @@
721
849
  return new Draggable(this, options);
722
850
  };
723
851
 
852
+ return Draggable;
853
+
854
+ }));
724
855
 
725
- }(jQuery, window, document));
856
+ ;(function(root, factory) {
726
857
 
727
- ;(function($, window, document, undefined) {
858
+ if (typeof define === 'function' && define.amd) {
859
+ define(['jquery', 'gridster-draggable', 'gridster-collision'], factory);
860
+ } else {
861
+ root.Gridster = factory(root.$ || root.jQuery, root.GridsterDraggable,
862
+ root.GridsterCollision);
863
+ }
864
+
865
+ }(this, function($, Draggable, Collision) {
728
866
 
729
867
  var defaults = {
730
868
  namespace: '',
@@ -734,11 +872,13 @@
734
872
  extra_rows: 0,
735
873
  extra_cols: 0,
736
874
  min_cols: 1,
737
- max_cols: null,
875
+ max_cols: Infinity,
738
876
  min_rows: 15,
739
877
  max_size_x: false,
878
+ autogrow_cols: false,
740
879
  autogenerate_stylesheet: true,
741
880
  avoid_overlapped_widgets: true,
881
+ auto_init: true,
742
882
  serialize_params: function($w, wgd) {
743
883
  return {
744
884
  col: wgd.col,
@@ -750,14 +890,16 @@
750
890
  collision: {},
751
891
  draggable: {
752
892
  items: '.gs-w',
753
- distance: 4
893
+ distance: 4,
894
+ ignore_dragging: Draggable.defaults.ignore_dragging.slice(0)
754
895
  },
755
896
  resize: {
756
897
  enabled: false,
757
- axes: ['x', 'y', 'both'],
898
+ axes: ['both'],
758
899
  handle_append_to: '',
759
900
  handle_class: 'gs-resize-handle',
760
- max_size: [Infinity, Infinity]
901
+ max_size: [Infinity, Infinity],
902
+ min_size: [1, 1]
761
903
  }
762
904
  };
763
905
 
@@ -796,6 +938,8 @@
796
938
  * @param {Boolean} [options.avoid_overlapped_widgets] Avoid that widgets loaded
797
939
  * from the DOM can be overlapped. It is helpful if the positions were
798
940
  * bad stored in the database or if there was any conflict.
941
+ * @param {Boolean} [options.auto_init] Automatically call gridster init
942
+ * method or not when the plugin is instantiated.
799
943
  * @param {Function} [options.serialize_params] Return the data you want
800
944
  * for each widget in the serialization. Two arguments are passed:
801
945
  * `$w`: the jQuery wrapped HTMLElement, and `wgd`: the grid
@@ -806,8 +950,10 @@
806
950
  * @param {Object} [options.draggable] An Object with all options for
807
951
  * Draggable class you want to overwrite. See Draggable docs for more
808
952
  * info.
809
- * @param {Object} [options.resize] An Object with resize config
810
- * options.
953
+ * @param {Object|Function} [options.draggable.ignore_dragging] Note that
954
+ * if you use a Function, and resize is enabled, you should ignore the
955
+ * resize handlers manually (options.resize.handle_class).
956
+ * @param {Object} [options.resize] An Object with resize config options.
811
957
  * @param {Boolean} [options.resize.enabled] Set to true to enable
812
958
  * resizing.
813
959
  * @param {Array} [options.resize.axes] Axes in which widgets can be
@@ -819,6 +965,9 @@
819
965
  * @param {Array} [options.resize.max_size] Limit widget dimensions
820
966
  * when resizing. Array values should be integers:
821
967
  * `[max_cols_occupied, max_rows_occupied]`
968
+ * @param {Array} [options.resize.min_size] Limit widget dimensions
969
+ * when resizing. Array values should be integers:
970
+ * `[min_cols_occupied, min_rows_occupied]`
822
971
  * @param {Function} [options.resize.start] Function executed
823
972
  * when resizing starts.
824
973
  * @param {Function} [otions.resize.resize] Function executed
@@ -829,7 +978,7 @@
829
978
  * @constructor
830
979
  */
831
980
  function Gridster(el, options) {
832
- this.options = $.extend(true, defaults, options);
981
+ this.options = $.extend(true, {}, defaults, options);
833
982
  this.$el = $(el);
834
983
  this.$wrapper = this.$el.parent();
835
984
  this.$widgets = this.$el.children(
@@ -842,13 +991,103 @@
842
991
  this.min_widget_height = (this.options.widget_margins[1] * 2) +
843
992
  this.options.widget_base_dimensions[1];
844
993
 
994
+ this.generated_stylesheets = [];
845
995
  this.$style_tags = $([]);
846
996
 
847
- this.init();
997
+ this.options.auto_init && this.init();
848
998
  }
849
999
 
1000
+ Gridster.defaults = defaults;
850
1001
  Gridster.generated_stylesheets = [];
851
1002
 
1003
+
1004
+ /**
1005
+ * Sorts an Array of grid coords objects (representing the grid coords of
1006
+ * each widget) in ascending way.
1007
+ *
1008
+ * @method sort_by_row_asc
1009
+ * @param {Array} widgets Array of grid coords objects
1010
+ * @return {Array} Returns the array sorted.
1011
+ */
1012
+ Gridster.sort_by_row_asc = function(widgets) {
1013
+ widgets = widgets.sort(function(a, b) {
1014
+ if (!a.row) {
1015
+ a = $(a).coords().grid;
1016
+ b = $(b).coords().grid;
1017
+ }
1018
+
1019
+ if (a.row > b.row) {
1020
+ return 1;
1021
+ }
1022
+ return -1;
1023
+ });
1024
+
1025
+ return widgets;
1026
+ };
1027
+
1028
+
1029
+ /**
1030
+ * Sorts an Array of grid coords objects (representing the grid coords of
1031
+ * each widget) placing first the empty cells upper left.
1032
+ *
1033
+ * @method sort_by_row_and_col_asc
1034
+ * @param {Array} widgets Array of grid coords objects
1035
+ * @return {Array} Returns the array sorted.
1036
+ */
1037
+ Gridster.sort_by_row_and_col_asc = function(widgets) {
1038
+ widgets = widgets.sort(function(a, b) {
1039
+ if (a.row > b.row || a.row === b.row && a.col > b.col) {
1040
+ return 1;
1041
+ }
1042
+ return -1;
1043
+ });
1044
+
1045
+ return widgets;
1046
+ };
1047
+
1048
+
1049
+ /**
1050
+ * Sorts an Array of grid coords objects by column (representing the grid
1051
+ * coords of each widget) in ascending way.
1052
+ *
1053
+ * @method sort_by_col_asc
1054
+ * @param {Array} widgets Array of grid coords objects
1055
+ * @return {Array} Returns the array sorted.
1056
+ */
1057
+ Gridster.sort_by_col_asc = function(widgets) {
1058
+ widgets = widgets.sort(function(a, b) {
1059
+ if (a.col > b.col) {
1060
+ return 1;
1061
+ }
1062
+ return -1;
1063
+ });
1064
+
1065
+ return widgets;
1066
+ };
1067
+
1068
+
1069
+ /**
1070
+ * Sorts an Array of grid coords objects (representing the grid coords of
1071
+ * each widget) in descending way.
1072
+ *
1073
+ * @method sort_by_row_desc
1074
+ * @param {Array} widgets Array of grid coords objects
1075
+ * @return {Array} Returns the array sorted.
1076
+ */
1077
+ Gridster.sort_by_row_desc = function(widgets) {
1078
+ widgets = widgets.sort(function(a, b) {
1079
+ if (a.row + a.size_y < b.row + b.size_y) {
1080
+ return 1;
1081
+ }
1082
+ return -1;
1083
+ });
1084
+ return widgets;
1085
+ };
1086
+
1087
+
1088
+
1089
+ /** Instance Methods **/
1090
+
852
1091
  var fn = Gridster.prototype;
853
1092
 
854
1093
  fn.init = function() {
@@ -856,6 +1095,7 @@
856
1095
  this.generate_grid_and_stylesheet();
857
1096
  this.get_widgets_from_DOM();
858
1097
  this.set_dom_grid_height();
1098
+ this.set_dom_grid_width();
859
1099
  this.$wrapper.addClass('ready');
860
1100
  this.draggable();
861
1101
  this.options.resize.enabled && this.resizable();
@@ -928,20 +1168,23 @@
928
1168
  * @param {Number} [col] The column the widget should start in.
929
1169
  * @param {Number} [row] The row the widget should start in.
930
1170
  * @param {Array} [max_size] max_size Maximun size (in units) for width and height.
1171
+ * @param {Array} [min_size] min_size Minimum size (in units) for width and height.
931
1172
  * @return {HTMLElement} Returns the jQuery wrapped HTMLElement representing.
932
1173
  * the widget that was just created.
933
1174
  */
934
- fn.add_widget = function(html, size_x, size_y, col, row, max_size) {
1175
+ fn.add_widget = function(html, size_x, size_y, col, row, max_size, min_size) {
935
1176
  var pos;
936
1177
  size_x || (size_x = 1);
937
1178
  size_y || (size_y = 1);
938
1179
 
939
1180
  if (!col & !row) {
940
1181
  pos = this.next_position(size_x, size_y);
941
- }else{
1182
+ } else {
942
1183
  pos = {
943
1184
  col: col,
944
- row: row
1185
+ row: row,
1186
+ size_x: size_x,
1187
+ size_y: size_y
945
1188
  };
946
1189
 
947
1190
  this.empty_cells(col, row, size_x, size_y);
@@ -965,12 +1208,42 @@
965
1208
  this.set_widget_max_size($w, max_size);
966
1209
  }
967
1210
 
1211
+ if (min_size) {
1212
+ this.set_widget_min_size($w, min_size);
1213
+ }
1214
+
1215
+ this.set_dom_grid_width();
968
1216
  this.set_dom_grid_height();
969
1217
 
1218
+ this.drag_api.set_limits(this.cols * this.min_widget_width);
1219
+
970
1220
  return $w.fadeIn();
971
1221
  };
972
1222
 
973
1223
 
1224
+ /**
1225
+ * Change widget size limits.
1226
+ *
1227
+ * @method set_widget_min_size
1228
+ * @param {HTMLElement|Number} $widget The jQuery wrapped HTMLElement
1229
+ * representing the widget or an index representing the desired widget.
1230
+ * @param {Array} min_size Minimum size (in units) for width and height.
1231
+ * @return {HTMLElement} Returns instance of gridster Class.
1232
+ */
1233
+ fn.set_widget_min_size = function($widget, min_size) {
1234
+ $widget = typeof $widget === 'number' ?
1235
+ this.$widgets.eq($widget) : $widget;
1236
+
1237
+ if (!$widget.length) { return this; }
1238
+
1239
+ var wgd = $widget.data('coords').grid;
1240
+ wgd.min_size_x = min_size[0];
1241
+ wgd.min_size_y = min_size[1];
1242
+
1243
+ return this;
1244
+ };
1245
+
1246
+
974
1247
  /**
975
1248
  * Change widget size limits.
976
1249
  *
@@ -1017,38 +1290,36 @@
1017
1290
  * @param {HTMLElement} $widget The jQuery wrapped HTMLElement
1018
1291
  * representing the widget.
1019
1292
  * @param {Number} size_x The number of columns that will occupy the widget.
1020
- * @param {Number} size_y The number of rows that will occupy the widget.
1021
- * @param {Boolean} [reposition] Set to false to not move the widget to
1022
- * the left if there is insufficient space on the right.
1023
1293
  * By default <code>size_x</code> is limited to the space available from
1024
1294
  * the column where the widget begins, until the last column to the right.
1295
+ * @param {Number} size_y The number of rows that will occupy the widget.
1025
1296
  * @param {Function} [callback] Function executed when the widget is removed.
1026
1297
  * @return {HTMLElement} Returns $widget.
1027
1298
  */
1028
- fn.resize_widget = function($widget, size_x, size_y, reposition, callback) {
1299
+ fn.resize_widget = function($widget, size_x, size_y, callback) {
1029
1300
  var wgd = $widget.coords().grid;
1030
- reposition !== false && (reposition = true);
1031
- size_x || (size_x = wgd.size_x);
1032
- size_y || (size_y = wgd.size_y);
1033
-
1034
- if (size_x > this.cols) {
1035
- size_x = this.cols;
1036
- }
1037
-
1301
+ var col = wgd.col;
1302
+ var max_cols = this.options.max_cols;
1038
1303
  var old_size_y = wgd.size_y;
1039
1304
  var old_col = wgd.col;
1040
1305
  var new_col = old_col;
1041
1306
 
1042
- if (reposition && old_col + size_x - 1 > this.cols) {
1043
- var diff = old_col + (size_x - 1) - this.cols;
1044
- var c = old_col - diff;
1045
- new_col = Math.max(1, c);
1307
+ size_x || (size_x = wgd.size_x);
1308
+ size_y || (size_y = wgd.size_y);
1309
+
1310
+ if (max_cols !== Infinity) {
1311
+ size_x = Math.min(size_x, max_cols - col + 1);
1046
1312
  }
1047
1313
 
1048
1314
  if (size_y > old_size_y) {
1049
1315
  this.add_faux_rows(Math.max(size_y - old_size_y, 0));
1050
1316
  }
1051
1317
 
1318
+ var player_rcol = (col + size_x - 1);
1319
+ if (player_rcol > this.cols) {
1320
+ this.add_faux_cols(player_rcol - this.cols);
1321
+ }
1322
+
1052
1323
  var new_grid_data = {
1053
1324
  col: new_col,
1054
1325
  row: wgd.row,
@@ -1059,6 +1330,7 @@
1059
1330
  this.mutate_widget_in_gridmap($widget, wgd, new_grid_data);
1060
1331
 
1061
1332
  this.set_dom_grid_height();
1333
+ this.set_dom_grid_width();
1062
1334
 
1063
1335
  if (callback) {
1064
1336
  callback.call(this, new_grid_data.size_x, new_grid_data.size_y);
@@ -1200,7 +1472,7 @@
1200
1472
 
1201
1473
  $nexts.not($exclude).each($.proxy(function(i, w) {
1202
1474
  var wgd = $(w).coords().grid;
1203
- if (!(wgd.row <= (row + size_y - 1))) { return; }
1475
+ if ( !(wgd.row <= (row + size_y - 1))) { return; }
1204
1476
  var diff = (row + size_y) - wgd.row;
1205
1477
  this.move_widget_down($(w), diff);
1206
1478
  }, this));
@@ -1280,7 +1552,7 @@
1280
1552
  }
1281
1553
 
1282
1554
  if (valid_pos.length) {
1283
- return this.sort_by_row_and_col_asc(valid_pos)[0];
1555
+ return Gridster.sort_by_row_and_col_asc(valid_pos)[0];
1284
1556
  }
1285
1557
  return false;
1286
1558
  };
@@ -1297,7 +1569,7 @@
1297
1569
  * @return {Class} Returns the instance of the Gridster Class.
1298
1570
  */
1299
1571
  fn.remove_widget = function(el, silent, callback) {
1300
- var $el = el instanceof jQuery ? el : $(el);
1572
+ var $el = el instanceof $ ? el : $(el);
1301
1573
  var wgd = $el.coords().grid;
1302
1574
 
1303
1575
  // if silent is a function assume it's a callback
@@ -1361,13 +1633,11 @@
1361
1633
  */
1362
1634
  fn.serialize = function($widgets) {
1363
1635
  $widgets || ($widgets = this.$widgets);
1364
- var result = [];
1365
- $widgets.each($.proxy(function(i, widget) {
1366
- result.push(this.options.serialize_params(
1367
- $(widget), $(widget).coords().grid ) );
1368
- }, this));
1369
1636
 
1370
- return result;
1637
+ return $widgets.map($.proxy(function(i, widget) {
1638
+ var $w = $(widget);
1639
+ return this.options.serialize_params($w, $w.coords().grid);
1640
+ }, this)).get();
1371
1641
  };
1372
1642
 
1373
1643
 
@@ -1385,22 +1655,49 @@
1385
1655
 
1386
1656
 
1387
1657
  /**
1388
- * Creates the grid coords object representing the widget a add it to the
1658
+ * Convert widgets from DOM elements to "widget grid data" Objects.
1659
+ *
1660
+ * @method dom_to_coords
1661
+ * @param {HTMLElement} $widget The widget to be converted.
1662
+ */
1663
+ fn.dom_to_coords = function($widget) {
1664
+ return {
1665
+ 'col': parseInt($widget.attr('data-col'), 10),
1666
+ 'row': parseInt($widget.attr('data-row'), 10),
1667
+ 'size_x': parseInt($widget.attr('data-sizex'), 10) || 1,
1668
+ 'size_y': parseInt($widget.attr('data-sizey'), 10) || 1,
1669
+ 'max_size_x': parseInt($widget.attr('data-max-sizex'), 10) || false,
1670
+ 'max_size_y': parseInt($widget.attr('data-max-sizey'), 10) || false,
1671
+ 'min_size_x': parseInt($widget.attr('data-min-sizex'), 10) || false,
1672
+ 'min_size_y': parseInt($widget.attr('data-min-sizey'), 10) || false,
1673
+ 'el': $widget
1674
+ };
1675
+ };
1676
+
1677
+
1678
+ /**
1679
+ * Creates the grid coords object representing the widget an add it to the
1389
1680
  * mapped array of positions.
1390
1681
  *
1391
1682
  * @method register_widget
1392
- * @return {Array} Returns the instance of the Gridster class.
1683
+ * @param {HTMLElement|Object} $el jQuery wrapped HTMLElement representing
1684
+ * the widget, or an "widget grid data" Object with (col, row, el ...).
1685
+ * @return {Boolean} Returns true if the widget final position is different
1686
+ * than the original.
1393
1687
  */
1394
1688
  fn.register_widget = function($el) {
1395
- var wgd = {
1396
- 'col': parseInt($el.attr('data-col'), 10),
1397
- 'row': parseInt($el.attr('data-row'), 10),
1398
- 'size_x': parseInt($el.attr('data-sizex'), 10),
1399
- 'size_y': parseInt($el.attr('data-sizey'), 10),
1400
- 'max_size_x': parseInt($el.attr('data-max-sizex'), 10) || false,
1401
- 'max_size_y': parseInt($el.attr('data-max-sizey'), 10) || false,
1402
- 'el': $el
1403
- };
1689
+ var isDOM = $el instanceof jQuery;
1690
+ var wgd = isDOM ? this.dom_to_coords($el) : $el;
1691
+ var posChanged = false;
1692
+ isDOM || ($el = wgd.el);
1693
+
1694
+ var empty_upper_row = this.can_go_widget_up(wgd);
1695
+ if (empty_upper_row) {
1696
+ wgd.row = empty_upper_row;
1697
+ $el.attr('data-row', empty_upper_row);
1698
+ this.$el.trigger('gridster:positionchanged', [wgd]);
1699
+ posChanged = true;
1700
+ }
1404
1701
 
1405
1702
  if (this.options.avoid_overlapped_widgets &&
1406
1703
  !this.can_move_to(
@@ -1413,6 +1710,7 @@
1413
1710
  'data-sizex': wgd.size_x,
1414
1711
  'data-sizey': wgd.size_y
1415
1712
  });
1713
+ posChanged = true;
1416
1714
  }
1417
1715
 
1418
1716
  // attach Coord object to player data-coord attribute
@@ -1424,7 +1722,7 @@
1424
1722
 
1425
1723
  this.options.resize.enabled && this.add_resize_handle($el);
1426
1724
 
1427
- return this;
1725
+ return posChanged;
1428
1726
  };
1429
1727
 
1430
1728
 
@@ -1495,9 +1793,9 @@
1495
1793
  var self = this;
1496
1794
  var draggable_options = $.extend(true, {}, this.options.draggable, {
1497
1795
  offset_left: this.options.widget_margins[0],
1498
- container_width: this.container_width,
1499
- ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON',
1500
- '.' + this.options.resize.handle_class],
1796
+ offset_top: this.options.widget_margins[1],
1797
+ container_width: this.cols * this.min_widget_width,
1798
+ limit: true,
1501
1799
  start: function(event, ui) {
1502
1800
  self.$widgets.filter('.player-revert')
1503
1801
  .removeClass('player-revert');
@@ -1537,6 +1835,8 @@
1537
1835
  offset_left: this.options.widget_margins[0],
1538
1836
  container_width: this.container_width,
1539
1837
  move_element: false,
1838
+ resize: true,
1839
+ limit: this.options.autogrow_cols ? false : true,
1540
1840
  start: $.proxy(this.on_start_resize, this),
1541
1841
  stop: $.proxy(function(event, ui) {
1542
1842
  delay($.proxy(function() {
@@ -1565,6 +1865,12 @@
1565
1865
  this.resize_handle_tpl = $.map(axes, function(type) {
1566
1866
  return handle_tpl.replace('{type}', type);
1567
1867
  }).join('');
1868
+
1869
+ if ($.isArray(this.options.draggable.ignore_dragging)) {
1870
+ this.options.draggable.ignore_dragging.push(
1871
+ '.' + this.resize_handle_class);
1872
+ }
1873
+
1568
1874
  return this;
1569
1875
  };
1570
1876
 
@@ -1579,13 +1885,23 @@
1579
1885
  fn.on_start_drag = function(event, ui) {
1580
1886
  this.$helper.add(this.$player).add(this.$wrapper).addClass('dragging');
1581
1887
 
1888
+ this.highest_col = this.get_highest_occupied_cell().col;
1889
+
1582
1890
  this.$player.addClass('player');
1583
1891
  this.player_grid_data = this.$player.coords().grid;
1584
1892
  this.placeholder_grid_data = $.extend({}, this.player_grid_data);
1585
1893
 
1586
- //set new grid height along the dragging period
1587
- this.$el.css('height', this.$el.height() +
1588
- (this.player_grid_data.size_y * this.min_widget_height));
1894
+ this.set_dom_grid_height(this.$el.height() +
1895
+ (this.player_grid_data.size_y * this.min_widget_height));
1896
+
1897
+ this.set_dom_grid_width(this.cols);
1898
+
1899
+ var pgd_sizex = this.player_grid_data.size_x;
1900
+ var cols_diff = this.cols - this.highest_col;
1901
+
1902
+ if (this.options.autogrow_cols && cols_diff <= pgd_sizex) {
1903
+ this.add_faux_cols(Math.min(pgd_sizex - cols_diff, 1));
1904
+ }
1589
1905
 
1590
1906
  var colliders = this.faux_grid;
1591
1907
  var coords = this.$player.data('coords').coords;
@@ -1636,18 +1952,30 @@
1636
1952
  top: ui.position.top + this.baseY
1637
1953
  };
1638
1954
 
1955
+ // auto grow cols
1956
+ if (this.options.autogrow_cols) {
1957
+ var prcol = this.placeholder_grid_data.col +
1958
+ this.placeholder_grid_data.size_x - 1;
1959
+
1960
+ // "- 1" due to adding at least 1 column in on_start_drag
1961
+ if (prcol >= this.cols - 1 && this.options.max_cols >= this.cols + 1) {
1962
+ this.add_faux_cols(1);
1963
+ this.set_dom_grid_width(this.cols + 1);
1964
+ this.drag_api.set_limits(this.container_width);
1965
+ }
1966
+
1967
+ this.collision_api.set_colliders(this.faux_grid);
1968
+ }
1969
+
1639
1970
  this.colliders_data = this.collision_api.get_closest_colliders(
1640
1971
  abs_offset);
1641
1972
 
1642
1973
  this.on_overlapped_column_change(
1643
- this.on_start_overlapping_column,
1644
- this.on_stop_overlapping_column
1645
- );
1974
+ this.on_start_overlapping_column, this.on_stop_overlapping_column);
1646
1975
 
1647
1976
  this.on_overlapped_row_change(
1648
- this.on_start_overlapping_row,
1649
- this.on_stop_overlapping_row
1650
- );
1977
+ this.on_start_overlapping_row, this.on_stop_overlapping_row);
1978
+
1651
1979
 
1652
1980
  if (this.helper && this.$player) {
1653
1981
  this.$player.css({
@@ -1661,6 +1989,7 @@
1661
1989
  }
1662
1990
  };
1663
1991
 
1992
+
1664
1993
  /**
1665
1994
  * This function is executed when the player stops being dragged.
1666
1995
  *
@@ -1720,8 +2049,12 @@
1720
2049
  this.cells_occupied_by_player = {};
1721
2050
 
1722
2051
  this.set_dom_grid_height();
1723
- };
2052
+ this.set_dom_grid_width();
1724
2053
 
2054
+ if (this.options.autogrow_cols) {
2055
+ this.drag_api.set_limits(this.cols * this.min_widget_width);
2056
+ }
2057
+ };
1725
2058
 
1726
2059
 
1727
2060
  /**
@@ -1739,13 +2072,25 @@
1739
2072
  this.resize_initial_height = this.resize_coords.coords.height;
1740
2073
  this.resize_initial_sizex = this.resize_coords.grid.size_x;
1741
2074
  this.resize_initial_sizey = this.resize_coords.grid.size_y;
2075
+ this.resize_initial_col = this.resize_coords.grid.col;
1742
2076
  this.resize_last_sizex = this.resize_initial_sizex;
1743
2077
  this.resize_last_sizey = this.resize_initial_sizey;
2078
+
1744
2079
  this.resize_max_size_x = Math.min(this.resize_wgd.max_size_x ||
1745
- this.options.resize.max_size[0], this.cols - this.resize_wgd.col + 1);
2080
+ this.options.resize.max_size[0],
2081
+ this.options.max_cols - this.resize_initial_col + 1);
1746
2082
  this.resize_max_size_y = this.resize_wgd.max_size_y ||
1747
2083
  this.options.resize.max_size[1];
1748
2084
 
2085
+ this.resize_min_size_x = (this.resize_wgd.min_size_x ||
2086
+ this.options.resize.min_size[0] || 1);
2087
+ this.resize_min_size_y = (this.resize_wgd.min_size_y ||
2088
+ this.options.resize.min_size[1] || 1);
2089
+
2090
+ this.resize_initial_last_col = this.get_highest_occupied_cell().col;
2091
+
2092
+ this.set_dom_grid_width(this.cols);
2093
+
1749
2094
  this.resize_dir = {
1750
2095
  right: ui.$player.is('.' + this.resize_handle_class + '-x'),
1751
2096
  bottom: ui.$player.is('.' + this.resize_handle_class + '-y')
@@ -1769,9 +2114,11 @@
1769
2114
 
1770
2115
  this.$resized_widget.addClass('resizing');
1771
2116
 
1772
- if (this.options.resize.start) {
2117
+ if (this.options.resize.start) {
1773
2118
  this.options.resize.start.call(this, event, ui, this.$resized_widget);
1774
2119
  }
2120
+
2121
+ this.$el.trigger('gridster:resizestart');
1775
2122
  };
1776
2123
 
1777
2124
 
@@ -1797,13 +2144,22 @@
1797
2144
  'min-width': '',
1798
2145
  'min-height': ''
1799
2146
  });
2147
+
2148
+ if (this.options.resize.stop) {
2149
+ this.options.resize.stop.call(this, event, ui, this.$resized_widget);
2150
+ }
2151
+
2152
+ this.$el.trigger('gridster:resizestop');
1800
2153
  }, this), 300);
1801
2154
 
1802
- if (this.options.resize.stop) {
1803
- this.options.resize.stop.call(this, event, ui, this.$resized_widget);
2155
+ this.set_dom_grid_width();
2156
+
2157
+ if (this.options.autogrow_cols) {
2158
+ this.drag_api.set_limits(this.cols * this.min_widget_width);
1804
2159
  }
1805
2160
  };
1806
2161
 
2162
+
1807
2163
  /**
1808
2164
  * This function is executed when a widget is being resized.
1809
2165
  *
@@ -1816,28 +2172,36 @@
1816
2172
  var rel_y = (ui.pointer.diff_top);
1817
2173
  var wbd_x = this.options.widget_base_dimensions[0];
1818
2174
  var wbd_y = this.options.widget_base_dimensions[1];
2175
+ var margin_x = this.options.widget_margins[0];
2176
+ var margin_y = this.options.widget_margins[1];
2177
+ var max_size_x = this.resize_max_size_x;
2178
+ var min_size_x = this.resize_min_size_x;
2179
+ var max_size_y = this.resize_max_size_y;
2180
+ var min_size_y = this.resize_min_size_y;
2181
+ var autogrow = this.options.autogrow_cols;
2182
+ var width;
1819
2183
  var max_width = Infinity;
1820
2184
  var max_height = Infinity;
1821
2185
 
1822
- var inc_units_x = Math.ceil((rel_x /
1823
- (this.options.widget_base_dimensions[0] +
1824
- this.options.widget_margins[0] * 2)) - 0.2);
1825
-
1826
- var inc_units_y = Math.ceil((rel_y /
1827
- (this.options.widget_base_dimensions[1] +
1828
- this.options.widget_margins[1] * 2)) - 0.2);
2186
+ var inc_units_x = Math.ceil((rel_x / (wbd_x + margin_x * 2)) - 0.2);
2187
+ var inc_units_y = Math.ceil((rel_y / (wbd_y + margin_y * 2)) - 0.2);
1829
2188
 
1830
2189
  var size_x = Math.max(1, this.resize_initial_sizex + inc_units_x);
1831
2190
  var size_y = Math.max(1, this.resize_initial_sizey + inc_units_y);
1832
2191
 
1833
- size_x = Math.min(size_x, this.resize_max_size_x);
1834
- max_width = (this.resize_max_size_x * wbd_x) +
1835
- ((size_x - 1) * this.options.widget_margins[0] * 2);
2192
+ var max_cols = (this.container_width / this.min_widget_width) -
2193
+ this.resize_initial_col + 1;
2194
+ var limit_width = ((max_cols * this.min_widget_width) - margin_x * 2);
1836
2195
 
1837
- size_y = Math.min(size_y, this.resize_max_size_y);
1838
- max_height = (this.resize_max_size_y * wbd_y) +
1839
- ((size_y - 1) * this.options.widget_margins[1] * 2);
2196
+ size_x = Math.max(Math.min(size_x, max_size_x), min_size_x);
2197
+ size_x = Math.min(max_cols, size_x);
2198
+ width = (max_size_x * wbd_x) + ((size_x - 1) * margin_x * 2);
2199
+ max_width = Math.min(width, limit_width);
2200
+ min_width = (min_size_x * wbd_x) + ((size_x - 1) * margin_x * 2);
1840
2201
 
2202
+ size_y = Math.max(Math.min(size_y, max_size_y), min_size_y);
2203
+ max_height = (max_size_y * wbd_y) + ((size_y - 1) * margin_y * 2);
2204
+ min_height = (min_size_y * wbd_y) + ((size_y - 1) * margin_y * 2);
1841
2205
 
1842
2206
  if (this.resize_dir.right) {
1843
2207
  size_y = this.resize_initial_sizey;
@@ -1845,18 +2209,30 @@
1845
2209
  size_x = this.resize_initial_sizex;
1846
2210
  }
1847
2211
 
2212
+ if (autogrow) {
2213
+ var last_widget_col = this.resize_initial_col + size_x - 1;
2214
+ if (autogrow && this.resize_initial_last_col <= last_widget_col) {
2215
+ this.set_dom_grid_width(Math.max(last_widget_col + 1, this.cols));
2216
+
2217
+ if (this.cols < last_widget_col) {
2218
+ this.add_faux_cols(last_widget_col - this.cols);
2219
+ }
2220
+ }
2221
+ }
2222
+
1848
2223
  var css_props = {};
1849
- !this.resize_dir.bottom && (css_props.width = Math.min(
1850
- this.resize_initial_width + rel_x, max_width));
1851
- !this.resize_dir.right && (css_props.height = Math.min(
1852
- this.resize_initial_height + rel_y, max_height));
2224
+ !this.resize_dir.bottom && (css_props.width = Math.max(Math.min(
2225
+ this.resize_initial_width + rel_x, max_width), min_width));
2226
+ !this.resize_dir.right && (css_props.height = Math.max(Math.min(
2227
+ this.resize_initial_height + rel_y, max_height), min_height));
1853
2228
 
1854
2229
  this.$resized_widget.css(css_props);
1855
2230
 
1856
2231
  if (size_x !== this.resize_last_sizex ||
1857
2232
  size_y !== this.resize_last_sizey) {
1858
2233
 
1859
- this.resize_widget(this.$resized_widget, size_x, size_y, false);
2234
+ this.resize_widget(this.$resized_widget, size_x, size_y);
2235
+ this.set_dom_grid_width(this.cols);
1860
2236
 
1861
2237
  this.$resize_preview_holder.css({
1862
2238
  'width': '',
@@ -1872,6 +2248,8 @@
1872
2248
  this.options.resize.resize.call(this, event, ui, this.$resized_widget);
1873
2249
  }
1874
2250
 
2251
+ this.$el.trigger('gridster:resize');
2252
+
1875
2253
  this.resize_last_sizex = size_x;
1876
2254
  this.resize_last_sizey = size_y;
1877
2255
  };
@@ -2028,7 +2406,7 @@
2028
2406
  if (this.can_go_widget_up(wgd)) {
2029
2407
  $widgets_can_go_up = $widgets_can_go_up.add($w);
2030
2408
  wgd_can_go_up.push(wgd);
2031
- }else{
2409
+ } else {
2032
2410
  wgd_can_not_go_up.push(wgd);
2033
2411
  }
2034
2412
  }, this));
@@ -2036,96 +2414,12 @@
2036
2414
  $widgets_can_not_go_up = $widgets.not($widgets_can_go_up);
2037
2415
 
2038
2416
  return {
2039
- can_go_up: this.sort_by_row_asc(wgd_can_go_up),
2040
- can_not_go_up: this.sort_by_row_desc(wgd_can_not_go_up)
2417
+ can_go_up: Gridster.sort_by_row_asc(wgd_can_go_up),
2418
+ can_not_go_up: Gridster.sort_by_row_desc(wgd_can_not_go_up)
2041
2419
  };
2042
2420
  };
2043
2421
 
2044
2422
 
2045
- /**
2046
- * Sorts an Array of grid coords objects (representing the grid coords of
2047
- * each widget) in ascending way.
2048
- *
2049
- * @method sort_by_row_asc
2050
- * @param {Array} widgets Array of grid coords objects
2051
- * @return {Array} Returns the array sorted.
2052
- */
2053
- fn.sort_by_row_asc = function(widgets) {
2054
- widgets = widgets.sort(function(a, b) {
2055
- if (!a.row) {
2056
- a = $(a).coords().grid;
2057
- b = $(b).coords().grid;
2058
- }
2059
-
2060
- if (a.row > b.row) {
2061
- return 1;
2062
- }
2063
- return -1;
2064
- });
2065
-
2066
- return widgets;
2067
- };
2068
-
2069
-
2070
- /**
2071
- * Sorts an Array of grid coords objects (representing the grid coords of
2072
- * each widget) placing first the empty cells upper left.
2073
- *
2074
- * @method sort_by_row_and_col_asc
2075
- * @param {Array} widgets Array of grid coords objects
2076
- * @return {Array} Returns the array sorted.
2077
- */
2078
- fn.sort_by_row_and_col_asc = function(widgets) {
2079
- widgets = widgets.sort(function(a, b) {
2080
- if (a.row > b.row || a.row === b.row && a.col > b.col) {
2081
- return 1;
2082
- }
2083
- return -1;
2084
- });
2085
-
2086
- return widgets;
2087
- };
2088
-
2089
-
2090
- /**
2091
- * Sorts an Array of grid coords objects by column (representing the grid
2092
- * coords of each widget) in ascending way.
2093
- *
2094
- * @method sort_by_col_asc
2095
- * @param {Array} widgets Array of grid coords objects
2096
- * @return {Array} Returns the array sorted.
2097
- */
2098
- fn.sort_by_col_asc = function(widgets) {
2099
- widgets = widgets.sort(function(a, b) {
2100
- if (a.col > b.col) {
2101
- return 1;
2102
- }
2103
- return -1;
2104
- });
2105
-
2106
- return widgets;
2107
- };
2108
-
2109
-
2110
- /**
2111
- * Sorts an Array of grid coords objects (representing the grid coords of
2112
- * each widget) in descending way.
2113
- *
2114
- * @method sort_by_row_desc
2115
- * @param {Array} widgets Array of grid coords objects
2116
- * @return {Array} Returns the array sorted.
2117
- */
2118
- fn.sort_by_row_desc = function(widgets) {
2119
- widgets = widgets.sort(function(a, b) {
2120
- if (a.row + a.size_y < b.row + b.size_y) {
2121
- return 1;
2122
- }
2123
- return -1;
2124
- });
2125
- return widgets;
2126
- };
2127
-
2128
-
2129
2423
  /**
2130
2424
  * Sorts an Array of grid coords objects (representing the grid coords of
2131
2425
  * each widget) in descending way.
@@ -2240,14 +2534,14 @@
2240
2534
  */
2241
2535
  fn.is_empty = function(col, row) {
2242
2536
  if (typeof this.gridmap[col] !== 'undefined') {
2243
- if(typeof this.gridmap[col][row] !== 'undefined' &&
2244
- this.gridmap[col][row] === false
2245
- ) {
2246
- return true;
2247
- }
2248
- return false;
2249
- }
2250
- return true;
2537
+ if(typeof this.gridmap[col][row] !== 'undefined' &&
2538
+ this.gridmap[col][row] === false
2539
+ ) {
2540
+ return true;
2541
+ }
2542
+ return false;
2543
+ }
2544
+ return true;
2251
2545
  };
2252
2546
 
2253
2547
 
@@ -2426,7 +2720,7 @@
2426
2720
  ) {
2427
2721
  upper_rows[tcol].push(r);
2428
2722
  min_row = r < min_row ? r : min_row;
2429
- }else{
2723
+ } else {
2430
2724
  break;
2431
2725
  }
2432
2726
  }
@@ -2545,7 +2839,7 @@
2545
2839
  if (valid_rows[0] !== p_top_row) {
2546
2840
  new_row = valid_rows[0] || false;
2547
2841
  }
2548
- }else{
2842
+ } else {
2549
2843
  if (valid_rows[0] !== p_top_row) {
2550
2844
  new_row = this.get_consecutive_numbers_index(
2551
2845
  valid_rows, size_y);
@@ -2569,7 +2863,7 @@
2569
2863
  break;
2570
2864
  }
2571
2865
  first = false;
2572
- }else{
2866
+ } else {
2573
2867
  result = [];
2574
2868
  first = true;
2575
2869
  }
@@ -2847,7 +3141,7 @@
2847
3141
  !this.is_placeholder_in(tcol, r)
2848
3142
  ) {
2849
3143
  urc[tcol].push(r);
2850
- }else{
3144
+ } else {
2851
3145
  break;
2852
3146
  }
2853
3147
  }
@@ -2930,7 +3224,7 @@
2930
3224
  });
2931
3225
  });
2932
3226
 
2933
- return this.sort_by_row_asc($nexts);
3227
+ return Gridster.sort_by_row_asc($nexts);
2934
3228
  };
2935
3229
 
2936
3230
 
@@ -2990,7 +3284,6 @@
2990
3284
  };
2991
3285
 
2992
3286
 
2993
-
2994
3287
  /**
2995
3288
  * Check if it's possible to move a widget to a specific col/row. It takes
2996
3289
  * into account the dimensions (`size_y` and `size_x` attrs. of the grid
@@ -3082,7 +3375,7 @@
3082
3375
  fn.get_cells_occupied = function(el_grid_data) {
3083
3376
  var cells = { cols: [], rows: []};
3084
3377
  var i;
3085
- if (arguments[1] instanceof jQuery) {
3378
+ if (arguments[1] instanceof $) {
3086
3379
  el_grid_data = arguments[1].coords().grid;
3087
3380
  }
3088
3381
 
@@ -3166,7 +3459,7 @@
3166
3459
 
3167
3460
  var cr, max;
3168
3461
  var action = type + '/' + direction;
3169
- if (arguments[2] instanceof jQuery) {
3462
+ if (arguments[2] instanceof $) {
3170
3463
  var el_grid_data = arguments[2].coords().grid;
3171
3464
  col = el_grid_data.col;
3172
3465
  row = el_grid_data.row;
@@ -3250,26 +3543,23 @@
3250
3543
  fn.get_highest_occupied_cell = function() {
3251
3544
  var r;
3252
3545
  var gm = this.gridmap;
3253
- var rows = [];
3546
+ var rl = gm[1].length;
3547
+ var rows = [], cols = [];
3254
3548
  var row_in_col = [];
3255
3549
  for (var c = gm.length - 1; c >= 1; c--) {
3256
- for (r = gm[c].length - 1; r >= 1; r--) {
3550
+ for (r = rl - 1; r >= 1; r--) {
3257
3551
  if (this.is_widget(c, r)) {
3258
3552
  rows.push(r);
3259
- row_in_col[r] = c;
3553
+ cols.push(c);
3260
3554
  break;
3261
3555
  }
3262
3556
  }
3263
3557
  }
3264
3558
 
3265
- var highest_row = Math.max.apply(Math, rows);
3266
-
3267
- this.highest_occupied_cell = {
3268
- col: row_in_col[highest_row],
3269
- row: highest_row
3559
+ return {
3560
+ col: Math.max.apply(Math, cols),
3561
+ row: Math.max.apply(Math, rows)
3270
3562
  };
3271
-
3272
- return this.highest_occupied_cell;
3273
3563
  };
3274
3564
 
3275
3565
 
@@ -3305,9 +3595,34 @@
3305
3595
  * @method set_dom_grid_height
3306
3596
  * @return {Object} Returns the instance of the Gridster class.
3307
3597
  */
3308
- fn.set_dom_grid_height = function() {
3309
- var r = this.get_highest_occupied_cell().row;
3310
- this.$el.css('height', r * this.min_widget_height);
3598
+ fn.set_dom_grid_height = function(height) {
3599
+ if (typeof height === 'undefined') {
3600
+ var r = this.get_highest_occupied_cell().row;
3601
+ height = r * this.min_widget_height;
3602
+ }
3603
+
3604
+ this.container_height = height;
3605
+ this.$el.css('height', this.container_height);
3606
+ return this;
3607
+ };
3608
+
3609
+ /**
3610
+ * Set the current width of the parent grid.
3611
+ *
3612
+ * @method set_dom_grid_width
3613
+ * @return {Object} Returns the instance of the Gridster class.
3614
+ */
3615
+ fn.set_dom_grid_width = function(cols) {
3616
+ if (typeof cols === 'undefined') {
3617
+ cols = this.get_highest_occupied_cell().col;
3618
+ }
3619
+
3620
+ var max_cols = (this.options.autogrow_cols ? this.options.max_cols :
3621
+ this.cols);
3622
+
3623
+ cols = Math.min(max_cols, Math.max(cols, this.options.min_cols));
3624
+ this.container_width = cols * this.min_widget_width;
3625
+ this.$el.css('width', this.container_width);
3311
3626
  return this;
3312
3627
  };
3313
3628
 
@@ -3347,6 +3662,7 @@
3347
3662
  return false;
3348
3663
  }
3349
3664
 
3665
+ this.generated_stylesheets.push(serialized_opts);
3350
3666
  Gridster.generated_stylesheets.push(serialized_opts);
3351
3667
 
3352
3668
  /* generate CSS styles for cols */
@@ -3377,6 +3693,8 @@
3377
3693
  (x - 1) * (opts.widget_margins[0] * 2)) + 'px; }\n');
3378
3694
  }
3379
3695
 
3696
+ this.remove_style_tags();
3697
+
3380
3698
  return this.add_style_tag(styles);
3381
3699
  };
3382
3700
 
@@ -3389,21 +3707,21 @@
3389
3707
  * @return {Object} Returns the instance of the Gridster class.
3390
3708
  */
3391
3709
  fn.add_style_tag = function(css) {
3392
- var d = document;
3393
- var tag = d.createElement('style');
3710
+ var d = document;
3711
+ var tag = d.createElement('style');
3394
3712
 
3395
- d.getElementsByTagName('head')[0].appendChild(tag);
3396
- tag.setAttribute('type', 'text/css');
3713
+ d.getElementsByTagName('head')[0].appendChild(tag);
3714
+ tag.setAttribute('type', 'text/css');
3397
3715
 
3398
- if (tag.styleSheet) {
3399
- tag.styleSheet.cssText = css;
3400
- }else{
3401
- tag.appendChild(document.createTextNode(css));
3402
- }
3716
+ if (tag.styleSheet) {
3717
+ tag.styleSheet.cssText = css;
3718
+ } else {
3719
+ tag.appendChild(document.createTextNode(css));
3720
+ }
3403
3721
 
3404
- this.$style_tags = this.$style_tags.add(tag);
3722
+ this.$style_tags = this.$style_tags.add(tag);
3405
3723
 
3406
- return this;
3724
+ return this;
3407
3725
  };
3408
3726
 
3409
3727
 
@@ -3414,7 +3732,14 @@
3414
3732
  * @return {Object} Returns the instance of the Gridster class.
3415
3733
  */
3416
3734
  fn.remove_style_tags = function() {
3735
+ var all_styles = Gridster.generated_stylesheets;
3736
+ var ins_styles = this.generated_stylesheets;
3737
+
3417
3738
  this.$style_tags.remove();
3739
+
3740
+ Gridster.generated_stylesheets = $.map(all_styles, function(s) {
3741
+ if ($.inArray(s, ins_styles) === -1) { return s; }
3742
+ });
3418
3743
  };
3419
3744
 
3420
3745
 
@@ -3509,8 +3834,9 @@
3509
3834
  fn.add_faux_cols = function(cols) {
3510
3835
  var actual_cols = this.cols;
3511
3836
  var max_cols = actual_cols + (cols || 1);
3837
+ max_cols = Math.min(max_cols, this.options.max_cols);
3512
3838
 
3513
- for (var c = actual_cols; c < max_cols; c++) {
3839
+ for (var c = actual_cols + 1; c <= max_cols; c++) {
3514
3840
  for (var r = this.rows; r >= 1; r--) {
3515
3841
  this.add_faux_cell(r, c);
3516
3842
  }
@@ -3543,7 +3869,6 @@
3543
3869
  left: this.baseX + (coords.data.col -1) * this.min_widget_width,
3544
3870
  top: this.baseY + (coords.data.row -1) * this.min_widget_height
3545
3871
  });
3546
-
3547
3872
  }, this));
3548
3873
 
3549
3874
  return this;
@@ -3557,9 +3882,21 @@
3557
3882
  * @return {Object} Returns the instance of the Gridster class.
3558
3883
  */
3559
3884
  fn.get_widgets_from_DOM = function() {
3560
- this.$widgets.each($.proxy(function(i, widget) {
3561
- this.register_widget($(widget));
3885
+ var widgets_coords = this.$widgets.map($.proxy(function(i, widget) {
3886
+ var $w = $(widget);
3887
+ return this.dom_to_coords($w);
3888
+ }, this));
3889
+
3890
+ widgets_coords = Gridster.sort_by_row_and_col_asc(widgets_coords);
3891
+
3892
+ var changes = $(widgets_coords).map($.proxy(function(i, wgd) {
3893
+ return this.register_widget(wgd) || null;
3562
3894
  }, this));
3895
+
3896
+ if (changes.length) {
3897
+ this.$el.trigger('gridster:positionschanged');
3898
+ }
3899
+
3563
3900
  return this;
3564
3901
  };
3565
3902
 
@@ -3573,7 +3910,6 @@
3573
3910
  */
3574
3911
  fn.generate_grid_and_stylesheet = function() {
3575
3912
  var aw = this.$wrapper.width();
3576
- var ah = this.$wrapper.height();
3577
3913
  var max_cols = this.options.max_cols;
3578
3914
 
3579
3915
  var cols = Math.floor(aw / this.min_widget_width) +
@@ -3588,28 +3924,23 @@
3588
3924
 
3589
3925
  var min_cols = Math.max.apply(Math, actual_cols);
3590
3926
 
3927
+ this.cols = Math.max(min_cols, cols, this.options.min_cols);
3928
+
3929
+ if (max_cols !== Infinity && max_cols >= min_cols && max_cols < this.cols) {
3930
+ this.cols = max_cols;
3931
+ }
3932
+
3591
3933
  // get all rows that could be occupied by the current widgets
3592
3934
  var max_rows = this.options.extra_rows;
3593
3935
  this.$widgets.each(function(i, w) {
3594
3936
  max_rows += (+$(w).attr('data-sizey'));
3595
3937
  });
3596
3938
 
3597
- this.cols = Math.max(min_cols, cols, this.options.min_cols);
3598
-
3599
- if (max_cols && max_cols >= min_cols && max_cols < this.cols) {
3600
- this.cols = max_cols;
3601
- }
3602
-
3603
3939
  this.rows = Math.max(max_rows, this.options.min_rows);
3604
3940
 
3605
3941
  this.baseX = ($(window).width() - aw) / 2;
3606
3942
  this.baseY = this.$wrapper.offset().top;
3607
3943
 
3608
- // left and right gutters not included
3609
- this.container_width = (this.cols *
3610
- this.options.widget_base_dimensions[0]) + ((this.cols - 1) * 2 *
3611
- this.options.widget_margins[0]);
3612
-
3613
3944
  if (this.options.autogenerate_stylesheet) {
3614
3945
  this.generate_stylesheet();
3615
3946
  }
@@ -3621,9 +3952,12 @@
3621
3952
  * Destroy this gridster by removing any sign of its presence, making it easy to avoid memory leaks
3622
3953
  *
3623
3954
  * @method destroy
3624
- * @return {undefined}
3955
+ * @param {Boolean} remove If true, remove gridster from DOM.
3956
+ * @return {Object} Returns the instance of the Gridster class.
3625
3957
  */
3626
- fn.destroy = function(){
3958
+ fn.destroy = function(remove) {
3959
+ this.$el.removeData('gridster');
3960
+
3627
3961
  // remove bound callback on window resize
3628
3962
  $(window).unbind('.gridster');
3629
3963
 
@@ -3633,10 +3967,7 @@
3633
3967
 
3634
3968
  this.remove_style_tags();
3635
3969
 
3636
- // lastly, remove gridster element
3637
- // this will additionally cause any data associated to this element to be removed, including this
3638
- // very gridster instance
3639
- this.$el.remove();
3970
+ remove && this.$el.remove();
3640
3971
 
3641
3972
  return this;
3642
3973
  };
@@ -3644,13 +3975,13 @@
3644
3975
 
3645
3976
  //jQuery adapter
3646
3977
  $.fn.gridster = function(options) {
3647
- return this.each(function() {
3648
- if (!$(this).data('gridster')) {
3649
- $(this).data('gridster', new Gridster( this, options ));
3650
- }
3651
- });
3978
+ return this.each(function() {
3979
+ if (! $(this).data('gridster')) {
3980
+ $(this).data('gridster', new Gridster( this, options ));
3981
+ }
3982
+ });
3652
3983
  };
3653
3984
 
3654
- $.Gridster = fn;
3985
+ return Gridster;
3655
3986
 
3656
- }(jQuery, window, document));
3987
+ }));