@refinitiv-ui/efx-grid 6.0.24 → 6.0.26

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. package/lib/core/dist/core.css +1 -1
  2. package/lib/core/dist/core.js +1331 -145
  3. package/lib/core/dist/core.min.js +1 -1
  4. package/lib/core/es6/grid/Core.d.ts +11 -0
  5. package/lib/core/es6/grid/Core.js +81 -10
  6. package/lib/core/es6/grid/util/ElementFrameWork.js +1 -1
  7. package/lib/core/es6/tr-grid-theme.js +1 -1
  8. package/lib/grid/index.js +1 -1
  9. package/lib/rt-grid/dist/rt-grid.js +768 -53
  10. package/lib/rt-grid/dist/rt-grid.min.js +1 -1
  11. package/lib/rt-grid/es6/ColumnDefinition.js +1 -1
  12. package/lib/rt-grid/es6/FieldDefinition.d.ts +2 -0
  13. package/lib/rt-grid/es6/FieldDefinition.js +13 -2
  14. package/lib/rt-grid/es6/Grid.d.ts +3 -1
  15. package/lib/rt-grid/es6/Grid.js +83 -39
  16. package/lib/rt-grid/es6/RowDefinition.d.ts +14 -1
  17. package/lib/rt-grid/es6/RowDefinition.js +54 -2
  18. package/lib/tr-grid-column-grouping/es6/ColumnGrouping.d.ts +3 -2
  19. package/lib/tr-grid-column-grouping/es6/ColumnGrouping.js +314 -566
  20. package/lib/tr-grid-column-selection/es6/ColumnSelection.d.ts +13 -11
  21. package/lib/tr-grid-column-selection/es6/ColumnSelection.js +233 -81
  22. package/lib/tr-grid-column-stack/es6/ColumnStack.d.ts +3 -3
  23. package/lib/tr-grid-column-stack/es6/ColumnStack.js +50 -56
  24. package/lib/tr-grid-in-cell-editing/es6/InCellEditing.js +21 -9
  25. package/lib/tr-grid-range-bar/es6/RangeBar.d.ts +18 -9
  26. package/lib/tr-grid-range-bar/es6/RangeBar.js +318 -139
  27. package/lib/tr-grid-util/es6/GridPlugin.d.ts +1 -1
  28. package/lib/tr-grid-util/es6/GridPlugin.js +13 -15
  29. package/lib/tr-grid-util/es6/GroupDefinitions.d.ts +58 -0
  30. package/lib/tr-grid-util/es6/GroupDefinitions.js +538 -0
  31. package/lib/tr-grid-util/es6/Popup.js +1 -1
  32. package/lib/tr-grid-util/es6/index.d.ts +2 -0
  33. package/lib/tr-grid-util/es6/index.js +3 -0
  34. package/lib/types/es6/ColumnGrouping.d.ts +3 -2
  35. package/lib/types/es6/ColumnSelection.d.ts +13 -11
  36. package/lib/types/es6/ColumnStack.d.ts +3 -3
  37. package/lib/types/es6/Core/grid/Core.d.ts +11 -0
  38. package/lib/types/es6/RealtimeGrid/FieldDefinition.d.ts +2 -0
  39. package/lib/types/es6/RealtimeGrid/Grid.d.ts +3 -1
  40. package/lib/types/es6/RealtimeGrid/RowDefinition.d.ts +14 -1
  41. package/lib/types/es6/index.d.ts +1 -1
  42. package/lib/versions.json +6 -6
  43. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { Ext } from "../../tr-grid-util/es6/Ext.js";
2
2
  import { cloneObject } from "../../tr-grid-util/es6/Util.js";
3
3
  import { GridPlugin } from "../../tr-grid-util/es6/GridPlugin.js";
4
+ import { GroupDefinitions } from "../../tr-grid-util/es6/GroupDefinitions.js";
4
5
  import { injectCss, prettifyCss } from "../../tr-grid-util/es6/Util.js";
5
6
 
6
7
  /** @typedef {Array<ColumnGroupingPlugin~GroupDefinition>} ColumnGroupingPlugin~Options
@@ -16,7 +17,7 @@ import { injectCss, prettifyCss } from "../../tr-grid-util/es6/Util.js";
16
17
  * @property {string} id Group id
17
18
  * @property {string} name Display group name
18
19
  * @property {(boolean|string)=} tooltip=true Show tooltip in column's header
19
- * @property {Array<string>} children Child member in this group
20
+ * @property {Array.<string>} children Child member in this group
20
21
  * @property {string=} alignment eg. left, center, right
21
22
  * @property {Function=} render render function handler
22
23
  */
