slickgrid-rails 0.2.0 → 0.3.0

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.
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
@@ -0,0 +1,59 @@
1
+ /* Menu button */
2
+ .slick-header-menubutton {
3
+ position: absolute;
4
+ right: 0;
5
+ top: 0;
6
+ bottom: 0;
7
+ width: 14px;
8
+ background-repeat: no-repeat;
9
+ background-position: left center;
10
+ background-image: url(../images/down.gif);
11
+ cursor: pointer;
12
+
13
+ display: none;
14
+ border-left: thin ridge silver;
15
+ }
16
+
17
+ .slick-header-column:hover > .slick-header-menubutton,
18
+ .slick-header-column-active .slick-header-menubutton {
19
+ display: inline-block;
20
+ }
21
+
22
+ /* Menu */
23
+ .slick-header-menu {
24
+ position: absolute;
25
+ display: inline-block;
26
+ margin: 0;
27
+ padding: 2px;
28
+ cursor: default;
29
+ }
30
+
31
+
32
+ /* Menu items */
33
+ .slick-header-menuitem {
34
+ list-style: none;
35
+ margin: 0;
36
+ padding: 0;
37
+ cursor: pointer;
38
+ }
39
+
40
+ .slick-header-menuicon {
41
+ display: inline-block;
42
+ width: 16px;
43
+ height: 16px;
44
+ vertical-align: middle;
45
+ margin-right: 4px;
46
+ background-repeat: no-repeat;
47
+ background-position: center center;
48
+ }
49
+
50
+ .slick-header-menucontent {
51
+ display: inline-block;
52
+ vertical-align: middle;
53
+ }
54
+
55
+
56
+ /* Disabled */
57
+ .slick-header-menuitem-disabled {
58
+ color: silver;
59
+ }
@@ -0,0 +1,275 @@
1
+ (function ($) {
2
+ // register namespace
3
+ $.extend(true, window, {
4
+ "Slick": {
5
+ "Plugins": {
6
+ "HeaderMenu": HeaderMenu
7
+ }
8
+ }
9
+ });
10
+
11
+
12
+ /***
13
+ * A plugin to add drop-down menus 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 menu 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
+ * menu: {
29
+ * items: [
30
+ * {
31
+ * // menu item options
32
+ * },
33
+ * {
34
+ * // menu item options
35
+ * }
36
+ * ]
37
+ * }
38
+ * }
39
+ * }
40
+ * ];
41
+ *
42
+ *
43
+ * Available menu options:
44
+ * tooltip: Menu button tooltip.
45
+ *
46
+ *
47
+ * Available menu item options:
48
+ * title: Menu item text.
49
+ * disabled: Whether the item is disabled.
50
+ * tooltip: Item tooltip.
51
+ * command: A command identifier to be passed to the onCommand event handlers.
52
+ * iconCssClass: A CSS class to be added to the menu item icon.
53
+ * iconImage: A url to the icon image.
54
+ *
55
+ *
56
+ * The plugin exposes the following events:
57
+ * onBeforeMenuShow: Fired before the menu is shown. You can customize the menu or dismiss it by returning false.
58
+ * Event args:
59
+ * grid: Reference to the grid.
60
+ * column: Column definition.
61
+ * menu: Menu options. Note that you can change the menu items here.
62
+ *
63
+ * onCommand: Fired on menu item click for buttons with 'command' specified.
64
+ * Event args:
65
+ * grid: Reference to the grid.
66
+ * column: Column definition.
67
+ * command: Button command identified.
68
+ * button: Button options. Note that you can change the button options in your
69
+ * event handler, and the column header will be automatically updated to
70
+ * reflect them. This is useful if you want to implement something like a
71
+ * toggle button.
72
+ *
73
+ *
74
+ * @param options {Object} Options:
75
+ * buttonCssClass: an extra CSS class to add to the menu button
76
+ * buttonImage: a url to the menu button image (default '../images/down.gif')
77
+ * @class Slick.Plugins.HeaderButtons
78
+ * @constructor
79
+ */
80
+ function HeaderMenu(options) {
81
+ var _grid;
82
+ var _self = this;
83
+ var _handler = new Slick.EventHandler();
84
+ var _defaults = {
85
+ buttonCssClass: null,
86
+ buttonImage: null
87
+ };
88
+ var $menu;
89
+ var $activeHeaderColumn;
90
+
91
+
92
+ function init(grid) {
93
+ options = $.extend(true, {}, _defaults, options);
94
+ _grid = grid;
95
+ _handler
96
+ .subscribe(_grid.onHeaderCellRendered, handleHeaderCellRendered)
97
+ .subscribe(_grid.onBeforeHeaderCellDestroy, handleBeforeHeaderCellDestroy);
98
+
99
+ // Force the grid to re-render the header now that the events are hooked up.
100
+ _grid.setColumns(_grid.getColumns());
101
+
102
+ // Hide the menu on outside click.
103
+ $(document.body).bind("mousedown", handleBodyMouseDown);
104
+ }
105
+
106
+
107
+ function destroy() {
108
+ _handler.unsubscribeAll();
109
+ $(document.body).unbind("mousedown", handleBodyMouseDown);
110
+ }
111
+
112
+
113
+ function handleBodyMouseDown(e) {
114
+ if ($menu && $menu[0] != e.target && !$.contains($menu[0], e.target)) {
115
+ hideMenu();
116
+ }
117
+ }
118
+
119
+
120
+ function hideMenu() {
121
+ if ($menu) {
122
+ $menu.remove();
123
+ $menu = null;
124
+ $activeHeaderColumn
125
+ .removeClass("slick-header-column-active");
126
+ }
127
+ }
128
+
129
+ function handleHeaderCellRendered(e, args) {
130
+ var column = args.column;
131
+ var menu = column.header && column.header.menu;
132
+
133
+ if (menu) {
134
+ var $el = $("<div></div>")
135
+ .addClass("slick-header-menubutton")
136
+ .data("column", column)
137
+ .data("menu", menu);
138
+
139
+ if (options.buttonCssClass) {
140
+ $el.addClass(options.buttonCssClass);
141
+ }
142
+
143
+ if (options.buttonImage) {
144
+ $el.css("background-image", "url(" + options.buttonImage + ")");
145
+ }
146
+
147
+ if (menu.tooltip) {
148
+ $el.attr("title", menu.tooltip);
149
+ }
150
+
151
+ $el
152
+ .bind("click", showMenu)
153
+ .appendTo(args.node);
154
+ }
155
+ }
156
+
157
+
158
+ function handleBeforeHeaderCellDestroy(e, args) {
159
+ var column = args.column;
160
+
161
+ if (column.header && column.header.menu) {
162
+ $(args.node).find(".slick-header-menubutton").remove();
163
+ }
164
+ }
165
+
166
+
167
+ function showMenu(e) {
168
+ var $menuButton = $(this);
169
+ var menu = $menuButton.data("menu");
170
+ var columnDef = $menuButton.data("column");
171
+
172
+ // Let the user modify the menu or cancel altogether,
173
+ // or provide alternative menu implementation.
174
+ if (_self.onBeforeMenuShow.notify({
175
+ "grid": _grid,
176
+ "column": columnDef,
177
+ "menu": menu
178
+ }, e, _self) == false) {
179
+ return;
180
+ }
181
+
182
+
183
+ if (!$menu) {
184
+ $menu = $("<div class='slick-header-menu'></div>")
185
+ .appendTo(_grid.getContainerNode());
186
+ }
187
+ $menu.empty();
188
+
189
+
190
+ // Construct the menu items.
191
+ for (var i = 0; i < menu.items.length; i++) {
192
+ var item = menu.items[i];
193
+
194
+ var $li = $("<div class='slick-header-menuitem'></div>")
195
+ .data("command", item.command || '')
196
+ .data("column", columnDef)
197
+ .data("item", item)
198
+ .bind("click", handleMenuItemClick)
199
+ .appendTo($menu);
200
+
201
+ if (item.disabled) {
202
+ $li.addClass("slick-header-menuitem-disabled");
203
+ }
204
+
205
+ if (item.tooltip) {
206
+ $li.attr("title", item.tooltip);
207
+ }
208
+
209
+ var $icon = $("<div class='slick-header-menuicon'></div>")
210
+ .appendTo($li);
211
+
212
+ if (item.iconCssClass) {
213
+ $icon.addClass(item.iconCssClass);
214
+ }
215
+
216
+ if (item.iconImage) {
217
+ $icon.css("background-image", "url(" + item.iconImage + ")");
218
+ }
219
+
220
+ $("<span class='slick-header-menucontent'></span>")
221
+ .text(item.title)
222
+ .appendTo($li);
223
+ }
224
+
225
+
226
+ // Position the menu.
227
+ $menu
228
+ .offset({ top: $(this).offset().top + $(this).height(), left: $(this).offset().left });
229
+
230
+
231
+ // Mark the header as active to keep the highlighting.
232
+ $activeHeaderColumn = $menuButton.closest(".slick-header-column");
233
+ $activeHeaderColumn
234
+ .addClass("slick-header-column-active");
235
+
236
+ // Stop propagation so that it doesn't register as a header click event.
237
+ e.preventDefault();
238
+ e.stopPropagation();
239
+ }
240
+
241
+
242
+ function handleMenuItemClick(e) {
243
+ var command = $(this).data("command");
244
+ var columnDef = $(this).data("column");
245
+ var item = $(this).data("item");
246
+
247
+ if (item.disabled) {
248
+ return;
249
+ }
250
+
251
+ hideMenu();
252
+
253
+ if (command != null && command != '') {
254
+ _self.onCommand.notify({
255
+ "grid": _grid,
256
+ "column": columnDef,
257
+ "command": command,
258
+ "item": item
259
+ }, e, _self);
260
+ }
261
+
262
+ // Stop propagation so that it doesn't register as a header click event.
263
+ e.preventDefault();
264
+ e.stopPropagation();
265
+ }
266
+
267
+ $.extend(this, {
268
+ "init": init,
269
+ "destroy": destroy,
270
+
271
+ "onBeforeMenuShow": new Slick.Event(),
272
+ "onCommand": new Slick.Event()
273
+ });
274
+ }
275
+ })(jQuery);
@@ -6,26 +6,29 @@
6
6
  }
