@refinitiv-ui/efx-grid 6.0.24 → 6.0.26

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 (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;