slickgrid-rails 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/.gitignore +2 -0
  2. data/README.md +9 -0
  3. data/Rakefile +33 -0
  4. data/slickgrid-rails.gemspec +1 -2
  5. data/vendor/assets/javascripts/slick/controls/columnpicker.css +31 -0
  6. data/vendor/assets/javascripts/slick/controls/columnpicker.js +32 -0
  7. data/vendor/assets/javascripts/slick/controls/pager.css +41 -0
  8. data/vendor/assets/javascripts/slick/controls/pager.js +4 -8
  9. data/vendor/assets/javascripts/slick/core.js +35 -1
  10. data/vendor/assets/javascripts/slick/dataview.js +240 -85
  11. data/vendor/assets/javascripts/slick/editors.js +5 -5
  12. data/vendor/assets/javascripts/slick/formatters.js +5 -1
  13. data/vendor/assets/javascripts/slick/grid.css +157 -0
  14. data/vendor/assets/javascripts/slick/grid.js +770 -269
  15. data/vendor/assets/javascripts/slick/groupitemmetadataprovider.js +15 -10
  16. data/vendor/assets/javascripts/slick/plugins/autotooltips.js +49 -14
  17. data/vendor/assets/javascripts/slick/plugins/cellrangeselector.js +9 -8
  18. data/vendor/assets/javascripts/slick/plugins/cellselectionmodel.js +62 -2
  19. data/vendor/assets/javascripts/slick/plugins/checkboxselectcolumn.js +8 -9
  20. data/vendor/assets/javascripts/slick/plugins/headerbuttons.css +39 -0
  21. data/vendor/assets/javascripts/slick/plugins/headerbuttons.js +177 -0
  22. data/vendor/assets/javascripts/slick/plugins/headermenu.css +59 -0
  23. data/vendor/assets/javascripts/slick/plugins/headermenu.js +275 -0
  24. data/vendor/assets/javascripts/slick/plugins/rowmovemanager.js +17 -11
  25. data/vendor/assets/javascripts/slick/plugins/rowselectionmodel.js +1 -1
  26. data/vendor/assets/javascripts/slick/remotemodel.js +164 -0
  27. data/vendor/assets/stylesheets/slick/controls/columnpicker.css +31 -0
  28. data/vendor/assets/stylesheets/slick/controls/pager.css +41 -0
  29. data/vendor/assets/stylesheets/slick/grid.css +157 -0
  30. data/vendor/assets/stylesheets/slick/plugins/headerbuttons.css +39 -0
  31. data/vendor/assets/stylesheets/slick/plugins/headermenu.css +59 -0
  32. metadata +51 -17
  33. data/.rvmrc +0 -1
  34. data/Gemfile.lock +0 -85
  35. data/fetch.sh +0 -8
  36. data/lib/slickgrid/rails/version.rb +0 -6
@@ -26,6 +26,7 @@
26
26
  var _grid;
27
27
  var _defaults = {
28
28
  groupCssClass: "slick-group",
29
+ groupTitleCssClass: "slick-group-title",
29
30
  totalsCssClass: "slick-group-totals",
30
31
  groupFocusable: true,
31
32
  totalsFocusable: false,
@@ -43,9 +44,15 @@
43
44
  return item.title;
44
45
  }
45
46
 
47
+ var indentation = item.level * 15 + "px";
48
+
46
49
  return "<span class='" + options.toggleCssClass + " " +
47
50
  (item.collapsed ? options.toggleCollapsedCssClass : options.toggleExpandedCssClass) +
48
- "'></span>" + item.title;
51
+ "' style='margin-left:" + indentation +"'>" +
52
+ "</span>" +
53
+ "<span class='" + options.groupTitleCssClass + "' level='" + item.level + "'>" +
54
+ item.title +
55
+ "</span>";
49
56
  }
50
57
 
