@refinitiv-ui/efx-grid 6.0.21 → 6.0.23

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. package/lib/column-dragging/es6/ColumnDragging.js +46 -24
  2. package/lib/core/dist/core.js +61 -14
  3. package/lib/core/dist/core.min.js +1 -1
  4. package/lib/core/es6/grid/Core.js +11 -1
  5. package/lib/core/es6/grid/LayoutGrid.js +1 -0
  6. package/lib/core/es6/grid/components/CellSpans.d.ts +2 -0
  7. package/lib/core/es6/grid/components/CellSpans.js +35 -10
  8. package/lib/core/es6/grid/plugins/SortableTitlePlugin.d.ts +2 -0
  9. package/lib/core/es6/grid/plugins/SortableTitlePlugin.js +14 -3
  10. package/lib/grid/index.js +1 -1
  11. package/lib/rt-grid/dist/rt-grid.js +369 -90
  12. package/lib/rt-grid/dist/rt-grid.min.js +1 -1
  13. package/lib/rt-grid/es6/ColumnDefinition.d.ts +1 -1
  14. package/lib/rt-grid/es6/ColumnDefinition.js +21 -36
  15. package/lib/rt-grid/es6/FieldDefinition.d.ts +7 -1
  16. package/lib/rt-grid/es6/FieldDefinition.js +93 -4
  17. package/lib/rt-grid/es6/Grid.d.ts +4 -1
  18. package/lib/rt-grid/es6/Grid.js +88 -25
  19. package/lib/rt-grid/es6/ReferenceCounter.js +13 -2
  20. package/lib/rt-grid/es6/RowDefinition.d.ts +2 -0
  21. package/lib/rt-grid/es6/RowDefinition.js +74 -8
  22. package/lib/rt-grid/es6/SnapshotFiller.js +1 -1
  23. package/lib/tr-grid-column-grouping/es6/ColumnGrouping.d.ts +5 -1
  24. package/lib/tr-grid-column-grouping/es6/ColumnGrouping.js +228 -55
  25. package/lib/types/es6/ColumnGrouping.d.ts +5 -1
  26. package/lib/types/es6/Core/grid/components/CellSpans.d.ts +2 -0
  27. package/lib/types/es6/Core/grid/plugins/SortableTitlePlugin.d.ts +2 -0
  28. package/lib/types/es6/RealtimeGrid/Grid.d.ts +4 -1
  29. package/lib/types/es6/RealtimeGrid/RowDefinition.d.ts +2 -0
  30. package/lib/versions.json +2 -2
  31. package/package.json +3 -2
@@ -89,7 +89,7 @@ declare class ColumnDefinition {
89
89
 
90
90
  public isRealTimeField(): boolean;
91
91
 
92
- public isTimeSeriesField(): boolean;
92
+ public isTimeSeries(): boolean;
93
93
 
94
94
  public isFormulaField(): boolean;
95
95
 
@@ -213,10 +213,6 @@ ColumnDefinition.prototype._eventArg;
213
213
  /** @type {boolean}
214
214
  * @private
215
215
  */
216
- ColumnDefinition.prototype._realTimeField = false;
217
- /** @type {boolean}
218
- * @private
219
- */
220
216
  ColumnDefinition.prototype._autoGenerated = false;
221
217
 
222
218
  /** @type {!Array.<string>}
@@ -263,10 +259,6 @@ ColumnDefinition.prototype._parent = null;
263
259
  * @private
264
260
  */
265
261
  ColumnDefinition.prototype._children = null;
266
- /** @type {boolean}
267
- * @private
268
- */
269
- ColumnDefinition.prototype._timeSeriesField = false;
270
262
  /** @type {Object}
271
263
  * @private
272
264
  */
@@ -353,7 +345,7 @@ ColumnDefinition.prototype.initialize = function(columnOption) {
353
345
  }
354
346
  }
355
347
 
356
- this._setField(field, columnOption["formula"]); // Perform some field manipulation
348
+ this._setField(field, columnOption); // Perform some field manipulation
357
349
 
