@refinitiv-ui/efx-grid 6.0.26 → 6.0.27

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.
@@ -12,6 +12,7 @@ import { preventDefault } from "../../tr-grid-util/es6/EventDispatcher.js";
12
12
  * @property {Array.<string>} fields Fields for stacking. The minimum is 2 fields.
13
13
  * @property {Array.<ColumnStackPlugin~StackDefinition>} stacks List of stacking configuration
14
14
  * @property {boolean=} autoStacking=false If enabled, columns will be auto stacked when new inserted column field match in stack
15
+ * @property {Function=} clicked=null Event handler when user clicks on stack/expanding icon
15
16
  */
16
17
 
17
18
  /** @typedef {Object} ColumnStackPlugin~ColumnOptions
@@ -45,6 +46,18 @@ import { preventDefault } from "../../tr-grid-util/es6/EventDispatcher.js";
45
46
  * @property {string=} activeColumn="" Column index or field for set as active column
46
47
  */
47
48
 
49
+ /** @event ColumnStackPlugin#clicked
50
+ * @description Fired when user clicks on stack/expanding icon
51
+ * @type {Object}
52
+ * @property {number} colIndex
53
+ * @property {number} rowIndex
54
+ * @property {Array.<Object>} menuData Data for populating context menu
55
+ * @property {number} activeIndex
56
+ * @property {Array.<number>} columnIndices
57
+ * @property {number} activeColIndex
58
+ * @property {Event} event Native event argument from click event
59
+ */
60
+
48
61
  /** @constructor
49
62
  * @extends {GridPlugin}
50
63
  */
@@ -55,12 +68,12 @@ var ColumnStackPlugin = function () {
55
68
  this._onColumnAdded = this._onColumnAdded.bind(this);
56
69
  this._onStackButtonClicked = this._onStackButtonClicked.bind(this);
57
70
  this._updateUI = this._updateUI.bind(this);
58
- this._setStack = this._setStack.bind(this);
71
+ this._requestStackingByFields = this._requestStackingByFields.bind(this);
59
72
  this._hosts = [];
60
73
  this._stacks = {};
61
74
 
62
75
  this._conflator = new Conflator(100, this._updateUI);
63
- this._stackConflator = new Conflator(100, this._setStack);
76
+ this._stackConflator = new Conflator(100, this._requestStackingByFields);
64
77
  };
65
78
 
66
79
  Ext.inherits(ColumnStackPlugin, GridPlugin);
@@ -73,10 +86,11 @@ ColumnStackPlugin.prototype._stacks;
73
86
  * @private
74
87
  */
75
88
  ColumnStackPlugin.prototype._pendingStacks;
76
- /** @type {Object}
89
+ /** A map from stack id to array of fields
90
+ * @type {Object}
77
91
  * @private
78
92
  */
79
- ColumnStackPlugin.prototype._columnStack = null;
93
+ ColumnStackPlugin.prototype._idToFields = null; // For auto-stacking
80
94
  /** @type {boolean}
81
95
  * @private
82
96
  */
@@ -85,6 +99,10 @@ ColumnStackPlugin.prototype._updating = false;
85
99
  * @private
86
100
  */
87
101
  ColumnStackPlugin.prototype._autoStacking = false;
102
+ /** @type {boolean}
103
+ * @private
104
+ */
105
+ ColumnStackPlugin.prototype._stacking = false;
88
106
 
89
107
 
