gridster-rails 0.1.5.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b869a9b59bca1d2a0551589ae56516d5126ce168
4
- data.tar.gz: 0c1a8618e4efedd30d4504c1b7681731c0611b79
3
+ metadata.gz: 674696cba3853465f747492df84085e31e5468d7
4
+ data.tar.gz: 35e4e3ef41c060e809e8251e66bf486e8cdbba02
5
5
  SHA512:
6
- metadata.gz: 67cd453eac549d2319d1135da16726593c32b719027f564aa0bd499273bcae63355eb4af109ffd601235d39472ae0d5622c8056cf78dbea8b75ebcb9c8c1ca4a
7
- data.tar.gz: 05a313e120b0f2267d75cc4ad90411229ead93849a1b583f406621ae6be89f82dd815b79d90aea9ff9a237b27127c1cc7dbb45aa2d5c6c54d8346ab91a37f431
6
+ metadata.gz: 072213c1adade7c2f507dfc95b8f7bd6185c2d11a44377abe6b6aebde174090fa076b423ee2742859388e0d62dda311a798a7c17fa64728a08bdd8a41a266d59
7
+ data.tar.gz: fc8736e205c589d16bd04e0f3cb5e2c921630fa363f0c86f579b647e1d21ad572c34278e78f9605eaeb54a912f2a551e772c98712c94537ce8394000ce6c26fc
data/README.md CHANGED
@@ -6,8 +6,8 @@ This is [gridster.js](http://gridster.net) GEMified for the Rails >= 3.1 asset p
6
6
  cd gridster-rails
7
7
  mkdir -p vendor/assets/javascripts
8
8
  mkdir -p vendor/assets/stylesheets
9
- curl https://raw.github.com/dustmoo/gridster.js/master/dist/jquery.gridster.js -o vendor/assets/javascripts/jquery.gridster.js
10
- curl https://raw.github.com/dustmoo/gridster.js/master/dist/jquery.gridster.css -o vendor/assets/stylesheets/jquery.gridster.css
9
+ curl https://raw.github.com/ducksboard/gridster.js/master/dist/jquery.gridster.js -o vendor/assets/javascripts/jquery.gridster.js
10
+ curl https://raw.github.com/ducksboard/gridster.js/master/dist/jquery.gridster.css -o vendor/assets/stylesheets/jquery.gridster.css
11
11
  echo "" >> README.md; echo "# gridster.js appended README #" >> README.md; echo "" >> README.md
12
12
  curl https://raw.github.com/dustmoo/gridster.js/master/README.md >> README.md
13
13
  echo "" >> LICENSE; echo "# gridster.js appended LICENSE #" >> LICENSE; echo "" >> LICENSE
@@ -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.1.5"
21
+ VERSION = "0.2.1"
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.1.5.1"
3
+ VERSION = "0.2.1"
4
4
  end
5
5
  end
@@ -1,10 +1,6 @@
1
- /*
2
- * jquery.coords
3
- * https://github.com/ducksboard/gridster.js
4
- *
5
- * Copyright (c) 2012 ducksboard
6
- * Licensed under the MIT licenses.
7
- */
1
+ /*! gridster.js - v0.2.1 - 2013-10-28
2
+ * http://gridster.net/
3
+ * Copyright (c) 2013 ducksboard; Licensed MIT */
8
4
 
9
5
  ;(function($, window, document, undefined){
10
6
  /**
@@ -107,14 +103,6 @@
107
103
 
108
104
  }(jQuery, window, document));
109
105
 
110
- /*
111
- * jquery.collision
112
- * https://github.com/ducksboard/gridster.js
113
- *
114
- * Copyright (c) 2012 ducksboard
115
- * Licensed under the MIT licenses.
116
- */
117
-
118
106
  ;(function($, window, document, undefined){
119
107
 
120
108
  var defaults = {
@@ -329,6 +317,14 @@
329
317
  }(jQuery, window, document));
330
318
 
331
319
  ;(function(window, undefined) {
320
+
321
+
322
+ window.delay = function(func, wait) {
323
+ var args = Array.prototype.slice.call(arguments, 2);
324
+ return setTimeout(function(){ return func.apply(null, args); }, wait);
325
+ };
326
+
327
+
332
328
  /* Debounce and throttle functions taken from underscore.js */
333
329
  window.debounce = function(func, wait, immediate) {
334
330
  var timeout;
@@ -370,35 +366,30 @@
370
366
 
371
367
  })(window);
372
368
 
373
- /*
374
- * jquery.draggable
375
- * https://github.com/ducksboard/gridster.js
376
- *
377
- * Copyright (c) 2012 ducksboard
378
- * Licensed under the MIT licenses.
379
- */
380
-
381
- ;(function($, window, document, undefined){
369
+ ;(function($, window, document, undefined) {
382
370
 
383
371
  var defaults = {
384
- items: '.gs_w',
372
+ items: 'li',
385
373
  distance: 1,
386
374
  limit: true,
387
375
  offset_left: 0,
388
376
  autoscroll: true,
389
377
  ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'],
390
- handle: null
391
- // drag: function(e){},
392
- // start : function(e, ui){},
393
- // stop : function(e){}
378
+ handle: null,
379
+ container_width: 0, // 0 == auto
380
+ move_element: true,
381
+ helper: false // or 'clone'
382
+ // drag: function(e) {},
383
+ // start : function(e, ui) {},
384
+ // stop : function(e) {}
394
385
  };
395
386
 
396
387
  var $window = $(window);
397
388
  var isTouch = !!('ontouchstart' in window);
398
389
  var pointer_events = {
399
- start: isTouch ? 'touchstart' : 'mousedown.draggable',
400
- move: isTouch ? 'touchmove' : 'mousemove.draggable',
401
- end: isTouch ? 'touchend' : 'mouseup.draggable'
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'
402
393
  };
403
394
 
404
395
  /**
@@ -445,26 +436,25 @@
445
436
  this.disabled = false;
446
437
  this.events();
447
438
 
448
- this.on_window_resize = throttle($.proxy(this.calculate_positions, this), 200);
449
- $(window).bind('resize', this.on_window_resize);
439
+ $(window).bind('resize.gridster-draggable',
440
+ throttle($.proxy(this.calculate_positions, this), 200));
450
441
  };
451
442
 
452
443
  fn.events = function() {
453
- this.proxied_on_select_start = $.proxy(this.on_select_start, this);
454
- this.$container.on('selectstart', this.proxied_on_select_start);
444
+ this.$container.on('selectstart.gridster-draggable',
445
+ $.proxy(this.on_select_start, this));
455
446
 
456
- this.proxied_drag_handler = $.proxy(this.drag_handler, this);
457
- this.$container.on(pointer_events.start, this.options.items, this.proxied_drag_handler);
447
+ this.$container.on(pointer_events.start, this.options.items,
448
+ $.proxy(this.drag_handler, this));
458
449
 
459
- this.proxied_pointer_events_end = $.proxy(function(e) {
450
+ this.$body.on(pointer_events.end, $.proxy(function(e) {
460
451
  this.is_dragging = false;
461
452
  if (this.disabled) { return; }
462
453
  this.$body.off(pointer_events.move);
463
454
  if (this.drag_start) {
464
455
  this.on_dragstop(e);
465
456
  }
466
- }, this);
467
- this.$body.on(pointer_events.end, this.proxied_pointer_events_end);
457
+ }, this));
468
458
  };
469
459
 
470
460
  fn.get_actual_pos = function($el) {
@@ -500,21 +490,36 @@
500
490
  if (this.options.limit) {
501
491
  if (left > this.player_max_left) {
502
492
  left = this.player_max_left;
503
- }else if(left < this.player_min_left) {
493
+ } else if(left < this.player_min_left) {
504
494
  left = this.player_min_left;
505
495
  }
506
496
  }
507
497
 
508
498
  return {
509
- left: left,
510
- top: top,
511
- mouse_left: mouse_actual_pos.left,
512
- mouse_top: mouse_actual_pos.top
499
+ position: {
500
+ left: left,
501
+ top: top
502
+ },
503
+ pointer: {
504
+ left: mouse_actual_pos.left,
505
+ top: mouse_actual_pos.top,
506
+ diff_left: diff_x,
507
+ diff_top: diff_y + this.scrollOffset
508
+ }
513
509
  };
514
510
  };
515
511
 
516
512
 
517
- fn.manage_scroll = function(offset) {
513
+ fn.get_drag_data = function(e) {
514
+ var offset = this.get_offset(e);
515
+ offset.$player = this.$player;
516
+ offset.$helper = this.helper ? this.$helper : this.$player;
517
+
518
+ return offset;
519
+ };
520
+
521
+
522
+ fn.manage_scroll = function(data) {
518
523
  /* scroll document */
519
524
  var nextScrollTop;
520
525
  var scrollTop = $window.scrollTop();
@@ -524,8 +529,8 @@
524
529
  var mouse_down_zone = max_window_y - 50;
525
530
  var mouse_up_zone = min_window_y + 50;
526
531
 
527
- var abs_mouse_left = offset.mouse_left;
528
- var abs_mouse_top = min_window_y + offset.mouse_top;
532
+ var abs_mouse_left = data.pointer.left;
533
+ var abs_mouse_top = min_window_y + data.pointer.top;
529
534
 
530
535
  var max_player_y = (this.doc_height - this.window_height +
531
536
  this.player_height);
@@ -571,7 +576,7 @@
571
576
  this.mouse_init_pos = this.get_mouse_pos(e);
572
577
  this.offsetY = this.mouse_init_pos.top - this.el_init_pos.top;
573
578
 
574
- this.on_pointer_events_move = function(mme){
579
+ this.$body.on(pointer_events.move, function(mme) {
575
580
  var mouse_actual_pos = self.get_mouse_pos(mme);
576
581
  var diff_x = Math.abs(
577
582
  mouse_actual_pos.left - self.mouse_init_pos.left);
@@ -594,18 +599,18 @@
594
599
  }
595
600
 
596
601
  return false;
597
- };
598
-
599
- this.$body.on(pointer_events.move, this.on_pointer_events_move);
602
+ });
600
603
 
601
- return false;
604
+ if (!isTouch) { return false; }
602
605
  };
603
606
 
604
607
 
605
608
  fn.on_dragstart = function(e) {
606
609
  e.preventDefault();
607
- this.drag_start = true;
608
- this.is_dragging = true;
610
+
611
+ if (this.is_dragging) { return this; }
612
+
613
+ this.drag_start = this.is_dragging = true;
609
614
  var offset = this.$container.offset();
610
615
  this.baseX = Math.round(offset.left);
611
616
  this.baseY = Math.round(offset.top);
@@ -615,63 +620,57 @@
615
620
  this.$helper = this.$player.clone()
616
621
  .appendTo(this.$container).addClass('helper');
617
622
  this.helper = true;
618
- }else{
623
+ } else {
619
624
  this.helper = false;
620
625
  }
626
+
621
627
  this.scrollOffset = 0;
622
628
  this.el_init_offset = this.$player.offset();
623
629
  this.player_width = this.$player.width();
624
630
  this.player_height = this.$player.height();
625
- this.player_max_left = (this.$container.width() - this.player_width +
631
+
632
+ var container_width = this.options.container_width || this.$container.width();
633
+ this.player_max_left = (container_width - this.player_width +
626
634
  this.options.offset_left);
627
635
 
628
636
  if (this.options.start) {
629
- this.options.start.call(this.$player, e, {
630
- helper: this.helper ? this.$helper : this.$player
631
- });
637
+ this.options.start.call(this.$player, e, this.get_drag_data(e));
632
638
  }
633
639
  return false;
634
640
  };
635
641
 
636
642
 
637
643
  fn.on_dragmove = function(e) {
638
- var offset = this.get_offset(e);
644
+ var data = this.get_drag_data(e);
639
645
 
640
- this.options.autoscroll && this.manage_scroll(offset);
646
+ this.options.autoscroll && this.manage_scroll(data);
641
647
 
642
- (this.helper ? this.$helper : this.$player).css({
643
- 'position': 'absolute',
644
- 'left' : offset.left,
645
- 'top' : offset.top
646
- });
648
+ if (this.options.move_element) {
649
+ (this.helper ? this.$helper : this.$player).css({
650
+ 'position': 'absolute',
651
+ 'left' : data.position.left,
652
+ 'top' : data.position.top
653
+ });
654
+ }
647
655
 
648
- var ui = {
649
- 'position': {
650
- 'left': offset.left,
651
- 'top': offset.top
652
- }
653
- };
656
+ var last_position = this.last_position || data.position;
657
+ data.prev_position = last_position;
654
658
 
655
659
  if (this.options.drag) {
656
- this.options.drag.call(this.$player, e, ui);
660
+ this.options.drag.call(this.$player, e, data);
657
661
  }
662
+
663
+ this.last_position = data.position;
658
664
  return false;
659
665
  };
660
666
 
661
667
 
662
668
  fn.on_dragstop = function(e) {
663
- var offset = this.get_offset(e);
669
+ var data = this.get_drag_data(e);
664
670
  this.drag_start = false;
665
671
 
666
- var ui = {
667
- 'position': {
668
- 'left': offset.left,
669
- 'top': offset.top
670
- }
671
- };
672
-
673
672
  if (this.options.stop) {
674
- this.options.stop.call(this.$player, e, ui);
673
+ this.options.stop.call(this.$player, e, data);
675
674
  }
676
675
 
677
676
  if (this.helper) {
@@ -699,15 +698,12 @@
699
698
  this.disabled = true;
700
699
  };
701
700
 
702
-
703
- fn.destroy = function(){
701
+ fn.destroy = function() {
704
702
  this.disable();
705
703
 
706
- this.$container.off('selectstart', this.proxied_on_select_start);
707
- this.$container.off(pointer_events.start, this.proxied_drag_handler);
708
- this.$body.off(pointer_events.end, this.proxied_pointer_events_end);
709
- this.$body.off(pointer_events.move, this.on_pointer_events_move);
710
- $(window).unbind('resize', this.on_window_resize);
704
+ this.$container.off('.gridster-draggable');
705
+ this.$body.off('.gridster-draggable');
706
+ $(window).off('.gridster-draggable');
711
707
 
712
708
  $.removeData(this.$container, 'drag');
713
709
  };
@@ -717,47 +713,32 @@
717
713
  return !$(event.target).is(this.options.handle);
718
714
  }
719
715
 
720
- return $.inArray(event.target.nodeName, this.options.ignore_dragging) >= 0;
716
+ return $(event.target).is(this.options.ignore_dragging.join(', '));
721
717
  };
722
718
 
723
719
  //jQuery adapter
724
- $.fn.dragg = function ( options ) {
725
- return this.each(function () {
726
- if (!$.data(this, 'drag')) {
727
- $.data(this, 'drag', new Draggable( this, options ));
728
- }
729
- });
720
+ $.fn.drag = function ( options ) {
721
+ return new Draggable(this, options);
730
722
  };
731
723
 
732
724
 
733
725
  }(jQuery, window, document));
734
726
 
735
- /*
736
- * jquery.gridster
737
- * https://github.com/ducksboard/gridster.js
738
- *
739
- * Copyright (c) 2012 ducksboard
740
- * Licensed under the MIT licenses.
741
- */
742
727
  ;(function($, window, document, undefined) {
743
728
 
744
- //ToDo Max_cols and Max_size_x conflict.. need to unify
745
729
  var defaults = {
746
730
  namespace: '',
747
731
  widget_selector: 'li',
748
- static_class: 'static',
749
732
  widget_margins: [10, 10],
750
733
  widget_base_dimensions: [400, 225],
751
734
  extra_rows: 0,
752
735
  extra_cols: 0,
753
736
  min_cols: 1,
754
- max_cols: 60,
737
+ max_cols: null,
755
738
  min_rows: 15,
756
- max_rows: 15,
757
- max_size_x: 6,
739
+ max_size_x: false,
758
740
  autogenerate_stylesheet: true,
759
741
  avoid_overlapped_widgets: true,
760
- shift_larger_widgets_down: true,
761
742
  serialize_params: function($w, wgd) {
762
743
  return {
763
744
  col: wgd.col,
@@ -768,12 +749,18 @@
768
749
  },
769
750
  collision: {},
770
751
  draggable: {
771
- distance: 4,
772
- items: ".gs_w:not(.static)"
752
+ items: '.gs-w',
753
+ distance: 4
754
+ },
755
+ resize: {
756
+ enabled: false,
757
+ axes: ['x', 'y', 'both'],
758
+ handle_append_to: '',
759
+ handle_class: 'gs-resize-handle',
760
+ max_size: [Infinity, Infinity]
773
761
  }
774
762
  };
775
763
 
776
-
777
764
  /**
778
765
  * @class Gridster
779
766
  * @uses Draggable
@@ -795,6 +782,8 @@
795
782
  * @param {Number} [options.extra_rows] Add more rows in addition to
796
783
  * those that have been calculated.
797
784
  * @param {Number} [options.min_cols] The minimum required columns.
785
+ * @param {Number} [options.max_cols] The maximum columns possible (set to null
786
+ * for no maximum).
798
787
  * @param {Number} [options.min_rows] The minimum required rows.
799
788
  * @param {Number} [options.max_size_x] The maximum number of columns
800
789
  * that a widget can span.
@@ -817,23 +806,45 @@
817
806
  * @param {Object} [options.draggable] An Object with all options for
818
807
  * Draggable class you want to overwrite. See Draggable docs for more
819
808
  * info.
809
+ * @param {Object} [options.resize] An Object with resize config
810
+ * options.
811
+ * @param {Boolean} [options.resize.enabled] Set to true to enable
812
+ * resizing.
813
+ * @param {Array} [options.resize.axes] Axes in which widgets can be
814
+ * resized. Possible values: ['x', 'y', 'both'].
815
+ * @param {String} [options.resize.handle_append_to] Set a valid CSS
816
+ * selector to append resize handles to.
817
+ * @param {String} [options.resize.handle_class] CSS class name used
818
+ * by resize handles.
819
+ * @param {Array} [options.resize.max_size] Limit widget dimensions
820
+ * when resizing. Array values should be integers:
821
+ * `[max_cols_occupied, max_rows_occupied]`
822
+ * @param {Function} [options.resize.start] Function executed
823
+ * when resizing starts.
824
+ * @param {Function} [otions.resize.resize] Function executed
825
+ * during the resizing.
826
+ * @param {Function} [options.resize.stop] Function executed
827
+ * when resizing stops.
820
828
  *
821
829
  * @constructor
822
830
  */
823
831
  function Gridster(el, options) {
824
- this.options = $.extend(true, defaults, options);
825
- this.$el = $(el);
826
- this.$wrapper = this.$el.parent();
827
- this.$widgets = this.$el.children(this.options.widget_selector).addClass('gs_w');
828
- this.widgets = [];
829
- this.$changed = $([]);
830
- this.w_queue = {};
831
- this.wrapper_width = this.$wrapper.width();
832
- this.min_widget_width = (this.options.widget_margins[0] * 2) +
833
- this.options.widget_base_dimensions[0];
834
- this.min_widget_height = (this.options.widget_margins[1] * 2) +
835
- this.options.widget_base_dimensions[1];
836
- this.init();
832
+ this.options = $.extend(true, defaults, options);
833
+ this.$el = $(el);
834
+ this.$wrapper = this.$el.parent();
835
+ this.$widgets = this.$el.children(
836
+ this.options.widget_selector).addClass('gs-w');
837
+ this.widgets = [];
838
+ this.$changed = $([]);
839
+ this.wrapper_width = this.$wrapper.width();
840
+ this.min_widget_width = (this.options.widget_margins[0] * 2) +
841
+ this.options.widget_base_dimensions[0];
842
+ this.min_widget_height = (this.options.widget_margins[1] * 2) +
843
+ this.options.widget_base_dimensions[1];
844
+
845
+ this.$style_tags = $([]);
846
+
847
+ this.init();
837
848
  }
838
849
 
839
850
  Gridster.generated_stylesheets = [];
@@ -841,14 +852,16 @@
841
852
  var fn = Gridster.prototype;
842
853
 
843
854
  fn.init = function() {
855
+ this.options.resize.enabled && this.setup_resize();
844
856
  this.generate_grid_and_stylesheet();
845
857
  this.get_widgets_from_DOM();
846
858
  this.set_dom_grid_height();
847
859
  this.$wrapper.addClass('ready');
848
860
  this.draggable();
861
+ this.options.resize.enabled && this.resizable();
849
862
 
850
- $(window).bind(
851
- 'resize', throttle($.proxy(this.recalculate_faux_grid, this), 200));
863
+ $(window).bind('resize.gridster', throttle(
864
+ $.proxy(this.recalculate_faux_grid, this), 200));
852
865
  };
853
866
 
854
867
 
@@ -877,6 +890,33 @@
877
890
  };
878
891
 
879
892
 
893
+
894
+ /**
895
+ * Disables drag-and-drop widget resizing.
896
+ *
897
+ * @method disable
898
+ * @return {Class} Returns instance of gridster Class.
899
+ */
900
+ fn.disable_resize = function() {
901
+ this.$el.addClass('gs-resize-disabled');
902
+ this.resize_api.disable();
903
+ return this;
904
+ };
905
+
906
+
907
+ /**
908
+ * Enables drag-and-drop widget resizing.
909
+ *
910
+ * @method enable
911
+ * @return {Class} Returns instance of gridster Class.
912
+ */
913
+ fn.enable_resize = function() {
914
+ this.$el.removeClass('gs-resize-disabled');
915
+ this.resize_api.enable();
916
+ return this;
917
+ };
918
+
919
+
880
920
  /**
881
921
  * Add a new widget to the grid.
882
922
  *
@@ -887,10 +927,11 @@
887
927
  * @param {Number} [size_y] The nº of columns the widget occupies vertically.
888
928
  * @param {Number} [col] The column the widget should start in.
889
929
  * @param {Number} [row] The row the widget should start in.
930
+ * @param {Array} [max_size] max_size Maximun size (in units) for width and height.
890
931
  * @return {HTMLElement} Returns the jQuery wrapped HTMLElement representing.
891
932
  * the widget that was just created.
892
933
  */
893
- fn.add_widget = function(html, size_x, size_y, col, row) {
934
+ fn.add_widget = function(html, size_x, size_y, col, row, max_size) {
894
935
  var pos;
895
936
  size_x || (size_x = 1);
896
937
  size_y || (size_y = 1);
@@ -911,35 +952,82 @@
911
952
  'data-row': pos.row,
912
953
  'data-sizex' : size_x,
913
954
  'data-sizey' : size_y
914
- }).addClass('gs_w').appendTo(this.$el).hide();
955
+ }).addClass('gs-w').appendTo(this.$el).hide();
915
956
 
916
957
  this.$widgets = this.$widgets.add($w);
917
- this.$changed = this.$changed.add($w);
918
958
 
919
959
  this.register_widget($w);
920
960
 
921
961
  this.add_faux_rows(pos.size_y);
922
962
  //this.add_faux_cols(pos.size_x);
923
963
 
964
+ if (max_size) {
965
+ this.set_widget_max_size($w, max_size);
966
+ }
967
+
924
968
  this.set_dom_grid_height();
925
969
 
926
970
  return $w.fadeIn();
927
971
  };
928
972
 
929
973
 
974
+ /**
975
+ * Change widget size limits.
976
+ *
977
+ * @method set_widget_max_size
978
+ * @param {HTMLElement|Number} $widget The jQuery wrapped HTMLElement
979
+ * representing the widget or an index representing the desired widget.
980
+ * @param {Array} max_size Maximun size (in units) for width and height.
981
+ * @return {HTMLElement} Returns instance of gridster Class.
982
+ */
983
+ fn.set_widget_max_size = function($widget, max_size) {
984
+ $widget = typeof $widget === 'number' ?
985
+ this.$widgets.eq($widget) : $widget;
986
+
987
+ if (!$widget.length) { return this; }
988
+
989
+ var wgd = $widget.data('coords').grid;
990
+ wgd.max_size_x = max_size[0];
991
+ wgd.max_size_y = max_size[1];
992
+
993
+ return this;
994
+ };
995
+
930
996
 
931
997
  /**
932
- * Change the size of a widget.
998
+ * Append the resize handle into a widget.
999
+ *
1000
+ * @method add_resize_handle
1001
+ * @param {HTMLElement} $widget The jQuery wrapped HTMLElement
1002
+ * representing the widget.
1003
+ * @return {HTMLElement} Returns instance of gridster Class.
1004
+ */
1005
+ fn.add_resize_handle = function($w) {
1006
+ var append_to = this.options.resize.handle_append_to;
1007
+ $(this.resize_handle_tpl).appendTo( append_to ? $(append_to, $w) : $w);
1008
+
1009
+ return this;
1010
+ };
1011
+
1012
+
1013
+ /**
1014
+ * Change the size of a widget. Width is limited to the current grid width.
933
1015
  *
934
1016
  * @method resize_widget
935
1017
  * @param {HTMLElement} $widget The jQuery wrapped HTMLElement
936
1018
  * representing the widget.
937
1019
  * @param {Number} size_x The number of columns that will occupy the widget.
938
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
+ * By default <code>size_x</code> is limited to the space available from
1024
+ * the column where the widget begins, until the last column to the right.
1025
+ * @param {Function} [callback] Function executed when the widget is removed.
939
1026
  * @return {HTMLElement} Returns $widget.
940
1027
  */
941
- fn.resize_widget = function($widget, size_x, size_y) {
1028
+ fn.resize_widget = function($widget, size_x, size_y, reposition, callback) {
942
1029
  var wgd = $widget.coords().grid;
1030
+ reposition !== false && (reposition = true);
943
1031
  size_x || (size_x = wgd.size_x);
944
1032
  size_y || (size_y = wgd.size_y);
945
1033
 
@@ -947,20 +1035,20 @@
947
1035
  size_x = this.cols;
948
1036
  }
949
1037
 
950
- var old_cells_occupied = this.get_cells_occupied(wgd);
951
- var old_size_x = wgd.size_x;
952
1038
  var old_size_y = wgd.size_y;
953
1039
  var old_col = wgd.col;
954
1040
  var new_col = old_col;
955
- var wider = size_x > old_size_x;
956
- var taller = size_y > old_size_y;
957
1041
 
958
- if (old_col + size_x - 1 > this.cols) {
1042
+ if (reposition && old_col + size_x - 1 > this.cols) {
959
1043
  var diff = old_col + (size_x - 1) - this.cols;
960
1044
  var c = old_col - diff;
961
1045
  new_col = Math.max(1, c);
962
1046
  }
963
1047
 
1048
+ if (size_y > old_size_y) {
1049
+ this.add_faux_rows(Math.max(size_y - old_size_y, 0));
1050
+ }
1051
+
964
1052
  var new_grid_data = {
965
1053
  col: new_col,
966
1054
  row: wgd.row,
@@ -968,7 +1056,34 @@
968
1056
  size_y: size_y
969
1057
  };
970
1058
 
971
- var new_cells_occupied = this.get_cells_occupied(new_grid_data);
1059
+ this.mutate_widget_in_gridmap($widget, wgd, new_grid_data);
1060
+
1061
+ this.set_dom_grid_height();
1062
+
1063
+ if (callback) {
1064
+ callback.call(this, new_grid_data.size_x, new_grid_data.size_y);
1065
+ }
1066
+
1067
+ return $widget;
1068
+ };
1069
+
1070
+
1071
+ /**
1072
+ * Mutate widget dimensions and position in the grid map.
1073
+ *
1074
+ * @method mutate_widget_in_gridmap
1075
+ * @param {HTMLElement} $widget The jQuery wrapped HTMLElement
1076
+ * representing the widget to mutate.
1077
+ * @param {Object} wgd Current widget grid data (col, row, size_x, size_y).
1078
+ * @param {Object} new_wgd New widget grid data.
1079
+ * @return {HTMLElement} Returns instance of gridster Class.
1080
+ */
1081
+ fn.mutate_widget_in_gridmap = function($widget, wgd, new_wgd) {
1082
+ var old_size_x = wgd.size_x;
1083
+ var old_size_y = wgd.size_y;
1084
+
1085
+ var old_cells_occupied = this.get_cells_occupied(wgd);
1086
+ var new_cells_occupied = this.get_cells_occupied(new_wgd);
972
1087
 
973
1088
  var empty_cols = [];
974
1089
  $.each(old_cells_occupied.cols, function(i, col) {
@@ -1002,48 +1117,46 @@
1002
1117
 
1003
1118
  if (occupied_cols.length) {
1004
1119
  var cols_to_empty = [
1005
- new_col, wgd.row, size_x, Math.min(old_size_y, size_y), $widget
1120
+ new_wgd.col, new_wgd.row, new_wgd.size_x, Math.min(old_size_y, new_wgd.size_y), $widget
1006
1121
  ];
1007
1122
  this.empty_cells.apply(this, cols_to_empty);
1008
1123
  }
1009
1124
 
1010
1125
  if (occupied_rows.length) {
1011
- var rows_to_empty = [new_col, wgd.row, size_x, size_y, $widget];
1126
+ var rows_to_empty = [new_wgd.col, new_wgd.row, new_wgd.size_x, new_wgd.size_y, $widget];
1012
1127
  this.empty_cells.apply(this, rows_to_empty);
1013
1128
  }
1014
1129
 
1015
- wgd.col = new_col;
1016
- wgd.size_x = size_x;
1017
- wgd.size_y = size_y;
1018
- this.add_to_gridmap(new_grid_data, $widget);
1130
+ // not the same that wgd = new_wgd;
1131
+ wgd.col = new_wgd.col;
1132
+ wgd.row = new_wgd.row;
1133
+ wgd.size_x = new_wgd.size_x;
1134
+ wgd.size_y = new_wgd.size_y;
1135
+
1136
+ this.add_to_gridmap(new_wgd, $widget);
1137
+
1138
+ $widget.removeClass('player-revert');
1019
1139
 
1020
1140
  //update coords instance attributes
1021
1141
  $widget.data('coords').update({
1022
- width: (size_x * this.options.widget_base_dimensions[0] +
1023
- ((size_x - 1) * this.options.widget_margins[0]) * 2),
1024
- height: (size_y * this.options.widget_base_dimensions[1] +
1025
- ((size_y - 1) * this.options.widget_margins[1]) * 2)
1142
+ width: (new_wgd.size_x * this.options.widget_base_dimensions[0] +
1143
+ ((new_wgd.size_x - 1) * this.options.widget_margins[0]) * 2),
1144
+ height: (new_wgd.size_y * this.options.widget_base_dimensions[1] +
1145
+ ((new_wgd.size_y - 1) * this.options.widget_margins[1]) * 2)
1026
1146
  });
1027
1147
 
1028
- if (size_y > old_size_y) {
1029
- this.add_faux_rows(size_y - old_size_y);
1030
- }
1031
-
1032
- if (size_x > old_size_x) {
1033
- this.add_faux_cols(size_x - old_size_x);
1034
- }
1035
-
1036
1148
  $widget.attr({
1037
- 'data-col': new_col,
1038
- 'data-sizex': size_x,
1039
- 'data-sizey': size_y
1149
+ 'data-col': new_wgd.col,
1150
+ 'data-row': new_wgd.row,
1151
+ 'data-sizex': new_wgd.size_x,
1152
+ 'data-sizey': new_wgd.size_y
1040
1153
  });
1041
1154
 
1042
1155
  if (empty_cols.length) {
1043
1156
  var cols_to_remove_holes = [
1044
- empty_cols[0], wgd.row,
1157
+ empty_cols[0], new_wgd.row,
1045
1158
  empty_cols.length,
1046
- Math.min(old_size_y, size_y),
1159
+ Math.min(old_size_y, new_wgd.size_y),
1047
1160
  $widget
1048
1161
  ];
1049
1162
 
@@ -1052,14 +1165,17 @@
1052
1165
 
1053
1166
  if (empty_rows.length) {
1054
1167
  var rows_to_remove_holes = [
1055
- new_col, wgd.row, size_x, size_y, $widget
1168
+ new_wgd.col, new_wgd.row, new_wgd.size_x, new_wgd.size_y, $widget
1056
1169
  ];
1057
1170
  this.remove_empty_cells.apply(this, rows_to_remove_holes);
1058
1171
  }
1059
1172
 
1060
- return $widget;
1173
+ this.move_widget_up($widget);
1174
+
1175
+ return this;
1061
1176
  };
1062
1177
 
1178
+
1063
1179
  /**
1064
1180
  * Move down widgets in cells represented by the arguments col, row, size_x,
1065
1181
  * size_y
@@ -1106,7 +1222,7 @@
1106
1222
  * occupy.
1107
1223
  * @param {Number} size_y The number of rows that the group of cells
1108
1224
  * occupy.
1109
- * @param {HTMLElement} $exclude Exclude widgets from being moved.
1225
+ * @param {HTMLElement} exclude Exclude widgets from being moved.
1110
1226
  * @return {Class} Returns the instance of the Gridster Class.
1111
1227
  */
1112
1228
  fn.remove_empty_cells = function(col, row, size_x, size_y, exclude) {
@@ -1117,12 +1233,9 @@
1117
1233
  size_y: size_y
1118
1234
  });
1119
1235
 
1120
- /*
1121
1236
  $nexts.not(exclude).each($.proxy(function(i, widget) {
1122
- console.log("from_remove")
1123
1237
  this.move_widget_up( $(widget), size_y );
1124
1238
  }, this));
1125
- */
1126
1239
 
1127
1240
  this.set_dom_grid_height();
1128
1241
 
@@ -1172,13 +1285,6 @@
1172
1285
  return false;
1173
1286
  };
1174
1287
 
1175
- fn.remove_by_grid = function(col, row){
1176
- var $w = this.is_widget(col, row);
1177
- if($w){
1178
- this.remove_widget($w);
1179
- }
1180
- }
1181
-
1182
1288
 
1183
1289
  /**
1184
1290
  * Remove a widget from the grid.
@@ -1222,6 +1328,8 @@
1222
1328
  callback.call(this, el);
1223
1329
  }
1224
1330
  }, this));
1331
+
1332
+ return this;
1225
1333
  };
1226
1334
 
1227
1335
 
@@ -1255,15 +1363,14 @@
1255
1363
  $widgets || ($widgets = this.$widgets);
1256
1364
  var result = [];
1257
1365
  $widgets.each($.proxy(function(i, widget) {
1258
- if(typeof($(widget).coords().grid) != "undefined"){
1259
- result.push(this.options.serialize_params(
1366
+ result.push(this.options.serialize_params(
1260
1367
  $(widget), $(widget).coords().grid ) );
1261
- }
1262
1368
  }, this));
1263
1369
 
1264
1370
  return result;
1265
1371
  };
1266
1372
 
1373
+
1267
1374
  /**
1268
1375
  * Returns a serialized array of the widgets that have changed their
1269
1376
  * position.
@@ -1285,12 +1392,13 @@
1285
1392
  * @return {Array} Returns the instance of the Gridster class.
1286
1393
  */
1287
1394
  fn.register_widget = function($el) {
1288
-
1289
1395
  var wgd = {
1290
1396
  'col': parseInt($el.attr('data-col'), 10),
1291
1397
  'row': parseInt($el.attr('data-row'), 10),
1292
1398
  'size_x': parseInt($el.attr('data-sizex'), 10),
1293
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,
1294
1402
  'el': $el
1295
1403
  };
1296
1404
 
@@ -1298,12 +1406,7 @@
1298
1406
  !this.can_move_to(
1299
1407
  {size_x: wgd.size_x, size_y: wgd.size_y}, wgd.col, wgd.row)
1300
1408
  ) {
1301
- /*if(!$el.hasClass('.disp_ad')){
1302
- $el.remove();
1303
- return false;
1304
- }*/
1305
- wgd = this.next_position(wgd.size_x, wgd.size_y);
1306
- wgd.el = $el;
1409
+ $.extend(wgd, this.next_position(wgd.size_x, wgd.size_y));
1307
1410
  $el.attr({
1308
1411
  'data-col': wgd.col,
1309
1412
  'data-row': wgd.row,
@@ -1314,12 +1417,13 @@
1314
1417
 
1315
1418
  // attach Coord object to player data-coord attribute
1316
1419
  $el.data('coords', $el.coords());
1317
-
1318
1420
  // Extend Coord object with grid position info
1319
1421
  $el.data('coords').grid = wgd;
1320
1422
 
1321
1423
  this.add_to_gridmap(wgd, $el);
1322
1424
 
1425
+ this.options.resize.enabled && this.add_resize_handle($el);
1426
+
1323
1427
  return this;
1324
1428
  };
1325
1429
 
@@ -1370,13 +1474,13 @@
1370
1474
  */
1371
1475
  fn.add_to_gridmap = function(grid_data, value) {
1372
1476
  this.update_widget_position(grid_data, value || grid_data.el);
1373
- /*if (grid_data.el) {
1477
+
1478
+ if (grid_data.el) {
1374
1479
  var $widgets = this.widgets_below(grid_data.el);
1375
1480
  $widgets.each($.proxy(function(i, widget) {
1376
- console.log("from_add_to_gridmap");
1377
1481
  this.move_widget_up( $(widget));
1378
1482
  }, this));
1379
- } */
1483
+ }
1380
1484
  };
1381
1485
 
1382
1486
 
@@ -1391,13 +1495,16 @@
1391
1495
  var self = this;
1392
1496
  var draggable_options = $.extend(true, {}, this.options.draggable, {
1393
1497
  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],
1394
1501
  start: function(event, ui) {
1395
1502
  self.$widgets.filter('.player-revert')
1396
1503
  .removeClass('player-revert');
1397
1504
 
1398
1505
  self.$player = $(this);
1399
- self.$helper = self.options.draggable.helper === 'clone' ?
1400
- $(ui.helper) : self.$player;
1506
+ self.$helper = $(ui.$helper);
1507
+
1401
1508
  self.helper = !self.$helper.is(self.$player);
1402
1509
 
1403
1510
  self.on_start_drag.call(self, event, ui);
@@ -1413,7 +1520,51 @@
1413
1520
  }, 60)
1414
1521
  });
1415
1522
 
1416
- this.drag_api = this.$el.dragg(draggable_options).data('drag');
1523
+ this.drag_api = this.$el.drag(draggable_options);
1524
+ return this;
1525
+ };
1526
+
1527
+
1528
+ /**
1529
+ * Bind resize events to get resize working.
1530
+ *
1531
+ * @method resizable
1532
+ * @return {Class} Returns instance of gridster Class.
1533
+ */
1534
+ fn.resizable = function() {
1535
+ this.resize_api = this.$el.drag({
1536
+ items: '.' + this.options.resize.handle_class,
1537
+ offset_left: this.options.widget_margins[0],
1538
+ container_width: this.container_width,
1539
+ move_element: false,
1540
+ start: $.proxy(this.on_start_resize, this),
1541
+ stop: $.proxy(function(event, ui) {
1542
+ delay($.proxy(function() {
1543
+ this.on_stop_resize(event, ui);
1544
+ }, this), 120);
1545
+ }, this),
1546
+ drag: throttle($.proxy(this.on_resize, this), 60)
1547
+ });
1548
+
1549
+ return this;
1550
+ };
1551
+
1552
+
1553
+ /**
1554
+ * Setup things required for resizing. Like build templates for drag handles.
1555
+ *
1556
+ * @method setup_resize
1557
+ * @return {Class} Returns instance of gridster Class.
1558
+ */
1559
+ fn.setup_resize = function() {
1560
+ this.resize_handle_class = this.options.resize.handle_class;
1561
+ var axes = this.options.resize.axes;
1562
+ var handle_tpl = '<span class="' + this.resize_handle_class + ' ' +
1563
+ this.resize_handle_class + '-{type}" />';
1564
+
1565
+ this.resize_handle_tpl = $.map(axes, function(type) {
1566
+ return handle_tpl.replace('{type}', type);
1567
+ }).join('');
1417
1568
  return this;
1418
1569
  };
1419
1570
 
@@ -1422,11 +1573,10 @@
1422
1573
  * This function is executed when the player begins to be dragged.
1423
1574
  *
1424
1575
  * @method on_start_drag
1425
- * @param {Event} The original browser event
1426
- * @param {Object} A prepared ui object.
1576
+ * @param {Event} event The original browser event
1577
+ * @param {Object} ui A prepared ui object with useful drag-related data
1427
1578
  */
1428
1579
  fn.on_start_drag = function(event, ui) {
1429
-
1430
1580
  this.$helper.add(this.$player).add(this.$wrapper).addClass('dragging');
1431
1581
 
1432
1582
  this.$player.addClass('player');
@@ -1448,12 +1598,11 @@
1448
1598
  this.last_cols = [];
1449
1599
  this.last_rows = [];
1450
1600
 
1451
-
1452
1601
  // see jquery.collision.js
1453
1602
  this.collision_api = this.$helper.collision(
1454
1603
  colliders, this.options.collision);
1455
1604
 
1456
- this.$preview_holder = $('<li />', {
1605
+ this.$preview_holder = $('<' + this.$player.get(0).tagName + ' />', {
1457
1606
  'class': 'preview-holder',
1458
1607
  'data-row': this.$player.attr('data-row'),
1459
1608
  'data-col': this.$player.attr('data-col'),
@@ -1473,8 +1622,8 @@
1473
1622
  * This function is executed when the player is being dragged.
1474
1623
  *
1475
1624
  * @method on_drag
1476
- * @param {Event} The original browser event
1477
- * @param {Object} A prepared ui object.
1625
+ * @param {Event} event The original browser event
1626
+ * @param {Object} ui A prepared ui object with useful drag-related data
1478
1627
  */
1479
1628
  fn.on_drag = function(event, ui) {
1480
1629
  //break if dragstop has been fired
@@ -1516,8 +1665,8 @@
1516
1665
  * This function is executed when the player stops being dragged.
1517
1666
  *
1518
1667
  * @method on_stop_drag
1519
- * @param {Event} The original browser event
1520
- * @param {Object} A prepared ui object.
1668
+ * @param {Event} event The original browser event
1669
+ * @param {Object} ui A prepared ui object with useful drag-related data
1521
1670
  */
1522
1671
  fn.on_stop_drag = function(event, ui) {
1523
1672
  this.$helper.add(this.$player).add(this.$wrapper)
@@ -1525,7 +1674,8 @@
1525
1674
 
1526
1675
  ui.position.left = ui.position.left + this.baseX;
1527
1676
  ui.position.top = ui.position.top + this.baseY;
1528
- this.colliders_data = this.collision_api.get_closest_colliders(ui.position);
1677
+ this.colliders_data = this.collision_api.get_closest_colliders(
1678
+ ui.position);
1529
1679
 
1530
1680
  this.on_overlapped_column_change(
1531
1681
  this.on_start_overlapping_column,
@@ -1568,12 +1718,165 @@
1568
1718
  this.player_grid_data = {};
1569
1719
  this.cells_occupied_by_placeholder = {};
1570
1720
  this.cells_occupied_by_player = {};
1571
- this.w_queue = {};
1572
1721
 
1573
1722
  this.set_dom_grid_height();
1574
1723
  };
1575
1724
 
1576
1725
 
1726
+
1727
+ /**
1728
+ * This function is executed every time a widget starts to be resized.
1729
+ *
1730
+ * @method on_start_resize
1731
+ * @param {Event} event The original browser event
1732
+ * @param {Object} ui A prepared ui object with useful drag-related data
1733
+ */
1734
+ fn.on_start_resize = function(event, ui) {
1735
+ this.$resized_widget = ui.$player.closest('.gs-w');
1736
+ this.resize_coords = this.$resized_widget.coords();
1737
+ this.resize_wgd = this.resize_coords.grid;
1738
+ this.resize_initial_width = this.resize_coords.coords.width;
1739
+ this.resize_initial_height = this.resize_coords.coords.height;
1740
+ this.resize_initial_sizex = this.resize_coords.grid.size_x;
1741
+ this.resize_initial_sizey = this.resize_coords.grid.size_y;
1742
+ this.resize_last_sizex = this.resize_initial_sizex;
1743
+ this.resize_last_sizey = this.resize_initial_sizey;
1744
+ 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);
1746
+ this.resize_max_size_y = this.resize_wgd.max_size_y ||
1747
+ this.options.resize.max_size[1];
1748
+
1749
+ this.resize_dir = {
1750
+ right: ui.$player.is('.' + this.resize_handle_class + '-x'),
1751
+ bottom: ui.$player.is('.' + this.resize_handle_class + '-y')
1752
+ };
1753
+
1754
+ this.$resized_widget.css({
1755
+ 'min-width': this.options.widget_base_dimensions[0],
1756
+ 'min-height': this.options.widget_base_dimensions[1]
1757
+ });
1758
+
1759
+ var nodeName = this.$resized_widget.get(0).tagName;
1760
+ this.$resize_preview_holder = $('<' + nodeName + ' />', {
1761
+ 'class': 'preview-holder resize-preview-holder',
1762
+ 'data-row': this.$resized_widget.attr('data-row'),
1763
+ 'data-col': this.$resized_widget.attr('data-col'),
1764
+ 'css': {
1765
+ 'width': this.resize_initial_width,
1766
+ 'height': this.resize_initial_height
1767
+ }
1768
+ }).appendTo(this.$el);
1769
+
1770
+ this.$resized_widget.addClass('resizing');
1771
+
1772
+ if (this.options.resize.start) {
1773
+ this.options.resize.start.call(this, event, ui, this.$resized_widget);
1774
+ }
1775
+ };
1776
+
1777
+
1778
+ /**
1779
+ * This function is executed every time a widget stops being resized.
1780
+ *
1781
+ * @method on_stop_resize
1782
+ * @param {Event} event The original browser event
1783
+ * @param {Object} ui A prepared ui object with useful drag-related data
1784
+ */
1785
+ fn.on_stop_resize = function(event, ui) {
1786
+ this.$resized_widget
1787
+ .removeClass('resizing')
1788
+ .css({
1789
+ 'width': '',
1790
+ 'height': ''
1791
+ });
1792
+
1793
+ delay($.proxy(function() {
1794
+ this.$resize_preview_holder
1795
+ .remove()
1796
+ .css({
1797
+ 'min-width': '',
1798
+ 'min-height': ''
1799
+ });
1800
+ }, this), 300);
1801
+
1802
+ if (this.options.resize.stop) {
1803
+ this.options.resize.stop.call(this, event, ui, this.$resized_widget);
1804
+ }
1805
+ };
1806
+
1807
+ /**
1808
+ * This function is executed when a widget is being resized.
1809
+ *
1810
+ * @method on_resize
1811
+ * @param {Event} event The original browser event
1812
+ * @param {Object} ui A prepared ui object with useful drag-related data
1813
+ */
1814
+ fn.on_resize = function(event, ui) {
1815
+ var rel_x = (ui.pointer.diff_left);
1816
+ var rel_y = (ui.pointer.diff_top);
1817
+ var wbd_x = this.options.widget_base_dimensions[0];
1818
+ var wbd_y = this.options.widget_base_dimensions[1];
1819
+ var max_width = Infinity;
1820
+ var max_height = Infinity;
1821
+
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);
1829
+
1830
+ var size_x = Math.max(1, this.resize_initial_sizex + inc_units_x);
1831
+ var size_y = Math.max(1, this.resize_initial_sizey + inc_units_y);
1832
+
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);
1836
+
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);
1840
+
1841
+
1842
+ if (this.resize_dir.right) {
1843
+ size_y = this.resize_initial_sizey;
1844
+ } else if (this.resize_dir.bottom) {
1845
+ size_x = this.resize_initial_sizex;
1846
+ }
1847
+
1848
+ 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));
1853
+
1854
+ this.$resized_widget.css(css_props);
1855
+
1856
+ if (size_x !== this.resize_last_sizex ||
1857
+ size_y !== this.resize_last_sizey) {
1858
+
1859
+ this.resize_widget(this.$resized_widget, size_x, size_y, false);
1860
+
1861
+ this.$resize_preview_holder.css({
1862
+ 'width': '',
1863
+ 'height': ''
1864
+ }).attr({
1865
+ 'data-row': this.$resized_widget.attr('data-row'),
1866
+ 'data-sizex': size_x,
1867
+ 'data-sizey': size_y
1868
+ });
1869
+ }
1870
+
1871
+ if (this.options.resize.resize) {
1872
+ this.options.resize.resize.call(this, event, ui, this.$resized_widget);
1873
+ }
1874
+
1875
+ this.resize_last_sizex = size_x;
1876
+ this.resize_last_sizey = size_y;
1877
+ };
1878
+
1879
+
1577
1880
  /**
1578
1881
  * Executes the callbacks passed as arguments when a column begins to be
1579
1882
  * overlapped or stops being overlapped.
@@ -1587,7 +1890,7 @@
1587
1890
  */
1588
1891
  fn.on_overlapped_column_change = function(start_callback, stop_callback) {
1589
1892
  if (!this.colliders_data.length) {
1590
- return;
1893
+ return this;
1591
1894
  }
1592
1895
  var cols = this.get_targeted_columns(
1593
1896
  this.colliders_data[0].el.data.col);
@@ -1620,14 +1923,14 @@
1620
1923
  *
1621
1924
  * @param {Function} start_callback Function executed when a new row begins
1622
1925
  * to be overlapped. The row is passed as first argument.
1623
- * @param {Function} stop_callback Function executed when a row stops being
1926
+ * @param {Function} end_callback Function executed when a row stops being
1624
1927
  * overlapped. The row is passed as first argument.
1625
1928
  * @method on_overlapped_row_change
1626
1929
  * @return {Class} Returns the instance of the Gridster Class.
1627
1930
  */
1628
1931
  fn.on_overlapped_row_change = function(start_callback, end_callback) {
1629
1932
  if (!this.colliders_data.length) {
1630
- return;
1933
+ return this;
1631
1934
  }
1632
1935
  var rows = this.get_targeted_rows(this.colliders_data[0].el.data.row);
1633
1936
  var last_n_rows = this.last_rows.length;
@@ -1653,22 +1956,20 @@
1653
1956
  /**
1654
1957
  * Sets the current position of the player
1655
1958
  *
1656
- * @param {Function} start_callback Function executed when a new row begins
1657
- * to be overlapped. The row is passed as first argument.
1658
- * @param {Function} stop_callback Function executed when a row stops being
1659
- * overlapped. The row is passed as first argument.
1959
+ * @param {Number} col
1960
+ * @param {Number} row
1961
+ * @param {Boolean} no_player
1660
1962
  * @method set_player
1661
- * @return {Class} Returns the instance of the Gridster Class.
1963
+ * @return {object}
1662
1964
  */
1663
1965
  fn.set_player = function(col, row, no_player) {
1664
1966
  var self = this;
1665
- var swap = false;
1666
1967
  if (!no_player) {
1667
1968
  this.empty_cells_player_occupies();
1668
1969
  }
1669
1970
  var cell = !no_player ? self.colliders_data[0].el.data : {col: col};
1670
1971
  var to_col = cell.col;
1671
- var to_row = cell.row || row;
1972
+ var to_row = row || cell.row;
1672
1973
 
1673
1974
  this.player_grid_data = {
1674
1975
  col: to_col,
@@ -1680,102 +1981,13 @@
1680
1981
  this.cells_occupied_by_player = this.get_cells_occupied(
1681
1982
  this.player_grid_data);
1682
1983
 
1683
- //Added placeholder for more advanced movement.
1684
- this.cells_occupied_by_placeholder = this.get_cells_occupied(
1685
- this.placeholder_grid_data);
1686
-
1687
1984
  var $overlapped_widgets = this.get_widgets_overlapped(
1688
1985
  this.player_grid_data);
1689
1986
 
1690
- var player_size_y = this.player_grid_data.size_y;
1691
- var player_size_x = this.player_grid_data.size_x;
1692
- var placeholder_cells = this.cells_occupied_by_placeholder;
1693
- var $gr = this;
1987
+ var constraints = this.widgets_constraints($overlapped_widgets);
1694
1988
 
1695
-
1696
- //Queue Swaps
1697
- $overlapped_widgets.each($.proxy(function(i, w){
1698
- var $w = $(w);
1699
- var wgd = $w.coords().grid;
1700
-
1701
- // Ensure all values are in integer format
1702
- wgd.col = parseInt(wgd.col);
1703
- wgd.row = parseInt(wgd.row);
1704
- wgd.size_x = parseInt(wgd.size_x);
1705
- wgd.size_y = parseInt(wgd.size_y);
1706
- player_size_x = parseInt(player_size_x);
1707
- player_size_y = parseInt(player_size_y);
1708
-
1709
- var outside_col = placeholder_cells.cols[0]+player_size_x-1;
1710
- var outside_row = placeholder_cells.rows[0]+player_size_y-1;
1711
- if ($w.hasClass($gr.options.static_class)){
1712
- //next iteration
1713
- return true;
1714
- }
1715
- if(wgd.size_x <= player_size_x && wgd.size_y <= player_size_y){
1716
- if(!$gr.is_swap_occupied(placeholder_cells.cols[0], wgd.row, wgd.size_x, wgd.size_y) && !$gr.is_player_in(placeholder_cells.cols[0], wgd.row) && !$gr.is_in_queue(placeholder_cells.cols[0], wgd.row, $w)){
1717
- swap = $gr.queue_widget(placeholder_cells.cols[0], wgd.row, $w);
1718
- }
1719
- else if(!$gr.is_swap_occupied(outside_col, wgd.row, wgd.size_x, wgd.size_y) && !$gr.is_player_in(outside_col, wgd.row) && !$gr.is_in_queue(outside_col, wgd.row, $w)){
1720
- swap = $gr.queue_widget(outside_col, wgd.row, $w);
1721
- }
1722
- else if(!$gr.is_swap_occupied(wgd.col, placeholder_cells.rows[0], wgd.size_x, wgd.size_y) && !$gr.is_player_in(wgd.col, placeholder_cells.rows[0]) && !$gr.is_in_queue(wgd.col, placeholder_cells.rows[0], $w)){
1723
- swap = $gr.queue_widget(wgd.col, placeholder_cells.rows[0], $w);
1724
- }
1725
- else if(!$gr.is_swap_occupied(wgd.col, outside_row, wgd.size_x, wgd.size_y) && !$gr.is_player_in(wgd.col, outside_row) && !$gr.is_in_queue(wgd.col, outside_row, $w)){
1726
- swap = $gr.queue_widget(wgd.col, outside_row, $w);
1727
- }
1728
- else if(!$gr.is_swap_occupied(placeholder_cells.cols[0],placeholder_cells.rows[0], wgd.size_x, wgd.size_y) && !$gr.is_player_in(placeholder_cells.cols[0],placeholder_cells.rows[0]) && !$gr.is_in_queue(placeholder_cells.cols[0],placeholder_cells.rows[0], $w)){
1729
- swap = $gr.queue_widget(placeholder_cells.cols[0], placeholder_cells.rows[0], $w);
1730
- } else {
1731
- //in one last attempt we check for any other empty spaces
1732
- for (var c = 0; c < player_size_x; c++){
1733
- for (var r = 0; r < player_size_y; r++){
1734
- var colc = placeholder_cells.cols[0]+c;
1735
- var rowc = placeholder_cells.rows[0]+r;
1736
- if (!$gr.is_swap_occupied(colc,rowc, wgd.size_x, wgd.size_y) && !$gr.is_player_in(colc,rowc) && !$gr.is_in_queue(colc, rowc, $w)){
1737
- swap = $gr.queue_widget(colc, rowc, $w);
1738
- c = player_size_x;
1739
- break;
1740
- }
1741
- }
1742
- }
1743
-
1744
- }
1745
- } else if ($gr.options.shift_larger_widgets_down && !swap) {
1746
- $overlapped_widgets.each($.proxy(function(i, w){
1747
- var $w = $(w);
1748
- var wgd = $w.coords().grid;
1749
-
1750
- if($gr.can_go_down($w)){
1751
- $gr.move_widget_down($w, $gr.player_grid_data.size_y);
1752
- $gr.set_placeholder(to_col, to_row);
1753
- }
1754
- }));
1755
- }
1756
-
1757
- $gr.clean_up_changed();
1758
- }));
1759
-
1760
-
1761
- /* To show queued items in console
1762
- for(var key in this.w_queue){
1763
- console.log("key " +key);
1764
- console.log(this.w_queue[key]);
1765
- }
1766
- */
1767
-
1768
- //Move queued widgets
1769
- if(swap && this.can_placeholder_be_set(to_col, to_row, player_size_x, player_size_y)){
1770
- for(var key in this.w_queue){
1771
- var col = parseInt(key.split("_")[0]);
1772
- var row = parseInt(key.split("_")[1]);
1773
- if (this.w_queue[key] != "full"){
1774
- this.new_move_widget_to(this.w_queue[key], col, row);
1775
- }
1776
- }
1777
- this.set_placeholder(to_col, to_row);
1778
- }
1989
+ this.manage_movements(constraints.can_go_up, to_col, to_row);
1990
+ this.manage_movements(constraints.can_not_go_up, to_col, to_row);
1779
1991
 
1780
1992
  /* if there is not widgets overlapping in the new player position,
1781
1993
  * update the new placeholder position. */
@@ -1784,13 +1996,9 @@
1784
1996
  if (pp !== false) {
1785
1997
  to_row = pp;
1786
1998
  }
1787
- if(this.can_placeholder_be_set(to_col, to_row, player_size_x, player_size_y)){
1788
- this.set_placeholder(to_col, to_row);
1789
- }
1999
+ this.set_placeholder(to_col, to_row);
1790
2000
  }
1791
2001
 
1792
- this.w_queue = {};
1793
-
1794
2002
  return {
1795
2003
  col: to_col,
1796
2004
  row: to_row
@@ -1798,159 +2006,14 @@
1798
2006
  };
1799
2007
 
1800
2008
 
1801
- fn.is_swap_occupied = function(col, row, w_size_x, w_size_y) {
1802
- var occupied = false;
1803
- for (var c = 0; c < w_size_x; c++){
1804
- for (var r = 0; r < w_size_y; r++){
1805
- var colc = col + c;
1806
- var rowc = row + r;
1807
- var key = colc+"_"+rowc;
1808
- if(this.is_occupied(colc,rowc)){
1809
- occupied = true;
1810
- } else if(key in this.w_queue){
1811
- if(this.w_queue[key] == "full"){
1812
- occupied = true;
1813
- continue;
1814
- }
1815
- $tw = this.w_queue[key];
1816
- tgd = $tw.coords().grid;
1817
- //remove queued items if no longer under player.
1818
- if(!this.is_widget_under_player(tgd.col,tgd.row)){
1819
- delete this.w_queue[key];
1820
- }
1821
- }
1822
- if(rowc > parseInt(this.options.max_rows)){
1823
- occupied = true;
1824
- }
1825
- if(colc > parseInt(this.options.max_cols)){
1826
- occupied = true;
1827
- }
1828
- if (this.is_player_in(colc,rowc)){
1829
- occupied = true;
1830
- }
1831
- }
1832
- }
1833
-
1834
- return occupied;
1835
- }
1836
-
1837
- fn.can_placeholder_be_set = function(col, row, player_size_x, player_size_y){
1838
- var can_set = true;
1839
- for (var c = 0; c < player_size_x; c++){
1840
- for (var r = 0; r < player_size_y; r++){
1841
- var colc = col + c;
1842
- var rowc = row + r;
1843
- var key = colc+"_"+rowc;
1844
- var $tw = this.is_widget(colc, rowc);
1845
- //if this space is occupied and not queued for move.
1846
- if(rowc > parseInt(this.options.max_rows)){
1847
- can_set = false;
1848
- }
1849
- if(colc > parseInt(this.options.max_cols)){
1850
- can_set = false;
1851
- }
1852
- if(this.is_occupied(colc,rowc) && !this.is_widget_queued_and_can_move($tw)){
1853
- can_set = false;
1854
- }
1855
- }
1856
- }
1857
- return can_set;
1858
- }
1859
-
1860
- fn.queue_widget = function(col, row, $widget){
1861
- var $w = $widget
1862
- var wgd = $w.coords().grid;
1863
- var primary_key = col+"_"+row;
1864
- if (primary_key in this.w_queue){
1865
- return false;
1866
- }
1867
-
1868
- this.w_queue[primary_key] = $w;
1869
-
1870
- for (var c = 0; c < wgd.size_x; c++){
1871
- for (var r = 0; r < wgd.size_y; r++){
1872
- var colc = col + c;
1873
- var rowc = row + r;
1874
- var key = colc+"_"+rowc;
1875
- if (key == primary_key){
1876
- continue;
1877
- }
1878
- this.w_queue[key] = "full";
1879
- }
1880
- }
1881
-
1882
- return true;
1883
- }
1884
-
1885
- fn.is_widget_queued_and_can_move = function($widget){
1886
- var queued = false;
1887
- if ($widget === false){
1888
- return false;
1889
- }
1890
-
1891
- for(var key in this.w_queue){
1892
- if(this.w_queue[key] == "full"){
1893
- continue;
1894
- }
1895
- if(this.w_queue[key].attr("data-col") == $widget.attr("data-col") && this.w_queue[key].attr("data-row") == $widget.attr("data-row")){
1896
- queued = true;
1897
- //test whole space
1898
- var $w = this.w_queue[key];
1899
- var dcol = parseInt(key.split("_")[0]);
1900
- var drow = parseInt(key.split("_")[1]);
1901
- var wgd = $w.coords().grid;
1902
-
1903
- for (var c = 0; c < wgd.size_x; c++){
1904
- for (var r = 0; r < wgd.size_y; r++){
1905
- var colc = dcol + c;
1906
- var rowc = drow + r;
1907
- if (this.is_player_in(colc,rowc)){
1908
- queued = false;
1909
- }
1910
-
1911
- }
1912
- }
1913
-
1914
- }
1915
- }
1916
-
1917
- return queued
1918
- }
1919
-
1920
- fn.is_in_queue = function(col,row, $widget){
1921
- var queued = false;
1922
- var key = col+"_"+row;
1923
-
1924
- if ((key in this.w_queue)){
1925
- if (this.w_queue[key] == "full"){
1926
- queued = true;
1927
- } else {
1928
- $tw = this.w_queue[key];
1929
- tgd = $tw.coords().grid;
1930
- if(!this.is_widget_under_player(tgd.col,tgd.row)){
1931
- delete this.w_queue[key]
1932
- queued = false;
1933
- } else if(this.w_queue[key].attr("data-col") == $widget.attr("data-col") && this.w_queue[key].attr("data-row") == $widget.attr("data-row")) {
1934
- delete this.w_queue[key]
1935
- queued = false;
1936
- } else {
1937
- queued = true;
1938
- }
1939
- }
1940
- }
1941
-
1942
- return queued;
1943
- }
1944
-
1945
-
1946
2009
  /**
1947
2010
  * See which of the widgets in the $widgets param collection can go to
1948
2011
  * a upper row and which not.
1949
2012
  *
1950
2013
  * @method widgets_contraints
1951
- * @param {HTMLElements} $widgets A jQuery wrapped collection of
2014
+ * @param {jQuery} $widgets A jQuery wrapped collection of
1952
2015
  * HTMLElements.
1953
- * @return {Array} Returns a literal Object with two keys: `can_go_up` &
2016
+ * @return {object} Returns a literal Object with two keys: `can_go_up` &
1954
2017
  * `can_not_go_up`. Each contains a set of HTMLElements.
1955
2018
  */
1956
2019
  fn.widgets_constraints = function($widgets) {
@@ -2066,11 +2129,9 @@
2066
2129
  /**
2067
2130
  * Sorts an Array of grid coords objects (representing the grid coords of
2068
2131
  * each widget) in descending way.
2069
-
2070
- * Depreciated.
2071
2132
  *
2072
2133
  * @method manage_movements
2073
- * @param {HTMLElements} $widgets A jQuery collection of HTMLElements
2134
+ * @param {jQuery} $widgets A jQuery collection of HTMLElements
2074
2135
  * representing the widgets you want to move.
2075
2136
  * @param {Number} to_col The column to which we want to move the widgets.
2076
2137
  * @param {Number} to_row The row to which we want to move the widgets.
@@ -2100,11 +2161,9 @@
2100
2161
  // so we need to move widget down to a position that dont
2101
2162
  // overlaps player
2102
2163
  var y = (to_row + this.player_grid_data.size_y) - wgd.row;
2103
- if (this.can_go_down($w)){
2104
- console.log("In Move Down!")
2105
- this.move_widget_down($w, y);
2106
- this.set_placeholder(to_col, to_row);
2107
- }
2164
+
2165
+ this.move_widget_down($w, y);
2166
+ this.set_placeholder(to_col, to_row);
2108
2167
  }
2109
2168
  }
2110
2169
  }, this));
@@ -2180,13 +2239,15 @@
2180
2239
  * @return {Boolean} Returns true or false.
2181
2240
  */
2182
2241
  fn.is_empty = function(col, row) {
2183
- if (typeof this.gridmap[col] !== 'undefined' &&
2184
- typeof this.gridmap[col][row] !== 'undefined' &&
2185
- this.gridmap[col][row] === false
2186
- ) {
2187
- return true;
2188
- }
2189
- return false;
2242
+ 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;
2190
2251
  };
2191
2252
 
2192
2253
 
@@ -2234,32 +2295,6 @@
2234
2295
  return false;
2235
2296
  };
2236
2297
 
2237
- /**
2238
- * Determines if widget is supposed to be static.
2239
- * @method is_static
2240
- * @param {Number} col The column to check.
2241
- * @param {Number} row The row to check.
2242
- * @return {Boolean} Returns true if widget exists and has static class,
2243
- * else returns false
2244
- */
2245
-
2246
- fn.is_static = function(col, row) {
2247
- var cell = this.gridmap[col];
2248
- if (!cell) {
2249
- return false;
2250
- }
2251
-
2252
- cell = cell[row];
2253
-
2254
- if (cell) {
2255
- if(cell.hasClass(this.options.static_class)){
2256
- return true;
2257
- }
2258
- }
2259
-
2260
- return false;
2261
- };
2262
-
2263
2298
 
2264
2299
  /**
2265
2300
  * Determines if there is a widget in the cell represented by col/row
@@ -2321,7 +2356,7 @@
2321
2356
  });
2322
2357
 
2323
2358
  // Prevents widgets go out of the grid
2324
- var right_col = (col + parseInt(phgd.size_x) - 1);
2359
+ var right_col = (col + phgd.size_x - 1);
2325
2360
  if (right_col > this.cols) {
2326
2361
  col = col - (right_col - col);
2327
2362
  }
@@ -2342,21 +2377,14 @@
2342
2377
 
2343
2378
  if (moved_down || changed_column) {
2344
2379
  $nexts.each($.proxy(function(i, widget) {
2345
- //Make sure widget is at it's topmost position
2346
- $w = $(widget);
2347
- wgd = $w.coords().grid;
2348
-
2349
- var can_go_widget_up = this.can_go_widget_up(wgd);
2350
-
2351
- if (can_go_widget_up) {
2352
- this.move_widget_to($w, can_go_widget_up);
2353
- }
2354
-
2380
+ this.move_widget_up(
2381
+ $(widget), this.placeholder_grid_data.col - col + phgd.size_y);
2355
2382
  }, this));
2356
2383
  }
2357
2384
 
2385
+ var $widgets_under_ph = this.get_widgets_under_player(
2386
+ this.cells_occupied_by_placeholder);
2358
2387
 
2359
- var $widgets_under_ph = this.get_widgets_under_player(this.cells_occupied_by_placeholder);
2360
2388
  if ($widgets_under_ph.length) {
2361
2389
  $widgets_under_ph.each($.proxy(function(i, widget) {
2362
2390
  var $w = $(widget);
@@ -2408,7 +2436,9 @@
2408
2436
  return true; //break
2409
2437
  }
2410
2438
 
2411
- upper_rows[tcol].sort();
2439
+ upper_rows[tcol].sort(function(a, b) {
2440
+ return a - b;
2441
+ });
2412
2442
  });
2413
2443
 
2414
2444
  if (!result) { return false; }
@@ -2463,7 +2493,9 @@
2463
2493
  return true; //break
2464
2494
  }
2465
2495
 
2466
- upper_rows[tcol].sort();
2496
+ upper_rows[tcol].sort(function(a, b) {
2497
+ return a - b;
2498
+ });
2467
2499
  });
2468
2500
 
2469
2501
  if (!result) { return false; }
@@ -2553,7 +2585,7 @@
2553
2585
  * Get widgets overlapping with the player.
2554
2586
  *
2555
2587
  * @method get_widgets_overlapped
2556
- * @return {HTMLElements} Returns a jQuery collection of HTMLElements.
2588
+ * @return {jQuery} Returns a jQuery collection of HTMLElements.
2557
2589
  */
2558
2590
  fn.get_widgets_overlapped = function() {
2559
2591
  var $w;
@@ -2586,7 +2618,7 @@
2586
2618
  *
2587
2619
  * @method on_start_overlapping_column
2588
2620
  * @param {Number} col The collided column.
2589
- * @return {HTMLElements} Returns a jQuery collection of HTMLElements.
2621
+ * @return {jQuery} Returns a jQuery collection of HTMLElements.
2590
2622
  */
2591
2623
  fn.on_start_overlapping_column = function(col) {
2592
2624
  this.set_player(col, false);
@@ -2597,8 +2629,8 @@
2597
2629
  * A callback executed when the player begins to collide with a row.
2598
2630
  *
2599
2631
  * @method on_start_overlapping_row
2600
- * @param {Number} col The collided row.
2601
- * @return {HTMLElements} Returns a jQuery collection of HTMLElements.
2632
+ * @param {Number} row The collided row.
2633
+ * @return {jQuery} Returns a jQuery collection of HTMLElements.
2602
2634
  */
2603
2635
  fn.on_start_overlapping_row = function(row) {
2604
2636
  this.set_player(false, row);
@@ -2610,17 +2642,16 @@
2610
2642
  *
2611
2643
  * @method on_stop_overlapping_column
2612
2644
  * @param {Number} col The collided row.
2613
- * @return {HTMLElements} Returns a jQuery collection of HTMLElements.
2645
+ * @return {jQuery} Returns a jQuery collection of HTMLElements.
2614
2646
  */
2615
2647
  fn.on_stop_overlapping_column = function(col) {
2616
- //this.set_player(col, false);
2648
+ this.set_player(col, false);
2649
+
2617
2650
  var self = this;
2618
- if(this.options.shift_larger_widgets_down){
2619
- this.for_each_widget_below(col, this.cells_occupied_by_player.rows[0],
2620
- function(tcol, trow) {
2621
- self.move_widget_up(this, self.player_grid_data.size_y);
2622
- });
2623
- }
2651
+ this.for_each_widget_below(col, this.cells_occupied_by_player.rows[0],
2652
+ function(tcol, trow) {
2653
+ self.move_widget_up(this, self.player_grid_data.size_y);
2654
+ });
2624
2655
  };
2625
2656
 
2626
2657
 
@@ -2629,40 +2660,20 @@
2629
2660
  *
2630
2661
  * @method on_stop_overlapping_row
2631
2662
  * @param {Number} row The collided row.
2632
- * @return {HTMLElements} Returns a jQuery collection of HTMLElements.
2663
+ * @return {jQuery} Returns a jQuery collection of HTMLElements.
2633
2664
  */
2634
2665
  fn.on_stop_overlapping_row = function(row) {
2635
- //this.set_player(false, row);
2666
+ this.set_player(false, row);
2667
+
2636
2668
  var self = this;
2637
2669
  var cols = this.cells_occupied_by_player.cols;
2638
- if(this.options.shift_larger_widgets_down){
2639
- for (var c = 0, cl = cols.length; c < cl; c++) {
2640
- this.for_each_widget_below(cols[c], row, function(tcol, trow) {
2641
- console.log("from_on_stop_overlapping_row");
2642
- self.move_widget_up(this, self.player_grid_data.size_y);
2643
- });
2644
- }
2670
+ for (var c = 0, cl = cols.length; c < cl; c++) {
2671
+ this.for_each_widget_below(cols[c], row, function(tcol, trow) {
2672
+ self.move_widget_up(this, self.player_grid_data.size_y);
2673
+ });
2645
2674
  }
2646
2675
  };
2647
2676
 
2648
- //Not yet part of api - DM.
2649
- fn.new_move_widget_to = function($widget, col, row){
2650
- var self = this;
2651
- var widget_grid_data = $widget.coords().grid;
2652
-
2653
- this.remove_from_gridmap(widget_grid_data);
2654
- widget_grid_data.row = row;
2655
- widget_grid_data.col = col;
2656
-
2657
- this.add_to_gridmap(widget_grid_data);
2658
- $widget.attr('data-row', row);
2659
- $widget.attr('data-col', col);
2660
- this.update_widget_position(widget_grid_data, $widget);
2661
- this.$changed = this.$changed.add($widget);
2662
-
2663
- return this;
2664
- }
2665
-
2666
2677
 
2667
2678
  /**
2668
2679
  * Move a widget to a specific row. The cell or cells must be empty.
@@ -2746,10 +2757,9 @@
2746
2757
 
2747
2758
  moved.push($widget);
2748
2759
 
2749
- /* $next_widgets.each($.proxy(function(i, widget) {
2750
- console.log("from_within_move_widget_up");
2760
+ $next_widgets.each($.proxy(function(i, widget) {
2751
2761
  this.move_widget_up($(widget), y_units);
2752
- }, this)); */
2762
+ }, this));
2753
2763
  }
2754
2764
  });
2755
2765
 
@@ -2760,16 +2770,20 @@
2760
2770
  * Move down the specified widget and all below it.
2761
2771
  *
2762
2772
  * @method move_widget_down
2763
- * @param {HTMLElement} $widget The jQuery object representing the widget
2773
+ * @param {jQuery} $widget The jQuery object representing the widget
2764
2774
  * you want to move.
2765
- * @param {Number} The number of cells that the widget has to move.
2775
+ * @param {Number} y_units The number of cells that the widget has to move.
2766
2776
  * @return {Class} Returns the instance of the Gridster Class.
2767
2777
  */
2768
2778
  fn.move_widget_down = function($widget, y_units) {
2769
- var el_grid_data = $widget.coords().grid;
2770
- var actual_row = el_grid_data.row;
2771
- var moved = [];
2772
- var y_diff = y_units;
2779
+ var el_grid_data, actual_row, moved, y_diff;
2780
+
2781
+ if (y_units <= 0) { return false; }
2782
+
2783
+ el_grid_data = $widget.coords().grid;
2784
+ actual_row = el_grid_data.row;
2785
+ moved = [];
2786
+ y_diff = y_units;
2773
2787
 
2774
2788
  if (!$widget) { return false; }
2775
2789
 
@@ -2898,7 +2912,7 @@
2898
2912
  *
2899
2913
  * @method widgets_below
2900
2914
  * @param {HTMLElement} $el The jQuery wrapped HTMLElement.
2901
- * @return {HTMLElements} A jQuery collection of HTMLElements.
2915
+ * @return {jQuery} A jQuery collection of HTMLElements.
2902
2916
  */
2903
2917
  fn.widgets_below = function($el) {
2904
2918
  var el_grid_data = $.isPlainObject($el) ? $el : $el.coords().grid;
@@ -2948,23 +2962,6 @@
2948
2962
  return this;
2949
2963
  };
2950
2964
 
2951
- fn.can_go_down = function($el) {
2952
- var can_go_down = true;
2953
- var $gr = this;
2954
-
2955
- if ($el.hasClass(this.options.static_class)){
2956
- can_go_down = false;
2957
- }
2958
-
2959
- this.widgets_below($el).each(function(){
2960
- if ($(this).hasClass($gr.options.static_class)){
2961
- can_go_down = false;
2962
- }
2963
- })
2964
-
2965
- return can_go_down;
2966
- }
2967
-
2968
2965
 
2969
2966
  fn.can_go_up = function($el) {
2970
2967
  var el_grid_data = $el.coords().grid;
@@ -3161,15 +3158,6 @@
3161
3158
  }
3162
3159
  };
3163
3160
 
3164
- fn.clean_up_changed = function(){
3165
- $gr = this;
3166
- $gr.$changed.each(function(){
3167
- if($gr.options.shift_larger_widgets_down){
3168
- $gr.move_widget_up($(this));
3169
- }
3170
- });
3171
- }
3172
-
3173
3161
 
3174
3162
 
3175
3163
  fn._traversing_widgets = function(type, direction, col, row, callback) {
@@ -3207,8 +3195,7 @@
3207
3195
  ) {
3208
3196
  cr = callback.call(ga[col][trow], col, trow);
3209
3197
  matched.push(ga[col][trow]);
3210
- //break was causing problems, leaving for testing.
3211
- //if (cr) { break; }
3198
+ if (cr) { break; }
3212
3199
  }
3213
3200
  }
3214
3201
  }
@@ -3335,7 +3322,7 @@
3335
3322
  */
3336
3323
  fn.generate_stylesheet = function(opts) {
3337
3324
  var styles = '';
3338
- var max_size_x = this.options.max_size_x;
3325
+ var max_size_x = this.options.max_size_x || this.cols;
3339
3326
  var max_rows = 0;
3340
3327
  var max_cols = 0;
3341
3328
  var i;
@@ -3367,7 +3354,7 @@
3367
3354
  styles += (opts.namespace + ' [data-col="'+ (i + 1) + '"] { left:' +
3368
3355
  ((i * opts.widget_base_dimensions[0]) +
3369
3356
  (i * opts.widget_margins[0]) +
3370
- ((i + 1) * opts.widget_margins[0])) + 'px;} ');
3357
+ ((i + 1) * opts.widget_margins[0])) + 'px; }\n');
3371
3358
  }
3372
3359
 
3373
3360
  /* generate CSS styles for rows */
@@ -3375,19 +3362,19 @@
3375
3362
  styles += (opts.namespace + ' [data-row="' + (i + 1) + '"] { top:' +
3376
3363
  ((i * opts.widget_base_dimensions[1]) +
3377
3364
  (i * opts.widget_margins[1]) +
3378
- ((i + 1) * opts.widget_margins[1]) ) + 'px;} ');
3365
+ ((i + 1) * opts.widget_margins[1]) ) + 'px; }\n');
3379
3366
  }
