gridster-rails 0.1.5.1 → 0.2.1

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: 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) {