UNPKG

13 kBJavaScriptView Raw
1/**
2 *
3 * Draggable Grouping contributed by: Muthukumar Selvarasu
4 * muthukumar{dot}se{at}gmail{dot}com
5 * github.com/muthukumarse/Slickgrid
6 *
7 * NOTES:
8 * This plugin provides the Draggable Grouping feature
9 */
10
11(function ($) {
12 // Register namespace
13 $.extend(true, window, {
14 "Slick": {
15 "DraggableGrouping": DraggableGrouping
16 }
17 });
18
19 /***
20 * A plugin to add Draggable Grouping feature.
21 *
22 * USAGE:
23 *
24 * Add the plugin .js & .css files and register it with the grid.
25 *
26 *
27 * The plugin expose the following methods:
28 * destroy: used to destroy the plugin
29 * setDroppedGroups: provide option to set default grouping on loading
30 * clearDroppedGroups: provide option to clear grouping
31 * getSetupColumnReorder: its function to setup draggable feature agains Header Column, should be passed on grid option. Also possible to pass custom function
32 *
33 *
34 * The plugin expose the following event(s):
35 * onGroupChanged: pass the grouped columns to who subscribed.
36 *
37 * @param options {Object} Options:
38 * deleteIconCssClass: an extra CSS class to add to the delete button (default undefined), if deleteIconCssClass && deleteIconImage undefined then slick-groupby-remove-image class will be added
39 * deleteIconImage: a url to the delete button image (default undefined)
40 * groupIconCssClass: an extra CSS class to add to the grouping field hint (default undefined)
41 * groupIconImage: a url to the grouping field hint image (default undefined)
42 * dropPlaceHolderText: option to specify set own placeholder note text
43 *
44
45 */
46
47 function DraggableGrouping(options) {
48 var _grid;
49 var _gridUid;
50 var _gridColumns;
51 var _dataView;
52 var dropbox;
53 var dropboxPlaceholder;
54 var groupToggler;
55 var _self = this;
56 var _defaults = {
57 };
58 var onGroupChanged = new Slick.Event();
59 var _handler = new Slick.EventHandler();
60
61 /**
62 * Initialize plugin.
63 */
64 function init(grid) {
65 options = $.extend(true, {}, _defaults, options);
66 _grid = grid;
67 _gridUid = _grid.getUID();
68 _gridColumns = _grid.getColumns();
69 _dataView = _grid.getData();
70
71 dropbox = $(_grid.getPreHeaderPanel());
72 var dropPlaceHolderText = options.dropPlaceHolderText || 'Drop a column header here to group by the column';
73 dropbox.html("<div class='slick-placeholder'>" + dropPlaceHolderText + "</div><div class='slick-group-toggle-all expanded' style='display:none'></div>");
74
75 dropboxPlaceholder = dropbox.find(".slick-placeholder");
76 groupToggler = dropbox.find(".slick-group-toggle-all");
77 setupColumnDropbox();
78
79
80 _handler.subscribe(_grid.onHeaderCellRendered, function (e, args) {
81 var column = args.column;
82 var node = args.node;
83 if (!$.isEmptyObject(column.grouping)) {
84 var groupableIcon = $("<span class='slick-column-groupable' />");
85 if(options.groupIconCssClass) { groupableIcon.addClass(options.groupIconCssClass); }
86 if(options.groupIconImage) { groupableIcon.css("background", "url(" + options.groupIconImage + ") no-repeat center center"); }
87 $(node).css('cursor', 'pointer').append(groupableIcon);
88 }
89 });
90
91 for (var i = 0; i < _gridColumns.length; i++) {
92 var columnId = _gridColumns[i].field;
93 _grid.updateColumnHeader(columnId);
94 }
95
96 }
97
98 function setupColumnReorder(grid, $headers, headerColumnWidthDiff, setColumns, setupColumnResize, columns, getColumnIndex, uid, trigger) {
99 $headers.filter(":ui-sortable").sortable("destroy");
100 var $headerDraggableGroupBy = $(grid.getPreHeaderPanel());
101 $headers.sortable({
102 distance: 3,
103 cursor: "default",
104 tolerance: "intersection",
105 helper: "clone",
106 placeholder: "slick-sortable-placeholder ui-state-default slick-header-column",
107 forcePlaceholderSize: true,
108 appendTo: "body",
109 start: function(e, ui) {
110 $(ui.helper).addClass("slick-header-column-active");
111 $headerDraggableGroupBy.find(".slick-placeholder").show();
112 $headerDraggableGroupBy.find(".slick-dropped-grouping").hide();
113 },
114 beforeStop: function(e, ui) {
115 $(ui.helper).removeClass("slick-header-column-active");
116 var hasDroppedColumn = $headerDraggableGroupBy.find(".slick-dropped-grouping").length;
117 if(hasDroppedColumn > 0){
118 $headerDraggableGroupBy.find(".slick-placeholder").hide();
119 $headerDraggableGroupBy.find(".slick-dropped-grouping").show();
120 }
121 },
122 stop: function(e) {
123 if (!grid.getEditorLock().commitCurrentEdit()) {
124 $(this).sortable("cancel");
125 return;
126 }
127 var reorderedIds = $headers.sortable("toArray");
128 // If frozen columns are used, headers has more than one entry and we need the ids from all of them.
129 // though there is only really a left and right header, this will work even if that should change.
130 if($headers.length > 1) {
131 for(var headerI=1,l=$headers.length; headerI < l; headerI+=1) {
132 var $header = $($headers[headerI]);
133 var ids = $header.sortable("toArray");
134 // Note: the loop below could be simplified with:
135 // reorderedIds.push.apply(reorderedIds,ids);
136 // However, the loop is more in keeping with way-backward compatibility
137 for(var idI=0,idL=ids.length; idI< idL; idI+=1) {
138 reorderedIds.push(ids[idI]);
139 }
140 }
141 }
142 var reorderedColumns = [];
143 for (var i = 0; i < reorderedIds.length; i++) {
144 reorderedColumns.push(columns[getColumnIndex(reorderedIds[i].replace(uid, ""))]);
145 }
146 setColumns(reorderedColumns);
147 trigger(grid.onColumnsReordered, {
148 grid: grid
149 });
150 e.stopPropagation();
151 setupColumnResize();
152 }
153 });
154 }
155
156 /**
157 * Destroy plugin.
158 */
159 function destroy() {
160 onGroupChanged.unsubscribe();
161 _handler.unsubscribeAll();
162 }
163
164
165 function setColumns(col) {
166 _gridColumns = col;
167 }
168
169 var emptyDropbox;
170
171 function setupColumnDropbox() {
172 dropbox.droppable({
173 activeClass: "ui-state-default",
174 hoverClass: "ui-state-hover",
175 accept: ":not(.ui-sortable-helper)",
176 deactivate: function(event, ui) {
177 dropbox.removeClass("slick-header-column-denied");
178 },
179 drop: function(event, ui) {
180 handleGroupByDrop(this, ui.draggable);
181 },
182 over: function(event, ui) {
183 var id = (ui.draggable).attr('id').replace(_gridUid, "");
184 _gridColumns.forEach(function(e, i, a) {
185 if (e.id == id) {
186 if (e.grouping == null) {
187 dropbox.addClass("slick-header-column-denied");
188 }
189 }
190 });
191 }
192 });
193 dropbox.sortable({
194 items: "div.slick-dropped-grouping",
195 cursor: "default",
196 tolerance: "pointer",
197 helper: "clone",
198 update: function(event, ui) {
199 var sortArray = $(this).sortable('toArray', {
200 attribute: 'data-id'
201 }),
202 newGroupingOrder = [];
203 for (var i = 0, l = sortArray.length; i < l; i++) {
204 for (var a = 0, b = columnsGroupBy.length; a < b; a++) {
205 if (columnsGroupBy[a].id == sortArray[i]) {
206 newGroupingOrder.push(columnsGroupBy[a]);
207 break;
208 }
209 }
210 }
211 columnsGroupBy = newGroupingOrder;
212 updateGroupBy("sort-group");
213 }
214 });
215 emptyDropbox = dropbox.html();
216
217 groupToggler.on('click', function(e) {
218 if (this.classList.contains('collapsed')) {
219 this.classList.remove('collapsed');
220 this.classList.add('expanded');
221 _dataView.expandAllGroups();
222 } else {
223 this.classList.add('collapsed');
224 this.classList.remove('expanded');
225 _dataView.collapseAllGroups();
226 }
227 });
228 }
229
230 var columnsGroupBy = [];
231 var groupBySorters = [];
232
233 function handleGroupByDrop(container, column) {
234 var columnid = column.attr('id').replace(_gridUid, "");
235 var columnAllowed = true;
236 columnsGroupBy.forEach(function(e, i, a) {
237 if (e.id == columnid) {
238 columnAllowed = false;
239 }
240 });
241 if (columnAllowed) {
242 _gridColumns.forEach(function(e, i, a) {
243 if (e.id == columnid) {
244 if (e.grouping != null && !$.isEmptyObject(e.grouping)) {
245 var entry = $("<div id='" + _gridUid + e.id + "_entry' data-id='" + e.id + "' class='slick-dropped-grouping'>");
246 var columnName = column.children('.slick-column-name').first();
247 var groupText = $("<div style='display: inline-flex'>" + (columnName.length ? columnName.text() : column.text()) + "</div>");
248 groupText.appendTo(entry);
249 var groupRemoveIcon = $("<div class='slick-groupby-remove'>&nbsp;</div>");
250 if(options.deleteIconCssClass) groupRemoveIcon.addClass(options.deleteIconCssClass);
251 if(options.deleteIconImage) groupRemoveIcon.css("background", "url(" + options.deleteIconImage + ") no-repeat center right");
252 if(!options.deleteIconCssClass && !options.deleteIconImage) groupRemoveIcon.addClass('slick-groupby-remove-image');
253 groupRemoveIcon.appendTo(entry);
254
255 $("</div>").appendTo(entry);
256 entry.appendTo(container);
257 addColumnGroupBy(e, column, container, entry);
258 addGroupByRemoveClickHandler(e.id, container, column, entry);
259 }
260 }
261 });
262 groupToggler.css('display', 'block');
263 }
264 }
265
266 function addColumnGroupBy(column) {
267 columnsGroupBy.push(column);
268 updateGroupBy("add-group");
269 }
270
271 function addGroupByRemoveClickHandler(id, container, column, entry) {
272 var text = entry;
273 $("#" + _gridUid + id + "_entry >.slick-groupby-remove").on('click', function() {
274 $(this).off('click');
275 removeGroupBy(id, column, text);
276 });
277 }
278
279 function setDroppedGroups(groupingInfo) {
280 var groupingInfos = (groupingInfo instanceof Array) ? groupingInfo : [groupingInfo];
281 dropboxPlaceholder.hide();
282 for (var i = 0; i < groupingInfos.length; i++) {
283 var column = $(_grid.getHeaderColumn(groupingInfos[i]));
284 handleGroupByDrop(dropbox, column);
285 }
286 }
287 function clearDroppedGroups() {
288 columnsGroupBy = [];
289 updateGroupBy("clear-all");
290 dropbox.find(".slick-dropped-grouping").remove();
291 groupToggler.css("display", "none");
292 dropboxPlaceholder.show();
293 }
294
295 function removeFromArray(arr) {
296 var what, a = arguments,
297 L = a.length,
298 ax;
299 while (L > 1 && arr.length) {
300 what = a[--L];
301 while ((ax = arr.indexOf(what)) != -1) {
302 arr.splice(ax, 1);
303 }
304 }
305 return arr;
306 }
307
308 function removeGroupBy(id, column, entry) {
309 entry.remove();
310 var groupby = [];
311 _gridColumns.forEach(function(e, i, a) {
312 groupby[e.id] = e;
313 });
314 removeFromArray(columnsGroupBy, groupby[id]);
315 if(columnsGroupBy.length === 0){
316 dropboxPlaceholder.show();
317 }
318 updateGroupBy("remove-group");
319 }
320
321 function updateGroupBy(originator) {
322 if (columnsGroupBy.length === 0) {
323 _dataView.setGrouping([]);
324 onGroupChanged.notify({ caller: originator, groupColumns: [] });
325 return;
326 }
327 var groupingArray = [];
328 columnsGroupBy.forEach(function(element, index, array) {
329 groupingArray.push(element.grouping);
330 });
331 _dataView.setGrouping(groupingArray);
332 /*
333 collapseAllGroups();
334 */
335 onGroupChanged.notify({ caller: originator, groupColumns: groupingArray});
336 }
337
338 // Public API
339 $.extend(this, {
340 "init": init,
341 "destroy": destroy,
342 "pluginName": "DraggableGrouping",
343
344 "onGroupChanged": onGroupChanged,
345 "setDroppedGroups": setDroppedGroups,
346 "clearDroppedGroups": clearDroppedGroups,
347 "getSetupColumnReorder": setupColumnReorder,
348 });
349 }
350})(jQuery);