3380
3367
 
3381
3368
  for (var y = 1; y <= opts.rows; y++) {
3382
3369
  styles += (opts.namespace + ' [data-sizey="' + y + '"] { height:' +
3383
3370
  (y * opts.widget_base_dimensions[1] +
3384
- (y - 1) * (opts.widget_margins[1] * 2)) + 'px;}');
3371
+ (y - 1) * (opts.widget_margins[1] * 2)) + 'px; }\n');
3385
3372
  }
3386
3373
 
3387
3374
  for (var x = 1; x <= max_size_x; x++) {
3388
3375
  styles += (opts.namespace + ' [data-sizex="' + x + '"] { width:' +
3389
3376
  (x * opts.widget_base_dimensions[0] +
3390
- (x - 1) * (opts.widget_margins[0] * 2)) + 'px;}');
3377
+ (x - 1) * (opts.widget_margins[0] * 2)) + 'px; }\n');
3391
3378
  }
3392
3379
 
3393
3380
  return this.add_style_tag(styles);
@@ -3413,10 +3400,24 @@
3413
3400
  }else{
3414
3401
  tag.appendChild(document.createTextNode(css));
3415
3402
  }
3403
+
3404
+ this.$style_tags = this.$style_tags.add(tag);
3405
+
3416
3406
  return this;