90
108
  /** @type {number}
@@ -213,79 +231,99 @@ ColumnStackPlugin.prototype.config = function (options) {
213
231
  columns = [];
214
232
  }
215
233
 
216
- var i, len = columns.length;
217
- for(i = 0; i < len; ++i) {
218
- this._setColumnStacking(i, {}); // used for further column index getting
234
+ var i;
235
+ var colCount = columns.length;
236
+ for(i = 0; i < colCount; ++i) {
237
+ this._setUniqueRef(i, {}); // used for further column index getting
219
238
  }
220
239
 
221
- var sid, stacks = {};
222
240
  var columnStack = options.columnStack;
223
- if(columnStack != null) {
241
+ var stackId = "";
242
+ var stacks = {};
243
+ var hasStack = false;
244
+ var stackConfig = null;
245
+ if(columnStack) {
246
+ this.addListener(columnStack, "clicked");
247
+
224
248
  if(columnStack.autoStacking != null) {
225
249
  this._autoStacking = columnStack.autoStacking;
226
250
  }
227
251
 
228
252
  if(columnStack.fields && columnStack.fields.length > 1) {
229
- this._columnStack = columnStack.fields;
230
- sid = this._generateStackId();
231
- stacks[sid] = {
253
+ hasStack = true;
254
+ stackId = this._generateStackId(); // TODO: Stack id may need to be hardcoded
255
+ if(!this._idToFields) {
256
+ this._idToFields = {};
257
+ }
258
+ this._idToFields[stackId] = columnStack.fields;
259
+ stacks[stackId] = {
232
260
  colRefs: columnStack.fields,
233
261
  spreading: columnStack.spreading === true,
234
262
  collapsed: columnStack.collapsed !== false
235
263
  };
236
264
  } else if (columnStack.stacks && columnStack.stacks.length) {
265
+ hasStack = true;
237
266
  var stackLen = columnStack.stacks.length;
238
267
  for(i = 0; i < stackLen; i++){
239
- var stackConfig = columnStack.stacks[i];
240
- sid = stackConfig.id || this._generateStackId();
268
+ stackConfig = columnStack.stacks[i];
269
+ stackId = stackConfig.id || this._generateStackId();
241
270
  if(stackConfig.collapsed == null){
242
271
  stackConfig.collapsed = true;
243
272
  }
244
273
  if(stackConfig.spreading == null){
245
274
  stackConfig.spreading = false;
246
275
  }
247
- stacks[sid] = stackConfig;
276
+ stacks[stackId] = stackConfig;
248
277
  }
249
278
  }
250
- } else {
251
- var column, stackOpt;
252
- for(i = 0; i < len; ++i) {
253
- column = columns[i];
254
- stackOpt = column["stackId"] || column["stack"];
279
+ }
280
+
281
+ if(!hasStack) {
282
+ for(i = 0; i < colCount; ++i) {
283
+ var column = columns[i];
284
+ var stackOpt = column["stackId"] || column["stack"];
285
+ if(!stackOpt) {
286
+ continue;
287
+ }
288
+
289
+ stackId = "";
290
+ var spreading = false;
291
+ var collapsed = true;
255
292
  if(typeof stackOpt === "string") {
256
- if(!stacks[stackOpt]) {
257
- stacks[stackOpt] = {
258
- colRefs: [],
259
- spreading: false
260
- };
261
- }
262
- stacks[stackOpt].colRefs.push(i);
293
+ stackId = stackOpt;
263
294
  } else if(typeof stackOpt === "object") {
264
- if(!stacks[stackOpt["id"]]) {
265
- stacks[stackOpt["id"]] = {
295
+ stackConfig = stackOpt;
296
+ stackId = stackConfig["id"] || "";
297
+ spreading = stackConfig["spreading"] === true; // WARNING: Only the first column in the stack has an effect
298
+ collapsed = stackConfig["collapsed"] !== false;
299
+ }
300
+ if(stackId) {
301
+ if(!stacks[stackId]) {
302
+ stacks[stackId] = {
266
303
  colRefs: [],
267
- spreading: stackOpt["spreading"] === true,
268
- collapsed: stackOpt["collapsed"] !== false
304
+ spreading: spreading, // Default is false (stacking mode)
305
+ collapsed: collapsed // Default is true (columns are hidden)
269
306
  };
307
+ hasStack = true;
270
308
  }
271
- stacks[stackOpt["id"]].colRefs.push(i);
309
+ stacks[stackId].colRefs.push(i);
272
310
  }
273
311
  }
274
312
  }
275
313
 
276
314
  if(this._initializedGrid) {
277
- if(Object.keys(stacks).length){
278
- this.removeAllStacks(false);
315
+ if(hasStack){
316
+ this.removeAllStacks(false); // No UI update
317
+ for(stackId in stacks) {
318
+ var config = stacks[stackId];
319
+ if(!config.colRefs){
320
+ this._transformStackConfig(config);
321
+ }
322
+ this.stackColumns(config.colRefs, stackId, config);
323
+ }
279
324
  } else {
280
325
  this.removeAllStacks();
281
326
  }
282
- for(sid in stacks) {
283
- var config = stacks[sid];
284
- if(!config.colRefs){
285
- this._transformStackConfig(config);
286
- }
287
- this.stackColumns(config.colRefs, sid, config);
288
- }
289
327
  } else {
290
328
  this._pendingStacks = this._pendingStacks || stacks;
291
329
  }
@@ -337,7 +375,7 @@ ColumnStackPlugin.prototype.getConfigObject = function (gridOptions) {
337
375
  }
338
376
 
339
377
  if (this._autoStacking) {
340
- var fields = this._columnStack[stackOption.stackId];
378
+ var fields = this._idToFields[stackOption.stackId];
341
379
  var activeColumnField = this._getField(activeColIndex);
342
380
 
343
381
  stackConfigObj.fields = fields;
@@ -361,6 +399,7 @@ ColumnStackPlugin.prototype.getConfigObject = function (gridOptions) {
361
399
  };
362
400
 
363
401
  /** @override
402
+ * @ignore
364
403
  */