51
58
  function defaultTotalsCellFormatter(row, cell, value, columnDef, item) {
@@ -71,10 +78,9 @@
71
78
  var item = this.getDataItem(args.row);
72
79
  if (item && item instanceof Slick.Group && $(e.target).hasClass(options.toggleCssClass)) {
73
80
  if (item.collapsed) {
74
- this.getData().expandGroup(item.value);
75
- }
76
- else {
77
- this.getData().collapseGroup(item.value);
81
+ this.getData().expandGroup(item.groupingKey);
82
+ } else {
83
+ this.getData().collapseGroup(item.groupingKey);
78
84
  }
79
85
 
80
86
  e.stopImmediatePropagation();
@@ -90,10 +96,9 @@
90
96
  var item = this.getDataItem(activeCell.row);
91
97
  if (item && item instanceof Slick.Group) {
92
98
  if (item.collapsed) {
93
- this.getData().expandGroup(item.value);
94
- }
95
- else {
96
- this.getData().collapseGroup(item.value);
99
+ this.getData().expandGroup(item.groupingKey);
100
+ } else {
101
+ this.getData().collapseGroup(item.groupingKey);
97
102
  }
98
103
 
99
104
  e.stopImmediatePropagation();
@@ -136,4 +141,4 @@
136
141
  "getTotalsRowMetadata": getTotalsRowMetadata
137
142
  };
138
143
  }
139
- })(jQuery);
144
+ })(jQuery);
@@ -1,45 +1,80 @@
1
1
  (function ($) {
2
- // register namespace
2
+ // Register namespace
3
3
  $.extend(true, window, {
4
4
  "Slick": {
5
5
  "AutoTooltips": AutoTooltips
6
6
  }
7
7
  });
8
8
 
9
-
9
+ /**
10
+ * AutoTooltips plugin to show/hide tooltips when columns are too narrow to fit content.
11
+ * @constructor
12
+ * @param {boolean} [options.enableForCells=true] - Enable tooltip for grid cells
13
+ * @param {boolean} [options.enableForHeaderCells=false] - Enable tooltip for header cells
14
+ * @param {number} [options.maxToolTipLength=null] - The maximum length for a tooltip
15
+ */
10
16
  function AutoTooltips(options) {
11
17
  var _grid;
12
18
  var _self = this;
13
19
  var _defaults = {
20
+ enableForCells: true,
21
+ enableForHeaderCells: false,
14
22
  maxToolTipLength: null
15
23
  };
16
-
24
+
25
+ /**
26
+ * Initialize plugin.
27
+ */
17
28
  function init(grid) {
18
29
  options = $.extend(true, {}, _defaults, options);
19
30
  _grid = grid;
20
- _grid.onMouseEnter.subscribe(handleMouseEnter);
31
+ if (options.enableForCells) _grid.onMouseEnter.subscribe(handleMouseEnter);
32
+ if (options.enableForHeaderCells) _grid.onHeaderMouseEnter.subscribe(handleHeaderMouseEnter);
21
33
  }
22
-
34
+
35
+ /**
36
+ * Destroy plugin.
37
+ */
23
38
  function destroy() {
24
- _grid.onMouseEnter.unsubscribe(handleMouseEnter);
39
+ if (options.enableForCells) _grid.onMouseEnter.unsubscribe(handleMouseEnter);
40
+ if (options.enableForHeaderCells) _grid.onHeaderMouseEnter.unsubscribe(handleHeaderMouseEnter);
25
41
  }
26
-
27
- function handleMouseEnter(e, args) {
42
+
43
+ /**
44
+ * Handle mouse entering grid cell to add/remove tooltip.
45
+ * @param {jQuery.Event} e - The event
46
+ */
47
+ function handleMouseEnter(e) {
28
48
  var cell = _grid.getCellFromEvent(e);
29
49
  if (cell) {
30
- var node = _grid.getCellNode(cell.row, cell.cell);
31
- if ($(node).innerWidth() < node.scrollWidth) {
32
- var text = $.trim($(node).text());
50
+ var $node = $(_grid.getCellNode(cell.row, cell.cell));
51
+ var text;
52
+ if ($node.innerWidth() < $node[0].scrollWidth) {
53
+ text = $.trim($node.text());
33
54
  if (options.maxToolTipLength && text.length > options.maxToolTipLength) {
34
55
  text = text.substr(0, options.maxToolTipLength - 3) + "...";
35
56
  }
36
- $(node).attr("title", text);
37
57
  } else {
38
- $(node).attr("title", "");
58
+ text = "";
39
59
  }
60
+ $node.attr("title", text);
40
61
  }
41
62
  }
42
-
63
+
64
+ /**
65
+ * Handle mouse entering header cell to add/remove tooltip.
66
+ * @param {jQuery.Event} e - The event
67
+ * @param {object} args.column - The column definition
68
+ */
69
+ function handleHeaderMouseEnter(e, args) {
70
+ var column = args.column,
71
+ $node = $(e.target).closest(".slick-header-column");
72
+ if (!column.toolTip) {
73
+ $node.attr("title", ($node.innerWidth() < $node[0].scrollWidth) ? column.name : "");
74
+ }
75
+ }
76
+
77
+ // Public API
43
78
  $.extend(this, {
44
79
  "init": init,
45
80
  "destroy": destroy
@@ -13,6 +13,7 @@
13
13
  var _dragging;
14
14
  var _decorator;
15
15
  var _self = this;
16
+ var _handler = new Slick.EventHandler();
16
17
  var _defaults = {
17
18
  selectionCss: {
18
19
  "border": "2px dashed blue"
@@ -25,17 +26,15 @@
25
26
  _decorator = new Slick.CellRangeDecorator(grid, options);
26
27
  _grid = grid;
27
28
  _canvas = _grid.getCanvasNode();
28
- _grid.onDragInit.subscribe(handleDragInit);
29
- _grid.onDragStart.subscribe(handleDragStart);
30
- _grid.onDrag.subscribe(handleDrag);
31
- _grid.onDragEnd.subscribe(handleDragEnd);
29
+ _handler
30
+ .subscribe(_grid.onDragInit, handleDragInit)
31
+ .subscribe(_grid.onDragStart, handleDragStart)
32
+ .subscribe(_grid.onDrag, handleDrag)
33
+ .subscribe(_grid.onDragEnd, handleDragEnd);
32
34
  }
33
35
 
34
36
  function destroy() {
35
- _grid.onDragInit.unsubscribe(handleDragInit);
36
- _grid.onDragStart.unsubscribe(handleDragStart);
37
- _grid.onDrag.unsubscribe(handleDrag);
38
- _grid.onDragEnd.unsubscribe(handleDragEnd);
37
+ _handler.unsubscribeAll();
39
38
  }
40
39
 
41
40
  function handleDragInit(e, dd) {
@@ -55,6 +54,8 @@
55
54
  return;
56
55
  }
57
56
 
57
+ _grid.focus();
58
+
58
59
  var start = _grid.getCellFromPoint(
59
60
  dd.startX - $(_canvas).offset().left,
60
61
  dd.startY - $(_canvas).offset().top);
@@ -28,6 +28,7 @@
28
28
  _grid = grid;
29
29
  _canvas = _grid.getCanvasNode();
30
30
  _grid.onActiveCellChanged.subscribe(handleActiveCellChange);
31
+ _grid.onKeyDown.subscribe(handleKeyDown);
31
32
  grid.registerPlugin(_selector);
32
33
  _selector.onCellRangeSelected.subscribe(handleCellRangeSelected);
33
34
  _selector.onBeforeCellRangeSelected.subscribe(handleBeforeCellRangeSelected);
@@ -35,6 +36,7 @@
35
36
 
36
37
  function destroy() {
37
38
  _grid.onActiveCellChanged.unsubscribe(handleActiveCellChange);
39
+ _grid.onKeyDown.unsubscribe(handleKeyDown);
38
40
  _selector.onCellRangeSelected.unsubscribe(handleCellRangeSelected);
39
41
  _selector.onBeforeCellRangeSelected.unsubscribe(handleBeforeCellRangeSelected);
40
42
  _grid.unregisterPlugin(_selector);
@@ -74,10 +76,68 @@
74
76
  }
75
77
 
76
78
  function handleActiveCellChange(e, args) {
77
- if (_options.selectActiveCell) {
79
+ if (_options.selectActiveCell && args.row != null && args.cell != null) {
78
80
  setSelectedRanges([new Slick.Range(args.row, args.cell)]);
79
81
  }
80
82
  }
83
+
84
+ function handleKeyDown(e) {
85
+ /***
86
+ * Кey codes
87
+ * 37 left
88
+ * 38 up
89
+ * 39 right
90
+ * 40 down
91
+ */
92
+ var ranges, last;
93
+ var active = _grid.getActiveCell();
94
+
95
+ if ( active && e.shiftKey && !e.ctrlKey && !e.altKey &&
96
+ (e.which == 37 || e.which == 39 || e.which == 38 || e.which == 40) ) {
97
+
98
+ ranges = getSelectedRanges();
99
+ if (!ranges.length)
100
+ ranges.push(new Slick.Range(active.row, active.cell));
101
+
102
+ // keyboard can work with last range only
103
+ last = ranges.pop();
104
+
105
+ // can't handle selection out of active cell
106
+ if (!last.contains(active.row, active.cell))
107
+ last = new Slick.Range(active.row, active.cell);
108
+
109
+ var dRow = last.toRow - last.fromRow,
110
+ dCell = last.toCell - last.fromCell,
111
+ // walking direction
112
+ dirRow = active.row == last.fromRow ? 1 : -1,
113
+ dirCell = active.cell == last.fromCell ? 1 : -1;
114
+
115
+ if (e.which == 37) {
116
+ dCell -= dirCell;
117
+ } else if (e.which == 39) {
118
+ dCell += dirCell ;
119
+ } else if (e.which == 38) {
120
+ dRow -= dirRow;
121
+ } else if (e.which == 40) {
122
+ dRow += dirRow;
123
+ }
124
+
125
+ // define new selection range
126
+ var new_last = new Slick.Range(active.row, active.cell, active.row + dirRow*dRow, active.cell + dirCell*dCell);
127
+ if (removeInvalidRanges([new_last]).length) {
128
+ ranges.push(new_last);
129
+ _grid.scrollRowIntoView(dirRow > 0 ? new_last.toRow : new_last.fromRow);
130
+ _grid.scrollCellIntoView(new_last.fromRow, dirCell > 0 ? new_last.toCell : new_last.fromCell);
131
+ }
132
+ else
133
+ ranges.push(last);
134
+
135
+ setSelectedRanges(ranges);
136
+
137
+ e.preventDefault();
138
+ e.stopPropagation();
139
+ }
140
+ }
81
141
 
82
142
  $.extend(this, {
83
143
  "getSelectedRanges": getSelectedRanges,
@@ -89,4 +149,4 @@
89
149
  "onSelectedRangesChanged": new Slick.Event()
90
150
  });
91
151
  }
92
- })(jQuery);
152
+ })(jQuery);
@@ -10,6 +10,7 @@
10
10
  function CheckboxSelectColumn(options) {
11
11
  var _grid;
12
12
  var _self = this;
13
+ var _handler = new Slick.EventHandler();
13
14
  var _selectedRowsLookup = {};
14
15
  var _defaults = {
15
16
  columnId: "_checkbox_selector",
@@ -22,17 +23,15 @@
22
23
 
23
24
  function init(grid) {
24
25
  _grid = grid;
25
- _grid.onSelectedRowsChanged.subscribe(handleSelectedRowsChanged);
26
- _grid.onClick.subscribe(handleClick);
27
- _grid.onHeaderClick.subscribe(handleHeaderClick);
28
- _grid.onKeyDown.subscribe(handleKeyDown);
26
+ _handler
27
+ .subscribe(_grid.onSelectedRowsChanged, handleSelectedRowsChanged)
28
+ .subscribe(_grid.onClick, handleClick)
29
+ .subscribe(_grid.onHeaderClick, handleHeaderClick)
30
+ .subscribe(_grid.onKeyDown, handleKeyDown);
29
31
  }
30
32
 
31
33
  function destroy() {
32
- _grid.onSelectedRowsChanged.unsubscribe(handleSelectedRowsChanged);
33
- _grid.onClick.unsubscribe(handleClick);
34
- _grid.onHeaderClick.unsubscribe(handleHeaderClick);
35
- _grid.onKeyDown.unsubscribe(handleKeyDown);
34
+ _handler.unsubscribeAll();
36
35
  }
37
36
 
38
37
  function handleSelectedRowsChanged(e, args) {
@@ -52,7 +51,7 @@
52
51
  _selectedRowsLookup = lookup;
53
52
  _grid.render();
54
53
 
55
- if (selectedRows.length == _grid.getDataLength()) {
54
+ if (selectedRows.length && selectedRows.length == _grid.getDataLength()) {
56
55
  _grid.updateColumnHeader(_options.columnId, "<input type='checkbox' checked='checked'>", _options.toolTip);
57
56
  } else {
58
57
  _grid.updateColumnHeader(_options.columnId, "<input type='checkbox'>", _options.toolTip);
@@ -0,0 +1,39 @@
1
+ .slick-column-name,
2
+ .slick-sort-indicator {
3
+ /**
4
+ * This makes all "float:right" elements after it that spill over to the next line
5
+ * display way below the lower boundary of the column thus hiding them.
6
+ */
7
+ display: inline-block;
8
+ float: left;
9
+ margin-bottom: 100px;
10
+ }
11
+
12
+ .slick-header-button {
13
+ display: inline-block;
14
+ float: right;
15
+ vertical-align: top;
16
+ margin: 1px;
17
+ /**
18
+ * This makes all "float:right" elements after it that spill over to the next line
19
+ * display way below the lower boundary of the column thus hiding them.
20
+ */
21
+ margin-bottom: 100px;
22
+ height: 15px;
23
+ width: 15px;
24
+ background-repeat: no-repeat;
25
+ background-position: center center;
26
+ cursor: pointer;
27
+ }
28
+
29
+ .slick-header-button-hidden {
30
+ width: 0;
31
+
32
+ -webkit-transition: 0.2s width;
33
+ -ms-transition: 0.2s width;
34
+ transition: 0.2s width;
35
+ }
36
+
37
+ .slick-header-column:hover > .slick-header-button {
38
+ width: 15px;
39
+ }
@@ -0,0 +1,177 @@
1
+ (function ($) {
2
+ // register namespace
3
+ $.extend(true, window, {
4
+ "Slick": {
5
+ "Plugins": {
6
+ "HeaderButtons": HeaderButtons
7
+ }
8
+ }
9
+ });
10
+
11
+
12
+ /***
13
+ * A plugin to add custom buttons to column headers.
14
+ *
15
+ * USAGE:
16
+ *
17
+ * Add the plugin .js & .css files and register it with the grid.
18
+ *
19
+ * To specify a custom button in a column header, extend the column definition like so:
20
+ *
21
+ * var columns = [
22
+ * {
23
+ * id: 'myColumn',
24
+ * name: 'My column',
25
+ *
26
+ * // This is the relevant part
27
+ * header: {
28
+ * buttons: [
29
+ * {
30
+ * // button options
31
+ * },
32
+ * {
33
+ * // button options
34
+ * }
35
+ * ]
36
+ * }
37
+ * }
38
+ * ];
39
+ *
40
+ * Available button options:
41
+ * cssClass: CSS class to add to the button.
42
+ * image: Relative button image path.
43
+ * tooltip: Button tooltip.
44
+ * showOnHover: Only show the button on hover.
45
+ * handler: Button click handler.
46
+ * command: A command identifier to be passed to the onCommand event handlers.
47
+ *
48
+ * The plugin exposes the following events:
49
+ * onCommand: Fired on button click for buttons with 'command' specified.
50
+ * Event args:
51
+ * grid: Reference to the grid.
52
+ * column: Column definition.
53
+ * command: Button command identified.
54
+ * button: Button options. Note that you can change the button options in your
55
+ * event handler, and the column header will be automatically updated to
56
+ * reflect them. This is useful if you want to implement something like a
57
+ * toggle button.
58
+ *
59
+ *
60
+ * @param options {Object} Options:
61
+ * buttonCssClass: a CSS class to use for buttons (default 'slick-header-button')
62
+ * @class Slick.Plugins.HeaderButtons
63
+ * @constructor
64
+ */
65
+ function HeaderButtons(options) {
66
+ var _grid;
67
+ var _self = this;
68
+ var _handler = new Slick.EventHandler();
69
+ var _defaults = {
70
+ buttonCssClass: "slick-header-button"
71
+ };
72
+
73
+
74
+ function init(grid) {
75
+ options = $.extend(true, {}, _defaults, options);
76
+ _grid = grid;
77
+ _handler
78
+ .subscribe(_grid.onHeaderCellRendered, handleHeaderCellRendered)
79
+ .subscribe(_grid.onBeforeHeaderCellDestroy, handleBeforeHeaderCellDestroy);
80
+
81
+ // Force the grid to re-render the header now that the events are hooked up.
82
+ _grid.setColumns(_grid.getColumns());
83
+ }
84
+
85
+
86
+ function destroy() {
87
+ _handler.unsubscribeAll();
88
+ }
89
+
90
+
91
+ function handleHeaderCellRendered(e, args) {
92
+ var column = args.column;
93
+
94
+ if (column.header && column.header.buttons) {
95
+ // Append buttons in reverse order since they are floated to the right.
96
+ var i = column.header.buttons.length;
97
+ while (i--) {
98
+ var button = column.header.buttons[i];
99
+ var btn = $("<div></div>")
100
+ .addClass(options.buttonCssClass)
101
+ .data("column", column)
102
+ .data("button", button);
103
+
104
+ if (button.showOnHover) {
105
+ btn.addClass("slick-header-button-hidden");
106
+ }
107
+
108
+ if (button.image) {
109
+ btn.css("backgroundImage", "url(" + button.image + ")");
110
+ }
111
+
112
+ if (button.cssClass) {
113
+ btn.addClass(button.cssClass);
114
+ }
115
+
116
+ if (button.tooltip) {
117
+ btn.attr("title", button.tooltip);
118
+ }
119
+
120
+ if (button.command) {
121
+ btn.data("command", button.command);
122
+ }
123
+
124
+ if (button.handler) {
125
+ btn.bind("click", button.handler);
126
+ }
127
+
128
+ btn
129
+ .bind("click", handleButtonClick)
130
+ .appendTo(args.node);
131
+ }
132
+ }
133
+ }
134
+
135
+
136
+ function handleBeforeHeaderCellDestroy(e, args) {
137
+ var column = args.column;
138
+
139
+ if (column.header && column.header.buttons) {
140
+ // Removing buttons via jQuery will also clean up any event handlers and data.
141
+ // NOTE: If you attach event handlers directly or using a different framework,
142
+ // you must also clean them up here to avoid memory leaks.
143
+ $(args.node).find("." + options.buttonCssClass).remove();
144
+ }
145
+ }
146
+
147
+
148
+ function handleButtonClick(e) {
149
+ var command = $(this).data("command");
150
+ var columnDef = $(this).data("column");
151
+ var button = $(this).data("button");
152
+
153
+ if (command != null) {
154
+ _self.onCommand.notify({
155
+ "grid": _grid,
156
+ "column": columnDef,
157
+ "command": command,
158
+ "button": button
159
+ }, e, _self);
160
+
161
+ // Update the header in case the user updated the button definition in the handler.
162
+ _grid.updateColumnHeader(columnDef.id);
163
+ }
164
+
165
+ // Stop propagation so that it doesn't register as a header click event.
166
+ e.preventDefault();
167
+ e.stopPropagation();
168
+ }
169
+
170
+ $.extend(this, {
171
+ "init": init,
172
+ "destroy": destroy,
173
+
174
+ "onCommand": new Slick.Event()
175
+ });
176
+ }
177
+ })(jQuery);