@refinitiv-ui/efx-grid 6.0.12 → 6.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/lib/core/dist/core.js +1209 -160
  2. package/lib/core/dist/core.min.js +1 -1
  3. package/lib/core/es6/data/DataCache.js +1 -1
  4. package/lib/core/es6/data/DataTable.d.ts +18 -3
  5. package/lib/core/es6/data/DataTable.js +203 -17
  6. package/lib/core/es6/data/DataView.d.ts +8 -1
  7. package/lib/core/es6/data/DataView.js +30 -2
  8. package/lib/core/es6/data/Segment.d.ts +36 -11
  9. package/lib/core/es6/data/Segment.js +575 -59
  10. package/lib/core/es6/data/SegmentCollection.d.ts +15 -1
  11. package/lib/core/es6/data/SegmentCollection.js +236 -80
  12. package/lib/core/es6/grid/Core.js +1 -1
  13. package/lib/grid/index.js +1 -1
  14. package/lib/grid/lib/efx-grid.js +1 -1
  15. package/lib/row-segmenting/es6/RowSegmenting.d.ts +2 -0
  16. package/lib/row-segmenting/es6/RowSegmenting.js +26 -3
  17. package/lib/rt-grid/dist/rt-grid.js +1144 -158
  18. package/lib/rt-grid/dist/rt-grid.min.js +1 -1
  19. package/lib/rt-grid/es6/ColumnDefinition.d.ts +6 -1
  20. package/lib/rt-grid/es6/ColumnDefinition.js +29 -0
  21. package/lib/rt-grid/es6/Grid.d.ts +2 -0
  22. package/lib/rt-grid/es6/Grid.js +53 -0
  23. package/lib/rt-grid/es6/RowDefinition.js +22 -2
  24. package/lib/tr-grid-column-grouping/es6/ColumnGrouping.d.ts +1 -0
  25. package/lib/tr-grid-column-grouping/es6/ColumnGrouping.js +194 -366
  26. package/lib/tr-grid-column-stack/es6/ColumnStack.d.ts +24 -4
  27. package/lib/tr-grid-column-stack/es6/ColumnStack.js +177 -52
  28. package/lib/tr-grid-util/es6/RowPainter.d.ts +2 -1
  29. package/lib/tr-grid-util/es6/RowPainter.js +7 -1
  30. package/lib/tr-grid-util/es6/jet/mockDataAPI.d.ts +1 -0
  31. package/lib/tr-grid-util/es6/jet/mockDataAPI.js +191 -52
  32. package/lib/types/es6/ColumnGrouping.d.ts +1 -0
  33. package/lib/types/es6/ColumnStack.d.ts +24 -4
  34. package/lib/types/es6/Core/data/DataTable.d.ts +18 -3
  35. package/lib/types/es6/Core/data/DataView.d.ts +8 -1
  36. package/lib/types/es6/Core/data/Segment.d.ts +36 -11
  37. package/lib/types/es6/Core/data/SegmentCollection.d.ts +15 -1
  38. package/lib/types/es6/RealtimeGrid/ColumnDefinition.d.ts +6 -1
  39. package/lib/types/es6/RealtimeGrid/Grid.d.ts +2 -0
  40. package/lib/types/es6/RowSegmenting.d.ts +2 -0
  41. package/lib/versions.json +4 -4
  42. package/package.json +1 -1