3417
3407
  };
3418
3408
 
3419
3409
 
3410
+ /**
3411
+ * Remove the style tag with the associated id from the head of the document
3412
+ *
3413
+ * @method remove_style_tag
3414
+ * @return {Object} Returns the instance of the Gridster class.
3415
+ */
3416
+ fn.remove_style_tags = function() {
3417
+ this.$style_tags.remove();
3418
+ };
3419
+
3420
+
3420
3421
  /**
3421
3422
  * Generates a faux grid to collide with it when a widget is dragged and
3422
3423
  * detect row or column that we want to go.
@@ -3573,14 +3574,15 @@
3573
3574
  fn.generate_grid_and_stylesheet = function() {
3574
3575
  var aw = this.$wrapper.width();
3575
3576
  var ah = this.$wrapper.height();
3577
+ var max_cols = this.options.max_cols;
3576
3578
 
3577
3579
  var cols = Math.floor(aw / this.min_widget_width) +
3578
3580
  this.options.extra_cols;
3579
3581
 
3580
3582
  var actual_cols = this.$widgets.map(function() {
3581
3583
  return $(this).attr('data-col');
3582
- });
3583
- actual_cols = Array.prototype.slice.call(actual_cols, 0);
3584
+ }).get();
3585
+
3584
3586
  //needed to pass tests with phantomjs
3585
3587
  actual_cols.length || (actual_cols = [0]);
3586
3588
 
@@ -3593,12 +3595,21 @@
3593
3595
  });
3594
3596
 
3595
3597
  this.cols = Math.max(min_cols, cols, this.options.min_cols);
3596
- //this.rows = Math.max(max_rows, this.options.min_rows);
3597
- this.rows = this.options.max_rows;
3598
+
3599
+ if (max_cols && max_cols >= min_cols && max_cols < this.cols) {
3600
+ this.cols = max_cols;
3601
+ }
3602
+
3603
+ this.rows = Math.max(max_rows, this.options.min_rows);
3598
3604
 
3599
3605
  this.baseX = ($(window).width() - aw) / 2;
3600
3606
  this.baseY = this.$wrapper.offset().top;
3601
3607
 
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
+
3602
3613
  if (this.options.autogenerate_stylesheet) {
3603
3614
  this.generate_stylesheet();
3604
3615
  }
@@ -3606,6 +3617,30 @@
3606
3617
  return this.generate_faux_grid(this.rows, this.cols);
3607
3618
  };
3608
3619
 
3620
+ /**
3621
+ * Destroy this gridster by removing any sign of its presence, making it easy to avoid memory leaks
3622
+ *
3623
+ * @method destroy
3624
+ * @return {undefined}
3625
+ */
3626
+ fn.destroy = function(){
3627
+ // remove bound callback on window resize
3628
+ $(window).unbind('.gridster');
3629
+
3630
+ if (this.drag_api) {
3631
+ this.drag_api.destroy();
3632
+ }
3633
+
3634
+ this.remove_style_tags();
3635
+
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();
3640
+
3641
+ return this;
3642
+ };
3643
+
3609
3644
 
3610
3645
  //jQuery adapter
3611
3646
  $.fn.gridster = function(options) {