365
404
  ColumnStackPlugin.prototype._afterInit = function () {
366
405
  if(this._pendingStacks) {
@@ -377,50 +416,80 @@ ColumnStackPlugin.prototype._afterInit = function () {
377
416
  // In case of lazy loading
378
417
  // DO something
379
418
  };
380
- /** @private
381
- * @param {object} stackRef
419
+ /** WARNING: This method is slow
420
+ * @private
421
+ * @param {Object} stackRef
422
+ * @param {number=} colCount
382
423
  * @return {number}
383
424
  */
384
- ColumnStackPlugin.prototype._getColumnIndex = function(stackRef) {
385
- var colCount = this.getColumnCount();
386
- var stacking, index = -1;
387
- for(var i = 0; i < colCount; i++) {
388
- stacking = this._getColumnStacking(i);
389
- if(stackRef === stacking) {
390
- index = i;
391
- break;
425
+ ColumnStackPlugin.prototype._getColumnIndex = function(stackRef, colCount) {
426
+ if(stackRef) {
427
+ if(colCount == null) {
428
+ colCount = this.getColumnCount();
429
+ }
430
+ for(var i = 0; i < colCount; i++) {
431
+ if(stackRef === this._getUniqueRef(i)) {
432
+ return i;
433
+ }
434
+ }
435
+ }
436
+ return -1;
437
+ };
438
+ /** WARNING: This method is really slow
439
+ * @private
440
+ * @param {!Array.<Object>} stackRefs
441
+ * @return {!Array.<number>}
442
+ */
443
+ ColumnStackPlugin.prototype._getColumnIndices = function(stackRefs) {
444
+ var refCount = stackRefs ? stackRefs.length : 0;
445
+ var ary = new Array(refCount);
446
+ if(refCount) {
447
+ var colCount = this.getColumnCount();
448
+ for(var i = 0; i < refCount; i++) {
449
+ ary[i] = this._getColumnIndex(stackRefs[i], colCount);
392
450
  }
393
451
  }
394
- return index;
452
+ return ary;
395
453
  };
396
454
  /** @private
397
455
  * @param {number} colIndex
398
- * @param {object} stacking
456
+ * @param {!Object} refObj
399
457
  */
400
- ColumnStackPlugin.prototype._setColumnStacking = function(colIndex, stacking) {
401
- var colData = this._newColumnData(colIndex);
402
- colData["stack"] = stacking;
458
+ ColumnStackPlugin.prototype._setUniqueRef = function(colIndex, refObj) {
459
+ this._newColumnData(colIndex)["stack"] = refObj;
403
460
  };
404
461
  /** @private
405
462
  * @param {number} colIndex
406
- * @return {*}
463
+ * @return {Object}
464
+ */
465
+ ColumnStackPlugin.prototype._getUniqueRef = function(colIndex) {
466
+ return this._getColumnOption(colIndex, "stack") || null;
467
+ };
468
+ /** @private
469
+ * @return {!Array.<Object>}
407
470
  */
408
- ColumnStackPlugin.prototype._getColumnStacking = function(colIndex) {
409
- return this._getColumnOption(colIndex, "stack");
471
+ ColumnStackPlugin.prototype._getUniqueRefs = function() {
472
+ var colCount = this.getColumnCount();
473
+ var ary = new Array(colCount);
474
+ for(var c = 0; c < colCount; ++c) {
475
+ ary[c] = this._getUniqueRef(c);
476
+ }
477
+ return ary;
410
478
  };
479
+
411
480
  /** @private
412
481
  * @param {number} colIndex
413
- * @param {object} stackOptions
482
+ * @param {Object} stackOptions
414
483
  */
415
484
  ColumnStackPlugin.prototype._setColumnStackOptions = function(colIndex, stackOptions) {
416
- var stacking = this._getColumnStacking(colIndex);
417
- if(stacking) {
418
- stacking["stackOpt"] = stackOptions;
485
+ var ref = this._getUniqueRef(colIndex);
486
+ if(ref) {
487
+ ref["stackOpt"] = stackOptions;
419
488
  }
420
489
  };
421
490
  /** @private
422
- * @param {object} stackConfig
423
- * @return {object} stack config object
491
+ * @param {Object} stackConfig
492
+ * @return {Object} stack config object
424
493
  */
425
494
  ColumnStackPlugin.prototype._transformStackConfig = function(stackConfig) {
426
495
  stackConfig.colRefs = [];
@@ -458,9 +527,9 @@ ColumnStackPlugin.prototype._transformStackConfig = function(stackConfig) {
458
527
  * @return {*}
459
528
  */
460
529
  ColumnStackPlugin.prototype._getColumnStackOptions = function(colIndex) {
461
- var stacking = this._getColumnStacking(colIndex);
462
- if(stacking){
463
- return stacking["stackOpt"] || null;
530
+ var refObj = this._getUniqueRef(colIndex);
531
+ if(refObj){
532
+ return refObj["stackOpt"] || null;
464
533
  }
465
534
  return null;
466
535
  };
@@ -468,9 +537,9 @@ ColumnStackPlugin.prototype._getColumnStackOptions = function(colIndex) {
468
537
  * @param {number} colIndex
469
538
  */
470
539
  ColumnStackPlugin.prototype._removeColumnStackOptions = function(colIndex) {
471
- var stacking = this._getColumnStacking(colIndex);
472
- if(stacking) {
473
- stacking["stackOpt"] = null;
540
+ var refObj = this._getUniqueRef(colIndex);
541
+ if(refObj) {
542
+ refObj["stackOpt"] = null;
474
543
  }
475
544
  };
476
545
  /** @private
@@ -492,28 +561,12 @@ ColumnStackPlugin.prototype._setColumnVisibility = function(colIndex, shown) {
492
561
  }
493
562
  };
494
563
  /** @private
495
- * @param {number} colIndex
496
- * @param {number} destIndex
497
- */
498
- ColumnStackPlugin.prototype._moveColumn = function(colIndex, destIndex) {
499
- if(colIndex >= 0 && destIndex >= 0 && colIndex !== destIndex) {
500
- for(var i = this._hosts.length; --i >= 0;) {
501
- this._hosts[i].moveColumn(colIndex, destIndex);
502
- }
503
- }
504
- };
505
- /** @private
506
- * @param {Array.<object>} stackRefs
564
+ * @param {Array.<Object>} stackRefs
507
565
  */
508
566
  ColumnStackPlugin.prototype._moveStackedColumns = function (stackRefs) {
509
- var len = stackRefs.length;
510
- for(var i = 1; i < len; ++i) {
511
- var fromIndex = this._getColumnIndex(stackRefs[i]);
512
- var destIndex = this._getColumnIndex(stackRefs[0]); // Active Column may be shifted due to the move
513
- if(fromIndex < destIndex){
514
- destIndex -= 1;
515
- }
516
- this._moveColumn(fromIndex, destIndex + i);
567
+ var ary = this._getColumnIndices(stackRefs);
568
+ if(ary.length > 1) {
569
+ this.reorderColumns(ary, ary[0]);
517
570
  }
518
571
  };
519
572
  /** @private
@@ -709,13 +762,7 @@ ColumnStackPlugin.prototype.getMemberIndices = function(colIndex) {
709
762
  return null;
710
763
  }
711
764
 
712
- var stackRefs = colData.stackRefs;
713
- var len = stackRefs.length;
714
- var indices = [];
715
- for(var i = 0; i < len; ++i) {
716
- indices.push(this._getColumnIndex(stackRefs[i]));
717
- }
718
- return indices;
765
+ return this._getColumnIndices(colData.stackRefs);
719
766
  };
720
767
  /** @public
721
768
  * @param {number} colIndex
@@ -943,9 +990,10 @@ ColumnStackPlugin.prototype.stackColumns = function(colRefs, stackId, options) {
943
990
 
944
991
  // Save stack fields for
945
992
  if(this._autoStacking){
946
- var columnStack = this._columnStack || {};
947
- columnStack[sid] = fields;
948
- this._columnStack = columnStack;
993
+ if(!this._idToFields) {
994
+ this._idToFields = {};
995
+ }
996
+ this._idToFields[sid] = fields;
949
997
  }
950
998
 
951
999
  var len = colRefs.length;
@@ -977,7 +1025,7 @@ ColumnStackPlugin.prototype.stackColumns = function(colRefs, stackId, options) {
977
1025
  for(i = 0; i < len; ++i) {
978
1026
  colIndex = colRefs[i];
979
1027
  this._setColumnStackOptions(colIndex, stack);
980
- stack.stackRefs[i] = this._getColumnStacking(colIndex);
1028
+ stack.stackRefs[i] = this._getUniqueRef(colIndex);
981
1029
 
982
1030
  if(colIndex == activeIndex){
983
1031
  stack.activeColumn = stack.stackRefs[i];
@@ -1085,8 +1133,8 @@ ColumnStackPlugin.prototype.unstackColumns = function(colIndices) {
1085
1133
  this._setColumnVisibility(colIndex, true);
1086
1134
  }
1087
1135
 
1088
- if(this._autoStacking) {
1089
- delete this._columnStack[sid];
1136
+ if(this._idToFields) {
1137
+ delete this._idToFields[sid]; // TODO: Clear the map whenever it no longer has a member
1090
1138
  }
1091
1139
  delete this._stacks[sid]; // Remove all reference to the stack
1092
1140
  }
@@ -1104,23 +1152,21 @@ ColumnStackPlugin.prototype.unstackColumns = function(colIndices) {
1104
1152
 
1105
1153
  return dirty;
1106
1154
  };
1107
- /** @public
1108
- * @param {boolean=} enableUpdateUI set false if you want to remove without update UI
1109
- * @return {boolean} true if at least one stacking removed
1155
+ /** @private
1156
+ * @param {string} stackId
1157
+ * @return {boolean} Returns true if there is any change
1110
1158
  */
1111
- ColumnStackPlugin.prototype.removeAllStacks = function(enableUpdateUI) {
1112
- var disableUpdateUI = enableUpdateUI === false;
1113
- var dirty = false;
1114
- for(var sid in this._stacks) {
1115
- var stack = this._stacks[sid];
1116
- dirty = true;
1117
-
1118
- var stackRefs = stack.stackRefs;
1159
+ ColumnStackPlugin.prototype._removeStack = function(stackId) {
1160
+ var stack = this._stacks[stackId];
1161
+ if(!stack) {
1162
+ return false;
1163
+ }
1119
1164
 
1120
- var len = stackRefs.length;
1121
- for(var i = 0; i < len; ++i) {
1122
- var stackRef = stackRefs[i];
1123
- var colIndex = this._getColumnIndex(stackRef);
1165
+ var colIndices = this._getColumnIndices(stack.stackRefs);
1166
+ var len = colIndices.length;
1167
+ for(var i = 0; i < len; ++i) {
1168
+ var colIndex = colIndices[i];
1169
+ if(colIndex >= 0) {
1124
1170
  if(stack.collapsed && stack.spreading) {
1125
1171
  this.collapseGroup(colIndex, false);
1126
1172
  }
@@ -1128,10 +1174,38 @@ ColumnStackPlugin.prototype.removeAllStacks = function(enableUpdateUI) {
1128
1174
  this._setColumnVisibility(colIndex, true);
1129
1175
  }
1130
1176
  }
1177
+ return true;
1178
+ };
1179
+ /** @public
1180
+ * @param {string} stackId
1181
+ * @return {boolean} Returns true if there is any change
1182
+ */
1183
+ ColumnStackPlugin.prototype.removeStack = function(stackId) {
1184
+ if(this._idToFields) {
1185
+ if(this._idToFields[stackId]) {
1186
+ delete this._idToFields[stackId];
1187
+ }
1188
+ }
1189
+ if(this._removeStack(stackId)) {
1190
+ this._updateUI();
1191
+ return true;
1192
+ }
1193
+ return false;
1194
+ };
1195
+ /** @public
1196
+ * @param {boolean=} enableUpdateUI=true Set false if you want to remove without update UI
1197
+ * @return {boolean} true if at least one stacking removed
1198
+ */
1199
+ ColumnStackPlugin.prototype.removeAllStacks = function(enableUpdateUI) {
1200
+ var dirty = false;
1201
+ for(var stackId in this._stacks) {
1202
+ dirty = true;
1203
+ this._removeStack(stackId);
1204
+ }
1131
1205
  if(dirty) {
1132
- this._columnStack = {};
1206
+ this._idToFields = null;
1133
1207
  this._stacks = {};
1134
- if(!disableUpdateUI) {
1208
+ if(enableUpdateUI !== false) {
1135
1209
  this._updateUI(); // asyncronous
1136
1210
  }
1137
1211
  }
@@ -1210,15 +1284,15 @@ ColumnStackPlugin.prototype._onColumnRemoved = function (e) {
1210
1284
  var colData = /** @type{Object} */(e.columnData);
1211
1285
  if(!colData) { return; }
1212
1286
 
1213
- var stacking = colData["stack"];
1214
- if(!stacking) { return; }
1287
+ var stackRef = colData["stack"];
1288
+ if(!stackRef) { return; }
1215
1289
 
1216
- var stackOpt = stacking["stackOpt"];
1290
+ var stackOpt = stackRef["stackOpt"];
1217
1291
  if(!stackOpt) { return; }
1218
1292
 
1219
1293
  // update members
1220
1294
  if(stackOpt.stackRefs) {
1221
- var index = stackOpt.stackRefs.indexOf(stacking);
1295
+ var index = stackOpt.stackRefs.indexOf(stackRef);
1222
1296
  if(index > -1) {
1223
1297
  stackOpt.stackRefs.splice(index, 1);
1224
1298
  if(stackOpt.stackRefs.length < 2) {
@@ -1248,6 +1322,10 @@ ColumnStackPlugin.prototype._onColumnRemoved = function (e) {
1248
1322
  * @param {Object} e
1249
1323
  */
1250
1324
  ColumnStackPlugin.prototype._onColumnMoved = function (e) {
1325
+ if(this._stacking) { // during the stacking, there is no need to recalculate stacks
1326
+ return;
1327
+ }
1328
+
1251
1329
  var toIndex = e.toColIndex;
1252
1330
  var stackOpt = this._getColumnStackOptions(toIndex);
1253
1331
 
@@ -1256,7 +1334,7 @@ ColumnStackPlugin.prototype._onColumnMoved = function (e) {
1256
1334
  return;
1257
1335
  }
1258
1336
 
1259
- var stackRef = this._getColumnStacking(toIndex);
1337
+ var stackRef = this._getUniqueRef(toIndex);
1260
1338
 
1261
1339
  var leftStackOpt = this._getColumnStackOptions(toIndex - 1);
1262
1340
  var rightStackOpt = this._getColumnStackOptions(toIndex + 1);
@@ -1265,7 +1343,7 @@ ColumnStackPlugin.prototype._onColumnMoved = function (e) {
1265
1343
  if(stackOpt) {
1266
1344
  if(stackOpt === leftStackOpt) {
1267
1345
  leftStackOpt.stackRefs.splice(leftStackOpt.stackRefs.indexOf(stackRef), 1);
1268
- leftColStackRef = this._getColumnStacking(toIndex - 1);
1346
+ leftColStackRef = this._getUniqueRef(toIndex - 1);
1269
1347
  index = leftStackOpt.stackRefs.indexOf(leftColStackRef);
1270
1348
  if(index > -1) {
1271
1349
  leftStackOpt.stackRefs.splice(index + 1, 0, stackRef);
@@ -1279,7 +1357,7 @@ ColumnStackPlugin.prototype._onColumnMoved = function (e) {
1279
1357
  return;
1280
1358
  } else if(stackOpt === rightStackOpt) {
1281
1359
  rightStackOpt.stackRefs.splice(rightStackOpt.stackRefs.indexOf(stackRef), 1);
1282
- var rightColStackRef = this._getColumnStacking(toIndex + 1);
1360
+ var rightColStackRef = this._getUniqueRef(toIndex + 1);
1283
1361
  index = rightStackOpt.stackRefs.indexOf(rightColStackRef);
1284
1362
  if(index > -1) {
1285
1363
  rightStackOpt.stackRefs.splice(index, 0, stackRef);
@@ -1342,7 +1420,7 @@ ColumnStackPlugin.prototype._onColumnMoved = function (e) {
1342
1420
  rightStackOpt = this._getColumnStackOptions(rIndex);
1343
1421
  if(leftStackOpt && leftStackOpt.spreading &&
1344
1422
  (leftStackOpt === rightStackOpt)) {
1345
- leftColStackRef = this._getColumnStacking(toIndex - 1);
1423
+ leftColStackRef = this._getUniqueRef(toIndex - 1);
1346
1424
  index = leftStackOpt.stackRefs.indexOf(leftColStackRef);
1347
1425
  if(index > -1) {
1348
1426
  leftStackOpt.stackRefs.splice(index + 1, 0, stackRef);
@@ -1366,20 +1444,21 @@ ColumnStackPlugin.prototype._onColumnMoved = function (e) {
1366
1444
  */
1367
1445
  ColumnStackPlugin.prototype._onColumnAdded = function (e) {
1368
1446
  var colIndex = e.colIndex;
1369
- this._setColumnStacking(colIndex, {});
1447
+ this._setUniqueRef(colIndex, {});
1370
1448
 
1371
- var columnStack = this._columnStack;
1372
- if (columnStack) {
1373
- this._setStack(); //asynchronous
1374
- } else {
1449
+ if (this._autoStacking) {
1450
+ if(this._idToFields) {
1451
+ this._requestStackingByFields();
1452
+ }
1453
+ } else { // TODO: This logic is too complicated
1375
1454
  // add to group
1376
1455
  var leftStackOpt = this._getColumnStackOptions(colIndex - 1);
1377
1456
  var rightStackOpt = this._getColumnStackOptions(colIndex + 1);
1378
1457
  if(leftStackOpt && (leftStackOpt === rightStackOpt)) {
1379
- var leftColStackRef = this._getColumnStacking(colIndex - 1);
1380
- var stackRef = this._getColumnStacking(colIndex);
1458
+ var leftColStackRef = this._getUniqueRef(colIndex - 1);
1459
+ var stackRef = this._getUniqueRef(colIndex);
1381
1460
  var index = leftStackOpt.stackRefs.indexOf(leftColStackRef);
1382
- if(index > -1) {
1461
+ if(index > -1) { // TODO: Reuse existing logic instead of modifying states like this
1383
1462
  leftStackOpt.stackRefs.splice(index + 1, 0, stackRef);
1384
1463
  leftStackOpt.activeColumn = leftStackOpt.stackRefs[leftStackOpt.stackRefs.length - 1];
1385
1464
  this._setColumnStackOptions(colIndex, leftStackOpt);
@@ -1414,10 +1493,9 @@ ColumnStackPlugin.prototype._onStackButtonClicked = function(e) {
1414
1493
  var activeIndex = stackRefs.indexOf(colData.activeColumn);
1415
1494
 
1416
1495
  var len = stackRefs.length;
1417
- var colIndices = new Array(len);
1496
+ var colIndices = this._getColumnIndices(stackRefs);
1418
1497
  var menuData = new Array(len);
1419
1498
  for(var i = len; --i >= 0;) {
1420
- colIndices[i] = this._getColumnIndex(stackRefs[i]);
1421
1499
  menuData[i] = {
1422
1500
  value: i,
1423
1501
  selected: i === activeIndex,
@@ -1438,12 +1516,12 @@ ColumnStackPlugin.prototype._onStackButtonClicked = function(e) {
1438
1516
  /** Remove existing stacks and apply persist stack
1439
1517
  * @private
1440
1518
  */
1441
- ColumnStackPlugin.prototype._setStack = function() {
1519
+ ColumnStackPlugin.prototype._requestStackingByFields = function() {
1442
1520
  if(this._stackConflator.conflate()) {
1443
1521
  return;
1444
1522
  }
1445
1523
 
1446
- var columnStack = this._columnStack;
1524
+ var columnStack = this._idToFields;
1447
1525
  if(columnStack){
1448
1526
  this.removeAllStacks(false);
1449
1527
  for(var sid in columnStack){
@@ -1462,19 +1540,13 @@ ColumnStackPlugin.prototype._setStack = function() {
1462
1540
  * @return {!Array.<number>} Member column indices
1463
1541
  */
1464
1542
  ColumnStackPlugin.prototype.getStackMemberIndices = function(stackId) {
1465
- var memberIndices = [];
1466
- if(stackId !== null) {
1543
+ if(stackId) {
1467
1544
  var stack = this._stacks[stackId];
1468
1545
  if(stack){
1469
- var stackRefs = stack.stackRefs;
1470
- for(var i = 0; i < stackRefs.length; ++i) {
1471
- var stackRef = stackRefs[i];
1472
- var colIndex = this._getColumnIndex(stackRef);
1473
- memberIndices.push(colIndex);
1474
- }
1546
+ return this._getColumnIndices(stack.stackRefs);
1475
1547
  }
1476
1548
  }
1477
- return memberIndices;
1549
+ return [];
1478
1550
  };
1479
1551
 
1480
1552
  /** @public
@@ -1571,7 +1643,7 @@ ColumnStackPlugin.prototype.addColumnToStack = function(colRef, stackId) {
1571
1643
 
1572
1644
  // apply stacking
1573
1645
  this._setColumnStackOptions(colRef, stack);
1574
- stack.stackRefs.push(this._getColumnStacking(colRef));
1646
+ stack.stackRefs.push(this._getUniqueRef(colRef));
1575
1647
 
1576
1648
  if(stack.spreading) {
1577
1649
  stack.activeColumn = stack.stackRefs[stack.stackRefs.length - 1];
@@ -1587,58 +1659,58 @@ ColumnStackPlugin.prototype.addColumnToStack = function(colRef, stackId) {
1587
1659
  };
1588
1660
 
1589
1661
  /** @public
1590
- * @description Remove specific column from a stack
1662
+ * @description Remove specific column from its own stack
1591
1663
  * @param {number|string} colRef column field or column index
1592
1664
  */
1593
1665
  ColumnStackPlugin.prototype.removeColumnFromStack = function(colRef) {
1594
- if(typeof colRef === "string") {
1595
- colRef = this.getColumnIndex(colRef);
1596
- if(colRef < 0) {
1597
- return;
1598
- }
1666
+ var colIndex = (typeof colRef === "string") ? this.getColumnIndex(colRef) : colRef;
1667
+ if(colIndex < 0) {
1668
+ return;
1599
1669
  }
1600
1670
 
1601
- var stackId = this.getStackId(colRef);
1671
+ var stackId = this.getStackId(colIndex);
1602
1672
  var stack = this._stacks[stackId];
1603
1673
  if(!stack) {
1604
1674
  return;
1605
1675
  }
1606
1676
 
1607
- var stackMembers = this.getStackMemberIndices(stackId);
1608
1677
  var stackRefs = stack.stackRefs;
1609
-
1610
- if(stackMembers.length < 3){
1611
- this.unstackColumns(stackMembers);
1612
- } else {
1613
- var isCollapsed = stack.spreading && stack.collapsed;
1614
-
1615
- for(var i = 0; i < stackRefs.length; ++i) {
1616
- var stackRef = stackRefs[i];
1617
- var colIndex = this._getColumnIndex(stackRef);
1618
-
1619
- if(colIndex === colRef){
1620
- if(isCollapsed) {
1621
- this._collapseMember(stackMembers[i], false);
1622
- }
1623
- stackRefs.splice(i, 1);
1624
- break;
1678
+ var memberCount = stackRefs.length;
1679
+ if(memberCount <= 2) {
1680
+ if(memberCount === 2) {
1681
+ var uniqueObj = this._getUniqueRef(colIndex);
1682
+ if(uniqueObj === stackRefs[0]) { // If the first column is removed from the stack, move it to the end of stack
1683
+ // This assumes that the column order is already in correct position
1684
+ this.moveColumnById(colIndex, this._getColumnIndex(stackRefs[1]) + 1);
1625
1685
  }
1626
1686
  }
1687
+ this.removeStack(stackId); // updateUI will be called
1688
+ return;
1689
+ }
1627
1690
 
1628
- this._removeColumnStackOptions(colRef);
1629
- this._setColumnVisibility(colRef, true);
1630
-
1631
- if(stack.spreading) {
1632
- stack.activeColumn = stackRefs[stackRefs.length - 1];
1633
- stack.collapsed = isCollapsed;
1634
- } else {
1635
- stack.activeColumn = stackRefs[0];
1691
+ var colIndices = this.getStackMemberIndices(stackId);
1692
+ var memberIdx = colIndices.indexOf(colIndex);
1693
+ var isCollapsed = stack.spreading && stack.collapsed;
1694
+ if(memberIdx >= 0) {
1695
+ if(isCollapsed) {
1696
+ this._collapseMember(colIndices[memberIdx], false); // TODO: This may change the column index
1636
1697
  }
1637
- this._stacks[stackId] = stack;
1698
+ stackRefs.splice(memberIdx, 1); // WARNING: colIndices is out of sync with stackRefs after this line
1699
+ }
1638
1700
 
1639
- this._moveStackedColumns(stack.stackRefs);
1640
- this._updateUI();
1701
+ this._removeColumnStackOptions(colIndex);
1702
+ this._setColumnVisibility(colIndex, true);
1703
+
1704
+ if(stack.spreading) {
1705
+ stack.activeColumn = stackRefs[stackRefs.length - 1];
1706
+ stack.collapsed = isCollapsed;
1707
+ } else {
1708
+ stack.activeColumn = stackRefs[0];
1641
1709
  }
1710
+ this._stacks[stackId] = stack; // TODO: This is unnecessary
1711
+
1712
+ this.moveColumnById(colIndex, colIndices[memberCount - 1] + 1); // This assumes that the column order is already in correct position
1713
+ this._updateUI();
1642
1714
  };
1643
1715
 
1644
1716
  /** @public
@@ -1742,6 +1814,70 @@ ColumnStackPlugin.prototype.getActiveColumnField = function(stackId) {
1742
1814
  return field;
1743
1815
  };
1744
1816
 
1817
+ /** @public
1818
+ * @param {string} stackId
1819
+ * @param {number|string} colRef Column field or column index
1820
+ */
1821
+ ColumnStackPlugin.prototype.addStackChild = function(stackId, colRef) {
1822
+ this.addColumnToStack(colRef, stackId);
1823
+ };
1824
+ /**
1825
+ * @public
1826
+ * @param {string} stackId
1827
+ * @param {number|string} colRef Column field or column index
1828
+ */
1829
+ ColumnStackPlugin.prototype.removeStackChild = function(stackId, colRef) {
1830
+ var colIndex = (typeof colRef === "string") ? this.getColumnIndex(colRef) : colRef;
1831
+ if(colIndex >= 0) {
1832
+ if(stackId === this.getStackId(colIndex)) {
1833
+ this.removeColumnFromStack(colIndex);
1834
+ }
1835
+ }
1836
+ };
1837
+ /** @public
1838
+ * @function
1839
+ * @param {number|string} colRef Column field or column index
1840
+ */
1841
+ ColumnStackPlugin.prototype.unsetParent = ColumnStackPlugin.prototype.removeColumnFromStack;
1842
+
1843
+ /** Move and reorder the specified columns to position before the destination
1844
+ * @public
1845
+ * @param {Array.<number|string>} colList Column list to be reordered
1846
+ * @param {(number|string)=} destCol Destination column id or index
1847
+ * @return {boolean}
1848
+ */
1849
+ ColumnStackPlugin.prototype.reorderColumns = function(colList, destCol) {
1850
+ var dirty = false;
1851
+ this._stacking = false;
1852
+
1853
+ var gridApi = this.getGridApi();
1854
+ if(gridApi && gridApi.reorderColumns) {
1855
+ dirty = gridApi.reorderColumns(colList, destCol); // TODO: Support multi-table feature
1856
+ }
1857
+
1858
+ this._stacking = true;
1859
+ return dirty;
1860
+ };
1861
+ /** Move the specified column to position before the destination
1862
+ * @public
1863
+ * @param {number|string} srcCol Source column id or index
1864
+ * @param {(number|string)=} destCol Destination column id or index
1865
+ * @return {boolean}
1866
+ */
1867
+ ColumnStackPlugin.prototype.moveColumnById = function(srcCol, destCol) {
1868
+ var dirty = false;
1869
+ this._stacking = false;
1870
+
1871
+ var gridApi = this.getGridApi();
1872
+ if(gridApi && gridApi.moveColumnById) {
1873
+ dirty = gridApi.moveColumnById(srcCol, destCol); // TODO: Support multi-table feature
1874
+ }
1875
+
1876
+ this._stacking = true;
1877
+ return dirty;
1878
+ };
1879
+
1880
+
1745
1881
 
1746
1882
  export default ColumnStackPlugin;
1747
1883
  export { ColumnStackPlugin, ColumnStackPlugin as ColumnStack, ColumnStackPlugin as ColumnStackExtension };