@@ -11788,7 +11788,7 @@ DataCache_DataCache.prototype._cloneRowData = function (obj, ric, newSubId) {
11788
11788
 
11789
11789
  /** @protected
11790
11790
  * @ignore
11791
- * @type {!Object.<string, Object.<string, *>>}
11791
+ * @type {!Object.<string, Object>}
11792
11792
  */
11793
11793
  DataCache_DataCache.prototype._rows;
11794
11794
 
@@ -11873,15 +11873,220 @@ DataCache_DataCache._proto = DataCache_DataCache.prototype;
11873
11873
  /* harmony default export */ const data_DataCache = (DataCache_DataCache);
11874
11874
 
11875
11875
 
11876
+ ;// CONCATENATED MODULE: ./node_modules/tr-grid-util/es6/EventDispatcher.js
11877
+ /** Abstract base class that provides event management methods for derived class
11878
+ * @constructor
11879
+ */
11880
+ var EventDispatcher_EventDispatcher = function () {};
11881
+
11882
+ /** @type {Object.<string, Function>}
11883
+ * @protected
11884
+ * @ignore
11885
+ */
11886
+ EventDispatcher_EventDispatcher.prototype._events = null;
11887
+ /** @type {number}
11888
+ * @protected
11889
+ * @ignore
11890
+ */
11891
+ EventDispatcher_EventDispatcher.prototype._listenerCount = 0;
11892
+
11893
+ //#region public function of event
11894
+ /** Add the function handler into the specific event.
11895
+ * @public
11896
+ * @param {string} type Event name
11897
+ * @param {Function} handler Event handler
11898
+ */
11899
+ EventDispatcher_EventDispatcher.prototype.addEventListener = function(type, handler) {
11900
+ if(!type || !handler) { return; }
11901
+ if(!this._events) {
11902
+ this._events = {};
11903
+ }
11904
+
11905
+ var listeners = this._events[type];
11906
+ if(listeners) {
11907
+ if(listeners.indexOf(handler) < 0) {
11908
+ listeners.push(handler);
11909
+ ++this._listenerCount;
11910
+ }
11911
+ } else {
11912
+ this._events[type] = [handler];
11913
+ ++this._listenerCount;
11914
+ }
11915
+ };
11916
+ /** Remove the function handler from the specific event.
11917
+ * @public
11918
+ * @param {string} type Event name
11919
+ * @param {Function} handler Event handler
11920
+ */
11921
+ EventDispatcher_EventDispatcher.prototype.removeEventListener = function(type, handler) {
11922
+ var listeners = (this._events) ? this._events[type] : null;
11923
+ if(listeners) {
11924
+ var at = listeners.indexOf(handler);
11925
+ if(at >= 0) {
11926
+ listeners.splice(at, 1);
11927
+ --this._listenerCount;
11928
+ }
11929
+ }
11930
+ };
11931
+ /** Remove all function handlers from all events.
11932
+ * @public
11933
+ */
11934
+ EventDispatcher_EventDispatcher.prototype.removeAllEventListeners = function() {
11935
+ this._events = null;
11936
+ this._listenerCount = 0;
11937
+ };
11938
+
11939
+ /** Check whether the specified event has a function handler.
11940
+ * @public
11941
+ * @param {string} type Event name
11942
+ * @return {boolean}
11943
+ */
11944
+ EventDispatcher_EventDispatcher.prototype.hasListener = function(type) {
11945
+ if(this._listenerCount) {
11946
+ if(type) {
11947
+ var listeners = this._events ? this._events[type] : null;
11948
+ return listeners ? (listeners.length > 0) : false;
11949
+ } else {
11950
+ return true;
11951
+ }
11952
+ } else {
11953
+ return false;
11954
+ }
11955
+ };
11956
+ /** Get event listener (function handler) from the specified event.
11957
+ * @public
11958
+ * @param {string} type Event name
11959
+ * @param {number=} idx=0 Index of the listener to be retrieved. This is used when there are multiple event listeners
11960
+ * @return {Function}
11961
+ */
11962
+ EventDispatcher_EventDispatcher.prototype.getListener = function(type, idx) {
11963
+ if(type) {
11964
+ var listeners = this._events ? this._events[type] : null;
11965
+ if(listeners) {
11966
+ if(!idx) {
11967
+ idx = 0;
11968
+ }
11969
+ return listeners[idx] || null;
11970
+ }
11971
+ }
11972
+ return null;
11973
+ };
11974
+ /** A shorthand to retrieve function from an object and add it as an Eventlistener
11975
+ * @public
11976
+ * @function
11977
+ * @param {Object} obj Object that contains a handler with the same name as the given `type`
11978
+ * @param {string} type Event name
11979
+ * @example
11980
+ * var obj = {"mouseUp": function(e) { console.log(e); }};
11981
+ * plugin.addListener(obj, "mouseUp");
11982
+ * plugin.addListener(obj, "mouseDown");
11983
+ */
11984
+ EventDispatcher_EventDispatcher.prototype.addListener = function(obj, type) {
11985
+ var func = obj ? obj[type] : null;
11986
+ if(typeof func === "function") {
11987
+ this.addEventListener(type, func);
11988
+ }
11989
+ };
11990
+
11991
+ /** Executed before dispatching, allowing modification of user's event argument object
11992
+ * @protected
11993
+ * @ignore
11994
+ * @param {string} type Event name
11995
+ * @param {Object} eventArg User's event argument object
11996
+ * @return {Object} New event argument object
11997
+ */
11998
+ EventDispatcher_EventDispatcher.prototype._prepareEventArguments = function(type, eventArg) {
11999
+ return eventArg;
12000
+ };
12001
+
12002
+ /** Publish the data to the listener.
12003
+ * @protected
12004
+ * @ignore
12005
+ * @param {string} type Event name
12006
+ * @param {Object} eventArg Event arguments
12007
+ */
12008
+ EventDispatcher_EventDispatcher.prototype._dispatch = function(type, eventArg) {
12009
+ var listeners = this._events ? this._events[type] : null;
12010
+ if(listeners) {
12011
+ eventArg = this._prepareEventArguments(type, eventArg);
12012
+ var len = listeners.length;
12013
+ for(var i = 0; i < len; ++i) {
12014
+ listeners[i](eventArg);
12015
+ }
12016
+ }
12017
+ };
12018
+
12019
+ /** @public
12020
+ * @function
12021
+ * @param {Event} e
12022
+ */
12023
+ var preventDefault = function(e) {
12024
+ if(e && e.preventDefault) {
12025
+ e.preventDefault();
12026
+ e.stopPropagation();
12027
+ }
12028
+ };
12029
+
12030
+ /** @public
12031
+ * @function
12032
+ * @param {Event} e
12033
+ */
12034
+ EventDispatcher_EventDispatcher.preventDefault = preventDefault;
12035
+
12036
+ /* harmony default export */ const es6_EventDispatcher = (EventDispatcher_EventDispatcher);
12037
+
12038
+
11876
12039
  ;// CONCATENATED MODULE: ./src/js/data/Segment.js
12040
+
12041
+
12042
+
11877
12043
  /** @constructor
11878
12044
  * @param {string} rid
12045
+ * @param {!Object} sharedObj
11879
12046
  */
11880
- var Segment = function(rid) {
12047
+ var Segment = function(rid, sharedObj) {
11881
12048
  this._rid = rid;
11882
12049
  this._children = {};
12050
+ this._shared = sharedObj;
12051
+ };
12052
+ es6_Ext.inherits(Segment, es6_EventDispatcher);
12053
+
12054
+ /** @private
12055
+ * @function
12056
+ * @param {string} a
12057
+ * @param {string} b
12058
+ * @return {number}
12059
+ */
12060
+ Segment._subSegSortLogic = function(a, b) {
12061
+ if(a === "Uncategorized") {
12062
+ return 1;
12063
+ }
12064
+ if(b === "Uncategorized") {
12065
+ return -1;
12066
+ }
12067
+
12068
+ if(a < b) {
12069
+ return -1;
12070
+ }
12071
+ if(b < a) {
12072
+ return 1;
12073
+ }
12074
+
12075
+ return 0;
12076
+ };
12077
+ /** @private
12078
+ * @function
12079
+ * @param {Segment} segment
12080
+ * @param {number} idx
12081
+ */
12082
+ Segment._assignSubSegmentOrder = function(segment, idx) {
12083
+ segment.setOrder(idx + 1);
11883
12084
  };
11884
12085
 
12086
+ /** @type {Object}
12087
+ * @private
12088
+ */
12089
+ Segment.prototype._shared = null;
11885
12090
 
11886
12091
  /** @type {string}
11887
12092
  * @private
@@ -11902,13 +12107,67 @@ Segment.prototype._collapsed = false;
11902
12107
  /** @type {number}
11903
12108
  * @private
11904
12109
  */
11905
- Segment.prototype._value = 0;
12110
+ Segment.prototype._order = 0;
12111
+ /** @type {boolean}
12112
+ * @private
12113
+ */
12114
+ Segment.prototype._disposed = false;
12115
+
12116
+ /** @type {Object}
12117
+ * @private
12118
+ */
12119
+ Segment.prototype._subSegDef = null;
11906
12120
  /** @type {number}
11907
12121
  * @private
11908
12122
  */
11909
- Segment.prototype._order = 0;
12123
+ Segment.prototype._subSegLevel = 0;
12124
+ /** @type {Object.<string, Segment>}
12125
+ * @private
12126
+ */
12127
+ Segment.prototype._subSegMap = null; // For immediate sub-segment children
12128
+ /** @type {Array.<string>}
12129
+ * @private
12130
+ */
12131
+ Segment.prototype._subSegNames = null; // For immediate sub-segment child names
12132
+ /** @type {string}
12133
+ * @private
12134
+ */
12135
+ Segment.prototype._subSegName = "";
12136
+ /** @type {*}
12137
+ * @private
12138
+ */
12139
+ Segment.prototype._subSegVal;
12140
+ /** @type {Segment}
12141
+ * @private
12142
+ */
12143
+ Segment.prototype._subSegParent = null;
11910
12144
 
11911
12145
 
12146
+ /** @public
12147
+ */
12148
+ Segment.prototype.dispose = function() {
12149
+ if(this._disposed) {
12150
+ return;
12151
+ }
12152
+ this._disposed = true;
12153
+
12154
+ this.removeAllEventListeners();
12155
+ var segmentNames = this._subSegNames;
12156
+ if(segmentNames) {
12157
+ var segmentCount = segmentNames.length;
12158
+ var segmentMap = this._subSegMap;
12159
+ for(var i = 0; i < segmentCount; ++i) {
12160
+ segmentMap[segmentNames[i]].dispose();
12161
+ }
12162
+ this._subSegMap = this._subSegNames = null;
12163
+ }
12164
+ if(this._collapsed) {
12165
+ this._shared.dirtyCollapsingState = true;
12166
+ }
12167
+
12168
+ this._shared = null;
12169
+ this._subSegParent = this._subSegDef = this._subSegVal = null;
12170
+ };
11912
12171
  /** @public
11913
12172
  * @return {string}
11914
12173
  */
@@ -11916,32 +12175,66 @@ Segment.prototype.getId = function() {
11916
12175
  return this._rid;
11917
12176
  };
11918
12177
  /** @public
12178
+ * @return {string}
12179
+ */
12180
+ Segment.prototype.getParentId = function() {
12181
+ if(this._subSegParent) {
12182
+ return this._subSegParent.getId();
12183
+ }
12184
+ return "";
12185
+ };
12186
+ /** @public
12187
+ * @param {Array.<string>=} out_ary
12188
+ * @return {Array.<string>}
12189
+ */
12190
+ Segment.prototype.getSubSegmentIds = function(out_ary) {
12191
+ var segmentNames = this._subSegNames;
12192
+ if(segmentNames) {
12193
+ if(!out_ary) {
12194
+ out_ary = [];
12195
+ }
12196
+ var segmentCount = segmentNames.length;
12197
+ var segmentMap = this._subSegMap;
12198
+ for(var i = 0; i < segmentCount; ++i) {
12199
+ var segmentName = segmentNames[i];
12200
+ var segment = segmentMap[segmentName];
12201
+ out_ary.push(segment.getId());
12202
+ segment.getSubSegmentIds(out_ary);
12203
+ }
12204
+
12205
+ return out_ary;
12206
+ }
12207
+ return null;
12208
+ };
12209
+ /** @public
11919
12210
  * @param {string} rid
11920
- * @param {Object=} objMap
12211
+ * @param {string=} dataId Row id for retrieving data
11921
12212
  * @return {boolean}
11922
12213
  */
11923
- Segment.prototype.addChild = function(rid, objMap) {
11924
- if(rid && !this._children[rid]) {
11925
- if(objMap) {
11926
- objMap[rid] = this._rid;
12214
+ Segment.prototype.addChild = function(rid, dataId) {
12215
+ if(rid) {
12216
+ this._shared.childToSegment[rid] = this._rid;
12217
+ if(this._collapsed) {
12218
+ this._shared.dirtyCollapsingState = true; // TODO: Check if we need to update this only when new child is added
12219
+ }
12220
+ if(!this._children[rid]) {
12221
+ this._children[rid] = dataId || rid;
12222
+ ++this._childCount;
12223
+ return true;
11927
12224
  }
11928
- this._children[rid] = 1;
11929
- ++this._childCount;
11930
- return true;
11931
12225
  }
11932
12226
  return false;
11933
12227
  };
11934
12228
  /** @public
11935
12229
  * @param {Array.<string>} rids
11936
- * @param {Object=} objMap
11937
12230
  * @return {boolean}
11938
12231
  */
11939
- Segment.prototype.addChildren = function(rids, objMap) {
12232
+ Segment.prototype.addChildren = function(rids) {
11940
12233
  var rowIds = Array.isArray(rids) ? rids : [rids];
11941
12234
  var rowCount = rowIds.length;
11942
12235
  var dirty = 0;
11943
12236
  for(var i = 0; i < rowCount; ++i) {
11944
- dirty |= this.addChild(rowIds[i], objMap);
12237
+ dirty |= this.addChild(rowIds[i]);
11945
12238
  }
11946
12239
  return dirty ? true : false;
11947
12240
  };
@@ -11954,26 +12247,37 @@ Segment.prototype.containsChild = function(rid) {
11954
12247
  };
11955
12248
  /** @public
11956
12249
  * @param {string} rid
11957
- * @param {Object=} objMap
11958
12250
  * @return {boolean}
11959
12251
  */
11960
- Segment.prototype.removeChild = function(rid, objMap) {
11961
- if(this._childCount && this._children[rid]) {
11962
- if(objMap) {
11963
- delete objMap[rid];
11964
- }
11965
- delete this._children[rid]; // Slow
11966
- --this._childCount;
11967
- return true;
12252
+ Segment.prototype.removeChild = function(rid) {
12253
+ if(this._subSegLevel) {
12254
+ return false; // Sub segments are not allowed to remove its children
11968
12255
  }
11969
- return false;
12256
+ if(!this._childCount) {
12257
+ return false;
12258
+ }
12259
+ if(!this._children[rid]) {
12260
+ return false; // The specified rid is not a child of this segment
12261
+ }
12262
+
12263
+ var objMap = this._shared.childToSegment;
12264
+ delete objMap[rid];
12265
+ delete this._children[rid]; // Slow
12266
+ --this._childCount;
12267
+
12268
+ if(this._collapsed) {
12269
+ this._shared.dirtyCollapsingState = true;
12270
+ }
12271
+ return true;
11970
12272
  };
11971
12273
  /** @public
11972
12274
  * @param {Array.<string>} rids
11973
- * @param {Object=} objMap
11974
12275
  * @return {boolean}
11975
12276
  */
11976
- Segment.prototype.removeChildren = function(rids, objMap) {
12277
+ Segment.prototype.removeChildren = function(rids) {
12278
+ if(this._subSegLevel) {
12279
+ return false; // Sub segments are not allowed to remove its children
12280
+ }
11977
12281
  if(!this._childCount) {
11978
12282
  return false;
11979
12283
  }
@@ -11981,7 +12285,7 @@ Segment.prototype.removeChildren = function(rids, objMap) {
11981
12285
  var rowCount = rowIds.length;
11982
12286
  var dirty = 0;
11983
12287
  for(var i = 0; i < rowCount; ++i) {
11984
- dirty |= this.removeChild(rowIds[i], objMap);
12288
+ dirty |= this.removeChild(rowIds[i]);
11985
12289
  }
11986
12290
  return dirty ? true : false;
11987
12291
  };
@@ -11989,21 +12293,27 @@ Segment.prototype.removeChildren = function(rids, objMap) {
11989
12293
  * @param {Object=} objMap
11990
12294
  * @return {boolean}
11991
12295
  */
11992
- Segment.prototype.removeAllChildren = function(objMap) {
11993
- if(this._childCount) {
11994
- if(objMap) {
11995
- var chdr = this._children;
11996
- for(var rid in chdr) {
11997
- if(objMap[rid]) {
11998
- delete objMap[rid];
11999
- }
12000
- }
12296
+ Segment.prototype.removeAllChildren = function() {
12297
+ if(this._subSegLevel) {
12298
+ return false; // Sub segments are not allowed to remove its children
12299
+ }
12300
+ if(!this._childCount) {
12301
+ return false;
12302
+ }
12303
+ var objMap = this._shared.childToSegment;
12304
+ var chdr = this._children;
12305
+ for(var rid in chdr) {
12306
+ if(objMap[rid]) {
12307
+ delete objMap[rid]; // TODO: Check if we need to do this
12001
12308
  }
12002
- this._children = {};
12003
- this._childCount = 0;
12004
- return true;
12005
12309
  }
12006
- return false;
12310
+ this._children = {};
12311
+ this._childCount = 0;
12312
+
12313
+ if(this._collapsed) {
12314
+ this._shared.dirtyCollapsingState = true;
12315
+ }
12316
+ return true;
12007
12317
  };
12008
12318
  /** @public
12009
12319
  * @return {!Array.<string>}
@@ -12019,6 +12329,309 @@ Segment.prototype.getChildCount = function() {
12019
12329
  };
12020
12330
 
12021
12331
 
12332
+ /** @public
12333
+ * @return {Array.<string>} fields
12334
+ */
12335
+ Segment.prototype.getClassification = function() {
12336
+ if(this._subSegDef) {
12337
+ return this._subSegDef.classifiers || null;
12338
+ }
12339
+ return null;
12340
+ };
12341
+ /** @public
12342
+ * @param {string|Array.<string>} fields
12343
+ * @return {boolean}
12344
+ */
12345
+ Segment.prototype.setClassification = function(fields) {
12346
+ if(this._subSegLevel) {
12347
+ return false; // non-root segment cannot be classified
12348
+ }
12349
+ var classifiers = null;
12350
+ if(this._subSegDef) {
12351
+ classifiers = this._subSegDef.classifiers;
12352
+ }
12353
+
12354
+ var newClassifiers = null;
12355
+ if(fields) {
12356
+ if(typeof fields === "string") {
12357
+ newClassifiers = [fields];
12358
+ } else if(Array.isArray(fields)) {
12359
+ newClassifiers = fields;
12360
+ }
12361
+ }
12362
+ var i;
12363
+ var fieldCount = newClassifiers ? newClassifiers.length : 0;
12364
+
12365
+ if(fieldCount) {
12366
+ var curCount = classifiers ? classifiers.length : 0;
12367
+ if(curCount === fieldCount) { // Check duplication
12368
+ for(i = 0; i < fieldCount; ++i) {
12369
+ if(newClassifiers[i] !== classifiers[i]) {
12370
+ break;
12371
+ }
12372
+ }
12373
+ if(i >= fieldCount) {
12374
+ return false; // nothing has change
12375
+ }
12376
+ }
12377
+
12378
+ if(!this._subSegDef) {
12379
+ this._subSegDef = {
12380
+ root: this,
12381
+ subSegments: null
12382
+ };
12383
+ }
12384
+
12385
+ this._subSegDef.classifiers = newClassifiers;
12386
+ // this._subSegDef.classifierChanged = true;
12387
+ return true;
12388
+ } else if(classifiers) { // Remove existing ones
12389
+ this._subSegDef.classifiers = null;
12390
+ this._subSegDef.subSegments = null;
12391
+ // this._subSegDef.classifierChanged = true;
12392
+ this._subSegDef = null; // WARNING: All sub segments remain existing
12393
+ return true;
12394
+ }
12395
+ return false;
12396
+ };
12397
+ /** @public
12398
+ * @param {Object.<string, Object>=} rows Object maps between row id and its record
12399
+ * @return {boolean}
12400
+ */
12401
+ Segment.prototype.classify = function(rows) {
12402
+ var classifiers = this._subSegDef ? this._subSegDef.classifiers : null;
12403
+ var classifierCount = classifiers ? classifiers.length : 0;
12404
+
12405
+ var segmentNames = this._subSegNames;
12406
+ var segmentCount = segmentNames ? segmentNames.length : 0;
12407
+
12408
+ if(!segmentCount) {
12409
+ if(this._subSegLevel >= classifierCount) {
12410
+ return false; // Current segment level is beyond existing classification level and this segment should already be removed
12411
+ }
12412
+ }
12413
+
12414
+ // Prepare existing sub segments for checking change in its members
12415
+ var i;
12416
+ var segmentName = "";
12417
+ var nonExistenceGroups = {};
12418
+ var removalCount = 0;
12419
+ var segmentMap = this._subSegMap;
12420
+ var segment = null;
12421
+ if(segmentCount) {
12422
+ removalCount = segmentCount;
12423
+ for(i = 0; i < removalCount; ++i) {
12424
+ segmentName = segmentNames[i];
12425
+ nonExistenceGroups[segmentName] = 1;
12426
+
12427
+ segment = segmentMap[segmentName];
12428
+ if(segment._childCount) { // Quick cleaning up
12429
+ segment._children = {};
12430
+ segment._childCount = 0;
12431
+ }
12432
+ }
12433
+ }
12434
+
12435
+ // Loop through row children and assign them to their corresponding sub segment
12436
+ var isRootSegment = !this._subSegLevel;
12437
+ var rid;
12438
+ var children = this._children;
12439
+ if(this._subSegLevel < classifierCount && rows) {
12440
+ if(!segmentMap) {
12441
+ segmentMap = this._subSegMap = {};
12442
+ segmentNames = this._subSegNames = [];
12443
+ }
12444
+
12445
+ var classifier = classifiers[this._subSegLevel];
12446
+
12447
+ for(rid in children) {
12448
+ var dataId = children[rid];
12449
+ var record = rows[dataId];
12450
+ var val = record ? record[classifier] : null; // WARNING: row could already be removed
12451
+
12452
+ this._shared.childToSegment[rid] = this._rid; // Relocate child in case of it has been moved to a non existence group
12453
+
12454
+ segmentName = "Uncategorized";
12455
+ if(val || val === 0 || val === false) { // Check for null, undefined, "", and NaN value
12456
+ segmentName = val + "";
12457
+ }
12458
+ if(nonExistenceGroups[segmentName]) {
12459
+ nonExistenceGroups[segmentName] = 0;
12460
+ --removalCount;
12461
+ }
12462
+
12463
+ segment = segmentMap[segmentName];
12464
+ if(!segment) { // New group is detected
12465
+ segment = new Segment(this._rid + "/" + segmentName, this._shared);
12466
+ segment._subSegDef = this._subSegDef;
12467
+ segment._subSegLevel = this._subSegLevel + 1;
12468
+ segment._subSegName = segmentName;
12469
+ segment._subSegVal = val;
12470
+ segment._subSegParent = this;
12471
+
12472
+ segmentMap[segmentName] = segment;
12473
+ segmentNames.push(segmentName);
12474
+
12475
+ this._dispatch("subSegmentAdded", {
12476
+ "rid": segment.getId(),
12477
+ "segment": segment
12478
+ });
12479
+ }
12480
+
12481
+ segment.addChild(rid, dataId);
12482
+ }
12483
+ } else if(isRootSegment) { // In case of no classification
12484
+ for(rid in children) {
12485
+ this._shared.childToSegment[rid] = this._rid; // Relocate child in case of it has been moved to a non existence group
12486
+ }
12487
+ }
12488
+
12489
+ // Remove all sub segments with no members
12490
+ if(removalCount > 0) {
12491
+ if(removalCount >= segmentNames.length) {
12492
+ segmentNames.length = 0;
12493
+ }
12494
+ for(segmentName in nonExistenceGroups) {
12495
+ if(nonExistenceGroups[segmentName]) {
12496
+ segment = segmentMap[segmentName];
12497
+ delete segmentMap[segmentName];
12498
+ // TODO: Slow
12499
+ var at = segmentNames.indexOf(segmentName);
12500
+ if(at >= 0) {
12501
+ segmentNames.splice(at, 1);
12502
+ }
12503
+
12504
+ this._dispatch("subSegmentRemoved", {
12505
+ "rid": segment.getId(),
12506
+ "segment": segment
12507
+ });
12508
+
12509
+ // segment.dispose(); Already done by segment collection
12510
+ }
12511
+ }
12512
+ if(!segmentNames.length) {
12513
+ segmentNames = this._subSegMap = this._subSegNames = null;
12514
+ }
12515
+ }
12516
+
12517
+ // Sort and classify existing sub segments
12518
+ segmentCount = segmentNames ? segmentNames.length : 0;
12519
+ if(segmentCount) {
12520
+ segmentNames.sort(Segment._subSegSortLogic);
12521
+ for(i = 0; i < segmentCount; ++i) {
12522
+ segment = segmentMap[segmentNames[i]];
12523
+ segment.classify(rows);
12524
+ }
12525
+ }
12526
+
12527
+ // Collecting all sub segments including all descendants and reassigning segment order.
12528
+ if(isRootSegment) { // If this is a root segment
12529
+ if(this._subSegDef) {
12530
+ if(segmentCount) {
12531
+ var subSegments = this._subSegDef.subSegments = [];
12532
+ this.getAllSubSegments(subSegments);
12533
+ subSegments.forEach(Segment._assignSubSegmentOrder);
12534
+ } else {
12535
+ this._subSegDef.subSegments = null;
12536
+ }
12537
+ // this._subSegDef.classifierChanged = false;
12538
+ }
12539
+ }
12540
+ return true;
12541
+ };
12542
+ /** @public
12543
+ * @return {boolean}
12544
+ */
12545
+ Segment.prototype.hasSubSegments = function() {
12546
+ if(this._subSegNames) {
12547
+ return this._subSegNames.length ? true : false;
12548
+ }
12549
+ return false;
12550
+ };
12551
+ /** @public
12552
+ * @return {boolean}
12553
+ */
12554
+ Segment.prototype.isSubSegment = function() {
12555
+ return this._subSegLevel ? true : false;
12556
+ };
12557
+ /** @public
12558
+ * @return {Segment}
12559
+ */
12560
+ Segment.prototype.getFirstAncestor = function() {
12561
+ if(this._subSegLevel && this._subSegDef) {
12562
+ var ancestor = this._subSegDef.root;
12563
+ return /** @type{Segment} */(ancestor) || null;
12564
+ }
12565
+ return null;
12566
+ };
12567
+ /** @public
12568
+ * @param {Array.<Segment>=} out_ary
12569
+ * @return {Array.<Segment>}
12570
+ */
12571
+ Segment.prototype.getAllSubSegments = function(out_ary) {
12572
+ var segmentNames = this._subSegNames;
12573
+ if(segmentNames) {
12574
+ if(!out_ary) {
12575
+ out_ary = [];
12576
+ }
12577
+ var segmentMap = this._subSegMap;
12578
+ var segmentCount = segmentNames.length;
12579
+ for(var i = 0; i < segmentCount; ++i) {
12580
+ var segment = segmentMap[segmentNames[i]];
12581
+ out_ary.push(segment);
12582
+ segment.getAllSubSegments(out_ary);
12583
+ }
12584
+ }
12585
+ return out_ary;
12586
+ };
12587
+ /** @public
12588
+ * @return {number}
12589
+ */
12590
+ Segment.prototype.getSegmentLevel = function() {
12591
+ return this._subSegLevel;
12592
+ };
12593
+ /** This method will be called on sub segments only
12594
+ * @public
12595
+ * @param {Object=} rows
12596
+ * @param {Object=} clsSource
12597
+ */
12598
+ Segment.prototype.setRowData = function(rows, clsSource) {
12599
+ if(!rows) {
12600
+ return;
12601
+ }
12602
+ var row = rows[this._rid];
12603
+ if(!row) {
12604
+ row = rows[this._rid] = {};
12605
+ }
12606
+
12607
+ if(!clsSource) {
12608
+ clsSource = rows;
12609
+ }
12610
+ row = clsSource[this._rid];
12611
+ if(!row) {
12612
+ row = clsSource[this._rid] = {};
12613
+ }
12614
+
12615
+ var segment = this;
12616
+ while(segment && segment.isSubSegment()) {
12617
+ segment.getSubSegmentName(row);
12618
+ segment = segment._subSegParent;
12619
+ }
12620
+ };
12621
+ /** @public
12622
+ * @param {Object=} row
12623
+ * @return {string}
12624
+ */
12625
+ Segment.prototype.getSubSegmentName = function(row) {
12626
+ if(row && this._subSegLevel) {
12627
+ var classifiers = this.getClassification();
12628
+ var field = classifiers[this._subSegLevel - 1];
12629
+ if(field) {
12630
+ row[field] = this._subSegName;
12631
+ }
12632
+ }
12633
+ return this._subSegName;
12634
+ };
12022
12635
 
12023
12636
  /** @public
12024
12637
  * @param {boolean=} bool
@@ -12028,6 +12641,7 @@ Segment.prototype.collapse = function(bool) {
12028
12641
  bool = (bool !== false);
12029
12642
  if(this._collapsed !== bool) {
12030
12643
  this._collapsed = bool;
12644
+ this._shared.dirtyCollapsingState = true;
12031
12645
  return true;
12032
12646
  }
12033
12647
  return false;
@@ -12047,44 +12661,109 @@ Segment.prototype.isCollapsed = function() {
12047
12661
  };
12048
12662
  /** @public
12049
12663
  * @param {Object=} objMap
12050
- * @return {!Object}
12664
+ * @param {boolean=} parentState=false Collapsing state from parent segment
12665
+ * @return {number}
12051
12666
  */
12052
- Segment.prototype.getCollapsingStates = function(objMap) {
12667
+ Segment.prototype.getCollapsingStates = function(objMap, parentState) {
12668
+ var segmentNames = this._subSegNames;
12669
+ if(!this._subSegLevel) { // Only root segment
12670
+ if(!segmentNames) { // No sub segment
12671
+ if(!this._collapsed) {
12672
+ return false;
12673
+ }
12674
+ }
12675
+ }
12676
+
12053
12677
  if(!objMap) {
12054
12678
  objMap = {};
12055
12679
  }
12680
+ var dirty = false;
12681
+ if(this._subSegLevel) { // Sub segments are also subjected to collapsing
12682
+ if(parentState) {
12683
+ objMap[this._rid] = true;
12684
+ dirty = true;
12685
+ }
12686
+ }
12056
12687
  if(this._childCount) {
12057
- var chdr = this._children;
12058
- var collapsed = this._collapsed;
12059
- for(var rid in chdr) {
12060
- objMap[rid] = collapsed;
12688
+ var collapsed = parentState || this._collapsed;
12689
+ if(segmentNames) {
12690
+ var segmentMap = this._subSegMap;
12691
+ var segmentCount = segmentNames.length;
12692
+ for(var i = 0; i < segmentCount; ++i) {
12693
+ var segment = segmentMap[segmentNames[i]];
12694
+ objMap[segment.getId()] = !!parentState;
12695
+ if(segment.getCollapsingStates(objMap, collapsed)) {
12696
+ dirty = true;
12697
+ }
12698
+ }
12699
+ } else if(collapsed) {
12700
+ var chdr = this._children;
12701
+ for(var rid in chdr) {
12702
+ objMap[rid] = collapsed;
12703
+ }
12704
+ dirty = true;
12061
12705
  }
12062
12706
  }
12063
- return objMap;
12707
+ return dirty;
12064
12708
  };
12709
+
12065
12710
  /** @public
12066
12711
  * @return {number}
12067
12712
  */
12068
- Segment.prototype.getValue = function() {
12069
- return this._value;
12713
+ Segment.prototype.getOrder = function() {
12714
+ if(this._subSegLevel) {
12715
+ var ancestor = this.getFirstAncestor();
12716
+ if(ancestor) {
12717
+ // WARNING: this._order cannot be greater than 9999
12718
+ return ancestor.getOrder() + this._order;
12719
+ }
12720
+ }
12721
+ return this._order * 10000;
12070
12722
  };
12071
12723
  /** @public
12072
12724
  * @param {number} val
12073
12725
  */
12074
- Segment.prototype.setValue = function(val) {
12075
- this._value = val;
12726
+ Segment.prototype.setOrder = function(val) {
12727
+ this._order = val;
12076
12728
  };
12077
- /** @public
12078
- * @return {number}
12729
+
12730
+ /** @private
12731
+ * @type {Array.<string>}
12079
12732
  */
12080
- Segment.prototype.getOrder = function() {
12081
- return this._order;
12082
- };
12733
+ Segment._tabs = null;
12083
12734
  /** @public
12084
- * @param {number} val
12735
+ * @param {Array.<string>} lines
12736
+ * @return {Array.<string>} lines
12085
12737
  */
12086
- Segment.prototype.setOrder = function(val) {
12087
- this._order = val;
12738
+ Segment.prototype.log = function(lines) {
12739
+ var i;
12740
+ var tabs = Segment._tabs;
12741
+ if(!tabs) {
12742
+ tabs = Segment._tabs = [];
12743
+ var tabCh = "";
12744
+ for(i = 0; i < 11; ++i) {
12745
+ tabs[i] = tabCh;
12746
+ tabCh += " ";
12747
+ }
12748
+ }
12749
+ var collapsedCh = this._collapsed ? "+ " : "- ";
12750
+ lines.push(tabs[this._subSegLevel] + collapsedCh + this._rid);
12751
+
12752
+ var segmentNames = this._subSegNames;
12753
+ if(segmentNames) {
12754
+ var segmentCount = segmentNames.length;
12755
+ var segmentMap = this._subSegMap;
12756
+ for(i = 0; i < segmentCount; ++i) {
12757
+ segmentMap[segmentNames[i]].log(lines);
12758
+ }
12759
+ } else if(this._childCount) {
12760
+ var indent = tabs[this._subSegLevel + 1];
12761
+ for(var rid in this._children) {
12762
+ lines.push(indent + "- " + rid);
12763
+ }
12764
+ }
12765
+
12766
+ return lines;
12088
12767
  };
12089
12768
 
12090
12769
 
@@ -12094,18 +12773,30 @@ Segment.prototype.setOrder = function(val) {
12094
12773
  ;// CONCATENATED MODULE: ./src/js/data/SegmentCollection.js
12095
12774
 
12096
12775
 
12776
+
12777
+
12097
12778
  /** @constructor
12098
12779
  */
12099
12780
  var SegmentCollection = function() {
12781
+ this._onSubSegmentAdded = this._onSubSegmentAdded.bind(this);
12782
+ this._onSubSegmentRemoved = this._onSubSegmentRemoved.bind(this);
12783
+
12100
12784
  this._segments = {};
12101
- this._childToSegmentId = {};
12785
+ this._insertionList = [];
12786
+ this._removalList = [];
12787
+
12788
+ this._shared = {
12789
+ childToSegment: {}, // child Id to segment Id
12790
+ dirtyCollapsingState: false
12791
+ };
12102
12792
  };
12793
+ es6_Ext.inherits(SegmentCollection, es6_EventDispatcher);
12103
12794
 
12104
12795
 
12105
12796
  /** @type {!Object.<string, Segment>}
12106
12797
  * @private
12107
12798
  */
12108
- SegmentCollection.prototype._segments;
12799
+ SegmentCollection.prototype._segments; // Contains both segment and their sub segments
12109
12800
  /** @type {number}
12110
12801
  * @private
12111
12802
  */
@@ -12114,28 +12805,53 @@ SegmentCollection.prototype._segmentCount = 0;
12114
12805
  * @private
12115
12806
  */
12116
12807
  SegmentCollection.prototype._collapsedRids = null;
12808
+ /** @type {!Object}
12809
+ * @private
12810
+ */
12811
+ SegmentCollection.prototype._shared;
12812
+ /** @type {Array.<Segment>}
12813
+ * @private
12814
+ */
12815
+ SegmentCollection.prototype._segmentList = null; // Array of main segments
12816
+ /** @type {Array.<Segment>}
12817
+ * @private
12818
+ */
12819
+ SegmentCollection.prototype._insertionList = null; // Array of sub segments
12820
+ /** @type {Array.<string>}
12821
+ * @private
12822
+ */
12823
+ SegmentCollection.prototype._removalList = null; // Array of sub segment ids
12117
12824
  /** @type {boolean}
12118
12825
  * @private
12119
12826
  */
12120
- SegmentCollection.prototype._dirtyCollapsingState = false;
12121
- /** @type {!Object.<string, string>}
12827
+ SegmentCollection.prototype._classification = false;
12828
+ /** @type {boolean}
12122
12829
  * @private
12123
12830
  */
12124
- SegmentCollection.prototype._childToSegmentId;
12125
-
12831
+ SegmentCollection.prototype._classifierChanged = false;
12126
12832
 
12833
+ /** @public
12834
+ */
12835
+ SegmentCollection.prototype.dispose = function() {
12836
+ this.removeAllSegments();
12837
+ this._collapsedRids = null;
12838
+ this._segmentList = this._insertionList = this._removalList = null;
12839
+ };
12127
12840
  /** @public
12128
12841
  * @param {string} rid
12129
12842
  * @return {boolean} Returns true if there is any change. Otherwise, returns false
12130
12843
  */
12131
12844
  SegmentCollection.prototype.addSegment = function(rid) {
12132
12845
  if(rid && !this._segments[rid]) {
12133
- if(this._childToSegmentId[rid]) {
12846
+ if(this.getParentRowId(rid)) {
12134
12847
  console.log("child of a segment cannot be set as a segment separator");
12135
12848
  return false;
12136
12849
  }
12137
- this._segments[rid] = new data_Segment(rid);
12850
+ var segment = this._segments[rid] = new data_Segment(rid, this._shared);
12851
+ segment.addEventListener("subSegmentAdded", this._onSubSegmentAdded);
12852
+ segment.addEventListener("subSegmentRemoved", this._onSubSegmentRemoved);
12138
12853
  ++this._segmentCount;
12854
+ this._segmentList = null; // order could be changed
12139
12855
  return true;
12140
12856
  }
12141
12857
  return false;
@@ -12165,7 +12881,7 @@ SegmentCollection.prototype.containsSegment = function(rid) {
12165
12881
  * @return {string} parent row id of this segmentation. If the parent row id for this segmentation cannot be found, return ""
12166
12882
  */
12167
12883
  SegmentCollection.prototype.getParentRowId = function(rid) {
12168
- return this._childToSegmentId[rid] || "";
12884
+ return this._shared.childToSegment[rid] || "";
12169
12885
  };
12170
12886
  /** @public
12171
12887
  * @param {string} rid
@@ -12174,10 +12890,27 @@ SegmentCollection.prototype.getParentRowId = function(rid) {
12174
12890
  SegmentCollection.prototype.removeSegment = function(rid) {
12175
12891
  var segment = this._segments[rid];
12176
12892
  if(segment) {
12177
- if(segment.isCollapsed()) {
12178
- this._dirtyCollapsingState = true;
12893
+ if(this._segmentCount <= 1) {
12894
+ return this.removeAllSegments();
12895
+ }
12896
+ if(segment.isSubSegment()) {
12897
+ this._removalList.push(segment.getId());
12898
+ }
12899
+ var subSegIds = segment.getSubSegmentIds();
12900
+ if(subSegIds) {
12901
+ var len = subSegIds.length;
12902
+ for(var i = 0; i < len; ++i) {
12903
+ var subSegId = subSegIds[i];
12904
+ if(this._segments[subSegId]) {
12905
+ this._removalList.push(subSegId);
12906
+ delete this._segments[subSegId]; // Slow
12907
+ --this._segmentCount;
12908
+ }
12909
+ }
12179
12910
  }
12180
- segment.removeAllChildren(this._childToSegmentId);
12911
+ segment.removeAllChildren(); // This is important for updating childToSegment
12912
+ segment.dispose();
12913
+
12181
12914
  delete this._segments[rid]; // Slow
12182
12915
  --this._segmentCount;
12183
12916
  return true;
@@ -12189,10 +12922,15 @@ SegmentCollection.prototype.removeSegment = function(rid) {
12189
12922
  */
12190
12923
  SegmentCollection.prototype.removeAllSegments = function() {
12191
12924
  if(this._segmentCount) {
12925
+ for(var key in this._segments) {
12926
+ this._segments[key].dispose();
12927
+ }
12192
12928
  this._segments = {};
12193
- this._childToSegmentId = {};
12194
12929
  this._segmentCount = 0;
12195
- this._dirtyCollapsingState = true;
12930
+ this._segmentList = null;
12931
+ this._shared.childToSegment = {};
12932
+
12933
+ this._classification = this._classifierChanged = false;
12196
12934
  return true;
12197
12935
  }
12198
12936
  return false;
@@ -12233,11 +12971,7 @@ SegmentCollection.prototype.getSegmentIds = function() {
12233
12971
  SegmentCollection.prototype.collapseSegment = function(segmentId, bool) {
12234
12972
  var segment = this._segments[segmentId];
12235
12973
  if(segment) {
12236
- var dirty = segment.collapse(bool);
12237
- if(dirty) {
12238
- this._dirtyCollapsingState = true;
12239
- return true;
12240
- }
12974
+ return segment.collapse(bool);
12241
12975
  }
12242
12976
  return false;
12243
12977
  };
@@ -12260,7 +12994,6 @@ SegmentCollection.prototype.expandAllSegments = function() {
12260
12994
  dirty |= segmentSeparators[rid].expand();
12261
12995
  }
12262
12996
  if(dirty) {
12263
- this._dirtyCollapsingState = true;
12264
12997
  return true;
12265
12998
  }
12266
12999
  }
@@ -12281,17 +13014,19 @@ SegmentCollection.prototype.isCollapsedSegment = function(segmentId) {
12281
13014
  * @return {Object}
12282
13015
  */
12283
13016
  SegmentCollection.prototype.getCollapsedRows = function() {
12284
- if(this._dirtyCollapsingState) {
12285
- this._dirtyCollapsingState = false;
13017
+ if(this._shared.dirtyCollapsingState) {
13018
+ this._shared.dirtyCollapsingState = false;
12286
13019
  var collapsedRids = null;
12287
13020
  var count = 0;
12288
13021
  if(this._segmentCount) {
12289
13022
  var segmentSeparators = this._segments;
12290
13023
  collapsedRids = {};
12291
13024
  for(var rid in segmentSeparators) {
12292
- if(segmentSeparators[rid].isCollapsed()) {
12293
- segmentSeparators[rid].getCollapsingStates(collapsedRids);
12294
- ++count;
13025
+ var segment = segmentSeparators[rid];
13026
+ if(!segment.isSubSegment()) {
13027
+ if(segment.getCollapsingStates(collapsedRids)) {
13028
+ ++count;
13029
+ }
12295
13030
  }
12296
13031
  }
12297
13032
  }
@@ -12303,18 +13038,13 @@ SegmentCollection.prototype.getCollapsedRows = function() {
12303
13038
  /** @public
12304
13039
  * @param {string} segmentId
12305
13040
  * @param {string} rid
13041
+ * @param {string=} dataId Row id for retrieving data
12306
13042
  * @return {boolean} Returns true if there is any change. Otherwise, returns false
12307
13043
  */
12308
- SegmentCollection.prototype.addSegmentChild = function(segmentId, rid) {
13044
+ SegmentCollection.prototype.addSegmentChild = function(segmentId, rid, dataId) {
12309
13045
  var segment = this._segments[segmentId];
12310
- if(segment) {
12311
- var dirty = segment.addChild(rid, this._childToSegmentId);
12312
- if(dirty) {
12313
- if(segment.isCollapsed()) {
12314
- this._dirtyCollapsingState = true;
12315
- }
12316
- return true;
12317
- }
13046
+ if(segment && !segment.isSubSegment()) {
13047
+ return segment.addChild(rid, dataId);
12318
13048
  }
12319
13049
  return false;
12320
13050
  };
@@ -12325,14 +13055,8 @@ SegmentCollection.prototype.addSegmentChild = function(segmentId, rid) {
12325
13055
  */
12326
13056
  SegmentCollection.prototype.addSegmentChildren = function(segmentId, rids) {
12327
13057
  var segment = this._segments[segmentId];
12328
- if(segment) {
12329
- var dirty = segment.addChildren(rids, this._childToSegmentId);
12330
- if(dirty) {
12331
- if(segment.isCollapsed()) {
12332
- this._dirtyCollapsingState = true;
12333
- }
12334
- return true;
12335
- }
13058
+ if(segment && !segment.isSubSegment()) {
13059
+ return segment.addChildren(rids);
12336
13060
  }
12337
13061
  return false;
12338
13062
  };
@@ -12356,13 +13080,7 @@ SegmentCollection.prototype.containsSegmentChild = function(segmentId, rid) {
12356
13080
  SegmentCollection.prototype.removeSegmentChild = function(segmentId, rid) {
12357
13081
  var segment = this._segments[segmentId];
12358
13082
  if(segment) {
12359
- var dirty = segment.removeChild(rid, this._childToSegmentId);
12360
- if(dirty) {
12361
- if(segment.isCollapsed()) {
12362
- this._dirtyCollapsingState = true;
12363
- }
12364
- return true;
12365
- }
13083
+ return segment.removeChild(rid);
12366
13084
  }
12367
13085
  return false;
12368
13086
  };
@@ -12374,13 +13092,7 @@ SegmentCollection.prototype.removeSegmentChild = function(segmentId, rid) {
12374
13092
  SegmentCollection.prototype.removeSegmentChildren = function(segmentId, rids) {
12375
13093
  var segment = this._segments[segmentId];
12376
13094
  if(segment) {
12377
- var dirty = segment.removeChildren(rids, this._childToSegmentId);
12378
- if(dirty) {
12379
- if(segment.isCollapsed()) {
12380
- this._dirtyCollapsingState = true;
12381
- }
12382
- return true;
12383
- }
13095
+ return segment.removeChildren(rids);
12384
13096
  }
12385
13097
  return false;
12386
13098
  };
@@ -12388,20 +13100,20 @@ SegmentCollection.prototype.removeSegmentChildren = function(segmentId, rids) {
12388
13100
  * @return {boolean} Returns true if there is any change. Otherwise, returns false
12389
13101
  */
12390
13102
  SegmentCollection.prototype.removeAllSegmentChildren = function() {
12391
- this._childToSegmentId = {};
13103
+ this._shared.childToSegment = {};
12392
13104
  var segmentSeparators = this._segments;
12393
- var dirtyCollapsingState = this._dirtyCollapsingState;
12394
13105
  var dirty = false;
12395
13106
  for(var rid in segmentSeparators) {
12396
- var segment = this._segments[rid];
13107
+ var segment = segmentSeparators[rid];
12397
13108
  if(segment.removeAllChildren()) {
12398
13109
  dirty = true;
12399
- if(!dirtyCollapsingState && segment.isCollapsed()) {
12400
- dirtyCollapsingState = this._dirtyCollapsingState = true;
12401
- }
12402
13110
  }
12403
13111
  }
12404
13112
 
13113
+ if(dirty) {
13114
+ this.classify();
13115
+ }
13116
+
12405
13117
  return dirty;
12406
13118
  };
12407
13119
 
@@ -12415,22 +13127,18 @@ SegmentCollection.prototype.fillSegment = function(segmentId, rids) {
12415
13127
  return;
12416
13128
  }
12417
13129
  var segmentSeparators = this._segments;
12418
- var childToSegmentId = this._childToSegmentId;
12419
13130
  var curSegment = segmentSeparators[segmentId];
12420
- if(curSegment) {
13131
+ if(curSegment && !curSegment.isSubSegment()) {
12421
13132
  var segmentAt = rids.indexOf(segmentId);
12422
13133
  if(segmentAt >= 0) {
12423
- if(curSegment.isCollapsed()) {
12424
- this._dirtyCollapsingState = true;
12425
- }
12426
- curSegment.removeAllChildren(childToSegmentId);
13134
+ curSegment.removeAllChildren();
12427
13135
  for(var r = segmentAt + 1; r < rowCount; ++r) {
12428
13136
  var rid = rids[r];
12429
13137
  var segmentSeparator = segmentSeparators[rid];
12430
13138
  if(segmentSeparator) {
12431
13139
  break;
12432
13140
  }
12433
- curSegment.addChild(rid, childToSegmentId);
13141
+ curSegment.addChild(rid);
12434
13142
  }
12435
13143
  }
12436
13144
  }
@@ -12440,23 +13148,20 @@ SegmentCollection.prototype.fillSegment = function(segmentId, rids) {
12440
13148
  * @return {boolean} Return true if the fill segments have changed, otherwise return false
12441
13149
  */
12442
13150
  SegmentCollection.prototype.fillSegments = function(rids) {
13151
+ this._shared.childToSegment = {};
13152
+
12443
13153
  var rowCount = Array.isArray(rids) ? rids.length : 0;
12444
- this._childToSegmentId = {};
12445
13154
  var segmentSeparators = this._segments;
12446
- var childToSegmentId = this._childToSegmentId;
12447
13155
  var curSegment = null;
12448
13156
  var change = false;
12449
13157
  for(var r = 0; r < rowCount; ++r) {
12450
13158
  var rid = rids[r];
12451
13159
  var segmentSeparator = segmentSeparators[rid];
12452
- if(segmentSeparator) {
13160
+ if(segmentSeparator && !segmentSeparator.isSubSegment()) {
12453
13161
  curSegment = segmentSeparator;
12454
- if(curSegment.isCollapsed()) {
12455
- this._dirtyCollapsingState = true;
12456
- }
12457
13162
  curSegment.removeAllChildren();
12458
- } else if(curSegment) {
12459
- curSegment.addChild(rid, childToSegmentId);
13163
+ } else if(curSegment && !curSegment.isSubSegment()) {
13164
+ curSegment.addChild(rid);
12460
13165
  change = true;
12461
13166
  }
12462
13167
  }
@@ -12466,6 +13171,13 @@ SegmentCollection.prototype.fillSegments = function(rids) {
12466
13171
  * @param {Array.<string>} rids
12467
13172
  */
12468
13173
  SegmentCollection.prototype.calcSegmentOrder = function(rids) {
13174
+ var segmentList = this._segmentList;
13175
+ if(segmentList) {
13176
+ segmentList.length = 0;
13177
+ } else {
13178
+ segmentList = this._segmentList = [];
13179
+ }
13180
+
12469
13181
  var ridCount = rids ? rids.length : 0;
12470
13182
  var segmentSeparators = this._segments;
12471
13183
  var segmentCount = this._segmentCount;
@@ -12474,8 +13186,11 @@ SegmentCollection.prototype.calcSegmentOrder = function(rids) {
12474
13186
  var rid = rids[i];
12475
13187
  var segment = segmentSeparators[rid];
12476
13188
  if(segment) {
12477
- segment.setOrder(++order);
12478
- if(order >= segmentCount) {
13189
+ if(!segment.isSubSegment()) {
13190
+ this._segmentList.push(segment);
13191
+ segment.setOrder(++order); // WARNING: Segments and sub segments start with 1
13192
+ }
13193
+ if(--segmentCount <= 0) {
12479
13194
  break;
12480
13195
  }
12481
13196
  }
@@ -12491,7 +13206,7 @@ SegmentCollection.prototype.getSegmentValues = function(rids) {
12491
13206
  return null;
12492
13207
  }
12493
13208
  var segmentSeparators = this._segments;
12494
- var childToSegmentId = this._childToSegmentId;
13209
+ var childToSegmentId = this._shared.childToSegment;
12495
13210
  var curSegment = null;
12496
13211
  var prevSegment = null;
12497
13212
  var segmentValues = new Array(rowCount);
@@ -12521,6 +13236,126 @@ SegmentCollection.prototype.getSegmentValues = function(rids) {
12521
13236
 
12522
13237
  return prevSegment ? segmentValues : null;
12523
13238
  };
13239
+ /** @public
13240
+ * @return {string}
13241
+ */
13242
+ SegmentCollection.prototype.logStructure = function() {
13243
+ var segmentList = this._segmentList;
13244
+ if(!segmentList) {
13245
+ return "";
13246
+ }
13247
+ var segmentCount = segmentList.length;
13248
+ var lines = [];
13249
+ for(var i = 0; i < segmentCount; ++i) {
13250
+ segmentList[i].log(lines);
13251
+ }
13252
+
13253
+ return lines.join("\n");
13254
+ };
13255
+ /** @public
13256
+ * @return {string}
13257
+ */
13258
+ SegmentCollection.prototype.logRowIdMap = function() {
13259
+ var lines = [];
13260
+ var childToSegmentId = this._shared.childToSegment;
13261
+ for(var rid in childToSegmentId) {
13262
+ var segmentId = childToSegmentId[rid];
13263
+ lines.push(rid + " > " + segmentId);
13264
+ }
13265
+
13266
+ return lines.join("\n");
13267
+ };
13268
+
13269
+
13270
+ /** @public
13271
+ * @param {string} segmentId
13272
+ * @param {string|Array.<string>} fields
13273
+ * @return {boolean}
13274
+ */
13275
+ SegmentCollection.prototype.setSegmentClassification = function(segmentId, fields) {
13276
+ var segment = this._segments[segmentId];
13277
+ if(segment) {
13278
+ if(segment.setClassification(fields)) {
13279
+ if(segment.getClassification()) {
13280
+ this._classification = true;
13281
+ }
13282
+ this._classifierChanged = true;
13283
+
13284
+ return true;
13285
+ }
13286
+ }
13287
+ return false;
13288
+ };
13289
+ /** @public
13290
+ * @return {boolean}
13291
+ */
13292
+ SegmentCollection.prototype.hasClassification = function() {
13293
+ // WARNING: This include the time when classification is removed
13294
+ return this._classification || this._classifierChanged;
13295
+ };
13296
+ /** @public
13297
+ * @param {Object.<string, Object>} rows Object maps between row id and its record
13298
+ * @return {boolean}
13299
+ */
13300
+ SegmentCollection.prototype.classify = function(rows) {
13301
+ if(!this._segmentCount) {
13302
+ return false;
13303
+ }
13304
+ if(!this.hasClassification()) {
13305
+ return false;
13306
+ }
13307
+ this._classification = this._classifierChanged = false;
13308
+
13309
+ var segmentSeparators = this._segments;
13310
+ for(var rid in segmentSeparators) {
13311
+ var segment = this._segments[rid];
13312
+ if(!segment.isSubSegment()) {
13313
+ if(segment.getClassification()) {
13314
+ this._classification = true;
13315
+ }
13316
+ segment.classify(rows);
13317
+ }
13318
+ }
13319
+ if(this._insertionList.length || this._removalList.length) {
13320
+ this._dispatch("subSegmentChanged", {
13321
+ "insertionList": this._insertionList,
13322
+ "removalList": this._removalList
13323
+ });
13324
+ this._insertionList.length = 0;
13325
+ this._removalList.length = 0;
13326
+
13327
+ this._dispatch("classified", {});
13328
+ return true;
13329
+ }
13330
+
13331
+ this._dispatch("classified", {});
13332
+ return false;
13333
+ };
13334
+
13335
+ /** @private
13336
+ * @param {!Object} e
13337
+ */
13338
+ SegmentCollection.prototype._onSubSegmentAdded = function(e) {
13339
+ var rid = e["rid"];
13340
+ if(!this._segments[rid]) {
13341
+ var segment = /** @type{Segment} */(e["segment"]);
13342
+ this._insertionList.push(segment);
13343
+ this._segments[rid] = segment;
13344
+ this._segmentCount++;
13345
+
13346
+ segment.addEventListener("subSegmentAdded", this._onSubSegmentAdded);
13347
+ segment.addEventListener("subSegmentRemoved", this._onSubSegmentRemoved);
13348
+ } else {
13349
+ console.log("Incorrect logic detected.");
13350
+ }
13351
+ };
13352
+ /** @private
13353
+ * @param {!Object} e
13354
+ */
13355
+ SegmentCollection.prototype._onSubSegmentRemoved = function(e) {
13356
+ var rid = e["rid"];
13357
+ this.removeSegment(rid);
13358
+ };
12524
13359
 
12525
13360
 
12526
13361
  /* harmony default export */ const data_SegmentCollection = (SegmentCollection);
@@ -12530,6 +13365,7 @@ SegmentCollection.prototype.getSegmentValues = function(rids) {
12530
13365
 
12531
13366
 
12532
13367
 
13368
+ // eslint-disable-line
12533
13369
 
12534
13370
 
12535
13371
  /** Trigger when data within the table has been changed
@@ -12552,11 +13388,15 @@ var DataTable = function() {
12552
13388
 
12553
13389
  this._removeRows = this._removeRows.bind(this);
12554
13390
  this._bySegmentSeparator = this._bySegmentSeparator.bind(this);
13391
+ this._onClassifyingTimer = this._onClassifyingTimer.bind(this);
13392
+ this._onSubSegmentChanged = this._onSubSegmentChanged.bind(this);
12555
13393
 
12556
13394
  this._prevData = {};
12557
13395
  this._rids = [];
12558
13396
 
12559
13397
  this._compMap = {};
13398
+
13399
+ this._addEvent("subSegmentChanged");
12560
13400
  };
12561
13401
  es6_Ext.inherits(DataTable, data_DataCache);
12562
13402
 
@@ -12599,6 +13439,14 @@ DataTable.prototype._removedRows = null;
12599
13439
  * @type {Function}
12600
13440
  */
12601
13441
  DataTable.prototype._userSegmentComparer = null;
13442
+ /** @private
13443
+ * @type {Object.<string, Object>}
13444
+ */
13445
+ DataTable.prototype._clsSource = null;
13446
+ /** @private
13447
+ * @type {number}
13448
+ */
13449
+ DataTable.prototype._classifyingTimer = 0;
12602
13450
 
12603
13451
 
12604
13452
  /** @typedef {Function} DataTable~SortLogic
@@ -12627,8 +13475,17 @@ DataTable.prototype.dispose = function() {
12627
13475
  this.unlistenAll();
12628
13476
  this.clearAllData(true);
12629
13477
 
13478
+ if(this._classifyingTimer) {
13479
+ clearTimeout(this._onClassifyingTimer);
13480
+ this._classifyingTimer = 0;
13481
+ }
13482
+
12630
13483
  this._compMap = null; // Release user function that may be bound
12631
- this._segments = null;
13484
+ this._clsSource = null;
13485
+ if(this._segments) {
13486
+ this._segments.dispose();
13487
+ this._segments = null;
13488
+ }
12632
13489
  };
12633
13490
 
12634
13491
  /** {@link DataCache#getColumnData}
@@ -12746,7 +13603,7 @@ DataTable.prototype.setRowData = function(rid, values, eventArg) { // Data chang
12746
13603
  this._prevData[rid] = {};
12747
13604
  if(eventArg) {
12748
13605
  var nextRid = /** @type{string} */(eventArg["nextRid"]); // Used for insertion only
12749
- var rowIndex = (nextRid != null) ? this.getRowIndex(nextRid) : -1;
13606
+ var rowIndex = (nextRid) ? this.getRowIndex(nextRid) : -1;
12750
13607
  if(rowIndex < 0) {
12751
13608
  rowIndex = /** @type{number} */(eventArg["fallback"]);
12752
13609
  }
@@ -12778,6 +13635,7 @@ DataTable.prototype.setRowData = function(rid, values, eventArg) { // Data chang
12778
13635
  var segment = this._segments.getSegment(rid);
12779
13636
  if(segment) {
12780
13637
  if(this._segments.removeSegment(rid)) {
13638
+ // TODO: Handle sub segment removal
12781
13639
  segmentChanged = true;
12782
13640
  if(!this._segments.getSegmentCount()) {
12783
13641
  this._segments = null;
@@ -12785,12 +13643,7 @@ DataTable.prototype.setRowData = function(rid, values, eventArg) { // Data chang
12785
13643
  }
12786
13644
  }
12787
13645
  }
12788
- for(var i = this._rids.length; --i >= 0;) {
12789
- if(this._rids[i] === rid) {
12790
- this._rids.splice(i, 1);
12791
- break;
12792
- }
12793
- }
13646
+ DataTable._removeArrayItem(this._rids, rid);
12794
13647
  dirty = true;
12795
13648
  }
12796
13649
  }
@@ -12809,7 +13662,7 @@ DataTable.prototype.setRowData = function(rid, values, eventArg) { // Data chang
12809
13662
  }
12810
13663
  this._dispatchDataChange(e);
12811
13664
  }
12812
-
13665
+ this.requestClassifying(); // TODO: Check if needFiring method should have an effect on this request
12813
13666
  }
12814
13667
  return dirty;
12815
13668
  };
@@ -13012,7 +13865,7 @@ DataTable.prototype.unshiftRow = function(opt_values, opt_rid) {
13012
13865
  return this.insertRow(0, opt_values, opt_rid);
13013
13866
  };
13014
13867
  /** @public
13015
- * @param {string|number|null=} rowRef
13868
+ * @param {(string|number|null)=} rowRef
13016
13869
  * @param {Object.<string, *>=} values Key/value pair object map
13017
13870
  * @param {string|null=} rid If the given row Id already exists, data is updated and no new row is added. Leave blank or null to let DataTable generate unique row Id
13018
13871
  * @return {string} Return Row id that has been inserted or changed
@@ -13021,11 +13874,13 @@ DataTable.prototype.unshiftRow = function(opt_values, opt_rid) {
13021
13874
  * @see {@link DataTable#removeRow}
13022
13875
  */
13023
13876
  DataTable.prototype.insertRow = function(rowRef, values, rid) {
13024
- var arg = {};
13877
+ var arg = null;
13025
13878
  if(typeof rowRef === "number") {
13879
+ arg = {};
13026
13880
  arg["nextRid"] = this._rids[rowRef];
13027
13881
  arg["fallback"] = rowRef; // Fallback index in case of no nextRid found
13028
- } else {
13882
+ } else if(rowRef) {
13883
+ arg = {};
13029
13884
  arg["nextRid"] = /** @type{string} */(rowRef);
13030
13885
  }
13031
13886
 
@@ -13110,12 +13965,34 @@ DataTable.prototype.removeRows = function(refs) {
13110
13965
  DataTable.prototype._removeRows = function(rid) {
13111
13966
  return !this._removedRows[rid];
13112
13967
  };
13968
+
13969
+ /** @private
13970
+ * @param {Array} ary
13971
+ * @param {*} item
13972
+ * @return {boolean}
13973
+ */
13974
+ DataTable._removeArrayItem = function(ary, item) {
13975
+ var at = ary.indexOf(item);
13976
+ if(at >= 0) {
13977
+ if(at >= ary.length) {
13978
+ ary.pop(); // Array.pop is 100 times faster than Array.splice
13979
+ } else {
13980
+ ary.splice(at, 1);
13981
+ }
13982
+ return true;
13983
+ }
13984
+ return false;
13985
+ };
13113
13986
  /** Remove all existing rows
13114
13987
  * @override
13115
13988
  */
13116
13989
  DataTable.prototype.clearAllData = function(suppressEvent) {
13117
13990
  DataTable.base(this, "clearAllData", true);
13118
13991
  this._prevData = {};
13992
+ // TODO: Clear all segments
13993
+ if(this._segments) {
13994
+ this._segments.removeAllSegmentChildren(); // This immediately remove all sub segments
13995
+ }
13119
13996
 
13120
13997
  if(this._rids.length) {
13121
13998
  this._rids.length = 0;
@@ -13422,6 +14299,7 @@ DataTable.prototype.setSegmentSeparator = function(rid, enabled) {
13422
14299
  if(enabled !== false) {
13423
14300
  if(!this._segments) {
13424
14301
  this._segments = new data_SegmentCollection();
14302
+ this._segments.addEventListener("subSegmentChanged", this._onSubSegmentChanged);
13425
14303
  }
13426
14304
  if(this._autoSegmentFilling) {
13427
14305
  var parentId = this._segments.getParentRowId(rid);
@@ -13494,6 +14372,29 @@ DataTable.prototype.isSegmentSeparator = function(rid) {
13494
14372
  }
13495
14373
  return false;
13496
14374
  };
14375
+ /** Get Segment object
14376
+ * @public
14377
+ * @param {string} rid Row id
14378
+ * @return {Segment} Return 0 if the given rid is not a segment
14379
+ */
14380
+ DataTable.prototype.getSegment = function(rid) {
14381
+ if(this._segments) {
14382
+ return this._segments.getSegment(rid);
14383
+ }
14384
+ return null;
14385
+ };
14386
+ /** Segment level starts from 1
14387
+ * @public
14388
+ * @param {string} rid
14389
+ * @return {number} Return 0 if the given rid is not a segment
14390
+ */
14391
+ DataTable.prototype.getSegmentLevel = function(rid) {
14392
+ var segment = this.getSegment(rid);
14393
+ if(segment) {
14394
+ return segment.getSegmentLevel() + 1;
14395
+ }
14396
+ return 0;
14397
+ };
13497
14398
  /**
13498
14399
  * @public
13499
14400
  * @param {string} rid
@@ -13567,6 +14468,7 @@ DataTable.prototype.fillSegment = function(segmentId) {
13567
14468
  if(this._segments) {
13568
14469
  this._segments.fillSegment(segmentId, this._rids);
13569
14470
  this.dispatchGlobalChange();
14471
+ this.requestClassifying();
13570
14472
  }
13571
14473
  };
13572
14474
  /** Remove all existing segment children in each segment and fill the segments with all contnet rows before the next segment separator
@@ -13578,6 +14480,7 @@ DataTable.prototype.fillSegments = function() {
13578
14480
  var dirty = this._segments.fillSegments(this._rids);
13579
14481
  if(dirty) {
13580
14482
  this.dispatchGlobalChange();
14483
+ this.requestClassifying();
13581
14484
  }
13582
14485
  return dirty;
13583
14486
  }
@@ -13586,15 +14489,17 @@ DataTable.prototype.fillSegments = function() {
13586
14489
  /** @public
13587
14490
  * @param {string} segmentId Row id
13588
14491
  * @param {string} rid Row id
14492
+ * @param {string=} dataId Row id for retrieving data
13589
14493
  * @return {boolean} Return true if there is any change
13590
14494
  */
13591
- DataTable.prototype.addSegmentChild = function(segmentId, rid) {
14495
+ DataTable.prototype.addSegmentChild = function(segmentId, rid, dataId) {
13592
14496
  if(this._segments) {
13593
- var dirty = this._segments.addSegmentChild(segmentId, rid);
14497
+ var dirty = this._segments.addSegmentChild(segmentId, rid, dataId);
13594
14498
  if(dirty) {
13595
14499
  if(this._sort(null)) {
13596
14500
  this._dispatchPositionChange();
13597
14501
  }
14502
+ this.requestClassifying();
13598
14503
  return true;
13599
14504
  }
13600
14505
  }
@@ -13612,6 +14517,7 @@ DataTable.prototype.addSegmentChildren = function(segmentId, rids) {
13612
14517
  if(this._sort(null)) {
13613
14518
  this._dispatchPositionChange();
13614
14519
  }
14520
+ this.requestClassifying();
13615
14521
  return true;
13616
14522
  }
13617
14523
  }
@@ -13627,6 +14533,7 @@ DataTable.prototype.removeSegmentChild = function(segmentId, rid) {
13627
14533
  var dirty = this._segments.removeSegmentChild(segmentId, rid);
13628
14534
  if(dirty) {
13629
14535
  this.dispatchGlobalChange();
14536
+ this.requestClassifying();
13630
14537
  }
13631
14538
  return dirty;
13632
14539
  }
@@ -13642,6 +14549,7 @@ DataTable.prototype.removeSegmentChildren = function(segmentId, rids) {
13642
14549
  var dirty = this._segments.removeSegmentChildren(segmentId, rids);
13643
14550
  if(dirty) {
13644
14551
  this.dispatchGlobalChange();
14552
+ this.requestClassifying();
13645
14553
  }
13646
14554
  return dirty;
13647
14555
  }
@@ -13652,7 +14560,7 @@ DataTable.prototype.removeSegmentChildren = function(segmentId, rids) {
13652
14560
  */
13653
14561
  DataTable.prototype.removeAllSegmentChildren = function() {
13654
14562
  if(this._segments) {
13655
- var dirty = this._segments.removeAllSegmentChildren();
14563
+ var dirty = this._segments.removeAllSegmentChildren(); // This immediately remove all sub segments
13656
14564
  if (dirty) {
13657
14565
  this.dispatchGlobalChange();
13658
14566
  }
@@ -13688,10 +14596,15 @@ DataTable.prototype.getSegmentChildIds = function(segmentId) {
13688
14596
  /** Sort all of existing segments by given compare function
13689
14597
  * @public
13690
14598
  * @param {Function} compare
14599
+ * @return {boolean}
13691
14600
  */
13692
14601
  DataTable.prototype.sortSegments = function (compare) {
13693
- if(!this._segments || typeof compare !== "function") {
13694
- return;
14602
+ if(!this._segments) {
14603
+ return false;
14604
+ }
14605
+ if(typeof compare !== "function") {
14606
+ this._segments.calcSegmentOrder(this._rids);
14607
+ return false;
13695
14608
  }
13696
14609
  var rids = this._rids;
13697
14610
  var segments = this._segments;
@@ -13735,7 +14648,9 @@ DataTable.prototype.sortSegments = function (compare) {
13735
14648
  this._segments.calcSegmentOrder(rids);
13736
14649
  this._sort(null);
13737
14650
  this._dispatchPositionChange();
14651
+ return true;
13738
14652
  }
14653
+ return false;
13739
14654
  };
13740
14655
  /** Sort all of existing segments by given compare function
13741
14656
  * @private
@@ -13750,6 +14665,112 @@ DataTable.prototype._bySegmentSeparator = function (segmentA, segmentB) {
13750
14665
  ));
13751
14666
  };
13752
14667
 
14668
+ /** A data source to be used with segment classification
14669
+ * @public
14670
+ * @param {DataCache} dc
14671
+ */
14672
+ DataTable.prototype.setClassificationSource = function(dc) {
14673
+ this._clsSource = null;
14674
+
14675
+ if(dc && dc._rows) {
14676
+ this._clsSource = dc._rows;
14677
+ }
14678
+ };
14679
+ /**
14680
+ * @public
14681
+ * @param {string} segmentId
14682
+ * @param {string|Array.<string>} fields
14683
+ * @return {boolean}
14684
+ */
14685
+ DataTable.prototype.setSegmentClassification = function(segmentId, fields) {
14686
+ if(this._segments) {
14687
+ var dirty = this._segments.setSegmentClassification(segmentId, fields);
14688
+ if(dirty) {
14689
+ return this.classifySegments();
14690
+ }
14691
+ }
14692
+ return false;
14693
+ };
14694
+ /** @public
14695
+ * @return {boolean}
14696
+ */
14697
+ DataTable.prototype.classifySegments = function() {
14698
+ if(this._segments) {
14699
+ if(this._rids.length) {
14700
+ return this._segments.classify(this._clsSource || this._rows);
14701
+ }
14702
+ }
14703
+ return false;
14704
+ };
14705
+
14706
+ /** @public
14707
+ */
14708
+ DataTable.prototype.requestClassifying = function() {
14709
+ if(this._segments && !this._classifyingTimer) {
14710
+ if(this._segments.hasClassification()) {
14711
+ this._classifyingTimer = setTimeout(this._onClassifyingTimer, 10);
14712
+ }
14713
+ }
14714
+ };
14715
+ /** @private
14716
+ */
14717
+ DataTable.prototype._onClassifyingTimer = function() {
14718
+ this._classifyingTimer = 0;
14719
+ this.classifySegments();
14720
+ };
14721
+ /** @private
14722
+ * @param {Object} e
14723
+ */
14724
+ DataTable.prototype._onSubSegmentChanged = function(e) {
14725
+ var insertionList = /** @type{Array.<Segment>} */(e["insertionList"]);
14726
+ var removalList = /** @type{Array.<string>} */(e["removalList"]);
14727
+
14728
+ var dirty = false;
14729
+ var rows = this._rows;
14730
+ var clsSource = this._clsSource || rows;
14731
+ var rids = this._rids;
14732
+ var prevData = this._prevData;
14733
+ var i;
14734
+
14735
+ var removalCount = removalList.length;
14736
+ var removedRows = {};
14737
+ for(i = 0; i < removalCount; i++) {
14738
+ var rid = removalList[i];
14739
+ if(rows[rid]) {
14740
+ removedRows[rid] = prevData[rid] = rows[rid];
14741
+ delete rows[rid];
14742
+ DataTable._removeArrayItem(rids, rid);
14743
+ dirty = true;
14744
+ // TODO: Remove classification source
14745
+ }
14746
+ }
14747
+
14748
+ var insertionCount = insertionList.length;
14749
+ for(i = 0; i < insertionCount; i++) {
14750
+ var segment = insertionList[i];
14751
+ var parentId = segment.getParentId();
14752
+ var segmentId = segment.getId();
14753
+
14754
+ if(!rows[segmentId]) {
14755
+ prevData[segmentId] = {};
14756
+ segment.setRowData(rows, clsSource);
14757
+
14758
+ var parentAt = rids.indexOf(parentId);
14759
+ if(parentAt < 0 || parentAt + 1 >= rids.length) {
14760
+ rids.push(segmentId);
14761
+ } else {
14762
+ rids.splice(parentAt + 1, 0, segmentId);
14763
+ }
14764
+ dirty = true;
14765
+ }
14766
+ }
14767
+ if(dirty) {
14768
+ e["removedRows"] = removedRows;
14769
+ this._dispatch("subSegmentChanged", e);
14770
+ this.dispatchGlobalChange(); // Rerender everything
14771
+ }
14772
+ };
14773
+
13753
14774
 
13754
14775
  /**
13755
14776
  * @public
@@ -16190,6 +17211,7 @@ Conflator.prototype.enable = function (opt_enabled) {
16190
17211
 
16191
17212
  // eslint-disable-line
16192
17213
 
17214
+ // eslint-disable-line
16193
17215
 
16194
17216
 
16195
17217
 
@@ -18534,6 +19556,22 @@ DataView.prototype.isSegmentSeparator = function(rid) {
18534
19556
  return this._dt.isSegmentSeparator(rid);
18535
19557
  };
18536
19558
 
19559
+ /** Get Segment object
19560
+ * @public
19561
+ * @param {string} rid Row id
19562
+ * @return {Segment} Return 0 if the given rid is not a segment
19563
+ */
19564
+ DataView.prototype.getSegment = function(rid) {
19565
+ return this._dt.getSegment(rid);
19566
+ };
19567
+ /** Segment level starts from 1
19568
+ * @public
19569
+ * @param {string} rid Row id
19570
+ * @return {number} Return 0 if the given rid is not a segment
19571
+ */
19572
+ DataView.prototype.getSegmentLevel = function(rid) {
19573
+ return this._dt.getSegmentLevel(rid);
19574
+ };
18537
19575
  /**
18538
19576
  * @public
18539
19577
  * @param {string} rid
@@ -18615,13 +19653,14 @@ DataView.prototype.fillSegments = function() {
18615
19653
  /** @public
18616
19654
  * @param {string|number} segmentRef Row id or row index
18617
19655
  * @param {string|number} rowRef Row id, row index
19656
+ * @param {string=} dataId Row id for retrieving data
18618
19657
  * @return {boolean} Return true if there is any change
18619
19658
  */
18620
- DataView.prototype.addSegmentChild = function(segmentRef, rowRef) {
19659
+ DataView.prototype.addSegmentChild = function(segmentRef, rowRef, dataId) {
18621
19660
  if(this._dt._getSegmentSeparators()) {
18622
19661
  var segmentId = this._toRowId(segmentRef);
18623
19662
  var rowId = this._toRowId(rowRef);
18624
- return this._dt.addSegmentChild(segmentId, rowId);
19663
+ return this._dt.addSegmentChild(segmentId, rowId, dataId);
18625
19664
  }
18626
19665
  return false;
18627
19666
  };
@@ -18693,6 +19732,16 @@ DataView.prototype.sortSegments = function (compare) {
18693
19732
  this._dt.sortSegments(compare);
18694
19733
  };
18695
19734
 
19735
+ /**
19736
+ * @public
19737
+ * @param {string|number} segmentRef Row id or row index
19738
+ * @param {string|Array.<string>} fields
19739
+ * @return {boolean}
19740
+ */
19741
+ DataView.prototype.setSegmentClassification = function(segmentRef, fields) {
19742
+ return this._dt.setSegmentClassification(this._toRowId(segmentRef), fields);
19743
+ };
19744
+
18696
19745
  /** @public
18697
19746
  * @ignore
18698
19747
  * @return {Object}
@@ -23149,7 +24198,7 @@ Core_Core.prototype._rowHeightTimerId = 0;
23149
24198
  * @return {string}
23150
24199
  */
23151
24200
  Core_Core.getVersion = function () {
23152
- return "5.1.20";
24201
+ return "5.1.26";
23153
24202
  };
23154
24203
  /** {@link ElementWrapper#dispose}
23155
24204
  * @override