@@ -35,9 +36,7 @@ var ColumnGroupingPlugin = function ColumnGroupingPlugin(options) {
35
36
  t._requestApplyAddChildGroup = t._requestApplyAddChildGroup.bind(this);
36
37
  t._onPostSectionRender = t._onPostSectionRender.bind(t);
37
38
  t._onBeforeColumnBoundUpdate = t._onBeforeColumnBoundUpdate.bind(t);
38
- t._groupDefs = [];
39
- t._groupMap = {};
40
- t._childToParent = {};
39
+ t._groupDefs = new GroupDefinitions();
41
40
  if (options) {
42
41
  t.config({
43
42
  "columnGrouping": options
@@ -46,21 +45,11 @@ var ColumnGroupingPlugin = function ColumnGroupingPlugin(options) {
46
45
  };
47
46
  Ext.inherits(ColumnGroupingPlugin, GridPlugin);
48
47
 
49
- /** @type {!ColumnGroupingPlugin~GroupDefinitions}
50
- * @description An array of group definition objects
51
- * @private
52
- */
53
- ColumnGroupingPlugin.prototype._groupDefs;
54
- /** @type {!Object.<string, ColumnGroupingPlugin~GroupDefinition>}
48
+ /** @type {!GroupDefinitions}
55
49
  * @description A map of group id to group defintion
56
50
  * @private
57
51
  */
58
- ColumnGroupingPlugin.prototype._groupMap;
59
- /** @type {!Object.<string, string>}
60
- * @description A map of child id to parent id
61
- * @private
62
- */
63
- ColumnGroupingPlugin.prototype._childToParent;
52
+ ColumnGroupingPlugin.prototype._groupDefs;
64
53
  /** @type {!Object.<string, ColumnGroupingPlugin~GroupDefinition>}
65
54
  * @description A map of visible group id to group defintion
66
55
  * @private
@@ -86,10 +75,14 @@ ColumnGroupingPlugin.prototype._rerenderTimerId = 0;
86
75
  * @private
87
76
  */
88
77
  ColumnGroupingPlugin.prototype._addingTimerId = 0;
89
- /** @type {Array<Object>}
78
+ /** @type {Array}
90
79
  * @private
91
80
  */
92
81
  ColumnGroupingPlugin.prototype._addingEvents = null;
82
+ /** @type {Object}
83
+ * @private
84
+ */
85
+ ColumnGroupingPlugin.prototype._legacyColumnGroups = null;
93
86
 
94
87
  /** @private
95
88
  * @param {number} a
@@ -122,7 +115,7 @@ ColumnGroupingPlugin._getTooltip = function (groupingOptions) {
122
115
  * @param {Object} groupDef
123
116
  * @return {boolean}
124
117
  */
125
- ColumnGroupingPlugin._isValidGroup = function (groupDef) {
118
+ ColumnGroupingPlugin._hasGroupId = function (groupDef) {
126
119
  if (groupDef) {
127
120
  if (groupDef.id) {
128
121
  return true;
@@ -130,6 +123,7 @@ ColumnGroupingPlugin._isValidGroup = function (groupDef) {
130
123
  }
131
124
  return false;
132
125
  };
126
+
133
127
  /** @private
134
128
  * @function
135
129
  * @param {Array|Object} obj
@@ -169,6 +163,43 @@ ColumnGroupingPlugin._cloneObject = function (obj) {
169
163
  }
170
164
  return newObj;
171
165
  };
166
+ /** Flatten tree structure to simple dictionary
167
+ * @private
168
+ * @function
169
+ * @param {ColumnGroupingPlugin~GroupDefinitions} groupDefs
170
+ */
171
+ ColumnGroupingPlugin._flattenGroupDefs = function (groupDefs) {
172
+ var grpCount = groupDefs ? groupDefs.length : 0;
173
+ for (var i = 0; i < grpCount; i++) {
174
+ ColumnGroupingPlugin._recursivelyFlatten(groupDefs[i], groupDefs);
175
+ }
176
+ };
177
+ /** Flatten group definition structure by using group ID instead of nested group definitions.
178
+ * @private
179
+ * @function
180
+ * @param {Object} groupDef
181
+ * @param {Array} groupDefs
182
+ */
183
+ ColumnGroupingPlugin._recursivelyFlatten = function (groupDef, groupDefs) {
184
+ if (groupDef && groupDef.children) {
185
+ var children = groupDef.children;
186
+ var member, groupId;
187
+ for (var i = 0; i < children.length; i++) {
188
+ member = children[i];
189
+ if (typeof member !== "string") {
190
+ // member is nested group definition
191
+ groupId = member.id;
192
+ if (groupId) {
193
+ children[i] = groupId; // Use group ID instead of nested group definition
194
+ if (groupDefs.indexOf(member) < 0) {
195
+ groupDefs.push(member);
196
+ }
197
+ ColumnGroupingPlugin._recursivelyFlatten(member, groupDefs);
198
+ }
199
+ } // TODO: Invalid group is not flatten
200
+ }
201
+ }
202
+ };
172
203
 
173
204
  /** @public
174
205
  * @return {string}
@@ -193,6 +224,9 @@ ColumnGroupingPlugin.prototype.initialize = function (host, options) {
193
224
  return;
194
225
  }
195
226
  this._hosts.push(host);
227
+ if (typeof host.setColumnGrouping === "function") {
228
+ host.setColumnGrouping(this._groupDefs);
229
+ }
196
230
  if (!this._addingEvents) {
197
231
  this._addingEvents = [];
198
232
  }
@@ -217,7 +251,6 @@ ColumnGroupingPlugin.prototype.initialize = function (host, options) {
217
251
  host._columnGroupingStyles = true;
218
252
  injectCss(ColumnGroupingPlugin._styles, host.getElement());
219
253
  }
220
- // TODO: wrong render group in hide/show column
221
254
  };
222
255
  /** Prevent built-in config
223
256
  * @public
@@ -249,6 +282,9 @@ ColumnGroupingPlugin.prototype.unload = function (host) {
249
282
  return;
250
283
  }
251
284
  this._hosts.splice(at, 1);
285
+ if (typeof host.setColumnGrouping === "function") {
286
+ host.setColumnGrouping(null);
287
+ }
252
288
  host.unlisten("columnAdded", this._onColumnChanged);
253
289
  host.unlisten("columnMoved", this._onColumnMoved);
254
290
  host.unlisten("columnRemoved", this._onColumnRemoved);
@@ -275,22 +311,28 @@ ColumnGroupingPlugin.prototype.config = function (options) {
275
311
  return;
276
312
  }
277
313
  var extOptions = options["columnGrouping"];
314
+ var groupDefs = null;
278
315
  if (Array.isArray(extOptions)) {
279
- var groupDefs = extOptions.filter(ColumnGroupingPlugin._isValidGroup);
280
- this._groupDefs = groupDefs.map(ColumnGroupingPlugin._cloneObject);
316
+ groupDefs = extOptions.filter(ColumnGroupingPlugin._hasGroupId);
317
+ groupDefs = groupDefs.map(ColumnGroupingPlugin._cloneObject);
281
318
  }
282
319
  var columns = options["columns"];
283
- if (!columns) {
284
- return;
320
+ if (columns) {
321
+ var len = columns.length;
322
+ for (var i = 0; i < len; ++i) {
323
+ var colData = this._newColumnData(i);
324
+ colData["columnGrouping"] = {
325
+ // used for columnRemoved event
326
+ id: columns[i].id // TODO: This does not work with runtime change
327
+ };
328
+ }
329
+
330
+ groupDefs = this._migrateLegacyStructure(groupDefs, options["columns"]);
285
331
  }
286
- var len = columns.length;
287
- for (var i = 0; i < len; ++i) {
288
- this._setColumnGrouping(i, {
289
- id: columns[i].id
290
- }); // used for columnRemoved event
332
+ if (groupDefs) {
333
+ ColumnGroupingPlugin._flattenGroupDefs(groupDefs);
334
+ this._groupDefs.setGroups(groupDefs);
291
335
  }
292
-
293
- this._migrateLegacyStructure(options["columns"]);
294
336
  };
295
337
  /** @public
296
338
  * @param {Object=} gridOptions
@@ -308,15 +350,6 @@ ColumnGroupingPlugin.prototype.getConfigObject = function (gridOptions) {
308
350
  };
309
351
 
310
352
  /** @private
311
- * @param {number} colIndex
312
- * @param {Object} data
313
- */
314
- ColumnGroupingPlugin.prototype._setColumnGrouping = function (colIndex, data) {
315
- var colData = this._newColumnData(colIndex);
316
- colData["columnGrouping"] = data;
317
- };
318
- /** Legacy group structure from composite grid will be converted to the new structure
319
- * @private
320
353
  * @param {Object.<string, Array>} objMap
321
354
  * @param {string} parentId
322
355
  * @param {string} childId
@@ -335,13 +368,19 @@ ColumnGroupingPlugin._mapParentToChildren = function (objMap, parentId, childId)
335
368
  };
336
369
  /** Legacy group structure from composite grid will be converted to the new structure
337
370
  * @private
338
- * @param {Array.<Object>} colModels
371
+ * @param {ColumnGroupingPlugin~GroupDefinitions} groupDefs
372
+ * @param {Array} colModels
373
+ * @return {ColumnGroupingPlugin~GroupDefinitions}
339
374
  */
340
- ColumnGroupingPlugin.prototype._migrateLegacyStructure = function (colModels) {
375
+ ColumnGroupingPlugin.prototype._migrateLegacyStructure = function (groupDefs, colModels) {
341
376
  var legacyColumnGroups = this._legacyColumnGroups;
342
377
  if (!legacyColumnGroups || !this._compositeGrid) {
343
- return;
378
+ return groupDefs;
344
379
  }
380
+ if (!groupDefs) {
381
+ groupDefs = [];
382
+ }
383
+
345
384
  // Collecting parent groups from col models (leaf node)
346
385
  var colCount = colModels.length;
347
386
  var groupMap = {}; // Parent-children pair map
@@ -373,10 +412,10 @@ ColumnGroupingPlugin.prototype._migrateLegacyStructure = function (colModels) {
373
412
  groupDef["legacyRender"] = groupDef["formatter"]["render"];
374
413
  delete groupDef["formatter"];
375
414
  }
376
- this._groupDefs.push(groupDef);
415
+ groupDefs.push(groupDef);
377
416
  }
378
417
  }
379
- this._groupDefs = this._groupDefs.filter(ColumnGroupingPlugin._isValidGroup);
418
+ return groupDefs.filter(ColumnGroupingPlugin._hasGroupId);
380
419
  };
381
420
 
382
421
  /** Consolidate and process configuration. Force rerendering on column adding, removing, moving, initializaing, and run-time API execution.
@@ -425,83 +464,27 @@ ColumnGroupingPlugin.prototype._applyGrouping = function () {
425
464
  }
426
465
  }
427
466
  };
467
+
428
468
  /** @private
429
469
  */
430
470
  ColumnGroupingPlugin.prototype._evaluateGroupStructure = function () {
431
- // Clear existing group structure
432
- var groupMap = this._groupMap = {}; // TODO: This is bad
433
- var childToParent = this._childToParent = {}; // TODO: This is bad
434
- var visibleGroupMap = this._visibleGroupMap = {};
435
- this._maxDepth = -1;
436
-
437
- // Flatten tree structure to simple dictionary
438
- var groupDefs = this._groupDefs;
439
- var len = groupDefs.length;
440
- var i;
441
- for (i = 0; i < len; i++) {
442
- this._flattenGroupDefs(groupDefs[i], groupDefs);
443
- }
444
-
445
- // Create group map
446
- var groupDef;
447
- len = groupDefs.length; // length can be changed after flattening
448
- for (i = 0; i < len; i++) {
449
- groupDef = groupDefs[i];
450
- groupMap[groupDef.id] = groupDef;
451
-
452
- // Clone group definitions for rendering
453
- visibleGroupMap[groupDef.id] = ColumnGroupingPlugin._cloneObject(groupDef);
454
- visibleGroupMap[groupDef.id].children = groupDef.children.slice();
455
- }
456
-
457
- // Create child to parent map
458
- var gid, children, member;
459
- for (gid in groupMap) {
460
- children = this._getAvaliableChildren(gid);
461
- if (children.length > 1) {
462
- for (i = 0; i < children.length; i++) {
463
- member = children[i];
464
- childToParent[member] = gid;
465
- }
466
- }
467
- }
468
-
469
- // Apply a parent id to group definition to make it easier to find depth
470
- var parentId;
471
- for (gid in visibleGroupMap) {
472
- parentId = childToParent[gid];
471
+ // Clone group definitions for rendering
472
+ var visibleGroupMap = this._visibleGroupMap = this._groupDefs.cloneGroupMap();
473
+ this._verifySingleChild(visibleGroupMap);
474
+
475
+ // Update depth (onRow) and parentId
476
+ var maxDepth = this._maxDepth = -1;
477
+ for (var groupId in visibleGroupMap) {
478
+ var groupDef = visibleGroupMap[groupId];
479
+ var parentId = groupDef.parentId;
473
480
  if (parentId) {
474
- visibleGroupMap[gid].parent = parentId;
475
- groupMap[gid].parent = parentId;
476
- }
477
- }
478
-
479
- // Filter out groups that are invisible
480
- var rootGroup = [];
481
- for (gid in visibleGroupMap) {
482
- groupDef = visibleGroupMap[gid];
483
- if (this._findGroupTreeDepth(groupDef, 1) === 1) {
484
- rootGroup.push(groupDef);
481
+ if (!visibleGroupMap[parentId]) {
482
+ groupDef.parentId = ""; // Parent has been removed from visible view
483
+ }
485
484
  }
486
- }
487
- len = rootGroup.length;
488
- for (i = 0; i < len; i++) {
489
- this._verifySingleChild(rootGroup[i]);
490
- }
491
485
 
492
- // Determine the depth of each group
493
- var depth;
494
- for (gid in visibleGroupMap) {
495
- groupDef = visibleGroupMap[gid];
496
- depth = this._findGroupTreeDepth(groupDef, 1);
497
- groupDef["onRow"] = depth - 1;
498
- }
499
-
500
- // Calculate the maximum depth
501
- var maxDepth = -1;
502
- for (gid in visibleGroupMap) {
503
- groupDef = visibleGroupMap[gid];
504
- depth = groupDef["onRow"];
486
+ var depth = GroupDefinitions.calcTreeDepth(visibleGroupMap, groupDef);
487
+ groupDef["onRow"] = depth;
505
488
  if (depth > maxDepth) {
506
489
  maxDepth = depth;
507
490
  }
@@ -509,88 +492,59 @@ ColumnGroupingPlugin.prototype._evaluateGroupStructure = function () {
509
492
  this._maxDepth = maxDepth + 1; // Column header depth = maximum group depth + 1
510
493
  };
511
494
 
512
- /** Flatten group definition structure by using group ID instead of nested group definitions.
513
- * @private
514
- * @param {Object} groupDef
515
- * @param {Array} groupDefs
495
+ /** @private
496
+ * @param {Object} groupMap
516
497
  */
517
- ColumnGroupingPlugin.prototype._flattenGroupDefs = function (groupDef, groupDefs) {
518
- if (groupDef && groupDef.children) {
519
- var children = groupDef.children;
520
- var member, groupId;
521
- for (var i = 0; i < children.length; i++) {
522
- member = children[i];
523
- if (typeof member !== "string") {
524
- // member is nested group definition
525
- groupId = member.id;
526
- if (groupId) {
527
- children[i] = groupId; // Use group ID instead of nested group definition
528
- if (groupDefs.indexOf(member) < 0) {
529
- groupDefs.push(member);
530
- }
531
- this._flattenGroupDefs(member, groupDefs);
532
- }
533
- } // TODO: Invalid group is not flatten
498
+ ColumnGroupingPlugin.prototype._verifySingleChild = function (groupMap) {
499
+ var api = this.getGridApi();
500
+ if (!api) {
501
+ return;
502
+ }
503
+ var core = this._hosts[0];
504
+ var colCount = this.getColumnCount();
505
+ var validIds = {};
506
+ var i, j;
507
+ // initialize a map for all valid and hidden ids of groups and columns
508
+ for (i = 0; i < colCount; i++) {
509
+ var colId = this.getColumnId(i);
510
+ if (colId) {
511
+ if (core.isColumnVisible(i)) {
512
+ validIds[colId] = 1;
513
+ }
534
514
  }
535
515
  }
536
- };
537
-
538
- /** @private
539
- * @param {Object} groupDef
540
- * @param {number} currentDepth
541
- * @return {number}
542
- */
543
- ColumnGroupingPlugin.prototype._findGroupTreeDepth = function (groupDef, currentDepth) {
544
- var parentId = groupDef["parent"];
545
- var parentNode = this._visibleGroupMap[parentId];
546
- if (parentNode) {
547
- return this._findGroupTreeDepth(parentNode, currentDepth + 1);
548
- } else {
549
- return currentDepth;
516
+ var groupIds = Object.keys(groupMap);
517
+ var groupCount = groupIds.length;
518
+ for (i = 0; i < groupCount; i++) {
519
+ validIds[groupIds[i]] = 1;
550
520
  }
551
- };
552
-
553
- /** @private
554
- * @param {Object} groupDef
555
- * @return {boolean}
556
- */
557
- ColumnGroupingPlugin.prototype._verifySingleChild = function (groupDef) {
558
- var children = groupDef.children;
559
- var visibleChildCount = 0;
560
- var visibleChildGroupCount = 0;
561
- var invisibleMembers = [];
562
- var i, member;
563
- for (i = 0; i < children.length; i++) {
564
- member = children[i];
565
- if (this._visibleGroupMap[member]) {
566
- if (this._verifySingleChild(this._visibleGroupMap[member])) {
567
- ++visibleChildCount;
568
- ++visibleChildGroupCount;
569
- } else {
570
- invisibleMembers.push(member);
521
+ var removable = true;
522
+ while (removable) {
523
+ removable = false;
524
+ for (i = 0; i < groupCount; i++) {
525
+ var groupId = groupIds[i];
526
+ var group = groupMap[groupId];
527
+ if (!group) {
528
+ continue;
571
529
  }
572
- } else {
573
- if (this._getColumnIndexById(member) > -1) {
574
- ++visibleChildCount;
530
+ var children = group["children"];
531
+ var childCount = children.length;
532
+ var validChildren = [];
533
+ for (j = 0; j < childCount; j++) {
534
+ var child = children[j];
535
+ if (validIds[child]) {
536
+ validChildren.push(child);
537
+ }
538
+ }
539
+ if (validChildren.length < 2) {
540
+ delete groupMap[groupId];
541
+ validIds[groupId] = 0;
542
+ removable = true;
575
543
  } else {
576
- invisibleMembers.push(member);
544
+ group.children = validChildren;
577
545
  }
578
546
  }
579
547
  }
580
-
581
- // Remove invisible members, keep only visible members
582
- if (invisibleMembers.length) {
583
- for (i = 0; i < invisibleMembers.length; i++) {
584
- member = invisibleMembers[i];
585
- groupDef.children.splice(children.indexOf(member), 1);
586
- }
587
- }
588
- if (visibleChildCount > 1 || visibleChildGroupCount > 1) {
589
- return true;
590
- } else {
591
- delete this._visibleGroupMap[groupDef.id];
592
- return false;
593
- }
594
548
  };
595
549
 
596
550
  /** Set a timer to call applyGrouping only once to avoid performance issue
@@ -609,35 +563,52 @@ ColumnGroupingPlugin.prototype._applyNearestGrouping = function (colIndex) {
609
563
  if (colIndex == null || colIndex < 0) {
610
564
  return;
611
565
  }
566
+ var colId = this.getColumnId(colIndex);
612
567
  var colIndexLeft = colIndex - 1;
613
568
  var colIndexRight = colIndex + 1;
614
569
  var groupLeftIds = this.getGroupIds(colIndexLeft);
615
570
  var groupRightIds = this.getGroupIds(colIndexRight);
616
- if (groupLeftIds && groupRightIds) {
617
- var colId = this.getColumnId(colIndex);
618
- var groupId = this._childToParent[colId];
619
- if (groupId) {
620
- if (groupLeftIds.indexOf(groupId) > -1 || groupRightIds.indexOf(groupId) > -1) {
571
+ var groupLeftCount = groupLeftIds ? groupLeftIds.length : 0;
572
+ var groupRightCount = groupRightIds ? groupRightIds.length : 0;
573
+ var parentId = this._groupDefs.getParentId(colId);
574
+ if (parentId) {
575
+ var chdr = this._groupDefs.getGroupChildren(parentId);
576
+ var childCount = chdr ? chdr.length : 0;
577
+ if (childCount <= 1) {
578
+ // If current column is only child in the group
579
+ return; // there is no need to put column into another group because its parent group will be moved along
580
+ }
581
+
582
+ // If current column has a group and stays close to its siblings, it stay in the same group
583
+ if (groupLeftCount) {
584
+ if (groupLeftIds[0] === parentId) {
621
585
  return;
622
586
  }
623
587
  }
624
- var i, j, groupLeftId, groupRightId;
625
- var found = false;
626
- for (i = 0; i < groupLeftIds.length; i++) {
627
- groupLeftId = groupLeftIds[i];
628
- for (j = 0; j < groupRightIds.length; j++) {
629
- groupRightId = groupRightIds[j];
630
- if (groupLeftId === groupRightId) {
631
- // found same Id between group
632
-
633
- // This method modifies the group definition and outdates the group structure.
634
- // It is necessary to recalculate group structure manually.
635
- this._addGroupChild(colId, groupRightId);
636
- found = true;
588
+ if (groupRightCount) {
589
+ if (groupRightIds[0] === parentId) {
590
+ return;
591
+ }
592
+ }
593
+ // The current column is no longer close to its parent
594
+ if (this._groupDefs.removeGroupChild(colId)) {
595
+ chdr = this._groupDefs.getGroupChildren(parentId);
596
+ childCount = chdr ? chdr.length : 0;
597
+ if (childCount === 1) {
598
+ // If there is only one child left, move the remaning child to its parent
599
+ var grandParentId = this._groupDefs.getParentId(parentId);
600
+ if (grandParentId) {
601
+ this._groupDefs.addGroupChild(grandParentId, chdr[0]);
637
602
  }
638
603
  }
639
- if (found) {
640
- this._evaluateGroupStructure();
604
+ }
605
+ }
606
+ if (groupLeftCount && groupRightCount) {
607
+ for (var i = 0; i < groupLeftCount; i++) {
608
+ var groupLeftId = groupLeftIds[i];
609
+ var sharedParentIdx = groupRightIds.indexOf(groupLeftId);
610
+ if (sharedParentIdx >= 0) {
611
+ this._groupDefs.addGroupChild(groupRightIds[sharedParentIdx], colId);
641
612
  break;
642
613
  }
643
614
  }
@@ -657,7 +628,7 @@ ColumnGroupingPlugin.prototype._spanGroupVertically = function (titleSection) {
657
628
  var colCount = api.getColumnCount();
658
629
  for (var col = 0; col < colCount; col++) {
659
630
  var toSpan = rowCount;
660
- var parentNode = this._getParentGroup(this.getColumnId(col));
631
+ var parentNode = this._getVisibleParentGroup(this.getColumnId(col));
661
632
  if (parentNode) {
662
633
  var depth = parentNode["onRow"] + 1;
663
634
  toSpan = rowCount - depth;
@@ -681,7 +652,7 @@ ColumnGroupingPlugin.prototype._spanGroupHorizontally = function (titleSection)
681
652
  for (var id in visibleGroupMap) {
682
653
  spanIndices = [];
683
654
  groupDef = visibleGroupMap[id];
684
- colIds = this._getGroupMembers(visibleGroupMap, groupDef);
655
+ colIds = GroupDefinitions.getLeafDescendants(visibleGroupMap, id);
685
656
  for (i = 0; i < colIds.length; i++) {
686
657
  index = this._getColumnIndexById(colIds[i]);
687
658
  if (index > -1) {
@@ -755,9 +726,13 @@ ColumnGroupingPlugin.prototype._onPostSectionRender = function (e) {
755
726
  * @param {Object} e dispatching of columnAdded event object
756
727
  */
757
728
  ColumnGroupingPlugin.prototype._requestApplyAddChildGroup = function (e) {
758
- this._addingEvents.push(e);
759
- if (!this._addingTimerId) {
760
- this._addingTimerId = setTimeout(this._applyTimeSeries.bind(this, e), 10);
729
+ var ctx = e.context;
730
+ var tsParentDef = ctx ? ctx.parent : null;
731
+ if (tsParentDef) {
732
+ this._addingEvents.push(e);
733
+ if (!this._addingTimerId) {
734
+ this._addingTimerId = setTimeout(this._applyTimeSeries.bind(this, e), 10);
735
+ }
761
736
  }
762
737
  };
763
738
 
@@ -766,61 +741,40 @@ ColumnGroupingPlugin.prototype._requestApplyAddChildGroup = function (e) {
766
741
  */
767
742
  ColumnGroupingPlugin.prototype._applyTimeSeries = function (e) {
768
743
  this._addingTimerId = 0; // clear timer
769
- var addingEvents = this._addingEvents.map(function (eventObj) {
770
- return eventObj;
771
- });
772
- this._addingEvents.length = 0; // clear conflation value
773
-
774
- var colIndex = e.colIndex;
775
- var i;
744
+ var addingEvents = this._addingEvents;
745
+ this._addingEvents = [];
776
746
  if (addingEvents.length > 0) {
777
- var addingEvent;
778
747
  var children = [];
779
- var firstChildColumn;
780
- for (i = 0; i < addingEvents.length; i++) {
781
- addingEvent = addingEvents[i];
782
- if (addingEvent.context.parent) {
783
- if (!firstChildColumn) {
784
- firstChildColumn = addingEvent.context;
785
- }
748
+ var tsParentDef;
749
+ for (var i = 0; i < addingEvents.length; i++) {
750
+ var addingEvent = addingEvents[i];
751
+ tsParentDef = addingEvent.context.parent;
752
+ if (tsParentDef) {
786
753
  var childIndex = addingEvent.colIndex; // Assume time series column ordered
787
754
  var childId = this.getColumnId(childIndex);
788
755
  children.push(childId);
789
756
  }
790
757
  }
791
- if (firstChildColumn && firstChildColumn.parent) {
792
- var tsParentDef = firstChildColumn.parent;
793
- if (tsParentDef) {
794
- var parentName = tsParentDef.getName();
795
- var parentId = tsParentDef.getId();
796
- var groupId = "timeSerieGroup_" + parentId;
797
- var groupDef = this._groupMap[groupId];
798
- if (groupDef) {
799
- // add children time series field to parent
800
- var dirty = false;
801
- var child;
802
- for (i = 0; i < children.length; i++) {
803
- child = children[i];
804
-
805
- // This method modifies the group definition and outdates the group structure.
806
- // It is necessary to recalculate group structure manually.
807
- dirty |= this._addGroupChild(child, groupId);
808
- }
809
- if (dirty) {
810
- this._evaluateGroupStructure();
811
- }
812
- } else {
813
- // create new group
814
- this.addGroup({
815
- id: groupId,
816
- title: parentName,
817
- children: children
818
- });
758
+ if (tsParentDef) {
759
+ var parentName = tsParentDef.getName();
760
+ var parentId = tsParentDef.getId();
761
+ var groupId = "timeSerieGroup_" + parentId;
762
+ var groupDef = this._groupDefs.getGroup(groupId);
763
+ if (groupDef) {
764
+ // add children time series field to parent
765
+ for (i = 0; i < children.length; i++) {
766
+ this._groupDefs.addGroupChild(groupId, children[i]);
819
767
  }
768
+ } else {
769
+ // create new group
770
+ this.addGroup({
771
+ id: groupId,
772
+ title: parentName,
773
+ children: children
774
+ });
820
775
  }
821
776
  }
822
777
  }
823
- this._applyNearestGrouping(colIndex);
824
778
  this._requestApplyGrouping();
825
779
  };
826
780
 
@@ -843,25 +797,7 @@ ColumnGroupingPlugin.prototype._onColumnChanged = function () {
843
797
  */
844
798
  ColumnGroupingPlugin.prototype._onColumnMoved = function (e) {
845
799
  if (this._autoGrouping) {
846
- var toColIndex = e.toColIndex;
847
- var colId = this.getColumnId(toColIndex);
848
- var groupId = this._childToParent[colId];
849
- if (groupId) {
850
- var colIdLeft = this.getColumnId(toColIndex - 1);
851
- var colIdRight = this.getColumnId(toColIndex + 1);
852
- var groupIdLeft = this._childToParent[colIdLeft];
853
- var groupIdRight = this._childToParent[colIdRight];
854
- if (groupId != groupIdLeft && groupId != groupIdRight) {
855
- // Remove column from previous group
856
- var children = this.getGroupChildren(groupId);
857
- var removeIndex = children.indexOf(colId);
858
- if (removeIndex > -1) {
859
- children.splice(removeIndex, 1);
860
- }
861
- this.setGroupChildren(groupId, children);
862
- }
863
- }
864
- this._applyNearestGrouping(toColIndex);
800
+ this._applyNearestGrouping(e.toColIndex);
865
801
  }
866
802
  this._requestApplyGrouping();
867
803
  };
@@ -872,8 +808,7 @@ ColumnGroupingPlugin.prototype._onColumnRemoved = function (e) {
872
808
  var colData = e.columnData;
873
809
  if (colData && colData.columnGrouping) {
874
810
  var colId = colData.columnGrouping.id;
875
- var groupId = this._childToParent[colId];
876
- if (groupId) {
811
+ if (this._groupDefs.removeGroupChild(colId)) {
877
812
  this._requestApplyGrouping();
878
813
  }
879
814
  }
@@ -883,7 +818,6 @@ ColumnGroupingPlugin.prototype._onColumnRemoved = function (e) {
883
818
  */
884
819
  ColumnGroupingPlugin.prototype._onBeforeColumnBoundUpdate = function (e) {
885
820
  var selectedColumns = e.selectedColumns; // Hidden columns are included
886
- var parentMap = this._childToParent;
887
821
 
888
822
  // Find non-grouped column
889
823
  var i, colId, nonGroupedColId, groupId;
@@ -892,12 +826,12 @@ ColumnGroupingPlugin.prototype._onBeforeColumnBoundUpdate = function (e) {
892
826
  for (i = 0; i < selectedColumns.length; i++) {
893
827
  colId = this.getColumnId(selectedColumns[i]);
894
828
  if (colId) {
895
- groupId = parentMap[colId];
829
+ groupId = this._groupDefs.getParentId(colId);
896
830
  if (!groupId) {
897
831
  nonGroupedColId = colId;
898
832
  break;
899
833
  } else {
900
- groupMap[groupId] = this._groupMap[groupId]; // Cache group node for further calculation
834
+ groupMap[groupId] = this._groupDefs.getGroup(groupId); // Cache group node for further calculation
901
835
  }
902
836
 
903
837
  colIds.push(colId); // Cache column id for further calculation
@@ -914,7 +848,7 @@ ColumnGroupingPlugin.prototype._onBeforeColumnBoundUpdate = function (e) {
914
848
  var rootGroupMap = {};
915
849
  var headerRowIndex, group;
916
850
  for (groupId in groupMap) {
917
- group = this._getRootGroup(groupId);
851
+ group = this._groupDefs.getRootGroup(groupId);
918
852
  rootGroupMap[group.id] = group;
919
853
  headerRowIndex = groupMap[groupId].onRow + 1;
920
854
  if (headerRowIndex < topBoundRowIndex) {
@@ -931,7 +865,7 @@ ColumnGroupingPlugin.prototype._onBeforeColumnBoundUpdate = function (e) {
931
865
  for (groupId in findingGroup) {
932
866
  group = findingGroup[groupId];
933
867
  allSelected = true;
934
- members = this._getGroupMembers(this._groupMap, group);
868
+ members = this._groupDefs.getLeafDescendants(groupId);
935
869
  if (members.length <= colIds.length) {
936
870
  for (n = 0; n < members.length; n++) {
937
871
  if (colIds.indexOf(members[n]) < 0) {
@@ -949,7 +883,7 @@ ColumnGroupingPlugin.prototype._onBeforeColumnBoundUpdate = function (e) {
949
883
  children = group.children;
950
884
  for (n = 0; n < children.length; n++) {
951
885
  var id = children[n];
952
- group = this._groupMap[id];
886
+ group = this._groupDefs.getGroup(id);
953
887
  if (group) {
954
888
  nextLevelGroups[id] = group;
955
889
  }
@@ -966,82 +900,40 @@ ColumnGroupingPlugin.prototype._onBeforeColumnBoundUpdate = function (e) {
966
900
  * @param {number} colIndex Column index
967
901
  */
968
902
  ColumnGroupingPlugin.prototype.addColumnToGroup = function (column, groupId, colIndex) {
969
- if (!column || !groupId) return;
970
- var columnIndex = colIndex || this.getColumnCount();
903
+ if (!column) return;
904
+ var columnIndex = -1;
905
+ if (colIndex == null) {
906
+ var groupDef = this._groupDefs.getGroup(groupId);
907
+ if (groupDef) {
908
+ var childIndices = this.getChildColumnIndices(groupId);
909
+ if (childIndices && childIndices.length) {
910
+ // Child indices need to be sorted here
911
+ columnIndex = childIndices[childIndices.length - 1] + 1; // Put new column next to the last child in the group
912
+ }
971
913
 
972
- // This method modifies the group definition and outdates the group structure.
973
- // It is necessary to recalculate group structure manually.
974
- if (this._addGroupChild(column.id, groupId)) {
975
- this._evaluateGroupStructure(); // To prevent event handler from using outdated group structure
914
+ this._groupDefs.addGroupChild(groupId, column.id);
915
+ }
916
+ } else {
917
+ columnIndex = colIndex;
918
+ }
919
+ if (columnIndex < 0) {
920
+ columnIndex = this.getColumnCount();
976
921
  }
977
-
978
922
  if (this._realTimeGrid) {
923
+ // TODO: Support multi-table feature
979
924
  this._realTimeGrid.insertColumn(column, columnIndex);
980
925
  } else if (this._compositeGrid) {
981
926
  this._compositeGrid.insertColumn(columnIndex, column);
982
927
  }
983
928
  };
984
929
 
985
- /** Remove each child from another group
986
- * @private
987
- * @param {Array.<string>} children
988
- */
989
- ColumnGroupingPlugin.prototype._ungroupChildren = function (children) {
990
- if (Array.isArray(children)) {
991
- var len = children.length;
992
- for (var i = 0; i < len; ++i) {
993
- this._unsetParent(children[i]);
994
- }
995
- }
996
- };
997
- /** Unset parent of the specified id
998
- * @private
999
- * @param {string} childId
1000
- */
1001
- ColumnGroupingPlugin.prototype._unsetParent = function (childId) {
1002
- var parentId = this._childToParent[childId];
1003
- if (parentId) {
1004
- this._childToParent[childId] = "";
1005
- var grpDef = this._groupMap[parentId];
1006
- if (grpDef) {
1007
- var chdr = grpDef.children;
1008
- if (chdr.length) {
1009
- var at = chdr.indexOf(childId);
1010
- if (at >= 0) {
1011
- chdr.splice(at, 1); // splice is slow
1012
- }
1013
- }
1014
- }
1015
- }
1016
- };
1017
- /** Remove all children from the specified group
1018
- * @private
1019
- * @param {string} grpId
1020
- */
1021
- ColumnGroupingPlugin.prototype._removeAllChildren = function (grpId) {
1022
- var grpDef = this._groupMap[grpId];
1023
- if (grpDef) {
1024
- var chdr = grpDef.children;
1025
- var len = chdr.length;
1026
- if (len) {
1027
- grpDef.children = [];
1028
- for (var i = 0; i < len; ++i) {
1029
- var childId = chdr[i];
1030
- if (this._childToParent[childId]) {
1031
- this._childToParent[childId] = "";
1032
- }
1033
- }
1034
- }
1035
- }
1036
- };
1037
-
1038
930
  /** Add new group definition to existing group structure. Existing group with the same id will be replaced.
1039
931
  * @public
1040
932
  * @param {ColumnGroupingPlugin~GroupDefinition} groupDef Group definition object
1041
933
  * @return {string} Return group ID
1042
934
  */
1043
935
  ColumnGroupingPlugin.prototype.addGroup = function (groupDef) {
1044
- if (ColumnGroupingPlugin._isValidGroup(groupDef)) {
936
+ if (ColumnGroupingPlugin._hasGroupId(groupDef)) {
1045
937
  return this.setGroupDefinition(groupDef.id, groupDef);
1046
938
  }
1047
939
  return "";
@@ -1056,16 +948,14 @@ ColumnGroupingPlugin.prototype.addGroup = function (groupDef) {
1056
948
  ColumnGroupingPlugin.prototype.addColumnGrouping = ColumnGroupingPlugin.prototype.addGroup;
1057
949
  /** @public
1058
950
  * @param {string} groupId
1059
- * @return {ColumnGroupingPlugin~GroupDefinition} Return removed group definition object.
951
+ * @return {boolean}
1060
952
  */
1061
953
  ColumnGroupingPlugin.prototype.removeGroup = function (groupId) {
1062
- var curDef = this._groupMap[groupId];
1063
- if (curDef) {
1064
- var at = this._groupDefs.indexOf(curDef);
1065
- this._groupDefs.splice(at, 1);
954
+ if (this._groupDefs.removeGroup(groupId)) {
1066
955
  this._applyGrouping();
956
+ return true;
1067
957
  }
1068
- return curDef;
958
+ return false;
1069
959
  };
1070
960
 
1071
961
  /** @public
@@ -1073,15 +963,11 @@ ColumnGroupingPlugin.prototype.removeGroup = function (groupId) {
1073
963
  * @return {ColumnGroupingPlugin~GroupDefinition}
1074
964
  */
1075
965
  ColumnGroupingPlugin.prototype.getGroupDefinition = function (groupId) {
1076
- if (groupId) {
1077
- // Check for group validility
1078
- var groupDef = this._groupMap[groupId];
1079
- if (!groupDef) {
1080
- return null;
1081
- }
966
+ var chdr = this._getAvaliableChildren(groupId);
967
+ if (chdr.length > 1) {
968
+ var groupDef = this._groupDefs.getGroup(groupId);
1082
969
  groupDef = ColumnGroupingPlugin._cloneObject(groupDef); // TODO: this is slow
1083
- var children = this._getAvaliableChildren(groupId);
1084
- groupDef.children = children;
970
+ groupDef.children = chdr;
1085
971
  return groupDef;
1086
972
  }
1087
973
  return null;
@@ -1092,11 +978,11 @@ ColumnGroupingPlugin.prototype.getGroupDefinition = function (groupId) {
1092
978
  */
1093
979
  ColumnGroupingPlugin.prototype.getGroupDefinitions = function () {
1094
980
  var validGroupDefs = [];
1095
- var len = this._groupDefs.length;
1096
- var groupDef;
1097
- for (var i = 0; i < len; i++) {
1098
- groupDef = this.getGroupDefinition(this._groupDefs[i].id);
1099
- if (groupDef && groupDef.children.length > 1) {
981
+ var groupMap = this._groupDefs.getGroupMap();
982
+ for (var grpId in groupMap) {
983
+ var groupDef = this.getGroupDefinition(grpId); // Clone
984
+ if (groupDef) {
985
+ delete groupDef.parentId;
1100
986
  validGroupDefs.push(groupDef);
1101
987
  }
1102
988
  }
@@ -1106,40 +992,28 @@ ColumnGroupingPlugin.prototype.getGroupDefinitions = function () {
1106
992
  * @public
1107
993
  * @param {string} groupId
1108
994
  * @param {ColumnGroupingPlugin~GroupDefinition=} groupDef
1109
- * @return {string} Group Id
995
+ * @return {string} Return group Id. Return empty string if nothing has been changed.
1110
996
  */
1111
997
  ColumnGroupingPlugin.prototype.setGroupDefinition = function (groupId, groupDef) {
1112
- if (!groupId) {
1113
- return "";
1114
- }
1115
- if (groupDef) {
1116
- var newDef = ColumnGroupingPlugin._toGroupDefinition(groupDef, groupId);
1117
- this._ungroupChildren(newDef.children);
1118
- var curDef = this._groupMap[groupId];
1119
- if (curDef) {
1120
- // Replace
1121
- var at = this._groupDefs.indexOf(curDef);
1122
- this._groupDefs[at] = newDef;
1123
- } else {
1124
- // Add
1125
- this._groupDefs.push(newDef);
1126
- }
1127
- var chdr = newDef.children;
1128
- var len = chdr.length;
1129
- // TODO: Filter out group id
1130
- if (len > 1) {
1131
- var gridApi = this.getGridApi();
1132
- if (gridApi && gridApi.reorderColumns) {
1133
- gridApi.reorderColumns(chdr, chdr[0]); // WARNING: group id doesn't work
998
+ if (this._groupDefs.setGroup(groupId, groupDef)) {
999
+ var newDef = this._groupDefs.getGroup(groupId);
1000
+ if (newDef) {
1001
+ var chdr = newDef.children;
1002
+ var len = chdr.length;
1003
+ // TODO: Filter out group id
1004
+ if (len > 1) {
1005
+ var gridApi = this.getGridApi();
1006
+ if (gridApi && gridApi.reorderColumns) {
1007
+ // TODO: Support multi-table feature
1008
+ gridApi.reorderColumns(chdr, chdr[0]); // WARNING: group id doesn't work
1009
+ }
1134
1010
  }
1135
1011
  }
1136
1012
 
1137
1013
  this._applyGrouping();
1138
- } else {
1139
- // Remove
1140
- this.removeGroup(groupId);
1014
+ return groupId;
1141
1015
  }
1142
- return groupId;
1016
+ return "";
1143
1017
  };
1144
1018
  /** Remove all existing group definitions and replace with the given definitions.
1145
1019
  * @public
@@ -1147,55 +1021,41 @@ ColumnGroupingPlugin.prototype.setGroupDefinition = function (groupId, groupDef)
1147
1021
  */
1148
1022
  ColumnGroupingPlugin.prototype.setGroupDefinitions = function (groupDefs) {
1149
1023
  if (Array.isArray(groupDefs)) {
1150
- groupDefs = groupDefs.filter(ColumnGroupingPlugin._isValidGroup);
1024
+ groupDefs = groupDefs.filter(ColumnGroupingPlugin._hasGroupId);
1151
1025
  groupDefs = groupDefs.map(ColumnGroupingPlugin._cloneObject);
1152
- if (!groupDefs.length) {
1153
- groupDefs = null;
1154
- }
1155
1026
  } else {
1156
1027
  groupDefs = null;
1157
1028
  }
1158
- if (groupDefs) {
1159
- this._groupDefs = groupDefs;
1160
- this._applyGrouping();
1161
- } else {
1162
- this._groupDefs = [];
1163
- this._applyGrouping();
1164
- }
1029
+ ColumnGroupingPlugin._flattenGroupDefs(groupDefs);
1030
+ this._groupDefs.setGroups(groupDefs);
1031
+ this._applyGrouping();
1165
1032
  };
1166
1033
  /** Replace and update existing group definition.
1167
1034
  * @public
1168
1035
  * @param {string} groupId
1169
1036
  * @param {Array.<string>} newChildList If null is given, all existing children in the group will be removed
1037
+ * @return {boolean}
1170
1038
  */
1171
1039
  ColumnGroupingPlugin.prototype.setGroupChildren = function (groupId, newChildList) {
1172
- var groupDef = this._groupMap[groupId];
1173
- if (groupDef) {
1174
- if (Array.isArray(newChildList)) {
1175
- groupDef.aaa = 0; // TODO: for testing, need to be removed
1176
- this._ungroupChildren(newChildList);
1177
- groupDef.children = newChildList.slice();
1178
- this._applyGrouping();
1179
- } else if (!newChildList && groupDef.children.length) {
1180
- groupDef.children = [];
1181
- this._applyGrouping();
1182
- }
1040
+ if (this._groupDefs.setGroupChildren(groupId, newChildList)) {
1041
+ this._applyGrouping();
1042
+ return true;
1183
1043
  }
1044
+ return false;
1184
1045
  };
1185
1046
  /** @private
1186
1047
  * @param {string} groupId
1187
- * @return {!Array.<string>}
1048
+ * @return {!Array.<string>} The list of immediate valid child, including invisible child groups
1188
1049
  */
1189
1050
  ColumnGroupingPlugin.prototype._getAvaliableChildren = function (groupId) {
1190
- var groupDef = this._groupMap[groupId];
1051
+ var chdr = this._groupDefs.getGroupChildren(groupId);
1052
+ var childCount = chdr ? chdr.length : 0;
1191
1053
  var validChildren = [];
1192
- if (groupDef) {
1054
+ if (childCount) {
1055
+ var groupMap = this._groupDefs.getGroupMap();
1193
1056
  // Filter out columns that do not exist
1194
- var groupMap = this._groupMap;
1195
- var children = groupDef.children;
1196
- var childId;
1197
- for (var i = 0; i < children.length; i++) {
1198
- childId = children[i];
1057
+ for (var i = 0; i < childCount; i++) {
1058
+ var childId = chdr[i];
1199
1059
  if (groupMap[childId] || this.getColumnIndex(childId) > -1) {
1200
1060
  validChildren.push(childId); // TODO: This is slow
1201
1061
  }
@@ -1223,9 +1083,8 @@ ColumnGroupingPlugin.prototype.getGroupChildren = function (groupId) {
1223
1083
  * @return {Array.<number>}
1224
1084
  */
1225
1085
  ColumnGroupingPlugin.prototype.getChildColumnIndices = function (groupId) {
1226
- var group = this._groupMap[groupId];
1227
- if (group) {
1228
- var colIds = this._getGroupMembers(this._groupMap, group);
1086
+ var colIds = this._groupDefs.getLeafDescendants(groupId);
1087
+ if (colIds) {
1229
1088
  var colIndices = [];
1230
1089
  var index;
1231
1090
  for (var i = 0; i < colIds.length; i++) {
@@ -1234,8 +1093,9 @@ ColumnGroupingPlugin.prototype.getChildColumnIndices = function (groupId) {
1234
1093
  colIndices.push(index);
1235
1094
  }
1236
1095
  }
1237
- return colIndices.sort(ColumnGroupingPlugin._ascSortLogic);
1096
+ return colIndices.sort(ColumnGroupingPlugin._ascSortLogic); // TODO: This could be unnecessary
1238
1097
  }
1098
+
1239
1099
  return null;
1240
1100
  };
1241
1101
 
@@ -1244,27 +1104,11 @@ ColumnGroupingPlugin.prototype.getChildColumnIndices = function (groupId) {
1244
1104
  * @return {Array.<string>}
1245
1105
  */
1246
1106
  ColumnGroupingPlugin.prototype.getGroupIds = function (colRef) {
1247
- if (colRef != null) {
1248
- var colId = colRef;
1249
- if (typeof colRef === "number") {
1250
- colId = this.getColumnId(colRef);
1251
- }
1252
- if (colId) {
1253
- var groupId = this._childToParent[colId];
1254
- if (groupId) {
1255
- var groupIds = [groupId];
1256
- var group = this._groupMap[groupId];
1257
- while (group && group.parent) {
1258
- group = this._groupMap[group.parent];
1259
- if (group) {
1260
- groupIds.push(group.id);
1261
- }
1262
- }
1263
- return groupIds;
1264
- }
1265
- }
1107
+ if (colRef == null) {
1108
+ return null;
1266
1109
  }
1267
- return null;
1110
+ var colId = typeof colRef === "number" ? this.getColumnId(colRef) : colRef;
1111
+ return this._groupDefs.getParentIds(colId);
1268
1112
  };
1269
1113
 
1270
1114
  /** Return deepest row index of column headers
@@ -1288,52 +1132,6 @@ ColumnGroupingPlugin.prototype.getGroupLevel = function (groupId) {
1288
1132
  return -1;
1289
1133
  };
1290
1134
 
1291
- /** @private
1292
- * @param {Object.<string, ColumnGroupingPlugin~GroupDefinition>} groupMap
1293
- * @param {ColumnGroupingPlugin~GroupDefinition} group Group definition
1294
- * @param {Array.<string>=} members
1295
- * @return {Array.<string>}
1296
- */
1297
- ColumnGroupingPlugin.prototype._getGroupMembers = function (groupMap, group, members) {
1298
- if (!members) {
1299
- members = [];
1300
- }
1301
- var children = this._getAvaliableChildren(group.id);
1302
- if (children.length < 2) {
1303
- return members;
1304
- }
1305
- var g, id;
1306
- for (var i = 0; i < children.length; i++) {
1307
- id = children[i];
1308
- if (id === group.id) {
1309
- // prevent from infinite loop
1310
- continue;
1311
- }
1312
- g = groupMap[id];
1313
- if (g) {
1314
- this._getGroupMembers(groupMap, g, members);
1315
- } else {
1316
- members.push(id);
1317
- }
1318
- }
1319
- return members;
1320
- };
1321
-
1322
- /** @private
1323
- * @param {String} groupId
1324
- * @return {ColumnGroupingPlugin~GroupDefinition}
1325
- */
1326
- ColumnGroupingPlugin.prototype._getRootGroup = function (groupId) {
1327
- if (!groupId) {
1328
- return null;
1329
- }
1330
- var group = this._groupMap[groupId];
1331
- while (group.parent) {
1332
- group = this._groupMap[group.parent];
1333
- }
1334
- return group;
1335
- };
1336
-
1337
1135
  /** This version exclude invisible column unlike the one in GridPlugin
1338
1136
  * @private
1339
1137
  * @param {string} id
@@ -1352,49 +1150,12 @@ ColumnGroupingPlugin.prototype._getColumnIndexById = function (id) {
1352
1150
  }
1353
1151
  return -1;
1354
1152
  };
1355
- /** This method modifies the group definition and outdates the group structure. It is necessary to recalculate group structure manually.
1356
- * @private
1357
- * @param {string} childId
1358
- * @param {string} groupId
1359
- * @return {boolean}
1360
- */
1361
- ColumnGroupingPlugin.prototype._addGroupChild = function (childId, groupId) {
1362
- var groupDef = this._groupMap[groupId];
1363
- if (childId && groupDef) {
1364
- var chdr = groupDef.children;
1365
- if (chdr && chdr.indexOf(childId) < 0) {
1366
- chdr.push(childId);
1367
- return true;
1368
- }
1369
- }
1370
- return false;
1371
- };
1372
1153
  /** @private
1373
1154
  * @param {string} childId
1374
1155
  * @return {ColumnGroupingPlugin~GroupDefinition}
1375
1156
  */
1376
- ColumnGroupingPlugin.prototype._getParentGroup = function (childId) {
1377
- return this._visibleGroupMap[this._childToParent[childId]];
1378
- };
1379
- /** @private
1380
- * @param {string} colId
1381
- * @param {number} groupLevel
1382
- * @return {string}
1383
- */
1384
- ColumnGroupingPlugin.prototype._getGroupId = function (colId, groupLevel) {
1385
- var groupId = this._childToParent[colId];
1386
- if (!groupId) {
1387
- return "";
1388
- }
1389
- if (groupLevel == null) {
1390
- return groupId;
1391
- }
1392
- var currentLevel = this.getGroupLevel(groupId);
1393
- while (currentLevel > groupLevel && groupId) {
1394
- groupId = this._childToParent[groupId];
1395
- currentLevel--;
1396
- }
1397
- return groupId || "";
1157
+ ColumnGroupingPlugin.prototype._getVisibleParentGroup = function (childId) {
1158
+ return this._visibleGroupMap[this._groupDefs.getParentId(childId)] || null;
1398
1159
  };
1399
1160
  /** @public
1400
1161
  * @param {Element|Event|MouseEvent} e
@@ -1407,27 +1168,30 @@ ColumnGroupingPlugin.prototype.getCellInfo = function (e) {
1407
1168
  return null;
1408
1169
  }
1409
1170
  var cellInfo = grid.getCellInfo(e);
1410
- if (!cellInfo.cell) {
1171
+ if (!cellInfo) {
1172
+ return e;
1173
+ }
1174
+ if (!cellInfo["cell"]) {
1411
1175
  var cell = cellInfo.section.getCell(cellInfo.colIndex, cellInfo.rowIndex);
1412
1176
  cellInfo["cell"] = cell;
1413
1177
  }
1414
1178
  var colId = this.getColumnId(cellInfo.colIndex);
1415
- var groupId = this._getGroupId(colId, cellInfo.sectionType == "title" ? cellInfo.rowIndex : null);
1179
+ var groupId = this._groupDefs.getParentId(colId, cellInfo.sectionType == "title" ? cellInfo.rowIndex : null);
1416
1180
  if (!groupId) {
1417
1181
  cellInfo["columnId"] = colId;
1418
1182
  return cellInfo;
1419
1183
  }
1420
- var groupInfo = this.getGroupDefinition(groupId);
1184
+ var groupInfo = this._groupDefs.getGroup(groupId); // TODO: Check if we need visible group
1421
1185
  if (groupInfo) {
1422
1186
  var isGroupHeader = cellInfo.sectionType == "title" && cellInfo.rowIndex == this.getGroupLevel(groupId);
1423
1187
  if (isGroupHeader) {
1424
1188
  cellInfo["groupId"] = groupInfo.id;
1425
- cellInfo["groupName"] = groupInfo.name;
1189
+ cellInfo["groupName"] = groupInfo.name || "";
1426
1190
  cellInfo["children"] = groupInfo.children;
1427
1191
  } else {
1428
1192
  cellInfo["columnId"] = colId;
1429
1193
  }
1430
- cellInfo["parent"] = isGroupHeader ? groupInfo.parent || null : groupInfo.id;
1194
+ cellInfo["parent"] = isGroupHeader ? groupInfo.parentId || null : groupInfo.id;
1431
1195
  }
1432
1196
  return cellInfo;
1433
1197
  };
@@ -1441,7 +1205,7 @@ ColumnGroupingPlugin.prototype.moveColumnIntoGroup = function (colRef, to, group
1441
1205
  if (fromIndex == -1) {
1442
1206
  return;
1443
1207
  }
1444
- var groupDef = this._groupMap[groupId];
1208
+ var groupDef = this._groupDefs.getGroup(groupId);
1445
1209
  if (!groupDef) {
1446
1210
  for (var j = this._hosts.length; --j >= 0;) {
1447
1211
  var grid = this._hosts[j];
@@ -1499,23 +1263,8 @@ ColumnGroupingPlugin.prototype.moveColumnIntoGroup = function (colRef, to, group
1499
1263
  host.moveColumn(fromIndex, to);
1500
1264
  }
1501
1265
  if (colId) {
1502
- // TODO:
1503
- // Remove from current group
1504
- var previousGroup = this._childToParent[colId];
1505
- if (previousGroup) {
1506
- var previousGroupChild = this.getGroupChildren(previousGroup);
1507
- var removeIndex = previousGroupChild.indexOf(colId);
1508
- if (removeIndex !== -1) {
1509
- previousGroupChild.splice(previousGroupChild.indexOf(colId), 1);
1510
- }
1511
- this.setGroupChildren(previousGroup, previousGroupChild);
1512
- }
1513
-
1514
- // Add to new group
1515
- var children = this.getGroupChildren(groupId);
1516
- if (children.indexOf(colId) < 0) {
1517
- children.push(colId);
1518
- this.setGroupChildren(groupId, children);
1266
+ if (this._groupDefs.addGroupChild(groupId, colId)) {
1267
+ this._applyGrouping();
1519
1268
  }
1520
1269
  }
1521
1270
  };
@@ -1549,12 +1298,11 @@ ColumnGroupingPlugin.prototype.setColumnParent = function (colRef, groupId) {
1549
1298
  * @returns {number} destination index
1550
1299
  */
1551
1300
  ColumnGroupingPlugin.prototype.getValidDestinationIndex = function (id, destCol) {
1552
- var groupDef, parentGroupDef;
1553
- groupDef = this._groupMap[id];
1554
- if (groupDef) {
1555
- parentGroupDef = this.getGroupDefinition(groupDef["parent"]);
1301
+ var parentGroupDef = null;
1302
+ if (this._groupDefs.getGroup(id)) {
1303
+ parentGroupDef = this._getVisibleParentGroup(id);
1556
1304
  } else if (this.getColumnIndex(id) > -1) {
1557
- parentGroupDef = this._getParentGroup(id);
1305
+ parentGroupDef = this._getVisibleParentGroup(id);
1558
1306
  }
1559
1307
  var startIndex = -1;
1560
1308
  var endIndex = -1;
@@ -1590,10 +1338,10 @@ ColumnGroupingPlugin.prototype.getValidDestinationIndex = function (id, destCol)
1590
1338
  // handle group/column should not insert between group when group/column is not a child of any group
1591
1339
  var destMemberIndices = [];
1592
1340
  var destColId = this.getColumnId(destColIndex);
1593
- var destParent = this._getParentGroup(destColId);
1341
+ var destParent = this._getVisibleParentGroup(destColId);
1594
1342
  if (destParent) {
1595
- if (destParent["parent"]) {
1596
- destParent = this._getRootGroup(destParent["id"]);
1343
+ if (destParent.parentId) {
1344
+ destParent = this._groupDefs.getRootGroup(destParent["id"]);
1597
1345
  }
1598
1346
  destMemberIndices = this.getChildColumnIndices(destParent["id"]);
1599
1347
  }
@@ -1618,7 +1366,7 @@ ColumnGroupingPlugin.prototype.getValidDestinationIndex = function (id, destCol)
1618
1366
  ColumnGroupingPlugin.prototype.moveGroup = function (id, destCol) {
1619
1367
  var groupDef;
1620
1368
  var members = [];
1621
- groupDef = this._groupMap[id];
1369
+ groupDef = this._groupDefs.getGroup(id);
1622
1370
  if (groupDef) {
1623
1371
  var indices = this.getChildColumnIndices(groupDef["id"]);
1624
1372
  for (var i = 0; i < indices.length; i++) {
@@ -1636,11 +1384,11 @@ ColumnGroupingPlugin.prototype.moveGroup = function (id, destCol) {
1636
1384
 
1637
1385
  // TODO: create method for toggling autoGrouping flag
1638
1386
  this._autoGrouping = false;
1639
- if (this._realTimeGrid) {
1640
- this._realTimeGrid.reorderColumns(members, destColId);
1641
- } else if (this._compositeGrid) {
1642
- this._compositeGrid.reorderColumns(members, destColId);
1387
+ var gridApi = this.getGridApi();
1388
+ if (gridApi && gridApi.reorderColumns) {
1389
+ gridApi.reorderColumns(members, destColId); // TODO: Support multi-table feature
1643
1390
  }
1391
+
1644
1392
  this._autoGrouping = true;
1645
1393
  };
1646
1394
  export default ColumnGroupingPlugin;