@refinitiv-ui/efx-grid 6.0.53 → 6.0.55

Sign up to get free protection for your applications and to get access to all the features.
@@ -10079,6 +10079,12 @@ Segment.prototype.getChildIds = function() {
10079
10079
  return this._childCount ? Object.keys(this._children) : [];
10080
10080
  };
10081
10081
  /** @public
10082
+ * @return {!Object}
10083
+ */
10084
+ Segment.prototype.getChildren = function() {
10085
+ return this._children;
10086
+ };
10087
+ /** @public
10082
10088
  * @return {number}
10083
10089
  */
10084
10090
  Segment.prototype.getChildCount = function() {
@@ -12425,9 +12431,9 @@ DataTable.prototype.getSegmentChildIds = function(segmentId) {
12425
12431
  };
12426
12432
  /** Sort all of existing segments by multiple sort logics
12427
12433
  * @public
12428
- * @param {Function|Array.<Function>} sortLogics
12429
- * @param {Array.<number>} sortOrders
12430
- * @param {Array.<string>} cids
12434
+ * @param {Function|Array.<Function>|Object} sortLogics
12435
+ * @param {Array.<number>=} sortOrders
12436
+ * @param {Array.<string>=} cids
12431
12437
  * @return {boolean}
12432
12438
  */
12433
12439
  DataTable.prototype.sortSeparators = function (sortLogics, sortOrders, cids) {
@@ -14466,9 +14472,9 @@ RowDefinition.dispose = function(rowDef) {
14466
14472
  * @const
14467
14473
  */
14468
14474
  var SYNAPSE_URL =
14469
- '/synapse/service/suggestions/suggest/?'
14470
- + 'hits=1' // search only 1 result
14471
- + '&profile=' + encodeURIComponent('Field Selector');
14475
+ "/synapse/service/suggestions/suggest/?"
14476
+ + "hits=1" // search only 1 result
14477
+ + "&profile=" + encodeURIComponent("Field Selector");
14472
14478
 
14473
14479
  /* @namespace */
14474
14480
  var FieldDefinition = {};
@@ -14585,18 +14591,13 @@ FieldDefinition._timeSeriesChildren = {};
14585
14591
  * @private
14586
14592
  * @const
14587
14593
  */
14588
- FieldDefinition._synapse = '';
14594
+ FieldDefinition._synapse = "";
14589
14595
  /**
14590
14596
  * @type {string}
14591
14597
  * @private
14592
14598
  * @const
14593
14599
  */
14594
- FieldDefinition._lang = 'en';
14595
- /**
14596
- * @type {boolean}
14597
- * @private
14598
- */
14599
- FieldDefinition._caching = false;
14600
+ FieldDefinition._lang = "en";
14600
14601
  /**
14601
14602
  * @type {boolean}
14602
14603
  * @private
@@ -14623,17 +14624,22 @@ FieldDefinition.set = function(field, def) {
14623
14624
  }
14624
14625
  }
14625
14626
  };
14626
- /** @public
14627
+ /** Get field definition object
14628
+ * @public
14627
14629
  * @function
14628
14630
  * @param {string} field
14629
14631
  * @return {Object}
14630
14632
  */
14631
14633
  FieldDefinition.get = function(field) {
14632
- if(this._caching) {
14633
- return FieldDefinition._defs[field];
14634
- }
14635
- return null;
14634
+ return FieldDefinition._defs[field] || null;
14636
14635
  };
14636
+ /** Get field definition object
14637
+ * @public
14638
+ * @function
14639
+ * @param {string} field
14640
+ * @return {Object}
14641
+ */
14642
+ FieldDefinition.getFieldInfo = FieldDefinition.get;
14637
14643
 
14638
14644
  /** @public
14639
14645
  * @function
@@ -14642,7 +14648,7 @@ FieldDefinition.get = function(field) {
14642
14648
  */
14643
14649
  FieldDefinition.hasFieldInfo = function(field) {
14644
14650
  var val = FieldDefinition.get(field);
14645
- return val && val.field; // Already preventing an error caused by accessing a property on a null value
14651
+ return (val && val.field) ? true : false; // Already preventing an error caused by accessing a property on a null value
14646
14652
  };
14647
14653
 
14648
14654
  /** @public
@@ -14678,15 +14684,6 @@ FieldDefinition.remove = function(field) {
14678
14684
  */
14679
14685
  FieldDefinition.setSynapseConfig = function (config) {
14680
14686
  FieldDefinition._synapse = config;
14681
-
14682
- };
14683
-
14684
- /** @public
14685
- * @function
14686
- * @param {boolean} caching
14687
- */
14688
- FieldDefinition.setFieldCaching = function (caching) {
14689
- FieldDefinition._caching = caching;
14690
14687
  };
14691
14688
 
14692
14689
  /** @public
@@ -14811,7 +14808,7 @@ FieldDefinition.getFieldProperty = function(field, propertyName) {
14811
14808
  return null;
14812
14809
  };
14813
14810
 
14814
- /** to get more info about field via synapse service
14811
+ /** To get more info about field via synapse service
14815
14812
  * @private
14816
14813
  * @param {string} field
14817
14814
  * @returns {Promise}
@@ -14843,12 +14840,12 @@ FieldDefinition.loadFieldInfo = function (field) {
14843
14840
  // everything fine, call synapse service
14844
14841
  else {
14845
14842
  var queryUrl = SYNAPSE_URL
14846
- + '&api-key=' + encodeURIComponent(synapse.apiKey)
14847
- + '&contextApp=' + encodeURIComponent(synapse.contextApp)
14848
- + '&language=' + encodeURIComponent(FieldDefinition._lang)
14849
- + '&query=' + encodeURIComponent(field);
14843
+ + "&api-key=" + encodeURIComponent(synapse.apiKey)
14844
+ + "&contextApp=" + encodeURIComponent(synapse.contextApp)
14845
+ + "&language=" + encodeURIComponent(FieldDefinition._lang)
14846
+ + "&query=" + encodeURIComponent(field);
14850
14847
  if (synapse.auth) {
14851
- queryUrl += '&auth=' + encodeURIComponent(synapse.auth);
14848
+ queryUrl += "&auth=" + encodeURIComponent(synapse.auth);
14852
14849
  }
14853
14850
  // TODO: handle client timeout
14854
14851
  var xmr = new XMLHttpRequest();
@@ -14857,9 +14854,9 @@ FieldDefinition.loadFieldInfo = function (field) {
14857
14854
  FieldDefinition._loadingField[field] = defer;
14858
14855
 
14859
14856
  // for now we care only successful case
14860
- xmr.addEventListener('loadend', onLoadEnd);
14861
- xmr.addEventListener('timeout', onError);
14862
- xmr.addEventListener('error', onError);
14857
+ xmr.addEventListener("loadend", onLoadEnd);
14858
+ xmr.addEventListener("timeout", onError);
14859
+ xmr.addEventListener("error", onError);
14863
14860
  xmr.open("GET", queryUrl, true); // true for asynchronous
14864
14861
  xmr.send();
14865
14862
  }
@@ -14887,7 +14884,7 @@ FieldDefinition._mockOnLoadEndData = function (field, defer) {
14887
14884
  var fieldUpperCase = field.toUpperCase();
14888
14885
  var fieldLowerCase = fieldUpperCase.toLowerCase();
14889
14886
  var label;
14890
- if (fieldLowerCase.indexOf('_') === 2) { // transform XX_ABCD -> Abcd
14887
+ if (fieldLowerCase.indexOf("_") === 2) { // transform XX_ABCD -> Abcd
14891
14888
  label = fieldUpperCase[3] + fieldLowerCase.substring(4);
14892
14889
  } else {
14893
14890
  label = fieldUpperCase[0] + fieldLowerCase.substring(1);
@@ -14949,49 +14946,49 @@ FieldDefinition._mockOnLoadEndData = function (field, defer) {
14949
14946
  function onLoadEnd(e) {
14950
14947
  var xmr = e.currentTarget;
14951
14948
  var defer = xmr._defer;
14952
- var resolve = defer.resolve;
14953
- var reject = defer.reject;
14949
+ var field = xmr._field;
14954
14950
 
14955
- delete FieldDefinition._loadingField[xmr._field];
14951
+ delete FieldDefinition._loadingField[field];
14956
14952
 
14957
14953
  if (xmr.status === 200) { // case success
14958
- var returnObj = {
14959
- field: xmr._field,
14960
- fieldDefinition: null
14961
- };
14962
14954
  var res = JSON.parse(xmr.responseText);
14955
+ var fieldDef = null;
14963
14956
 
14964
14957
  var result = res.result && res.result[0];
14965
14958
  if (result) {
14966
14959
  var item = result.hits && result.hits[0];
14967
14960
  if (item && item.p) {
14968
14961
  var profile = item.p;
14969
- if (profile.fn.toUpperCase() === xmr._field.toUpperCase()) {
14970
- var fieldDef = FieldDefinition.get(xmr._field) || {};
14962
+ if (profile.fn.toUpperCase() === field.toUpperCase()) {
14963
+ fieldDef = FieldDefinition.get(field) || {};
14971
14964
 
14972
14965
  fieldDef.field = profile.fn; // name
14966
+ fieldDef.name = profile.fl; // label
14973
14967
  fieldDef.rank = profile.Rank;
14974
14968
  fieldDef.fieldDataType = profile.fdt; // data type
14969
+ fieldDef.id = profile.fid;
14975
14970
  fieldDef.IsMonitorOnlyField = profile.fimo;
14976
14971
  fieldDef.IsRealtimePortfolioField = profile.firp;
14977
14972
  fieldDef.IsRealtimeField = profile.firt;
14978
- fieldDef.name = profile.fl; // label
14979
14973
  fieldDef.source = profile.fsrc;
14980
14974
  fieldDef.sourceRank = profile.fsrnk;
14981
14975
  fieldDef.description = item.title;
14982
14976
 
14983
- FieldDefinition.set(xmr._field, fieldDef);
14984
- returnObj.fieldDefinition = fieldDef;
14977
+ FieldDefinition.set(field, fieldDef);
14985
14978
  }
14986
14979
  }
14987
14980
  }
14988
- resolve(returnObj);
14981
+ if(fieldDef) {
14982
+ defer.resolve(fieldDef);
14983
+ } else {
14984
+ defer.reject("No definition for " + field);
14985
+ }
14989
14986
  } else if (xmr._error) { // case error && time out
14990
- xmr._error.field = xmr._field;
14991
- reject(xmr._error);
14987
+ xmr._error.field = field;
14988
+ defer.reject(xmr._error);
14992
14989
  } else { // case status not 200
14993
- reject({
14994
- field: xmr._field,
14990
+ defer.reject({
14991
+ field: field,
14995
14992
  status: xmr.status,
14996
14993
  statusText: xmr.statusText,
14997
14994
  request: xmr
@@ -16754,7 +16751,7 @@ GroupDefinitions.getLeafDescendants = function (groupMap, groupId) {
16754
16751
  groupDef = unvisitedGroups[visitedCount++];
16755
16752
  visitedMap[groupDef.id] = true;
16756
16753
  var chdr = groupDef.children;
16757
- var len = chdr.length;
16754
+ var len = chdr ? chdr.length : 0;
16758
16755
  for(var i = 0; i < len; ++i) {
16759
16756
  var childId = chdr[i];
16760
16757
  groupDef = groupMap[childId];
@@ -16774,44 +16771,30 @@ GroupDefinitions.getLeafDescendants = function (groupMap, groupId) {
16774
16771
  /** @private
16775
16772
  * @function
16776
16773
  * @param {Object} obj
16777
- * @return {Object}
16774
+ * @return {Object} Return a new object with guaranteed children property
16778
16775
  */
16779
16776
  GroupDefinitions._cloneObject = function(obj) {
16780
16777
  var newObj = cloneObject(obj);
16781
- if(Array.isArray(newObj.children)) {
16782
- newObj.children = newObj.children;
16778
+ if(Array.isArray(newObj.children)) { // This is to prevent modification from the outside source
16779
+ newObj.children = newObj.children.slice();
16783
16780
  } else {
16784
16781
  newObj.children = [];
16785
16782
  }
16786
16783
  return newObj;
16787
16784
  };
16788
- /** @private
16789
- * @param {Object} groupMap
16790
- * @return {!Object}
16791
- */
16792
- GroupDefinitions._cloneGroupMap = function (groupMap) {
16793
- var outMap = {};
16794
- for(var groupId in groupMap) {
16795
- var groupDef = groupMap[groupId];
16796
- var obj = GroupDefinitions._cloneObject(groupDef);
16797
- obj.children = groupDef.children.slice();
16798
- outMap[groupId] = obj;
16799
- }
16800
- return outMap;
16801
- };
16802
16785
 
16803
16786
  /** @private
16804
16787
  * @function
16805
16788
  * @param {Array.<string>|Object} obj
16806
16789
  * @param {string=} groupId
16807
- * @return {Object}
16790
+ * @return {Object} Return a new object with guaranteed children property
16808
16791
  */
16809
16792
  GroupDefinitions._toGroupDefinition = function(obj, groupId) {
16810
16793
  var groupDef = null;
16811
16794
  if(obj) {
16812
16795
  if(Array.isArray(obj)) {
16813
16796
  groupDef = {
16814
- children: obj
16797
+ children: obj.slice()
16815
16798
  };
16816
16799
  } else {
16817
16800
  groupDef = GroupDefinitions._cloneObject(obj);
@@ -16891,7 +16874,43 @@ GroupDefinitions.prototype.getGroupMap = function () {
16891
16874
  * @return {!Object.<string, Object>}
16892
16875
  */
16893
16876
  GroupDefinitions.prototype.cloneGroupMap = function () {
16894
- return GroupDefinitions._cloneGroupMap(this._groupMap);
16877
+ var groupMap = this._groupMap;
16878
+ var outMap = {};
16879
+ for(var groupId in groupMap) {
16880
+ var groupDef = groupMap[groupId];
16881
+ var obj = GroupDefinitions._cloneObject(groupDef);
16882
+ outMap[groupId] = obj;
16883
+ }
16884
+ return outMap;
16885
+ };
16886
+ /** In case of a children array has been modified outside of GroupDefinitions, this method is needed to re-create internal maps to reflect existing structure
16887
+ * @public
16888
+ */
16889
+ GroupDefinitions.prototype.rebuildMap = function () {
16890
+ var groupMap = this._groupMap;
16891
+ var childToParent = this._childToParent = {};
16892
+
16893
+ // Create child to parent map
16894
+ var groupIds = Object.keys(groupMap);
16895
+ var grpCount = groupIds.length;
16896
+ var i, groupId;
16897
+ for(i = 0; i < grpCount; ++i) {
16898
+ groupId = groupIds[i];
16899
+ var chdr = groupMap[groupId].children;
16900
+ var childCount = chdr ? chdr.length : 0;
16901
+ for (var j = 0; j < childCount; j++) {
16902
+ childToParent[chdr[j]] = groupId;
16903
+ }
16904
+ }
16905
+
16906
+ // Apply a parent id to group definition to make it easier to find depth
16907
+ for(i = 0; i < grpCount; ++i) {
16908
+ groupId = groupIds[i];
16909
+ var parentId = childToParent[groupId];
16910
+ if(parentId) {
16911
+ groupMap[groupId].parentId = parentId;
16912
+ }
16913
+ }
16895
16914
  };
16896
16915
 
16897
16916
  /** Get immediate child ids of the specified group. The returned array can contain both child ids and group ids
@@ -16971,7 +16990,7 @@ GroupDefinitions.prototype.getParentIds = function(childId) {
16971
16990
  };
16972
16991
  /** @public
16973
16992
  * @param {string} childId
16974
- * @param {number=} groupLevel
16993
+ * @param {number=} groupLevel Default is to retrieve immediate parent id. Use 0 to get root (topmost) group id
16975
16994
  * @return {string}
16976
16995
  */
16977
16996
  GroupDefinitions.prototype.getParentId = function (childId, groupLevel) {
@@ -16999,47 +17018,25 @@ GroupDefinitions.prototype.removeAllGroups = function () {
16999
17018
  }
17000
17019
  return false;
17001
17020
  };
17002
- /** Remove all existing group definitions and replace them with the given definitions.
17021
+ /** Remove all existing group definitions and replace them with the given definitions. Note that this method does not check for circular referencing nor duplication of ids
17003
17022
  * @public
17004
17023
  * @param {Array.<Object>=} groupDefs Use null or empty array to remove all existing groups
17005
17024
  */
17006
17025
  GroupDefinitions.prototype.setGroups = function (groupDefs) {
17007
17026
  // Clear existing group structure
17008
17027
  var groupMap = this._groupMap = {};
17009
- var childToParent = this._childToParent = {};
17010
17028
 
17011
17029
  // Create group map
17012
- var i;
17013
17030
  var grpCount = groupDefs ? groupDefs.length : 0;
17014
- var groupId = "";
17015
- for (i = 0; i < grpCount; i++) {
17031
+ for (var i = 0; i < grpCount; i++) {
17016
17032
  var groupDef = groupDefs[i];
17017
- groupId = groupDef.id;
17033
+ var groupId = groupDef.id;
17018
17034
  if(groupId) {
17019
- groupMap[groupId] = groupDef;
17020
- }
17021
- }
17022
-
17023
- // Create child to parent map
17024
- var groupIds = Object.keys(groupMap);
17025
- grpCount = groupIds.length;
17026
- for(i = 0; i < grpCount; ++i) {
17027
- groupId = groupIds[i];
17028
- var children = groupMap[groupId].children;
17029
- var childCount = children.length;
17030
- for (var j = 0; j < childCount; j++) {
17031
- childToParent[children[j]] = groupId;
17035
+ groupMap[groupId] = GroupDefinitions._cloneObject(groupDef);
17032
17036
  }
17033
17037
  }
17034
17038
 
17035
- // Apply a parent id to group definition to make it easier to find depth
17036
- for(i = 0; i < grpCount; ++i) {
17037
- groupId = groupIds[i];
17038
- var parentId = childToParent[groupId];
17039
- if(parentId) {
17040
- groupMap[groupId].parentId = parentId;
17041
- }
17042
- }
17039
+ this.rebuildMap();
17043
17040
  };
17044
17041
  /** Add new group definition to existing group structure. Existing group with the same id will be replaced.
17045
17042
  * @public
@@ -17068,11 +17065,11 @@ GroupDefinitions.prototype.removeGroup = function (groupId) {
17068
17065
  }
17069
17066
  return false;
17070
17067
  };
17071
- /** Replace and update existing group definition. New group is added if the given id has no match. Existing group will be removed of no new definition is given.
17068
+ /** Replace and update existing group definition. A new group will be added, only if the given id has no match. Existing group will be removed of no new definition is given.
17072
17069
  * @public
17073
17070
  * @param {string} groupId
17074
- * @param {Array.<string>|Object=} groupDef
17075
- * @return {string} Return group Id. Return empty string if nothing has been changed.
17071
+ * @param {(Array.<string>|Object)=} groupDef
17072
+ * @return {string} Return group Id. Return empty string, if nothing has been changed
17076
17073
  */
17077
17074
  GroupDefinitions.prototype.setGroup = function (groupId, groupDef) {
17078
17075
  if(!groupId) {
@@ -17093,7 +17090,7 @@ GroupDefinitions.prototype.setGroup = function (groupId, groupDef) {
17093
17090
  }
17094
17091
  this._groupMap[groupId] = newDef;
17095
17092
 
17096
- var chdr = newDef.children;
17093
+ var chdr = newDef.children; // newDef is guaranteed to have children property
17097
17094
  var len = chdr.length;
17098
17095
  for(var i = 0; i < len; ++i) {
17099
17096
  var childId = chdr[i];
@@ -17125,7 +17122,8 @@ GroupDefinitions.prototype._ungroupChildren = function(children) {
17125
17122
  }
17126
17123
  };
17127
17124
 
17128
- /** @public
17125
+ /** Check if the given child id is an immediate child of the given group
17126
+ * @public
17129
17127
  * @param {string} parentId Group id
17130
17128
  * @param {string} childId
17131
17129
  * @return {boolean}
@@ -17135,7 +17133,30 @@ GroupDefinitions.prototype.hasGroupChild = function (parentId, childId) {
17135
17133
  if(childId && groupDef) {
17136
17134
  var chdr = groupDef.children;
17137
17135
  if(chdr) {
17138
- return chdr.indexOf(childId) >= 0;
17136
+ return chdr.indexOf(childId) >= 0; // TODO: Use childToParent map to improve performance
17137
+ }
17138
+ }
17139
+ return false;
17140
+ };
17141
+ /** Check if the specified id is contained within the given group regardless of any group level that the id is in
17142
+ * @public
17143
+ * @param {string} groupId
17144
+ * @param {string} childId
17145
+ * @return {boolean}
17146
+ */
17147
+ GroupDefinitions.prototype.contains = function (groupId, childId) {
17148
+ if(groupId && childId) {
17149
+ if(groupId === childId) {
17150
+ return true;
17151
+ }
17152
+ var levelLimit = 20;
17153
+ var parentId = this._childToParent[childId];
17154
+ while(parentId && levelLimit) { // WARNING: Circular dependency could happen
17155
+ if(groupId === parentId) {
17156
+ return true;
17157
+ }
17158
+ --levelLimit;
17159
+ parentId = this._childToParent[parentId];
17139
17160
  }
17140
17161
  }
17141
17162
  return false;
@@ -17202,7 +17223,7 @@ GroupDefinitions.prototype.unsetParent = function (childId) {
17202
17223
  var parentDef = this._groupMap[parentId];
17203
17224
  if(parentDef) {
17204
17225
  var chdr = parentDef.children;
17205
- if(chdr.length) {
17226
+ if(chdr && chdr.length) {
17206
17227
  var at = chdr.indexOf(childId);
17207
17228
  if (at >= 0) {
17208
17229
  chdr.splice(at, 1); // splice is slow
@@ -17220,7 +17241,7 @@ GroupDefinitions.prototype.removeAllChildren = function(groupId) {
17220
17241
  var grpDef = this._groupMap[groupId];
17221
17242
  if(grpDef) {
17222
17243
  var chdr = grpDef.children;
17223
- var len = chdr.length;
17244
+ var len = chdr ? chdr.length : 0;
17224
17245
  if(len) {
17225
17246
  grpDef.children = [];
17226
17247
  for(var i = 0; i < len; ++i) {
@@ -28976,6 +28997,8 @@ var DataView = function(source) {
28976
28997
  t._onRefreshTimeout = t._onRefreshTimeout.bind(t);
28977
28998
  t._updateWrapCount = t._updateWrapCount.bind(t);
28978
28999
 
29000
+ t._byRemovalMap = t._byRemovalMap.bind(t);
29001
+
28979
29002
  t._rids = [];
28980
29003
  t._sortingDefs = [];
28981
29004
  t._columnStats = {};
@@ -29029,6 +29052,15 @@ DataView.prototype._hiddenRids = null;
29029
29052
  * @type {Object.<string, boolean>}
29030
29053
  */
29031
29054
  DataView.prototype._collapsedRids = null; // for segmentation
29055
+ /** @private
29056
+ * @type {Object.<string, number>}
29057
+ */
29058
+ DataView.prototype._excludedRids = null;
29059
+ /** @private
29060
+ * @type {boolean}
29061
+ */
29062
+ DataView.prototype._emptySegmentFiltering = false;
29063
+
29032
29064
  /** @private
29033
29065
  * @type {Object.<string, number>}
29034
29066
  */
@@ -29725,8 +29757,6 @@ DataView.prototype.hideRow = function(rId, hidden) {
29725
29757
  */
29726
29758
  DataView.prototype.hideRows = function(rowRefs, hidden) {
29727
29759
  hidden = hidden !== false;
29728
- var dirty = false;
29729
- var rids = this._toRowIds(rowRefs);
29730
29760
  var hiddenRids = this._hiddenRids;
29731
29761
 
29732
29762
  if(hidden){
@@ -29737,11 +29767,19 @@ DataView.prototype.hideRows = function(rowRefs, hidden) {
29737
29767
  return; // All rows are visible
29738
29768
  }
29739
29769
 
29770
+ var rids = this._toRowIds(rowRefs);
29771
+ var dirty = false;
29772
+
29740
29773
  for(var i = rids.length; --i >= 0;) {
29741
29774
  var rid = rids[i];
29742
29775
  if(rid) { // undefined, null, and an empty string value are not a valid row id
29743
- if(!!hiddenRids[rid] !== hidden) {
29744
- hiddenRids[rid] = hidden;
29776
+ if(hidden) {
29777
+ if(!hiddenRids[rid]) {
29778
+ hiddenRids[rid] = true;
29779
+ dirty = true;
29780
+ }
29781
+ } else if(hiddenRids[rid]) {
29782
+ delete hiddenRids[rid];
29745
29783
  dirty = true;
29746
29784
  }
29747
29785
  }
@@ -29750,11 +29788,9 @@ DataView.prototype.hideRows = function(rowRefs, hidden) {
29750
29788
  if(dirty) {
29751
29789
  if(!hidden) {
29752
29790
  var hasHiddenRow = false;
29753
- for(var key in hiddenRids) {
29754
- if(hiddenRids[key]) {
29755
- hasHiddenRow = true;
29756
- break;
29757
- }
29791
+ for(var key in hiddenRids) { // eslint-disable-line
29792
+ hasHiddenRow = true;
29793
+ break;
29758
29794
  }
29759
29795
  if(!hasHiddenRow) {
29760
29796
  hiddenRids = this._hiddenRids = null;
@@ -29762,6 +29798,7 @@ DataView.prototype.hideRows = function(rowRefs, hidden) {
29762
29798
  }
29763
29799
  this._refreshAndNotify(); // Very slow
29764
29800
  }
29801
+
29765
29802
  };
29766
29803
  /**
29767
29804
  * Show/hide rows in the data view
@@ -29843,23 +29880,14 @@ DataView.prototype.filterOut = function(cid, value) {
29843
29880
  */
29844
29881
  DataView.prototype.filterInOnce = function(cid, value, opt_filteringOut) {
29845
29882
  var checker = this._getFilterLogic(cid, value);
29846
- if(!checker) { return; }
29847
-
29848
- var filteringOut = (opt_filteringOut === true);
29849
- var rids = this._rids;
29850
- var dt = this._dt;
29851
29883
  var removalMap = {};
29852
- var totalRem = 0;
29853
- var len = rids.length;
29854
- for(var i = len; --i >= 0;) {
29855
- var rid = rids[i];
29856
- var values = dt.getRowData(rid);
29857
- if (!values || checker(rid, values) === filteringOut) {
29858
- removalMap[rid] = true;
29859
- ++totalRem;
29860
- }
29884
+ if(!this._getRemovalMap(
29885
+ removalMap,
29886
+ checker,
29887
+ (opt_filteringOut === true)
29888
+ )) {
29889
+ return;
29861
29890
  }
29862
- if(totalRem <= 0) { return; }
29863
29891
 
29864
29892
  var firstChange = this._removeRowIds(removalMap);
29865
29893
 
@@ -29882,13 +29910,13 @@ DataView.prototype.filterOutOnce = function(cid, value) {
29882
29910
  this.filterInOnce(cid, value, true);
29883
29911
  };
29884
29912
  /** @private
29885
- * @param {!Object.<string, *>} removalMap
29913
+ * @param {!Object} removalMap
29886
29914
  * @return {number}
29887
29915
  */
29888
29916
  DataView.prototype._removeRowIds = function(removalMap) {
29889
- var firstChange = this._removeArrayItems(this._rids, removalMap);
29917
+ var firstChange = DataView._removeArrayItems(this._rids, removalMap);
29890
29918
  if(this._groupView) {
29891
- firstChange = this._removeArrayItems(this._groupView, removalMap);
29919
+ firstChange = DataView._removeArrayItems(this._groupView, removalMap);
29892
29920
  }
29893
29921
 
29894
29922
  if(this._groupMembers) {
@@ -29899,6 +29927,7 @@ DataView.prototype._removeRowIds = function(removalMap) {
29899
29927
  }
29900
29928
  }
29901
29929
  return firstChange;
29930
+
29902
29931
  };
29903
29932
  /** @public
29904
29933
  * @fires DataView#pageCountChanged
@@ -31452,9 +31481,9 @@ DataView.prototype.getSegmentChildIds = function(segmentRef) {
31452
31481
  };
31453
31482
  /** Sort all of existing segments by multiple sort logics
31454
31483
  * @public
31455
- * @param {Array.<Function>} sortLogics
31456
- * @param {Array.<number>} sortOrders
31457
- * @param {Array.<string>} cids
31484
+ * @param {Function|Array.<Function>|Object} sortLogics
31485
+ * @param {Array.<number>=} sortOrders
31486
+ * @param {Array.<string>=} cids
31458
31487
  */
31459
31488
  DataView.prototype.sortSeparators = function (sortLogics, sortOrders, cids) {
31460
31489
  this._dt.sortSeparators(sortLogics, sortOrders, cids);
@@ -31466,7 +31495,19 @@ DataView.prototype.sortSeparators = function (sortLogics, sortOrders, cids) {
31466
31495
  DataView.prototype.sortSegments = function (compare) {
31467
31496
  this._dt.sortSegments(compare);
31468
31497
  };
31469
-
31498
+ /** Automatically hide empty segment when all of its member are filtered out. An empty segment will not be hidden, if there is no active filter. Collapsed segment does not count as filtering.
31499
+ * @public
31500
+ * @param {boolean=} enabled
31501
+ */
31502
+ DataView.prototype.enableEmptySegmentFiltering = function (enabled) {
31503
+ enabled = enabled !== false;
31504
+ if(this._emptySegmentFiltering !== enabled) {
31505
+ this._emptySegmentFiltering = enabled;
31506
+ if(this._userFilter) {
31507
+ this._refreshAndNotify();
31508
+ }
31509
+ }
31510
+ };
31470
31511
  /**
31471
31512
  * @public
31472
31513
  * @param {string|number} segmentRef Row id or row index
@@ -31626,26 +31667,35 @@ DataView.prototype._updateRowIds = function(opt_rowIds) {
31626
31667
  // Perform the following sequences: parent view cloning >> row hiding >> row filtering >> row grouping >> sorting >> paging
31627
31668
  this._rids = opt_rowIds || this._parent.getAllRowIds(); // Get all data ids
31628
31669
 
31629
- if(this._hiddenRids) {
31630
- this._removeArrayItems(this._rids, this._hiddenRids);
31631
- }
31670
+ this._dispatch("beforeFiltering", {});
31671
+
31672
+ this._excludedRids = {};
31673
+ var exclusionCount = 0;
31674
+ exclusionCount += DataView._copyObjectKeys(this._excludedRids, this._hiddenRids);
31675
+
31676
+ // Segment separators should not be filtered out (hidden)
31632
31677
  var segments = this._dt._getSegmentSeparators();
31678
+ var filterExceptions = segments ? segments.getSegments() : null;
31679
+ var userRemoval = this._getRemovalMap(this._excludedRids, this._userFilter, this._filteringOut, filterExceptions);
31680
+ exclusionCount += userRemoval;
31681
+
31633
31682
  this._collapsedRids = null;
31634
- var filterExceptions = null;
31635
31683
  if(segments) {
31636
- filterExceptions = segments.getSegments(); // Segment separators should not be filtered out (hidden)
31637
- var collapsedRows = this._collapsedRids = segments.getCollapsedRows(); // Children of collapsed segments must be filtered out (hidden)
31638
- if(collapsedRows) {
31639
- this._removeArrayItems(this._rids, collapsedRows);
31684
+ if(userRemoval && this._emptySegmentFiltering) {
31685
+ exclusionCount += this._getEmptySegments(this._excludedRids, filterExceptions);
31640
31686
  }
31687
+ this._collapsedRids = segments.getCollapsedRows();
31688
+ // Children of collapsed segments must be filtered out (hidden)
31689
+ exclusionCount += DataView._copyObjectKeys(this._excludedRids, this._collapsedRids);
31641
31690
  }
31642
31691
 
31643
- this._dispatch("beforeFiltering", {});
31644
- this._quickFilter(this._userFilter, this._filteringOut, filterExceptions);
31645
-
31646
- if(this._groupLevel > 0 && !opt_rowIds) {
31647
- this._quickFilter(this._groupFilterLogic, false); // Filter In
31692
+ if(this._groupLevel > 0 && !opt_rowIds) { // WARNING: The line below is quite slow
31693
+ exclusionCount += this._getRemovalMap(this._excludedRids, this._groupFilterLogic, false); // Filter In
31648
31694
  }
31695
+ if(exclusionCount) {
31696
+ this._rids = this._rids.filter(this._byRemovalMap);
31697
+ }
31698
+ this._excludedRids = null;
31649
31699
 
31650
31700
  if(this._groupMembers) { // Has grouping
31651
31701
  this._populateGroups(); // View will be properly re-populate inside _populateGroups()
@@ -31917,9 +31967,9 @@ DataView.prototype._onRowUpdated = function(e) { // onUpdate
31917
31967
 
31918
31968
  if(this._groupLevel > 0) {
31919
31969
  if(processingFlag === 1) { // The row is moved to the other group
31920
- if(this._removeArrayItem(this._rids, rid) >= 0) {
31970
+ if(DataView._removeArrayItem(this._rids, rid) >= 0) {
31921
31971
  if(this._groupView) {
31922
- this._removeArrayItem(this._groupView, rid);
31972
+ DataView._removeArrayItem(this._groupView, rid);
31923
31973
  }
31924
31974
  }
31925
31975
  if(this._shared.multiGroupRow) {
@@ -32119,34 +32169,31 @@ DataView.prototype._getRowIndex = function(rids, opt_nextRid, opt_fallback) {
32119
32169
  * @returns {number}
32120
32170
  */
32121
32171
  DataView.prototype._removeDataRow = function(rid) {
32122
- var at = this._removeArrayItem(this._rids, rid);
32172
+ var at = DataView._removeArrayItem(this._rids, rid);
32123
32173
  if(this._groupView && at >= 0) {
32124
- at = this._removeArrayItem(this._groupView, rid);
32174
+ at = DataView._removeArrayItem(this._groupView, rid);
32125
32175
  }
32126
32176
  return at;
32127
32177
  };
32128
32178
  /** @private
32129
- * @param {Array} ary
32179
+ * @param {!Array} ary
32130
32180
  * @param {*} item
32131
32181
  * @return {number} Index of the removed item
32132
32182
  */
32133
- DataView.prototype._removeArrayItem = function(ary, item) {
32134
- var len = ary.length;
32135
- for(var i = 0; i < len; ++i) {
32136
- if(ary[i] === item) {
32137
- ary.splice(i, 1);
32138
- return i;
32139
- }
32183
+ DataView._removeArrayItem = function(ary, item) {
32184
+ var at = ary.indexOf(item);
32185
+ if(at >= 0) {
32186
+ ary.splice(at, 1);
32140
32187
  }
32141
- return -1;
32188
+ return at;
32142
32189
  };
32143
32190
  /** Remove multiple array items
32144
32191
  * @private
32145
32192
  * @param {Array.<string>} ary
32146
- * @param {Object.<string, *>} items
32193
+ * @param {Object} items
32147
32194
  * @return {number} First item index that is being removed. NaN if no item is removed
32148
32195
  */
32149
- DataView.prototype._removeArrayItems = function(ary, items) {
32196
+ DataView._removeArrayItems = function(ary, items) {
32150
32197
  var f = NaN;
32151
32198
  var c = 0;
32152
32199
  for(var i = ary.length; --i >= 0;) {
@@ -32164,6 +32211,24 @@ DataView.prototype._removeArrayItems = function(ary, items) {
32164
32211
  }
32165
32212
  return f;
32166
32213
  };
32214
+ /** @private
32215
+ * @param {Object} baseObj
32216
+ * @param {Object} masterObj
32217
+ * @returns {number}
32218
+ */
32219
+ DataView._copyObjectKeys = function(baseObj, masterObj) {
32220
+ if(masterObj) {
32221
+ var count = 0;
32222
+
32223
+ for(var key in masterObj) {
32224
+ baseObj[key] = 1;
32225
+ ++count; // WARNING: duplicated key can be counted more than once
32226
+ }
32227
+ return count;
32228
+ }
32229
+ return 0;
32230
+ };
32231
+
32167
32232
  /** @private
32168
32233
  * @param {string|null} rid
32169
32234
  * @param {Object} rowData
@@ -32198,9 +32263,6 @@ DataView.prototype.isRowFiltered = function(rid, rowData) {
32198
32263
  return true;
32199
32264
  }
32200
32265
  }
32201
- if(this.isSegmentSeparator(rid)) {
32202
- return false; // Segment separator cannot be filtered
32203
- }
32204
32266
  if(this._collapsedRids) {
32205
32267
  if(this._collapsedRids[rid]) {
32206
32268
  return true;
@@ -32242,41 +32304,92 @@ DataView.prototype._sort = function() {
32242
32304
  };
32243
32305
 
32244
32306
  /** @private
32307
+ * @param {string} rid
32308
+ * @returns {boolean}
32309
+ */
32310
+ DataView.prototype._byRemovalMap = function(rid) {
32311
+ return !this._excludedRids[rid];
32312
+ };
32313
+ /** @private
32314
+ * @param {Object} removalMap
32245
32315
  * @param {Function} checker
32246
32316
  * @param {boolean} filteringOut
32247
32317
  * @param {Object=} exceptions
32318
+ * @returns {number} Number of rids that would be filtered out
32248
32319
  */
32249
- DataView.prototype._quickFilter = function(checker, filteringOut, exceptions) {
32320
+ DataView.prototype._getRemovalMap = function(removalMap, checker, filteringOut, exceptions) {
32250
32321
  if(!checker) {
32251
- return;
32322
+ return 0;
32252
32323
  }
32253
32324
 
32254
32325
  var rids = this._rids; // Make local variable to speed up the process
32255
- var len = rids.length;
32256
32326
  var dt = this._dt;
32257
- var spliceCount = 0;
32258
- for(var i = len; --i >= 0;) {
32259
- var rid = rids[i];
32260
- var removed = false;
32261
- if(!exceptions || !exceptions[rid]) {
32262
- var values = dt.getRowData(rid);
32327
+ var count = 0;
32328
+ var rid, i, values;
32329
+ var len = rids.length;
32330
+
32331
+ if(exceptions) {
32332
+ for(i = len; --i >= 0;) {
32333
+ rid = rids[i];
32334
+ if(!exceptions[rid]) {
32335
+ values = dt.getRowData(rid);
32336
+ if (values) {
32337
+ if(checker(rid, values) === filteringOut) {
32338
+ removalMap[rid] = 1;
32339
+ ++count;
32340
+ }
32341
+ } else {
32342
+ removalMap[rid] = 1;
32343
+ ++count;
32344
+ }
32345
+ }
32346
+ }
32347
+ } else {
32348
+ for(i = len; --i >= 0;) {
32349
+ rid = rids[i];
32350
+ values = dt.getRowData(rid);
32263
32351
  if (values) {
32264
- removed = checker(rid, values) === filteringOut;
32352
+ if(checker(rid, values) === filteringOut) {
32353
+ removalMap[rid] = 1;
32354
+ ++count;
32355
+ }
32265
32356
  } else {
32266
- removed = true;
32357
+ removalMap[rid] = 1;
32358
+ ++count;
32267
32359
  }
32268
32360
  }
32269
- if(removed) {
32270
- ++spliceCount;
32271
- } else if(spliceCount > 0) {
32272
- rids.splice(i + 1, spliceCount);
32273
- spliceCount = 0;
32274
- }
32275
32361
  }
32276
- if(spliceCount > 0) {
32277
- rids.splice(0, spliceCount);
32362
+ return count;
32363
+ };
32364
+ /** @private
32365
+ * @param {Object} removalMap
32366
+ * @param {Object} segmentRids
32367
+ * @returns {number} Number of rids that would be filtered out
32368
+ */
32369
+ DataView.prototype._getEmptySegments = function(removalMap, segmentRids) {
32370
+ var segments = this._dt._getSegmentSeparators();
32371
+ var count = 0;
32372
+ for(var segmentId in segmentRids) {
32373
+ var segment = segments.getSegment(segmentId);
32374
+ if(segment) {
32375
+ var chdr = segment.getChildren();
32376
+ var emptySegment = true;
32377
+ for(var childId in chdr) {
32378
+ if(!removalMap[childId]) {
32379
+ emptySegment = false;
32380
+ break;
32381
+ }
32382
+ }
32383
+ if(emptySegment) {
32384
+ removalMap[segmentId] = 1;
32385
+ ++count;
32386
+ }
32387
+ }
32278
32388
  }
32389
+
32390
+ return count;
32279
32391
  };
32392
+
32280
32393
  /** @private
32281
32394
  * @param {string|Function|undefined} cid
32282
32395
  * @param {*} value
@@ -32555,13 +32668,13 @@ DataView.prototype._removeGroupMember = function (groupIndex, groupId) {
32555
32668
  };
32556
32669
  /** @private
32557
32670
  * @param {string} cid
32558
- * @param {Object.<string, *>} values
32671
+ * @param {Object} values
32559
32672
  * @return {Array.<string>}
32560
32673
  */
32561
32674
  DataView.prototype._defaultGroupCriteria = function(cid, values) {
32562
32675
  var val = values[cid];
32563
32676
  if(Array.isArray(val)) {
32564
- return val.map(function(data) {
32677
+ return val.map(function(data) { // TODO: this is very slow
32565
32678
  return data + "";
32566
32679
  });
32567
32680
  } else {
@@ -32570,11 +32683,11 @@ DataView.prototype._defaultGroupCriteria = function(cid, values) {
32570
32683
  };
32571
32684
  /** @private
32572
32685
  * @param {string|null} rid
32573
- * @param {Object.<string, *>} values
32686
+ * @param {Object} values
32574
32687
  * @return {boolean}
32575
32688
  */
32576
32689
  DataView.prototype._groupFilterLogic = function(rid, values) {
32577
- var gids = this._groupCriteria[this._groupLevel - 1](values);
32690
+ var gids = this._groupCriteria[this._groupLevel - 1](values); // TODO: this is very slow
32578
32691
  return gids.indexOf(this._groupId) >= 0;
32579
32692
  };
32580
32693
 
@@ -36014,7 +36127,7 @@ Core.prototype._batches = null;
36014
36127
  * @return {string}
36015
36128
  */
36016
36129
  Core.getVersion = function () {
36017
- return "5.1.67";
36130
+ return "5.1.71";
36018
36131
  };
36019
36132
  /** {@link ElementWrapper#dispose}
36020
36133
  * @override
@@ -39941,7 +40054,14 @@ Core.prototype.stopBatch = function (batchType) {
39941
40054
  if(!batchType){
39942
40055
  return false;
39943
40056
  }
40057
+ // The "columnVisibilityChanged" event is blocked while the "reset" batch operation is in progress, so this event will not be fired until the batch operation succeeds.
40058
+ if(batchType === "reset") {
40059
+ this._disableEvent("columnVisibilityChanged", true);
40060
+ }
39944
40061
  this._dispatch("afterBatchOperation", { batches: this._batches, batchType: batchType });
40062
+ if(batchType === "reset") {
40063
+ this._disableEvent("columnVisibilityChanged", false);
40064
+ }
39945
40065
 
39946
40066
  delete this._batches[batchType];
39947
40067
  if(isEmptyObject(this._batches)){
@@ -40408,13 +40528,10 @@ Core.prototype._onSectionDataChanged = function (e) {
40408
40528
  for (var r = fromR; r < toR; ++r) {
40409
40529
  if(hasDataView) {
40410
40530
  var rowData = rowDataCollection[r];
40411
- if(!rowData) { // This is a header row
40412
- continue;
40413
- }
40414
40531
 
40415
40532
  e["rowData"] = rowData;
40416
40533
  e["rowId"] = rids[r];
40417
- e["dataValue"] = rowData[cid];
40534
+ e["dataValue"] = rowData ? rowData[cid] : null;
40418
40535
  }
40419
40536
  e["rowIndex"] = r;
40420
40537
  e["cell"] = section["getCell"](c, r, false); // Accessing cell by using bracket allows extenal object to mock Section
@@ -42955,7 +43072,7 @@ SortableTitlePlugin.prototype.sortColumns = function (sortOptions, opt_arg) {
42955
43072
  opt["sortOrder"] || opt["order"]
42956
43073
  );
42957
43074
  if (state) {
42958
- states[i] = state;
43075
+ states.push(state);
42959
43076
  }
42960
43077
  }
42961
43078
  this._sortColumn(states, opt_arg);
@@ -43537,10 +43654,12 @@ SortableTitlePlugin.prototype.sortSeparators = function (comparer) {
43537
43654
  var sortOrders = [];
43538
43655
  var sortFields = [];
43539
43656
  var sortStateCount = this._sortStates.length;
43657
+ var rowDefField = SortableTitlePlugin._toRowDefField();
43540
43658
  for(var i = 0; i < sortStateCount; i++){
43541
43659
  var sortState = this._sortStates[i];
43660
+ var field = this._rowDefMode ? rowDefField : sortState["field"];
43542
43661
  sortOrders.push(sortState["sortOrder"]);
43543
- sortFields.push(sortState["field"]);
43662
+ sortFields.push(field);
43544
43663
  }
43545
43664
  dv.sortSeparators(sortLogics, sortOrders, sortFields);
43546
43665
  }
@@ -44241,15 +44360,6 @@ var cloneRowData = function(fromRowDef, toRowDef) {
44241
44360
  }
44242
44361
  };
44243
44362
 
44244
- /** @private
44245
- * @param {string} sortField
44246
- * @param {Object} elemData
44247
- * @param {number} index
44248
- */
44249
- var mapRowOrder = function (sortField, elemData, index) { // edit name
44250
- elemData[sortField] = index; // Make column for sort with user data array
44251
- };
44252
-
44253
44363
  /** @private
44254
44364
  * @param {RowDefinition} rowDef
44255
44365
  * @return {boolean}
@@ -44334,6 +44444,19 @@ var _hasFieldOrId = function(colDef, str) {
44334
44444
  return (colDef.getField() === str) || (colDef.getId() === str);
44335
44445
  };
44336
44446
 
44447
+ /** Compare the difference in the 'id' property.
44448
+ * @private
44449
+ * @param {Object} obj1
44450
+ * @param {Object} obj2
44451
+ * @returns {boolean} If the id property of two objects is equal, the return will be true, otherwise it will be false.
44452
+ */
44453
+ var _hasMatchingId = function(obj1, obj2) {
44454
+ if(!obj1 || !obj2 || !obj1.id || !obj2.id) { // Handle nullable, if the object or id have null, it's means difference value
44455
+ return false;
44456
+ }
44457
+ return obj1.id === obj2.id;
44458
+ };
44459
+
44337
44460
  /** @constructor
44338
44461
  * @extends {EventDispatcher}
44339
44462
  * @param {(Element|null)=} placeholder
@@ -44883,7 +45006,6 @@ Grid.prototype.initialize = function(gridOption) {
44883
45006
 
44884
45007
  if (gridOption["fieldCaching"]) {
44885
45008
  t._fieldCaching = gridOption["fieldCaching"];
44886
- js_FieldDefinition.setFieldCaching(t._fieldCaching);
44887
45009
  }
44888
45010
 
44889
45011
  if(gridOption["timeSeriesExpansion"] != null) {
@@ -45633,8 +45755,8 @@ Grid.prototype.replaceColumn = function (columnOption, colRef) {
45633
45755
  * @param {Object} response
45634
45756
  */
45635
45757
  Grid.prototype._onFieldLoadedSuccess = function (field, colDef, response) {
45636
- if (response && response.fieldDefinition) {
45637
- var fieldDef = response.fieldDefinition;
45758
+ if (response && response.id) {
45759
+ var fieldDef = response;
45638
45760
  if (colDef && colDef.getField() === field) {
45639
45761
  if (colDef.isDefaultName() && fieldDef.name) {
45640
45762
  colDef.setName(fieldDef.name);
@@ -45682,6 +45804,34 @@ Grid.prototype._setScrollbarParent = function (host) {
45682
45804
  this._grid.getHScrollbar().attachToExternalElement(host);
45683
45805
  };
45684
45806
 
45807
+ /** Get stored field information. If field information has not been requested or no data has been received yet, null value is returned.
45808
+ * @public
45809
+ * @function
45810
+ * @param {string} field
45811
+ * @return {Object}
45812
+ */
45813
+ Grid.prototype.getFieldInfo = function(field) {
45814
+ return js_FieldDefinition.getFieldInfo(field);
45815
+ };
45816
+ /** Request field information from Synapse service. If field information already exists, a resolved promise is returned. Synapse config must be supplied before the request can be made.
45817
+ * @public
45818
+ * @function
45819
+ * @param {string} field
45820
+ * @return {Promise}
45821
+ * @example
45822
+ * var gridConfig = {
45823
+ * synapse: { // define synapse configuration
45824
+ * apiKey: "xxx",
45825
+ * contextApp: "xxx",
45826
+ * auth: "xxx" (optional)
45827
+ * }
45828
+ * };
45829
+ * var promise = grid.loadFieldInfo("CF_LAST");
45830
+ */
45831
+ Grid.prototype.loadFieldInfo = function(field) {
45832
+ return js_FieldDefinition.loadFieldInfo(field);
45833
+ };
45834
+
45685
45835
  /**
45686
45836
  * @private
45687
45837
  * @param {string} field
@@ -45740,8 +45890,9 @@ Grid.prototype.setColumns = function(columns) {
45740
45890
  /** Remove, add and keep column based on the given column data
45741
45891
  * @public
45742
45892
  * @param {Array.<Object>} columns Array of column options
45893
+ * @param {boolean=} byId=false, if enable it, this method will only check for differences in the 'id' property
45743
45894
  */
45744
- Grid.prototype.restoreColumns = function(columns) {
45895
+ Grid.prototype.restoreColumns = function(columns, byId) {
45745
45896
  var grid = this._grid;
45746
45897
  grid.startBatch("reset");
45747
45898
  var configObj = this.getConfigObject();
@@ -45750,6 +45901,7 @@ Grid.prototype.restoreColumns = function(columns) {
45750
45901
  var preColLen = previousColumns.length;
45751
45902
  var newColLen = columns.length;
45752
45903
 
45904
+ var compareLogic = byId ? _hasMatchingId : deepEqual;
45753
45905
  var removingFields = [];
45754
45906
  var keepingColumns = [];
45755
45907
  var columnOrdering = [];
@@ -45759,7 +45911,7 @@ Grid.prototype.restoreColumns = function(columns) {
45759
45911
  for (i = 0; i < preColLen; i++) {
45760
45912
  found = false;
45761
45913
  for (j = 0; j < newColLen; j++) {
45762
- if (deepEqual(previousColumns[i], columns[j])) {
45914
+ if(compareLogic(previousColumns[i], columns[j])) {
45763
45915
  keepingColumns.push(previousColumns[i]);
45764
45916
  found = true;
45765
45917
  break;
@@ -45780,7 +45932,7 @@ Grid.prototype.restoreColumns = function(columns) {
45780
45932
  for (i = 0; i < newColLen; i++) {
45781
45933
  found = false;
45782
45934
  for (j = 0; j < keepingLen; j++) { // loop only keeping column
45783
- if (deepEqual(columns[i], keepingColumns[j])) {
45935
+ if(compareLogic(columns[i], keepingColumns[j])) {
45784
45936
  found = true;
45785
45937
  var colIndex = this.getColumnIndex(columns[i].field); // We cannot use 'i' (colIndex) in this case, as it will sort the columns. Instead, we need to obtain a new column index from the field.
45786
45938
  columnOrdering.push(this.getColumnId(colIndex));
@@ -46459,20 +46611,11 @@ Grid.prototype.updateDataSet = function(records, rowIdentifier) {
46459
46611
  }
46460
46612
 
46461
46613
  // Map new data index
46462
- var newDataMap = {};
46463
46614
  var recordCount = records.length;
46464
- var record, i;
46465
- for (i = 0; i < recordCount; i++) {
46466
- record = records[i];
46467
- newDataMap[record[rowIdentifier]] = record; // Assign a new data map to compare to the previous data
46468
- }
46469
-
46470
46615
  var fieldSorting = "ROW_ORDER"; // TODO: Should be config by options
46471
- records.forEach(mapRowOrder.bind(null, fieldSorting));
46472
-
46473
46616
  var oldDataMap = {};
46474
- var rowDef, id;
46475
- var rowDefs = this.getRowDefinitions(); // WARNING: Filtered and hidden rows are not included
46617
+ var rowDef, id, record, i;
46618
+ var rowDefs = this.getAllRowDefinitions(); // Include the filter/hidden rows
46476
46619
  var rowDefCount = rowDefs.length;
46477
46620
  for (i = 0; i < rowDefCount; i++) {
46478
46621
  rowDef = rowDefs[i];
@@ -46486,26 +46629,35 @@ Grid.prototype.updateDataSet = function(records, rowIdentifier) {
46486
46629
  }
46487
46630
  }
46488
46631
 
46489
- // Check Remove previous data
46490
- for (var rowIdentifierName in oldDataMap) {
46491
- if (oldDataMap[rowIdentifierName] && !newDataMap[rowIdentifierName]) {
46492
- this.removeRow(oldDataMap[rowIdentifierName]); // Slow
46493
- }
46494
- }
46495
-
46496
46632
  // Check Update and Insert
46497
- for (i = 0; i < recordCount; i++) {
46633
+ var idMap = {};
46634
+ var newDataMap = {};
46635
+ for (i = recordCount - 1; i >= 0; i--) {
46498
46636
  record = records[i];
46499
46637
  id = record[rowIdentifier];
46500
46638
  rowDef = oldDataMap[id];
46639
+ newDataMap[id] = record; // Assign a new data map to compare to the previous data
46640
+ record[fieldSorting] = i;
46641
+ if(idMap[id]) { // Prevent assign data in duplicate row
46642
+ continue;
46643
+ }
46644
+ idMap[id] = true;
46501
46645
  if (!rowDef) {
46502
- this.insertRow({ values: newDataMap[id]}); // Insert last position
46646
+ this.insertRow({ values: record}); // Insert last position
46503
46647
  } else {
46504
46648
  rowDef.setRowData(record);
46505
46649
  }
46506
46650
  }
46651
+
46652
+ // Check Remove previous data
46653
+ for (var rowIdentifierName in oldDataMap) {
46654
+ if (oldDataMap[rowIdentifierName] && !newDataMap[rowIdentifierName]) {
46655
+ this.removeRow(oldDataMap[rowIdentifierName]); // Slow
46656
+ }
46657
+ }
46658
+
46507
46659
  // Sorting
46508
- this._dt.sortOnce("ROW_DEF", "a", compareNumber, fieldSorting);
46660
+ this._dt.sortOnce(ROW_DEF, "a", compareNumber, fieldSorting);
46509
46661
  };
46510
46662
  /** @private
46511
46663
  * @param {Array|Object} item
@@ -49674,7 +49826,11 @@ var _joinSubKeys = function(subA, subB) {
49674
49826
  */
49675
49827
  var _isDynamicChain = function(ric) {
49676
49828
  // Dynamic chain will be 2 . (dot) for example .PG.PA
49677
- return ric.match(/\./g).length > 1;
49829
+ var matching = ric.match(/\./g); // Can be null when doesn't found dot(.)
49830
+ if(matching) {
49831
+ return matching.length > 1;
49832
+ }
49833
+ return false;
49678
49834
  };
49679
49835
 
49680
49836
  /** @private