358
350
  val = columnOption["name"] || columnOption["title"]; // title is migrated from Composite Grid
359
351
  if(val != null) { // Name can be empty string
@@ -368,7 +360,7 @@ ColumnDefinition.prototype.initialize = function(columnOption) {
368
360
 
369
361
  val = columnOption["notRealTimeField"];
370
362
  if(val != null) {
371
- this._realTimeField = !val;
363
+ FieldDefinition.setFieldProperty(field, "IsRealtimeField", !val);
372
364
  }
373
365
 
374
366
  val = columnOption["tooltip"];
@@ -585,17 +577,13 @@ ColumnDefinition.prototype.getAllFields = function() {
585
577
  * @return {boolean}
586
578
  */
587
579
  ColumnDefinition.prototype.isRealTimeField = function() {
588
- // TODO: Simplify this logic
589
- if(this._field && this._realTimeField && !this._formula) {
590
- return ColumnDefinition.isRealTimeField(this._field);
591
- }
592
- return false;
580
+ return FieldDefinition.isRealTimeField(this._field);
593
581
  };
594
582
  /** @public
595
583
  * @return {boolean}
596
584
  */
597
- ColumnDefinition.prototype.isTimeSeriesField = function() {
598
- return this._timeSeriesField;
585
+ ColumnDefinition.prototype.isTimeSeries = function() {
586
+ return FieldDefinition.isTimeSeries(this._field);
599
587
  };
600
588
  /** @public
601
589
  * @return {boolean}
@@ -608,27 +596,21 @@ ColumnDefinition.prototype.isFormulaField = function() {
608
596
  * @return {boolean}
609
597
  */
610
598
  ColumnDefinition.isFormulaField = function(field) {
611
- return field.charAt(0) === "=";
599
+ return FieldDefinition.isFormula(field);
612
600
  };
613
601
  /** @public
614
602
  * @param {string} field
615
603
  * @return {boolean}
616
604
  */
617
605
  ColumnDefinition.isAdcField = function(field) {
618
- return field.indexOf("TR.") === 0;
606
+ return FieldDefinition.isAdc(field);
619
607
  };
620
608
  /** @public
621
609
  * @param {string} field
622
610
  * @return {boolean}
623
611
  */
624
612
  ColumnDefinition.isRealTimeField = function(field) {
625
- if(field) {
626
- if(!ColumnDefinition.isFormulaField(field)) {
627
- return !ColumnDefinition.isAdcField(field);
628
- }
629
- }
630
-
631
- return false;
613
+ return FieldDefinition.isRealTimeField(field);
632
614
  };
633
615
  /** @public
634
616
  * @function
@@ -753,8 +735,10 @@ ColumnDefinition.prototype.getConfigObject = function(colOptions) {
753
735
  obj["name"] = this._name;
754
736
  }
755
737
 
756
- if(!this._realTimeField) {
757
- obj["notRealTimeField"] = true;
738
+ // The 'IsRealtimeField' property will only be set if the user sets 'notRealTimeField' in the column options. It will be returned if the user has this option enabled, otherwise it will not be returned
739
+ value = FieldDefinition.getFieldProperty(this._field, "IsRealtimeField") === false;
740
+ if(value) {
741
+ obj["notRealTimeField"] = value;
758
742
  }
759
743
 
760
744
  if(this._tooltip != null) {
@@ -975,7 +959,7 @@ ColumnDefinition.prototype.setSorter = function(func) {
975
959
  */
976
960
  ColumnDefinition.prototype.isRowSorting = function() {
977
961
  if(this._rowSorting == null) {
978
- return !this._realTimeField;
962
+ return !FieldDefinition.getFieldProperty(this._field, "IsRealtimeField");
979
963
  }
980
964
  return this._rowSorting ? true : false;
981
965
  };
@@ -998,9 +982,9 @@ ColumnDefinition.prototype.setName = function(str) {
998
982
 
999
983
  /** @private
1000
984
  * @param {string|null=} field
1001
- * @param {string} formulaStr
985
+ * @param {ColumnDefinition~Options=} columnOption
1002
986
  */
1003
- ColumnDefinition.prototype._setField = function(field, formulaStr) {
987
+ ColumnDefinition.prototype._setField = function(field, columnOption) {
1004
988
  var defaultField = (field == null); // undefined or null
1005
989
  if(!field) {
1006
990
  field = "";
@@ -1008,6 +992,7 @@ ColumnDefinition.prototype._setField = function(field, formulaStr) {
1008
992
  // Trim white spaces -- equivalent to String.trim(), which is not support in IE8
1009
993
  field = field.replace(/^\s+|\s+$/gm, "");
1010
994
 
995
+ var formulaStr = columnOption["formula"];
1011
996
  if(this._fnEngine) {
1012
997
  var uppercasedF = field.toUpperCase(); // For comparison only
1013
998
  var predefinedF = formulaStr || PredefinedFormula.get(uppercasedF);
@@ -1035,13 +1020,13 @@ ColumnDefinition.prototype._setField = function(field, formulaStr) {
1035
1020
  this._field = field;
1036
1021
  this._name = field;
1037
1022
  this._emptyField = false;
1038
- this._realTimeField = field ? true : false;
1039
1023
  }
1040
1024
 
1041
- if(FieldDefinition.isTimeSeriesField(field)) {
1042
- // children will be clone the config from parent too
1043
- this._realTimeField = false;
1044
- this._timeSeriesField = true;
1025
+ // We need to cache time series in field definition for improve performance of checking methond
1026
+ FieldDefinition.setFieldProperty(field, "timeSeries", FieldDefinition.isTimeSeries(field) ? true : false);
1027
+
1028
+ if(columnOption["parent"]) {
1029
+ FieldDefinition.setFieldProperty(field, "timeSeriesChild", true);
1045
1030
  }
1046
1031
 
1047
1032
  this._isDefaultName = true;
@@ -18,7 +18,13 @@ declare namespace FieldDefinition {
18
18
 
19
19
  function setFieldCaching(caching: boolean): void;
20
20
 
21
- function isTimeSeriesField(field: string): boolean;
21
+ function isFormula(field: string): boolean;
22
+
23
+ function isAdc(field: string): boolean;
24
+
25
+ function isRealTimeField(field: string): boolean;
26
+
27
+ function isTimeSeries(field: string): boolean;
22
28
 
23
29
  }
24
30
 
@@ -57,7 +57,7 @@ var FieldDefinition = {};
57
57
  FieldDefinition._defs = {
58
58
  "X_RIC_NAME": {
59
59
  name: "RIC",
60
- notRealTimeField: true,
60
+ IsRealtimeField: false,
61
61
  width: 100,
62
62
  binding: xRicNameRenderer,
63
63
  sortLogic: xRicNameSorter
@@ -195,7 +195,13 @@ FieldDefinition._loadingField = {};
195
195
  * @param {Object} def
196
196
  */
197
197
  FieldDefinition.set = function(field, def) {
198
- FieldDefinition._defs[field] = def || null;
198
+ if (!FieldDefinition._defs[field]) {
199
+ FieldDefinition._defs[field] = def;
200
+ } else {
201
+ for (var key in def) {
202
+ FieldDefinition._defs[field][key] = def[key];
203
+ }
204
+ }
199
205
  };
200
206
  /** @public
201
207
  * @function
@@ -252,11 +258,64 @@ FieldDefinition.setFieldCaching = function (caching) {
252
258
  FieldDefinition._caching = caching;
253
259
  };
254
260
 
261
+ /** @public
262
+ * @param {string} field
263
+ * @return {boolean}
264
+ */
265
+ FieldDefinition.isFormula = function(field) {
266
+ return field.charAt(0) === "=";
267
+ };
268
+ /** @public
269
+ * @param {string} field
270
+ * @return {boolean}
271
+ */
272
+ FieldDefinition.isAdc = function(field) {
273
+ return field.indexOf("TR.") === 0;
274
+ };
275
+
276
+ /** @public
277
+ * @param {string} field
278
+ * @return {boolean}
279
+ */
280
+ FieldDefinition.isRealTimeField = function(field) {
281
+ if (!field) {
282
+ return false;
283
+ }
284
+
285
+ if(FieldDefinition.isAdc(field)) {
286
+ return false;
287
+ }
288
+
289
+ if(FieldDefinition.isFormula(field)) {
290
+ return false;
291
+ }
292
+
293
+ if(FieldDefinition.getFieldProperty(field, "timeSeriesChild")) {
294
+ return false;
295
+ }
296
+
297
+ if(FieldDefinition.isTimeSeries(field)) {
298
+ return false;
299
+ }
300
+
301
+ return FieldDefinition.getFieldProperty(field, "IsRealtimeField") !== false;
302
+ };
303
+
255
304
  /** @public
256
305
  * @param {string} field
257
306
  * @return {boolean}=true if field is time series field
258
307
  */
259
- FieldDefinition.isTimeSeriesField = function (field) {
308
+ FieldDefinition.isTimeSeries = function (field) {
309
+ if (!field) {
310
+ return false;
311
+ }
312
+
313
+ // We can check time series using a cache to avoid duplicating checks in regular expressions.
314
+ var timeSeriesField = FieldDefinition.getFieldProperty(field, "timeSeries");
315
+ if (timeSeriesField != null) {
316
+ return timeSeriesField;
317
+ }
318
+
260
319
  /*
261
320
  ^TR. => start with TR.
262
321
  [\w]+ => any field with string and value
@@ -265,9 +324,39 @@ FieldDefinition.isTimeSeriesField = function (field) {
265
324
  EDATE\=+ => EDATE in bucket
266
325
  [\w\-\=\,]+ => another propertie param
267
326
  [\)]$ => end with only )
327
+ i => for match both upper and lower cases
268
328
  */
329
+ var timeSeriesRegex = /^TR.[\w]+[\(][\w\-\=\,]*EDATE\=+[\w\-\=\,]+[\)]$/i;
330
+ return timeSeriesRegex.test(field);
331
+ };
269
332
 
270
- return !!field.toUpperCase().match(/^TR.[\w]+[\(][\w\-\=\,]*EDATE\=+[\w\-\=\,]+[\)]$/g);
333
+ /**
334
+ * Set property value into field definition
335
+ * @private
336
+ * @param {string} field field definition
337
+ * @param {string} propertyName
338
+ * @param {*} value
339
+ */
340
+ FieldDefinition.setFieldProperty = function(field, propertyName, value) {
341
+ if(!FieldDefinition._defs[field]) {
342
+ FieldDefinition._defs[field] = {};
343
+ }
344
+ FieldDefinition._defs[field][propertyName] = value;
345
+ };
346
+
347
+ /**
348
+ * Set property value into field definition
349
+ * @private
350
+ * @param {string} field field definition
351
+ * @param {string} propertyName
352
+ * @return {*}
353
+ */
354
+ FieldDefinition.getFieldProperty = function(field, propertyName) {
355
+ var fieldDef = FieldDefinition._defs[field];
356
+ if(fieldDef) {
357
+ return fieldDef[propertyName];
358
+ }
359
+ return null;
271
360
  };
272
361
 
273
362
  /** to get more info about field via synapse service
@@ -80,7 +80,8 @@ declare namespace Grid {
80
80
  scrollbarParent?: Element|null,
81
81
  formulaEngine?: boolean|null,
82
82
  adcPollingInterval?: number|null,
83
- fieldCaching?: boolean|null
83
+ fieldCaching?: boolean|null,
84
+ childDataField?: string|null
84
85
  };
85
86
 
86
87
  type RowReference = number|string|RowDefinition|null;
@@ -143,6 +144,8 @@ declare class Grid extends EventDispatcher {
143
144
 
144
145
  public moveColumnById(srcCol: number|string|null, destCol?: (number|string)|null): boolean;
145
146
 
147
+ public reorderColumns(colRefs: number|string|(number|string)[]|null, destCol: number|string|null): boolean;
148
+
146
149
  public hideColumn(colRef: Grid.ColumnReference|null, hidden?: boolean|null): void;
147
150
 
148
151
  public hideColumns(colRefs: (Grid.ColumnReference)[]|null, hidden?: boolean|null): void;
@@ -84,6 +84,7 @@ import { ElementWrapper } from "../../core/es6/grid/components/ElementWrapper.js
84
84
  * @property {boolean=} formulaEngine=false If enabled, field with leading equal sign will be treated as a formula and rows will be filled with the calculated values.
85
85
  * @property {number=} adcPollingInterval=0 Length of polling interval for refreshing ADC data in milliseconds. The default value (0) means no polling.
86
86
  * @property {boolean=} fieldCaching=false If enabled, field definition will be caching internal mechanism
87
+ * @property {string=} childDataField=CHILD_VALUES The given field will be used to store children's static data, such as row color assignment.
87
88
  */
88
89
 
89
90
  /** @typedef {number|string|RowDefinition} Grid~RowReference
@@ -280,8 +281,7 @@ var Grid = function(placeholder, config) {
280
281
  t._recalculateFormulas = t._recalculateFormulas.bind(t);
281
282
  t._updateStreamingData = t._updateStreamingData.bind(t);
282
283
  t.updateColumnTitle = t.updateColumnTitle.bind(t);
283
- t._insertTimeSeriesChildren = t._insertTimeSeriesChildren.bind(t);
284
-
284
+ t._populateTimeSeriesChildren = t._populateTimeSeriesChildren.bind(t);
285
285
 
286
286
  t._onPostSectionDataBinding = t._onPostSectionDataBinding.bind(t);
287
287
  t._asyncClearDataUpdates = t._asyncClearDataUpdates.bind(t);
@@ -305,7 +305,7 @@ var Grid = function(placeholder, config) {
305
305
  t._formulaConflator = new Conflator(300, t._onFormulaDataChanged);
306
306
  t._chainConflator = new Conflator(100, t._addMemberOfChain);
307
307
  t._columnTitleConflator = new Conflator(0, t.updateColumnTitle);
308
- t._timeSeriesChildConflator = new Conflator(0, t._insertTimeSeriesChildren);
308
+ t._timeSeriesChildConflator = new Conflator(0, t._populateTimeSeriesChildren);
309
309
 
310
310
 
311
311
  t._defaultColumnOptions = {};
@@ -546,6 +546,10 @@ Grid.prototype._pollingEnabled = true;
546
546
  * @private
547
547
  */
548
548
  Grid.prototype._fieldCaching = false;
549
+ /** @type {string}
550
+ * @private
551
+ */
552
+ Grid.prototype._childDataField = "";
549
553
 
550
554
 
551
555
  /** @public
@@ -960,6 +964,9 @@ Grid.prototype.initialize = function(gridOption) {
960
964
  }
961
965
 
962
966
  // Row operations
967
+ if(gridOption["childDataField"] != null) {
968
+ this._childDataField = RowDefinition._childDataField = gridOption["childDataField"];
969
+ }
963
970
  var rows = gridOption["rows"];
964
971
  if(!rows) {
965
972
  rows = gridOption["rics"] || null; // Make "rics" an alias to "rows"
@@ -1115,6 +1122,10 @@ Grid.prototype.getConfigObject = function (gridOptions) {
1115
1122
  obj["fieldCaching"] = this._fieldCaching;
1116
1123
  }
1117
1124
 
1125
+ if(this._childDataField) {
1126
+ obj["childDataField"] = this._childDataField;
1127
+ }
1128
+
1118
1129
  // get all rows config
1119
1130
  var rowDefs = this.getAllRowDefinitions();
1120
1131
  var rows = obj["rows"] = [];
@@ -1252,9 +1263,8 @@ Grid.prototype._onFieldAdded = function(e) {
1252
1263
 
1253
1264
  // JET
1254
1265
  if (this._subs) {
1255
- var colDefs = this.getColumnDefinitions();
1256
- var fields = colDefs.reduce(ColumnDefinition.getRealTimeFields, []);
1257
- this._subs["addFields"](fields);
1266
+ var realtimeFields = addedFields.filter(FieldDefinition.isRealTimeField);
1267
+ this._subs["addFields"](realtimeFields);
1258
1268
  }
1259
1269
 
1260
1270
  this._dispatch(e.type, e);
@@ -1265,6 +1275,7 @@ Grid.prototype._onFieldAdded = function(e) {
1265
1275
  Grid.prototype._onFieldRemoved = function(e) {
1266
1276
  var removedFields = e.removedFields;
1267
1277
 
1278
+ // TODO: ADC fields have an interval load. Currently, we only keep the field but do not delete it.
1268
1279
  // JET
1269
1280
  if(this._subs) {
1270
1281
  this._subs["removeFields"](removedFields);
@@ -1361,7 +1372,7 @@ Grid.prototype._updateTimeSeriesFields = function (e) {
1361
1372
  /** @private
1362
1373
  * @param {ColumnDefinition} colDef
1363
1374
  */
1364
- Grid.prototype._insertTimeSeriesChildren = function (colDef) {
1375
+ Grid.prototype._populateTimeSeriesChildren = function (colDef) {
1365
1376
  if(this._timeSeriesChildConflator.conflate(colDef) ) {
1366
1377
  return;
1367
1378
  }
@@ -1411,7 +1422,7 @@ Grid.prototype._cloneTimeSeriesColumn = function (parentColDef, childField, idx)
1411
1422
  }
1412
1423
  }
1413
1424
  columnOption = cloneObject(obj);
1414
- columnOption["field"] = childField.replace("TR.", "");
1425
+ columnOption["field"] = childField.replace("TR.", ""); // We need to remove the 'TR' prefix from the field to avoid confusion with time series fields.
1415
1426
  columnOption["name"] = childField.split("_")[1].split("T")[0]; // Currently, response server format utc date ex "2022-11-23T00:00:00"
1416
1427
  columnOption["parent"] = parentColDef;
1417
1428
  this.insertColumn(columnOption, idx++);
@@ -1518,15 +1529,12 @@ Grid.prototype._onFieldLoadedError = function (err) {
1518
1529
  * @param {string} referrer
1519
1530
  */
1520
1531
  Grid.prototype._onFieldLoaded = function (field, referrer) {
1521
- // async process, the field can be remove before column added
1522
- var colIndex = this.getColumnIndex(field);
1523
- if(colIndex > -1) {
1524
- var colDef = this._getColumnDefinition(field);
1525
- if(colDef.isTimeSeriesField()) {
1526
- this._insertTimeSeriesChildren(colDef);
1527
- }
1528
- this._connector.addFields(field, referrer);
1532
+ // For time series, we need to wait until the field is loadedm, then we can insert a child from the field data.
1533
+ if(FieldDefinition.isTimeSeries(field)) {
1534
+ var colDef = this.getColumnDefinitionById(referrer); // The 'referrer' is a column ID that was just added
1535
+ this._populateTimeSeriesChildren(colDef);
1529
1536
  }
1537
+ this._connector.addFields(field, referrer);
1530
1538
  };
1531
1539
 
1532
1540
  /**
@@ -1555,7 +1563,7 @@ Grid.prototype._shouldLoadFieldInfo = function (field, isRealTime) {
1555
1563
  var fieldDef = FieldDefinition.get(field);
1556
1564
  if (!fieldDef &&
1557
1565
  field !== 'X_RIC_NAME' && // ignore X_RIC_NAME
1558
- (isRealTime || ColumnDefinition.isAdcField(field)) && // realtime field or adc field (Without static field)
1566
+ (isRealTime || FieldDefinition.isAdc(field)) && // realtime field or adc field (Without static field)
1559
1567
  (this._RTK || window["JET"]) // have rtk instance or window jet sub
1560
1568
  ) {
1561
1569
  return true;
@@ -1659,14 +1667,13 @@ Grid.prototype._onColumnAdded = function(e) {
1659
1667
  }
1660
1668
  }
1661
1669
  this._grid.setDataColumnName(idx, ROW_DEF); // This make ColumnDefinition renderer work
1662
-
1663
1670
  var fields = colDef.getAllFields();
1664
1671
  var referrer = colDef.getId();
1665
1672
  var len = fields.length;
1666
1673
  var field, dataType, prom, isRealTimeField, onLoaded;
1667
1674
  for(i = 0; i < len; i++) {
1668
1675
  field = fields[i];
1669
- isRealTimeField = ColumnDefinition.isRealTimeField(field);
1676
+ isRealTimeField = FieldDefinition.isRealTimeField(field);
1670
1677
  if(this._shouldLoadFieldInfo(field, isRealTimeField)) {
1671
1678
  if(field === colField) {
1672
1679
  dataType = colDef.getDataType(); // Data-type from user's column options
@@ -1682,14 +1689,14 @@ Grid.prototype._onColumnAdded = function(e) {
1682
1689
  onLoaded = this._onFieldLoaded.bind(this, field, referrer);
1683
1690
  prom = prom.then(onLoaded).catch(onLoaded);
1684
1691
  } else {
1685
- if(colDef.isTimeSeriesField()) {
1686
- this._insertTimeSeriesChildren(colDef);
1692
+ if(colDef.isTimeSeries()) {
1693
+ this._populateTimeSeriesChildren(colDef);
1687
1694
  }
1688
1695
  this._connector.addFields(field, referrer);
1689
1696
  }
1690
1697
  } else {
1691
- if(colDef.isTimeSeriesField()) {
1692
- this._insertTimeSeriesChildren(colDef);
1698
+ if(colDef.isTimeSeries()) {
1699
+ this._populateTimeSeriesChildren(colDef);
1693
1700
  }
1694
1701
  this._connector.addFields(field, referrer);
1695
1702
  }
@@ -1845,6 +1852,62 @@ Grid.prototype.moveColumnById = function (srcCol, destCol) {
1845
1852
  return this.moveColumn(srcIndex, destIndex);
1846
1853
  };
1847
1854
 
1855
+ /** @public
1856
+ * @param {number|string|Array.<number|string>} colRefs List of column index or column id to be moved
1857
+ * @param {number|string} destCol Destination position where the moved columns will be placed BEFORE the specified position. This can be column id or index
1858
+ * @return {boolean} Return true if there is any change, and false otherwise
1859
+ */
1860
+ Grid.prototype.reorderColumns = function (colRefs, destCol) {
1861
+ var destId = (typeof destCol === "number") ? this.getColumnId(destCol) : destCol;
1862
+
1863
+ if(Array.isArray(colRefs)) {
1864
+ var srcLen = colRefs.length;
1865
+ if(srcLen > 1) {
1866
+ var colIds = this.getColumnIds();
1867
+ var srcIds = [];
1868
+ var invalidDest = false;
1869
+ var i;
1870
+ for(i = 0; i < srcLen; ++i) {
1871
+ var colRef = colRefs[i];
1872
+ var srcId = (typeof colRef === "number") ? colIds[colRef] : colRef;
1873
+ if(srcId) {
1874
+ srcIds.push(srcId);
1875
+ if(destId === srcId) {
1876
+ invalidDest = true; // Destination must not exist in source columns
1877
+ }
1878
+ }
1879
+ }
1880
+ srcLen = srcIds.length;
1881
+ if(invalidDest) { // Find the next valid destination where it is not contained in the source columns
1882
+ var colCount = colIds.length;
1883
+ var destIdx = this.getColumnIndex(destId);
1884
+ if(destIdx >= 0) {
1885
+ while(++destIdx < colCount) {
1886
+ destId = colIds[destIdx];
1887
+ if(srcIds.indexOf(destId) < 0) {
1888
+ break;
1889
+ }
1890
+ }
1891
+ }
1892
+ if(destIdx < 0 || destIdx >= colCount) {
1893
+ destId = "";
1894
+ }
1895
+ }
1896
+
1897
+ var dirty = 0;
1898
+ for(i = 0; i < srcLen; ++i) {
1899
+ dirty |= this.moveColumnById(srcIds[i], destId);
1900
+ }
1901
+ // TODO: Handle the case where all columns stay in the same place
1902
+ return dirty ? true : false;
1903
+ } else {
1904
+ return this.moveColumnById(colRefs[0], destId);
1905
+ }
1906
+ }
1907
+
1908
+ // colRefs will be a number or string
1909
+ return this.moveColumnById(colRefs, destId);
1910
+ };
1848
1911
 
1849
1912
  /** The hidden column still occupies the same index.
1850
1913
  * @public
@@ -1915,7 +1978,7 @@ Grid.prototype.addDataFields = function(fieldRef, referrer) {
1915
1978
  var i, field, dataType, prom, isRealTimeField, onLoaded;
1916
1979
  for(i = 0; i < len; i++) {
1917
1980
  field = fields[i];
1918
- isRealTimeField = ColumnDefinition.isRealTimeField(field);
1981
+ isRealTimeField = FieldDefinition.isRealTimeField(field);
1919
1982
  if(this._shouldLoadFieldInfo(field, isRealTimeField)) {
1920
1983
  dataType = ColumnDefinition.getDataType(field);
1921
1984
  prom = FieldDefinition.loadFieldInfo(field)
@@ -3035,7 +3098,7 @@ Grid.prototype.unpinColumn = function(colRef, dest) {
3035
3098
  var len = ary.length;
3036
3099
 
3037
3100
  var dirty = 0;
3038
- for(var i = 0; i < len; ++i) {
3101
+ for(var i = len; --i >= 0;) { // WARNING: unpinning is done in reversed order
3039
3102
  dirty |= this._unpinColumn(ary[i], dest);
3040
3103
  }
3041
3104
  return dirty ? true : false;
@@ -66,6 +66,7 @@ ReferenceCounter.prototype.getSession = function() {
66
66
  } else if(val < 0) {
67
67
  removedEntries.push(key);
68
68
  }
69
+ // else {} // when val 0 do nothing, doesn't change anything
69
70
  }
70
71
  return {
71
72
  newEntries: newEntries.filter(Boolean),
@@ -94,9 +95,15 @@ ReferenceCounter.prototype.addReference = function(key, referer) {
94
95
 
95
96
  if(this._counter[key]) {
96
97
  ++this._counter[key];
98
+ // The session will not change when a field already exists and a counter is attempted to be added
97
99
  } else {
98
100
  this._counter[key] = 1;
99
- this._session[key] = 1;
101
+ if(this._session[key] === -1) {
102
+ this._session[key] = 0;
103
+ } else {
104
+ this._session[key] = 1;
105
+ }
106
+
100
107
  return true;
101
108
  }
102
109
  }
@@ -146,7 +153,11 @@ ReferenceCounter.prototype.removeReference = function(key, referer, count) {
146
153
  val -= count;
147
154
  if(!val || val < 0) {
148
155
  delete this._counter[key];
149
- this._session[key] = -1;
156
+ if(this._session[key] === 1) {
157
+ this._session[key] = 0;
158
+ } else {
159
+ this._session[key] = -1;
160
+ }
150
161
  return true;
151
162
  }
152
163
 
@@ -45,6 +45,8 @@ declare class RowDefinition {
45
45
 
46
46
  public setStaticRowData(data: { [key: string]: any }|any[], opt_fields?: (string)[]|null): void;
47
47
 
48
+ public _getStaticRowData(): { [key: string]: any };
49
+
48
50
  public updateRowData(data: { [key: string]: any }|any[], opt_fields?: (string)[]|null): void;
49
51
 
50
52
  public setStaticData(field: string, value: any): void;