7
7
  });
8
8
 
9
- function RowMoveManager() {
9
+ function RowMoveManager(options) {
10
10
  var _grid;
11
11
  var _canvas;
12
12
  var _dragging;
13
13
  var _self = this;
14
+ var _handler = new Slick.EventHandler();
15
+ var _defaults = {
16
+ cancelEditOnDrag: false
17
+ };
14
18
 
15
19
  function init(grid) {
20
+ options = $.extend(true, {}, _defaults, options);
16
21
  _grid = grid;
17
22
  _canvas = _grid.getCanvasNode();
18
- _grid.onDragInit.subscribe(handleDragInit);
19
- _grid.onDragStart.subscribe(handleDragStart);
20
- _grid.onDrag.subscribe(handleDrag);
21
- _grid.onDragEnd.subscribe(handleDragEnd);
23
+ _handler
24
+ .subscribe(_grid.onDragInit, handleDragInit)
25
+ .subscribe(_grid.onDragStart, handleDragStart)
26
+ .subscribe(_grid.onDrag, handleDrag)
27
+ .subscribe(_grid.onDragEnd, handleDragEnd);
22
28
  }
23
29
 
24
30
  function destroy() {
25
- _grid.onDragInit.unsubscribe(handleDragInit);
26
- _grid.onDragStart.unsubscribe(handleDragStart);
27
- _grid.onDrag.unsubscribe(handleDrag);
28
- _grid.onDragEnd.unsubscribe(handleDragEnd);
31
+ _handler.unsubscribeAll();
29
32
  }
30
33
 
31
34
  function handleDragInit(e, dd) {
@@ -35,6 +38,11 @@
35
38
 
36
39
  function handleDragStart(e, dd) {
37
40
  var cell = _grid.getCellFromEvent(e);
41
+
42
+ if (options.cancelEditOnDrag && _grid.getEditorLock().isActive()) {
43
+ _grid.getEditorLock().cancelCurrentEdit();
44
+ }
45
+
38
46
  if (_grid.getEditorLock().isActive() || !/move|selectAndMove/.test(_grid.getColumns()[cell.cell].behavior)) {
39
47
  return false;
40
48
  }
@@ -68,8 +76,6 @@
68
76
  .appendTo(_canvas);
69
77
 
70
78
  dd.insertBefore = -1;
71
-
72
- return $("<div></div>").appendTo(_canvas);
73
79
  }
74
80
 
75
81
  function handleDrag(e, dd) {
@@ -90,7 +90,7 @@
90
90
  }
91
91
 
92
92
  function handleActiveCellChange(e, data) {
93
- if (_options.selectActiveRow) {
93
+ if (_options.selectActiveRow && data.row != null) {
94
94
  setSelectedRanges([new Slick.Range(data.row, 0, data.row, _grid.getColumns().length - 1)]);
95
95
  }
96
96
  }
@@ -0,0 +1,164 @@
1
+ (function ($) {
2
+ /***
3
+ * A sample AJAX data store implementation.
4
+ * Right now, it's hooked up to load all Apple-related Digg stories, but can
5
+ * easily be extended to support and JSONP-compatible backend that accepts paging parameters.
6
+ */
7
+ function RemoteModel() {
8
+ // private
9
+ var PAGESIZE = 50;
10
+ var data = {length: 0};
11
+ var searchstr = "apple";
12
+ var sortcol = null;
13
+ var sortdir = 1;
14
+ var h_request = null;
15
+ var req = null; // ajax request
16
+
17
+ // events
18
+ var onDataLoading = new Slick.Event();
19
+ var onDataLoaded = new Slick.Event();
20
+
21
+
22
+ function init() {
23
+ }
24
+
25
+
26
+ function isDataLoaded(from, to) {
27
+ for (var i = from; i <= to; i++) {
28
+ if (data[i] == undefined || data[i] == null) {
29
+ return false;
30
+ }
31
+ }
32
+
33
+ return true;
34
+ }
35
+
36
+
37
+ function clear() {
38
+ for (var key in data) {
39
+ delete data[key];
40
+ }
41
+ data.length = 0;
42
+ }
43
+
44
+
45
+ function ensureData(from, to) {
46
+ if (req) {
47
+ req.abort();
48
+ for (var i = req.fromPage; i <= req.toPage; i++)
49
+ data[i * PAGESIZE] = undefined;
50
+ }
51
+
52
+ if (from < 0) {
53
+ from = 0;
54
+ }
55
+
56
+ var fromPage = Math.floor(from / PAGESIZE);
57
+ var toPage = Math.floor(to / PAGESIZE);
58
+
59
+ while (data[fromPage * PAGESIZE] !== undefined && fromPage < toPage)
60
+ fromPage++;
61
+
62
+ while (data[toPage * PAGESIZE] !== undefined && fromPage < toPage)
63
+ toPage--;
64
+
65
+ if (fromPage > toPage || ((fromPage == toPage) && data[fromPage * PAGESIZE] !== undefined)) {
66
+ // TODO: look-ahead
67
+ return;
68
+ }
69
+
70
+ var url = "http://services.digg.com/search/stories?query=" + searchstr + "&offset=" + (fromPage * PAGESIZE) + "&count=" + (((toPage - fromPage) * PAGESIZE) + PAGESIZE) + "&appkey=http://slickgrid.googlecode.com&type=javascript";
71
+
72
+ switch (sortcol) {
73
+ case "diggs":
74
+ url += ("&sort=" + ((sortdir > 0) ? "digg_count-asc" : "digg_count-desc"));
75
+ break;
76
+ }
77
+
78
+ if (h_request != null) {
79
+ clearTimeout(h_request);
80
+ }
81
+
82
+ h_request = setTimeout(function () {
83
+ for (var i = fromPage; i <= toPage; i++)
84
+ data[i * PAGESIZE] = null; // null indicates a 'requested but not available yet'
85
+
86
+ onDataLoading.notify({from: from, to: to});
87
+
88
+ req = $.jsonp({
89
+ url: url,
90
+ callbackParameter: "callback",
91
+ cache: true, // Digg doesn't accept the autogenerated cachebuster param
92
+ success: onSuccess,
93
+ error: function () {
94
+ onError(fromPage, toPage)
95
+ }
96
+ });
97
+ req.fromPage = fromPage;
98
+ req.toPage = toPage;
99
+ }, 50);
100
+ }
101
+
102
+
103
+ function onError(fromPage, toPage) {
104
+ alert("error loading pages " + fromPage + " to " + toPage);
105
+ }
106
+
107
+ function onSuccess(resp) {
108
+ var from = this.fromPage * PAGESIZE, to = from + resp.count;
109
+ data.length = parseInt(resp.total);
110
+
111
+ for (var i = 0; i < resp.stories.length; i++) {
112
+ data[from + i] = resp.stories[i];
113
+ data[from + i].index = from + i;
114
+ }
115
+
116
+ req = null;
117
+
118
+ onDataLoaded.notify({from: from, to: to});
119
+ }
120
+
121
+
122
+ function reloadData(from, to) {
123
+ for (var i = from; i <= to; i++)
124
+ delete data[i];
125
+
126
+ ensureData(from, to);
127
+ }
128
+
129
+
130
+ function setSort(column, dir) {
131
+ sortcol = column;
132
+ sortdir = dir;
133
+ clear();
134
+ }
135
+
136
+ function setSearch(str) {
137
+ searchstr = str;
138
+ clear();
139
+ }
140
+
141
+
142
+ init();
143
+
144
+ return {
145
+ // properties
146
+ "data": data,
147
+
148
+ // methods
149
+ "clear": clear,
150
+ "isDataLoaded": isDataLoaded,
151
+ "ensureData": ensureData,
152
+ "reloadData": reloadData,
153
+ "setSort": setSort,
154
+ "setSearch": setSearch,
155
+
156
+ // events
157
+ "onDataLoading": onDataLoading,
158
+ "onDataLoaded": onDataLoaded
159
+ };
160
+ }
161
+
162
+ // Slick.Data.RemoteModel
163
+ $.extend(true, window, { Slick: { Data: { RemoteModel: RemoteModel }}});
164
+ })(jQuery);