@refinitiv-ui/efx-grid 6.0.13 → 6.0.15

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 (47) hide show
  1. package/lib/column-format-dialog/index.d.ts +2 -1
  2. package/lib/column-format-dialog/index.js +2 -1
  3. package/lib/column-selection-dialog/index.d.ts +2 -1
  4. package/lib/column-selection-dialog/index.js +2 -1
  5. package/lib/core/dist/core.js +1220 -161
  6. package/lib/core/dist/core.min.js +1 -1
  7. package/lib/core/es6/data/DataCache.js +1 -1
  8. package/lib/core/es6/data/DataTable.d.ts +18 -3
  9. package/lib/core/es6/data/DataTable.js +203 -17
  10. package/lib/core/es6/data/DataView.d.ts +8 -1
  11. package/lib/core/es6/data/DataView.js +30 -2
  12. package/lib/core/es6/data/Segment.d.ts +37 -12
  13. package/lib/core/es6/data/Segment.js +584 -60
  14. package/lib/core/es6/data/SegmentCollection.d.ts +16 -2
  15. package/lib/core/es6/data/SegmentCollection.js +238 -80
  16. package/lib/core/es6/grid/Core.js +1 -1
  17. package/lib/filter-dialog/index.d.ts +2 -1
  18. package/lib/filter-dialog/index.js +2 -1
  19. package/lib/grid/index.d.ts +2 -1
  20. package/lib/grid/index.js +3 -2
  21. package/lib/row-segmenting/es6/RowSegmenting.d.ts +2 -0
  22. package/lib/row-segmenting/es6/RowSegmenting.js +26 -3
  23. package/lib/rt-grid/dist/rt-grid.js +1194 -158
  24. package/lib/rt-grid/dist/rt-grid.min.js +1 -1
  25. package/lib/rt-grid/es6/Grid.d.ts +4 -0
  26. package/lib/rt-grid/es6/Grid.js +75 -0
  27. package/lib/rt-grid/es6/RowDefinition.d.ts +4 -0
  28. package/lib/rt-grid/es6/RowDefinition.js +79 -2
  29. package/lib/tr-grid-column-grouping/es6/ColumnGrouping.d.ts +1 -0
  30. package/lib/tr-grid-column-grouping/es6/ColumnGrouping.js +194 -366
  31. package/lib/tr-grid-column-stack/es6/ColumnStack.d.ts +10 -3
  32. package/lib/tr-grid-column-stack/es6/ColumnStack.js +93 -36
  33. package/lib/tr-grid-util/es6/RowPainter.d.ts +2 -1
  34. package/lib/tr-grid-util/es6/RowPainter.js +7 -1
  35. package/lib/tr-grid-util/es6/jet/mockDataAPI.d.ts +1 -0
  36. package/lib/tr-grid-util/es6/jet/mockDataAPI.js +191 -52
  37. package/lib/types/es6/ColumnGrouping.d.ts +1 -0
  38. package/lib/types/es6/ColumnStack.d.ts +10 -3
  39. package/lib/types/es6/Core/data/DataTable.d.ts +18 -3
  40. package/lib/types/es6/Core/data/DataView.d.ts +8 -1
  41. package/lib/types/es6/Core/data/Segment.d.ts +36 -11
  42. package/lib/types/es6/Core/data/SegmentCollection.d.ts +15 -1
  43. package/lib/types/es6/RealtimeGrid/ColumnDefinition.d.ts +6 -1
  44. package/lib/types/es6/RealtimeGrid/Grid.d.ts +2 -0
  45. package/lib/types/es6/RowSegmenting.d.ts +2 -0
  46. package/lib/versions.json +4 -4
  47. package/package.json +15 -2
@@ -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,221 @@ 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
12044
+ * @extends {EventDispatcher}
11878
12045
  * @param {string} rid
12046
+ * @param {!Object} sharedObj
11879
12047
  */
11880
- var Segment = function(rid) {
12048
+ var Segment = function(rid, sharedObj) {
11881
12049
  this._rid = rid;
11882
12050
  this._children = {};
12051
+ this._shared = sharedObj;
11883
12052
  };
12053
+ es6_Ext.inherits(Segment, es6_EventDispatcher);
11884
12054
 
12055
+ /** @private
12056
+ * @function
12057
+ * @param {string} a
12058
+ * @param {string} b
12059
+ * @return {number}
12060
+ */
12061
+ Segment._subSegSortLogic = function(a, b) {
12062
+ if(a === "Uncategorized") {
12063
+ return 1;
12064
+ }
12065
+ if(b === "Uncategorized") {
12066
+ return -1;
12067
+ }
12068
+
12069
+ if(a < b) {
12070
+ return -1;
12071
+ }
12072
+ if(b < a) {
12073
+ return 1;
12074
+ }
12075
+
12076
+ return 0;
12077
+ };
12078
+ /** @private
12079
+ * @function
12080
+ * @param {Segment} segment
12081
+ * @param {number} idx
12082
+ */
12083
+ Segment._assignSubSegmentOrder = function(segment, idx) {
12084
+ segment.setOrder(idx + 1);
12085
+ };
12086
+
12087
+ /** @type {Object}
12088
+ * @private
12089
+ */
12090
+ Segment.prototype._shared = null;
11885
12091
 
11886
12092
  /** @type {string}
11887
12093
  * @private
@@ -11902,13 +12108,67 @@ Segment.prototype._collapsed = false;
11902
12108
  /** @type {number}
11903
12109
  * @private
11904
12110
  */
11905
- Segment.prototype._value = 0;
12111
+ Segment.prototype._order = 0;
12112
+ /** @type {boolean}
12113
+ * @private
12114
+ */
12115
+ Segment.prototype._disposed = false;
12116
+
12117
+ /** @type {Object}
12118
+ * @private
12119
+ */
12120
+ Segment.prototype._subSegDef = null;
11906
12121
  /** @type {number}
11907
12122
  * @private
11908
12123
  */
11909
- Segment.prototype._order = 0;
12124
+ Segment.prototype._subSegLevel = 0;
12125
+ /** @type {Object.<string, Segment>}
12126
+ * @private
12127
+ */
12128
+ Segment.prototype._subSegMap = null; // For immediate sub-segment children
12129
+ /** @type {Array.<string>}
12130
+ * @private
12131
+ */
12132
+ Segment.prototype._subSegNames = null; // For immediate sub-segment child names
12133
+ /** @type {string}
12134
+ * @private
12135
+ */
12136
+ Segment.prototype._subSegName = "";
12137
+ /** @type {*}
12138
+ * @private
12139
+ */
12140
+ Segment.prototype._subSegVal;
12141
+ /** @type {Segment}
12142
+ * @private
12143
+ */
12144
+ Segment.prototype._subSegParent = null;
11910
12145
 
11911
12146
 
12147
+ /** @public
12148
+ */
12149
+ Segment.prototype.dispose = function() {
12150
+ if(this._disposed) {
12151
+ return;
12152
+ }
12153
+ this._disposed = true;
12154
+
12155
+ this.removeAllEventListeners();
12156
+ var segmentNames = this._subSegNames;
12157
+ if(segmentNames) {
12158
+ var segmentCount = segmentNames.length;
12159
+ var segmentMap = this._subSegMap;
12160
+ for(var i = 0; i < segmentCount; ++i) {
12161
+ segmentMap[segmentNames[i]].dispose();
12162
+ }
12163
+ this._subSegMap = this._subSegNames = null;
12164
+ }
12165
+ if(this._collapsed) {
12166
+ this._shared.dirtyCollapsingState = true;
12167
+ }
12168
+
12169
+ this._shared = null;
12170
+ this._subSegParent = this._subSegDef = this._subSegVal = null;
12171
+ };
11912
12172
  /** @public
11913
12173
  * @return {string}
11914
12174
  */
@@ -11916,32 +12176,66 @@ Segment.prototype.getId = function() {
11916
12176
  return this._rid;
11917
12177
  };
11918
12178
  /** @public
12179
+ * @return {string}
12180
+ */
12181
+ Segment.prototype.getParentId = function() {
12182
+ if(this._subSegParent) {
12183
+ return this._subSegParent.getId();
12184
+ }
12185
+ return "";
12186
+ };
12187
+ /** @public
12188
+ * @param {Array.<string>=} out_ary
12189
+ * @return {Array.<string>}
12190
+ */
12191
+ Segment.prototype.getSubSegmentIds = function(out_ary) {
12192
+ var segmentNames = this._subSegNames;
12193
+ if(segmentNames) {
12194
+ if(!out_ary) {
12195
+ out_ary = [];
12196
+ }
12197
+ var segmentCount = segmentNames.length;
12198
+ var segmentMap = this._subSegMap;
12199
+ for(var i = 0; i < segmentCount; ++i) {
12200
+ var segmentName = segmentNames[i];
12201
+ var segment = segmentMap[segmentName];
12202
+ out_ary.push(segment.getId());
12203
+ segment.getSubSegmentIds(out_ary);
12204
+ }
12205
+
12206
+ return out_ary;
12207
+ }
12208
+ return null;
12209
+ };
12210
+ /** @public
11919
12211
  * @param {string} rid
11920
- * @param {Object=} objMap
12212
+ * @param {string=} dataId Row id for retrieving data
11921
12213
  * @return {boolean}
11922
12214
  */
11923
- Segment.prototype.addChild = function(rid, objMap) {
11924
- if(rid && !this._children[rid]) {
11925
- if(objMap) {
11926
- objMap[rid] = this._rid;
12215
+ Segment.prototype.addChild = function(rid, dataId) {
12216
+ if(rid) {
12217
+ this._shared.childToSegment[rid] = this._rid;
12218
+ if(this._collapsed) {
12219
+ this._shared.dirtyCollapsingState = true; // TODO: Check if we need to update this only when new child is added
12220
+ }
12221
+ if(!this._children[rid]) {
12222
+ this._children[rid] = dataId || rid;
12223
+ ++this._childCount;
12224
+ return true;
11927
12225
  }
11928
- this._children[rid] = 1;
11929
- ++this._childCount;
11930
- return true;
11931
12226
  }
11932
12227
  return false;
11933
12228
  };
11934
12229
  /** @public
11935
12230
  * @param {Array.<string>} rids
11936
- * @param {Object=} objMap
11937
12231
  * @return {boolean}
11938
12232
  */
11939
- Segment.prototype.addChildren = function(rids, objMap) {
12233
+ Segment.prototype.addChildren = function(rids) {
11940
12234
  var rowIds = Array.isArray(rids) ? rids : [rids];
11941
12235
  var rowCount = rowIds.length;
11942
12236
  var dirty = 0;
11943
12237
  for(var i = 0; i < rowCount; ++i) {
11944
- dirty |= this.addChild(rowIds[i], objMap);
12238
+ dirty |= this.addChild(rowIds[i]);
11945
12239
  }
11946
12240
  return dirty ? true : false;
11947
12241
  };
@@ -11954,26 +12248,37 @@ Segment.prototype.containsChild = function(rid) {
11954
12248
  };
11955
12249
  /** @public
11956
12250
  * @param {string} rid
11957
- * @param {Object=} objMap
11958
12251
  * @return {boolean}
11959
12252
  */
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;
12253
+ Segment.prototype.removeChild = function(rid) {
12254
+ if(this._subSegLevel) {
12255
+ return false; // Sub segments are not allowed to remove its children
11968
12256
  }
11969
- return false;
12257
+ if(!this._childCount) {
12258
+ return false;
12259
+ }
12260
+ if(!this._children[rid]) {
12261
+ return false; // The specified rid is not a child of this segment
12262
+ }
12263
+
12264
+ var objMap = this._shared.childToSegment;
12265
+ delete objMap[rid];
12266
+ delete this._children[rid]; // Slow
12267
+ --this._childCount;
12268
+
12269
+ if(this._collapsed) {
12270
+ this._shared.dirtyCollapsingState = true;
12271
+ }
12272
+ return true;
11970
12273
  };
11971
12274
  /** @public
11972
12275
  * @param {Array.<string>} rids
11973
- * @param {Object=} objMap
11974
12276
  * @return {boolean}
11975
12277
  */
11976
- Segment.prototype.removeChildren = function(rids, objMap) {
12278
+ Segment.prototype.removeChildren = function(rids) {
12279
+ if(this._subSegLevel) {
12280
+ return false; // Sub segments are not allowed to remove its children
12281
+ }
11977
12282
  if(!this._childCount) {
11978
12283
  return false;
11979
12284
  }
@@ -11981,29 +12286,34 @@ Segment.prototype.removeChildren = function(rids, objMap) {
11981
12286
  var rowCount = rowIds.length;
11982
12287
  var dirty = 0;
11983
12288
  for(var i = 0; i < rowCount; ++i) {
11984
- dirty |= this.removeChild(rowIds[i], objMap);
12289
+ dirty |= this.removeChild(rowIds[i]);
11985
12290
  }
11986
12291
  return dirty ? true : false;
11987
12292
  };
11988
12293
  /** @public
11989
- * @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,317 @@ 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
+ var sharedObj = this._shared;
12415
+ if(this._collapsed) {
12416
+ sharedObj.dirtyCollapsingState = true;
12417
+ }
12418
+
12419
+ // Prepare existing sub segments for checking change in its members
12420
+ var i;
12421
+ var segmentName = "";
12422
+ var nonExistenceGroups = {};
12423
+ var removalCount = 0;
12424
+ var segmentMap = this._subSegMap;
12425
+ var segment = null;
12426
+ if(segmentCount) {
12427
+ removalCount = segmentCount;
12428
+ for(i = 0; i < removalCount; ++i) {
12429
+ segmentName = segmentNames[i];
12430
+ nonExistenceGroups[segmentName] = 1;
12431
+
12432
+ segment = segmentMap[segmentName];
12433
+ if(segment._childCount) { // Quick cleaning up
12434
+ segment._children = {};
12435
+ segment._childCount = 0;
12436
+ }
12437
+ if(segment._collapsed) {
12438
+ sharedObj.dirtyCollapsingState = true;
12439
+ }
12440
+ }
12441
+ }
12442
+
12443
+ // Loop through row children and assign them to their corresponding sub segment
12444
+ var isRootSegment = !this._subSegLevel;
12445
+ var rid;
12446
+ var children = this._children;
12447
+ if(this._subSegLevel < classifierCount && rows) {
12448
+ if(!segmentMap) {
12449
+ segmentMap = this._subSegMap = {};
12450
+ segmentNames = this._subSegNames = [];
12451
+ }
12452
+
12453
+ var classifier = classifiers[this._subSegLevel];
12454
+
12455
+ for(rid in children) {
12456
+ var dataId = children[rid];
12457
+ var record = rows[dataId];
12458
+ var val = record ? record[classifier] : null; // WARNING: row could already be removed
12459
+
12460
+ sharedObj.childToSegment[rid] = this._rid; // Relocate child in case of it has been moved to a non existence group
12461
+
12462
+ segmentName = "Uncategorized";
12463
+ if(val || val === 0 || val === false) { // Check for null, undefined, "", and NaN value
12464
+ segmentName = val + "";
12465
+ }
12466
+ if(nonExistenceGroups[segmentName]) {
12467
+ nonExistenceGroups[segmentName] = 0;
12468
+ --removalCount;
12469
+ }
12470
+
12471
+ segment = segmentMap[segmentName];
12472
+ if(!segment) { // New group is detected
12473
+ segment = new Segment(this._rid + "/" + segmentName, sharedObj);
12474
+ segment._subSegDef = this._subSegDef;
12475
+ segment._subSegLevel = this._subSegLevel + 1;
12476
+ segment._subSegName = segmentName;
12477
+ segment._subSegVal = val;
12478
+ segment._subSegParent = this;
12479
+
12480
+ segmentMap[segmentName] = segment;
12481
+ segmentNames.push(segmentName);
12482
+
12483
+ this._dispatch("subSegmentAdded", {
12484
+ "rid": segment.getId(),
12485
+ "segment": segment
12486
+ });
12487
+ }
12488
+
12489
+ segment.addChild(rid, dataId);
12490
+ }
12491
+ } else if(isRootSegment) { // In case of no classification
12492
+ for(rid in children) {
12493
+ sharedObj.childToSegment[rid] = this._rid; // Relocate child in case of it has been moved to a non existence group
12494
+ }
12495
+ }
12496
+
12497
+ // Remove all sub segments with no members
12498
+ if(removalCount > 0) {
12499
+ if(removalCount >= segmentNames.length) {
12500
+ segmentNames.length = 0;
12501
+ }
12502
+ for(segmentName in nonExistenceGroups) {
12503
+ if(nonExistenceGroups[segmentName]) {
12504
+ segment = segmentMap[segmentName];
12505
+ delete segmentMap[segmentName];
12506
+ // TODO: Slow
12507
+ var at = segmentNames.indexOf(segmentName);
12508
+ if(at >= 0) {
12509
+ segmentNames.splice(at, 1);
12510
+ }
12511
+
12512
+ this._dispatch("subSegmentRemoved", {
12513
+ "rid": segment.getId(),
12514
+ "segment": segment
12515
+ });
12516
+
12517
+ // segment.dispose(); Already done by segment collection
12518
+ }
12519
+ }
12520
+ if(!segmentNames.length) {
12521
+ segmentNames = this._subSegMap = this._subSegNames = null;
12522
+ }
12523
+ }
12524
+
12525
+ // Sort and classify existing sub segments
12526
+ segmentCount = segmentNames ? segmentNames.length : 0;
12527
+ if(segmentCount) {
12528
+ segmentNames.sort(Segment._subSegSortLogic);
12529
+ for(i = 0; i < segmentCount; ++i) {
12530
+ segment = segmentMap[segmentNames[i]];
12531
+ segment.classify(rows);
12532
+ }
12533
+ }
12534
+
12535
+ // Collecting all sub segments including all descendants and reassigning segment order.
12536
+ if(isRootSegment) { // If this is a root segment
12537
+ if(this._subSegDef) {
12538
+ if(segmentCount) {
12539
+ var subSegments = this._subSegDef.subSegments = [];
12540
+ this.getAllSubSegments(subSegments);
12541
+ subSegments.forEach(Segment._assignSubSegmentOrder);
12542
+ } else {
12543
+ this._subSegDef.subSegments = null;
12544
+ }
12545
+ // this._subSegDef.classifierChanged = false;
12546
+ }
12547
+ }
12548
+ return true;
12549
+ };
12550
+ /** @public
12551
+ * @return {boolean}
12552
+ */
12553
+ Segment.prototype.hasSubSegments = function() {
12554
+ if(this._subSegNames) {
12555
+ return this._subSegNames.length ? true : false;
12556
+ }
12557
+ return false;
12558
+ };
12559
+ /** @public
12560
+ * @return {boolean}
12561
+ */
12562
+ Segment.prototype.isSubSegment = function() {
12563
+ return this._subSegLevel ? true : false;
12564
+ };
12565
+ /** @public
12566
+ * @return {Segment}
12567
+ */
12568
+ Segment.prototype.getFirstAncestor = function() {
12569
+ if(this._subSegLevel && this._subSegDef) {
12570
+ var ancestor = this._subSegDef.root;
12571
+ return /** @type{Segment} */(ancestor) || null;
12572
+ }
12573
+ return null;
12574
+ };
12575
+ /** @public
12576
+ * @param {Array.<Segment>=} out_ary
12577
+ * @return {Array.<Segment>}
12578
+ */
12579
+ Segment.prototype.getAllSubSegments = function(out_ary) {
12580
+ var segmentNames = this._subSegNames;
12581
+ if(segmentNames) {
12582
+ if(!out_ary) {
12583
+ out_ary = [];
12584
+ }
12585
+ var segmentMap = this._subSegMap;
12586
+ var segmentCount = segmentNames.length;
12587
+ for(var i = 0; i < segmentCount; ++i) {
12588
+ var segment = segmentMap[segmentNames[i]];
12589
+ out_ary.push(segment);
12590
+ segment.getAllSubSegments(out_ary);
12591
+ }
12592
+ }
12593
+ return out_ary || null;
12594
+ };
12595
+ /** @public
12596
+ * @return {number}
12597
+ */
12598
+ Segment.prototype.getSegmentLevel = function() {
12599
+ return this._subSegLevel;
12600
+ };
12601
+ /** This method will be called on sub segments only
12602
+ * @public
12603
+ * @param {Object=} rows
12604
+ * @param {Object=} clsSource
12605
+ */
12606
+ Segment.prototype.setRowData = function(rows, clsSource) {
12607
+ if(!rows) {
12608
+ return;
12609
+ }
12610
+ var row = rows[this._rid];
12611
+ if(!row) {
12612
+ row = rows[this._rid] = {};
12613
+ }
12614
+
12615
+ if(!clsSource) {
12616
+ clsSource = rows;
12617
+ }
12618
+ row = clsSource[this._rid];
12619
+ if(!row) {
12620
+ row = clsSource[this._rid] = {};
12621
+ }
12622
+
12623
+ var segment = this;
12624
+ while(segment && segment.isSubSegment()) {
12625
+ segment.getSubSegmentName(row);
12626
+ segment = segment._subSegParent;
12627
+ }
12628
+ };
12629
+ /** @public
12630
+ * @param {Object=} row
12631
+ * @return {string}
12632
+ */
12633
+ Segment.prototype.getSubSegmentName = function(row) {
12634
+ if(row && this._subSegLevel) {
12635
+ var classifiers = this.getClassification();
12636
+ var field = classifiers[this._subSegLevel - 1];
12637
+ if(field) {
12638
+ row[field] = this._subSegName;
12639
+ }
12640
+ }
12641
+ return this._subSegName;
12642
+ };
12022
12643
 
12023
12644
  /** @public
12024
12645
  * @param {boolean=} bool
@@ -12028,6 +12649,7 @@ Segment.prototype.collapse = function(bool) {
12028
12649
  bool = (bool !== false);
12029
12650
  if(this._collapsed !== bool) {
12030
12651
  this._collapsed = bool;
12652
+ this._shared.dirtyCollapsingState = true;
12031
12653
  return true;
12032
12654
  }
12033
12655
  return false;
@@ -12047,44 +12669,109 @@ Segment.prototype.isCollapsed = function() {
12047
12669
  };
12048
12670
  /** @public
12049
12671
  * @param {Object=} objMap
12050
- * @return {!Object}
12672
+ * @param {boolean=} parentState=false Collapsing state from parent segment
12673
+ * @return {boolean}
12051
12674
  */
12052
- Segment.prototype.getCollapsingStates = function(objMap) {
12675
+ Segment.prototype.getCollapsingStates = function(objMap, parentState) {
12676
+ var segmentNames = this._subSegNames;
12677
+ if(!this._subSegLevel) { // Only root segment
12678
+ if(!segmentNames) { // No sub segment
12679
+ if(!this._collapsed) {
12680
+ return false;
12681
+ }
12682
+ }
12683
+ }
12684
+
12053
12685
  if(!objMap) {
12054
12686
  objMap = {};
12055
12687
  }
12688
+ var dirty = false;
12689
+ if(this._subSegLevel) { // Sub segments are also subjected to collapsing
12690
+ if(parentState) {
12691
+ objMap[this._rid] = true;
12692
+ dirty = true;
12693
+ }
12694
+ }
12056
12695
  if(this._childCount) {
12057
- var chdr = this._children;
12058
- var collapsed = this._collapsed;
12059
- for(var rid in chdr) {
12060
- objMap[rid] = collapsed;
12696
+ var collapsed = parentState || this._collapsed;
12697
+ if(segmentNames) {
12698
+ var segmentMap = this._subSegMap;
12699
+ var segmentCount = segmentNames.length;
12700
+ for(var i = 0; i < segmentCount; ++i) {
12701
+ var segment = segmentMap[segmentNames[i]];
12702
+ objMap[segment.getId()] = !!parentState;
12703
+ if(segment.getCollapsingStates(objMap, collapsed)) {
12704
+ dirty = true;
12705
+ }
12706
+ }
12707
+ } else if(collapsed) {
12708
+ var chdr = this._children;
12709
+ for(var rid in chdr) {
12710
+ objMap[rid] = collapsed;
12711
+ }
12712
+ dirty = true;
12061
12713
  }
12062
12714
  }
12063
- return objMap;
12715
+ return dirty;
12064
12716
  };
12717
+
12065
12718
  /** @public
12066
12719
  * @return {number}
12067
12720
  */
12068
- Segment.prototype.getValue = function() {
12069
- return this._value;
12721
+ Segment.prototype.getOrder = function() {
12722
+ if(this._subSegLevel) {
12723
+ var ancestor = this.getFirstAncestor();
12724
+ if(ancestor) {
12725
+ // WARNING: this._order cannot be greater than 9999
12726
+ return ancestor.getOrder() + this._order;
12727
+ }
12728
+ }
12729
+ return this._order * 10000;
12070
12730
  };
12071
12731
  /** @public
12072
12732
  * @param {number} val
12073
12733
  */
12074
- Segment.prototype.setValue = function(val) {
12075
- this._value = val;
12734
+ Segment.prototype.setOrder = function(val) {
12735
+ this._order = val;
12076
12736
  };
12077
- /** @public
12078
- * @return {number}
12737
+
12738
+ /** @private
12739
+ * @type {Array.<string>}
12079
12740
  */
12080
- Segment.prototype.getOrder = function() {
12081
- return this._order;
12082
- };
12741
+ Segment._tabs = null;
12083
12742
  /** @public
12084
- * @param {number} val
12743
+ * @param {Array.<string>} lines
12744
+ * @return {Array.<string>} lines
12085
12745
  */
12086
- Segment.prototype.setOrder = function(val) {
12087
- this._order = val;
12746
+ Segment.prototype.log = function(lines) {
12747
+ var i;
12748
+ var tabs = Segment._tabs;
12749
+ if(!tabs) {
12750
+ tabs = Segment._tabs = [];
12751
+ var tabCh = "";
12752
+ for(i = 0; i < 11; ++i) {
12753
+ tabs[i] = tabCh;
12754
+ tabCh += " ";
12755
+ }
12756
+ }
12757
+ var collapsedCh = this._collapsed ? "+ " : "- ";
12758
+ lines.push(tabs[this._subSegLevel] + collapsedCh + this._rid);
12759
+
12760
+ var segmentNames = this._subSegNames;
12761
+ if(segmentNames) {
12762
+ var segmentCount = segmentNames.length;
12763
+ var segmentMap = this._subSegMap;
12764
+ for(i = 0; i < segmentCount; ++i) {
12765
+ segmentMap[segmentNames[i]].log(lines);
12766
+ }
12767
+ } else if(this._childCount) {
12768
+ var indent = tabs[this._subSegLevel + 1];
12769
+ for(var rid in this._children) {
12770
+ lines.push(indent + "- " + rid);
12771
+ }
12772
+ }
12773
+
12774
+ return lines;
12088
12775
  };
12089
12776
 
12090
12777
 
@@ -12094,18 +12781,31 @@ Segment.prototype.setOrder = function(val) {
12094
12781
  ;// CONCATENATED MODULE: ./src/js/data/SegmentCollection.js
12095
12782
 
12096
12783
 
12784
+
12785
+
12097
12786
  /** @constructor
12787
+ * @extends {EventDispatcher}
12098
12788
  */
12099
12789
  var SegmentCollection = function() {
12790
+ this._onSubSegmentAdded = this._onSubSegmentAdded.bind(this);
12791
+ this._onSubSegmentRemoved = this._onSubSegmentRemoved.bind(this);
12792
+
12100
12793
  this._segments = {};
12101
- this._childToSegmentId = {};
12794
+ this._insertionList = [];
12795
+ this._removalList = [];
12796
+
12797
+ this._shared = {
12798
+ childToSegment: {}, // child Id to segment Id
12799
+ dirtyCollapsingState: false
12800
+ };
12102
12801
  };
12802
+ es6_Ext.inherits(SegmentCollection, es6_EventDispatcher);
12103
12803
 
12104
12804
 
12105
12805
  /** @type {!Object.<string, Segment>}
12106
12806
  * @private
12107
12807
  */
12108
- SegmentCollection.prototype._segments;
12808
+ SegmentCollection.prototype._segments; // Contains both segment and their sub segments
12109
12809
  /** @type {number}
12110
12810
  * @private
12111
12811
  */
@@ -12114,28 +12814,54 @@ SegmentCollection.prototype._segmentCount = 0;
12114
12814
  * @private
12115
12815
  */
12116
12816
  SegmentCollection.prototype._collapsedRids = null;
12817
+ /** @type {!Object}
12818
+ * @private
12819
+ */
12820
+ SegmentCollection.prototype._shared;
12821
+ /** @type {Array.<Segment>}
12822
+ * @private
12823
+ */
12824
+ SegmentCollection.prototype._segmentList = null; // Array of main segments
12825
+ /** @type {Array.<Segment>}
12826
+ * @private
12827
+ */
12828
+ SegmentCollection.prototype._insertionList = null; // Array of sub segments
12829
+ /** @type {Array.<string>}
12830
+ * @private
12831
+ */
12832
+ SegmentCollection.prototype._removalList = null; // Array of sub segment ids
12117
12833
  /** @type {boolean}
12118
12834
  * @private
12119
12835
  */
12120
- SegmentCollection.prototype._dirtyCollapsingState = false;
12121
- /** @type {!Object.<string, string>}
12836
+ SegmentCollection.prototype._classification = false;
12837
+ /** @type {boolean}
12122
12838
  * @private
12123
12839
  */
12124
- SegmentCollection.prototype._childToSegmentId;
12125
-
12840
+ SegmentCollection.prototype._classifierChanged = false;
12126
12841
 
12842
+ /** @public
12843
+ */
12844
+ SegmentCollection.prototype.dispose = function() {
12845
+ this.removeAllSegments();
12846
+ this.removeAllEventListeners();
12847
+ this._collapsedRids = null;
12848
+ this._segmentList = this._insertionList = this._removalList = null;
12849
+ };
12127
12850
  /** @public
12128
12851
  * @param {string} rid
12129
12852
  * @return {boolean} Returns true if there is any change. Otherwise, returns false
12130
12853
  */
12131
12854
  SegmentCollection.prototype.addSegment = function(rid) {
12132
12855
  if(rid && !this._segments[rid]) {
12133
- if(this._childToSegmentId[rid]) {
12856
+ if(this.getParentRowId(rid)) {
12134
12857
  console.log("child of a segment cannot be set as a segment separator");
12135
12858
  return false;
12136
12859
  }
12137
- this._segments[rid] = new data_Segment(rid);
12860
+ var segment = this._segments[rid] = new data_Segment(rid, this._shared);
12861
+ segment.addEventListener("subSegmentAdded", this._onSubSegmentAdded);
12862
+ segment.addEventListener("subSegmentRemoved", this._onSubSegmentRemoved);
12138
12863
  ++this._segmentCount;
12864
+ this._segmentList = null; // order could be changed
12139
12865
  return true;
12140
12866
  }
12141
12867
  return false;
@@ -12165,7 +12891,7 @@ SegmentCollection.prototype.containsSegment = function(rid) {
12165
12891
  * @return {string} parent row id of this segmentation. If the parent row id for this segmentation cannot be found, return ""
12166
12892
  */
12167
12893
  SegmentCollection.prototype.getParentRowId = function(rid) {
12168
- return this._childToSegmentId[rid] || "";
12894
+ return this._shared.childToSegment[rid] || "";
12169
12895
  };
12170
12896
  /** @public
12171
12897
  * @param {string} rid
@@ -12174,10 +12900,27 @@ SegmentCollection.prototype.getParentRowId = function(rid) {
12174
12900
  SegmentCollection.prototype.removeSegment = function(rid) {
12175
12901
  var segment = this._segments[rid];
12176
12902
  if(segment) {
12177
- if(segment.isCollapsed()) {
12178
- this._dirtyCollapsingState = true;
12903
+ if(this._segmentCount <= 1) {
12904
+ return this.removeAllSegments();
12905
+ }
12906
+ if(segment.isSubSegment()) {
12907
+ this._removalList.push(segment.getId());
12908
+ }
12909
+ var subSegIds = segment.getSubSegmentIds();
12910
+ if(subSegIds) {
12911
+ var len = subSegIds.length;
12912
+ for(var i = 0; i < len; ++i) {
12913
+ var subSegId = subSegIds[i];
12914
+ if(this._segments[subSegId]) {
12915
+ this._removalList.push(subSegId);
12916
+ delete this._segments[subSegId]; // Slow
12917
+ --this._segmentCount;
12918
+ }
12919
+ }
12179
12920
  }
12180
- segment.removeAllChildren(this._childToSegmentId);
12921
+ segment.removeAllChildren(); // This is important for updating childToSegment
12922
+ segment.dispose();
12923
+
12181
12924
  delete this._segments[rid]; // Slow
12182
12925
  --this._segmentCount;
12183
12926
  return true;
@@ -12189,10 +12932,15 @@ SegmentCollection.prototype.removeSegment = function(rid) {
12189
12932
  */
12190
12933
  SegmentCollection.prototype.removeAllSegments = function() {
12191
12934
  if(this._segmentCount) {
12935
+ for(var key in this._segments) {
12936
+ this._segments[key].dispose();
12937
+ }
12192
12938
  this._segments = {};
12193
- this._childToSegmentId = {};
12194
12939
  this._segmentCount = 0;
12195
- this._dirtyCollapsingState = true;
12940
+ this._segmentList = null;
12941
+ this._shared.childToSegment = {};
12942
+
12943
+ this._classification = this._classifierChanged = false;
12196
12944
  return true;
12197
12945
  }
12198
12946
  return false;
@@ -12233,11 +12981,7 @@ SegmentCollection.prototype.getSegmentIds = function() {
12233
12981
  SegmentCollection.prototype.collapseSegment = function(segmentId, bool) {
12234
12982
  var segment = this._segments[segmentId];
12235
12983
  if(segment) {
12236
- var dirty = segment.collapse(bool);
12237
- if(dirty) {
12238
- this._dirtyCollapsingState = true;
12239
- return true;
12240
- }
12984
+ return segment.collapse(bool);
12241
12985
  }
12242
12986
  return false;
12243
12987
  };
@@ -12260,7 +13004,6 @@ SegmentCollection.prototype.expandAllSegments = function() {
12260
13004
  dirty |= segmentSeparators[rid].expand();
12261
13005
  }
12262
13006
  if(dirty) {
12263
- this._dirtyCollapsingState = true;
12264
13007
  return true;
12265
13008
  }
12266
13009
  }
@@ -12281,17 +13024,19 @@ SegmentCollection.prototype.isCollapsedSegment = function(segmentId) {
12281
13024
  * @return {Object}
12282
13025
  */
12283
13026
  SegmentCollection.prototype.getCollapsedRows = function() {
12284
- if(this._dirtyCollapsingState) {
12285
- this._dirtyCollapsingState = false;
13027
+ if(this._shared.dirtyCollapsingState) {
13028
+ this._shared.dirtyCollapsingState = false;
12286
13029
  var collapsedRids = null;
12287
13030
  var count = 0;
12288
13031
  if(this._segmentCount) {
12289
13032
  var segmentSeparators = this._segments;
12290
13033
  collapsedRids = {};
12291
13034
  for(var rid in segmentSeparators) {
12292
- if(segmentSeparators[rid].isCollapsed()) {
12293
- segmentSeparators[rid].getCollapsingStates(collapsedRids);
12294
- ++count;
13035
+ var segment = segmentSeparators[rid];
13036
+ if(!segment.isSubSegment()) {
13037
+ if(segment.getCollapsingStates(collapsedRids)) {
13038
+ ++count;
13039
+ }
12295
13040
  }
12296
13041
  }
12297
13042
  }
@@ -12303,18 +13048,13 @@ SegmentCollection.prototype.getCollapsedRows = function() {
12303
13048
  /** @public
12304
13049
  * @param {string} segmentId
12305
13050
  * @param {string} rid
13051
+ * @param {string=} dataId Row id for retrieving data
12306
13052
  * @return {boolean} Returns true if there is any change. Otherwise, returns false
12307
13053
  */
12308
- SegmentCollection.prototype.addSegmentChild = function(segmentId, rid) {
13054
+ SegmentCollection.prototype.addSegmentChild = function(segmentId, rid, dataId) {
12309
13055
  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
- }
13056
+ if(segment && !segment.isSubSegment()) {
13057
+ return segment.addChild(rid, dataId);
12318
13058
  }
12319
13059
  return false;
12320
13060
  };
@@ -12325,14 +13065,8 @@ SegmentCollection.prototype.addSegmentChild = function(segmentId, rid) {
12325
13065
  */
12326
13066
  SegmentCollection.prototype.addSegmentChildren = function(segmentId, rids) {
12327
13067
  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
- }
13068
+ if(segment && !segment.isSubSegment()) {
13069
+ return segment.addChildren(rids);
12336
13070
  }
12337
13071
  return false;
12338
13072
  };
@@ -12356,13 +13090,7 @@ SegmentCollection.prototype.containsSegmentChild = function(segmentId, rid) {
12356
13090
  SegmentCollection.prototype.removeSegmentChild = function(segmentId, rid) {
12357
13091
  var segment = this._segments[segmentId];
12358
13092
  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
- }
13093
+ return segment.removeChild(rid);
12366
13094
  }
12367
13095
  return false;
12368
13096
  };
@@ -12374,13 +13102,7 @@ SegmentCollection.prototype.removeSegmentChild = function(segmentId, rid) {
12374
13102
  SegmentCollection.prototype.removeSegmentChildren = function(segmentId, rids) {
12375
13103
  var segment = this._segments[segmentId];
12376
13104
  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
- }
13105
+ return segment.removeChildren(rids);
12384
13106
  }
12385
13107
  return false;
12386
13108
  };
@@ -12388,20 +13110,20 @@ SegmentCollection.prototype.removeSegmentChildren = function(segmentId, rids) {
12388
13110
  * @return {boolean} Returns true if there is any change. Otherwise, returns false
12389
13111
  */
12390
13112
  SegmentCollection.prototype.removeAllSegmentChildren = function() {
12391
- this._childToSegmentId = {};
13113
+ this._shared.childToSegment = {};
12392
13114
  var segmentSeparators = this._segments;
12393
- var dirtyCollapsingState = this._dirtyCollapsingState;
12394
13115
  var dirty = false;
12395
13116
  for(var rid in segmentSeparators) {
12396
- var segment = this._segments[rid];
13117
+ var segment = segmentSeparators[rid];
12397
13118
  if(segment.removeAllChildren()) {
12398
13119
  dirty = true;
12399
- if(!dirtyCollapsingState && segment.isCollapsed()) {
12400
- dirtyCollapsingState = this._dirtyCollapsingState = true;
12401
- }
12402
13120
  }
12403
13121
  }
12404
13122
 
13123
+ if(dirty) {
13124
+ this.classify(null);
13125
+ }
13126
+
12405
13127
  return dirty;
12406
13128
  };
12407
13129
 
@@ -12415,22 +13137,18 @@ SegmentCollection.prototype.fillSegment = function(segmentId, rids) {
12415
13137
  return;
12416
13138
  }
12417
13139
  var segmentSeparators = this._segments;
12418
- var childToSegmentId = this._childToSegmentId;
12419
13140
  var curSegment = segmentSeparators[segmentId];
12420
- if(curSegment) {
13141
+ if(curSegment && !curSegment.isSubSegment()) {
12421
13142
  var segmentAt = rids.indexOf(segmentId);
12422
13143
  if(segmentAt >= 0) {
12423
- if(curSegment.isCollapsed()) {
12424
- this._dirtyCollapsingState = true;
12425
- }
12426
- curSegment.removeAllChildren(childToSegmentId);
13144
+ curSegment.removeAllChildren();
12427
13145
  for(var r = segmentAt + 1; r < rowCount; ++r) {
12428
13146
  var rid = rids[r];
12429
13147
  var segmentSeparator = segmentSeparators[rid];
12430
13148
  if(segmentSeparator) {
12431
13149
  break;
12432
13150
  }
12433
- curSegment.addChild(rid, childToSegmentId);
13151
+ curSegment.addChild(rid);
12434
13152
  }
12435
13153
  }
12436
13154
  }
@@ -12440,23 +13158,20 @@ SegmentCollection.prototype.fillSegment = function(segmentId, rids) {
12440
13158
  * @return {boolean} Return true if the fill segments have changed, otherwise return false
12441
13159
  */
12442
13160
  SegmentCollection.prototype.fillSegments = function(rids) {
13161
+ this._shared.childToSegment = {};
13162
+
12443
13163
  var rowCount = Array.isArray(rids) ? rids.length : 0;
12444
- this._childToSegmentId = {};
12445
13164
  var segmentSeparators = this._segments;
12446
- var childToSegmentId = this._childToSegmentId;
12447
13165
  var curSegment = null;
12448
13166
  var change = false;
12449
13167
  for(var r = 0; r < rowCount; ++r) {
12450
13168
  var rid = rids[r];
12451
13169
  var segmentSeparator = segmentSeparators[rid];
12452
- if(segmentSeparator) {
13170
+ if(segmentSeparator && !segmentSeparator.isSubSegment()) {
12453
13171
  curSegment = segmentSeparator;
12454
- if(curSegment.isCollapsed()) {
12455
- this._dirtyCollapsingState = true;
12456
- }
12457
13172
  curSegment.removeAllChildren();
12458
- } else if(curSegment) {
12459
- curSegment.addChild(rid, childToSegmentId);
13173
+ } else if(curSegment && !curSegment.isSubSegment()) {
13174
+ curSegment.addChild(rid);
12460
13175
  change = true;
12461
13176
  }
12462
13177
  }
@@ -12466,6 +13181,13 @@ SegmentCollection.prototype.fillSegments = function(rids) {
12466
13181
  * @param {Array.<string>} rids
12467
13182
  */
12468
13183
  SegmentCollection.prototype.calcSegmentOrder = function(rids) {
13184
+ var segmentList = this._segmentList;
13185
+ if(segmentList) {
13186
+ segmentList.length = 0;
13187
+ } else {
13188
+ segmentList = this._segmentList = [];
13189
+ }
13190
+
12469
13191
  var ridCount = rids ? rids.length : 0;
12470
13192
  var segmentSeparators = this._segments;
12471
13193
  var segmentCount = this._segmentCount;
@@ -12474,8 +13196,11 @@ SegmentCollection.prototype.calcSegmentOrder = function(rids) {
12474
13196
  var rid = rids[i];
12475
13197
  var segment = segmentSeparators[rid];
12476
13198
  if(segment) {
12477
- segment.setOrder(++order);
12478
- if(order >= segmentCount) {
13199
+ if(!segment.isSubSegment()) {
13200
+ this._segmentList.push(segment);
13201
+ segment.setOrder(++order); // WARNING: Segments and sub segments start with 1
13202
+ }
13203
+ if(--segmentCount <= 0) {
12479
13204
  break;
12480
13205
  }
12481
13206
  }
@@ -12491,7 +13216,7 @@ SegmentCollection.prototype.getSegmentValues = function(rids) {
12491
13216
  return null;
12492
13217
  }
12493
13218
  var segmentSeparators = this._segments;
12494
- var childToSegmentId = this._childToSegmentId;
13219
+ var childToSegmentId = this._shared.childToSegment;
12495
13220
  var curSegment = null;
12496
13221
  var prevSegment = null;
12497
13222
  var segmentValues = new Array(rowCount);
@@ -12521,6 +13246,126 @@ SegmentCollection.prototype.getSegmentValues = function(rids) {
12521
13246
 
12522
13247
  return prevSegment ? segmentValues : null;
12523
13248
  };
13249
+ /** @public
13250
+ * @return {string}
13251
+ */
13252
+ SegmentCollection.prototype.logStructure = function() {
13253
+ var segmentList = this._segmentList;
13254
+ if(!segmentList) {
13255
+ return "";
13256
+ }
13257
+ var segmentCount = segmentList.length;
13258
+ var lines = [];
13259
+ for(var i = 0; i < segmentCount; ++i) {
13260
+ segmentList[i].log(lines);
13261
+ }
13262
+
13263
+ return lines.join("\n");
13264
+ };
13265
+ /** @public
13266
+ * @return {string}
13267
+ */
13268
+ SegmentCollection.prototype.logRowIdMap = function() {
13269
+ var lines = [];
13270
+ var childToSegmentId = this._shared.childToSegment;
13271
+ for(var rid in childToSegmentId) {
13272
+ var segmentId = childToSegmentId[rid];
13273
+ lines.push(rid + " > " + segmentId);
13274
+ }
13275
+
13276
+ return lines.join("\n");
13277
+ };
13278
+
13279
+
13280
+ /** @public
13281
+ * @param {string} segmentId
13282
+ * @param {string|Array.<string>} fields
13283
+ * @return {boolean}
13284
+ */
13285
+ SegmentCollection.prototype.setSegmentClassification = function(segmentId, fields) {
13286
+ var segment = this._segments[segmentId];
13287
+ if(segment) {
13288
+ if(segment.setClassification(fields)) {
13289
+ if(segment.getClassification()) {
13290
+ this._classification = true;
13291
+ }
13292
+ this._classifierChanged = true;
13293
+
13294
+ return true;
13295
+ }
13296
+ }
13297
+ return false;
13298
+ };
13299
+ /** @public
13300
+ * @return {boolean}
13301
+ */
13302
+ SegmentCollection.prototype.hasClassification = function() {
13303
+ // WARNING: This include the time when classification is removed
13304
+ return this._classification || this._classifierChanged;
13305
+ };
13306
+ /** @public
13307
+ * @param {Object.<string, Object>} rows Object maps between row id and its record
13308
+ * @return {boolean}
13309
+ */
13310
+ SegmentCollection.prototype.classify = function(rows) {
13311
+ if(!this._segmentCount) {
13312
+ return false;
13313
+ }
13314
+ if(!this.hasClassification()) {
13315
+ return false;
13316
+ }
13317
+ this._classification = this._classifierChanged = false;
13318
+
13319
+ var segmentSeparators = this._segments;
13320
+ for(var rid in segmentSeparators) {
13321
+ var segment = this._segments[rid];
13322
+ if(!segment.isSubSegment()) {
13323
+ if(segment.getClassification()) {
13324
+ this._classification = true;
13325
+ }
13326
+ segment.classify(rows);
13327
+ }
13328
+ }
13329
+ if(this._insertionList.length || this._removalList.length) {
13330
+ this._dispatch("subSegmentChanged", {
13331
+ "insertionList": this._insertionList,
13332
+ "removalList": this._removalList
13333
+ });
13334
+ this._insertionList.length = 0;
13335
+ this._removalList.length = 0;
13336
+
13337
+ this._dispatch("classified", {});
13338
+ return true;
13339
+ }
13340
+
13341
+ this._dispatch("classified", {});
13342
+ return false;
13343
+ };
13344
+
13345
+ /** @private
13346
+ * @param {!Object} e
13347
+ */
13348
+ SegmentCollection.prototype._onSubSegmentAdded = function(e) {
13349
+ var rid = e["rid"];
13350
+ if(!this._segments[rid]) {
13351
+ var segment = /** @type{Segment} */(e["segment"]);
13352
+ this._insertionList.push(segment);
13353
+ this._segments[rid] = segment;
13354
+ this._segmentCount++;
13355
+
13356
+ segment.addEventListener("subSegmentAdded", this._onSubSegmentAdded);
13357
+ segment.addEventListener("subSegmentRemoved", this._onSubSegmentRemoved);
13358
+ } else {
13359
+ console.log("Incorrect logic detected.");
13360
+ }
13361
+ };
13362
+ /** @private
13363
+ * @param {!Object} e
13364
+ */
13365
+ SegmentCollection.prototype._onSubSegmentRemoved = function(e) {
13366
+ var rid = e["rid"];
13367
+ this.removeSegment(rid);
13368
+ };
12524
13369
 
12525
13370
 
12526
13371
  /* harmony default export */ const data_SegmentCollection = (SegmentCollection);
@@ -12530,6 +13375,7 @@ SegmentCollection.prototype.getSegmentValues = function(rids) {
12530
13375
 
12531
13376
 
12532
13377
 
13378
+ // eslint-disable-line
12533
13379
 
12534
13380
 
12535
13381
  /** Trigger when data within the table has been changed
@@ -12552,11 +13398,15 @@ var DataTable = function() {
12552
13398
 
12553
13399
  this._removeRows = this._removeRows.bind(this);
12554
13400
  this._bySegmentSeparator = this._bySegmentSeparator.bind(this);
13401
+ this._onClassifyingTimer = this._onClassifyingTimer.bind(this);
13402
+ this._onSubSegmentChanged = this._onSubSegmentChanged.bind(this);
12555
13403
 
12556
13404
  this._prevData = {};
12557
13405
  this._rids = [];
12558
13406
 
12559
13407
  this._compMap = {};
13408
+
13409
+ this._addEvent("subSegmentChanged");
12560
13410
  };
12561
13411
  es6_Ext.inherits(DataTable, data_DataCache);
12562
13412
 
@@ -12599,6 +13449,14 @@ DataTable.prototype._removedRows = null;
12599
13449
  * @type {Function}
12600
13450
  */
12601
13451
  DataTable.prototype._userSegmentComparer = null;
13452
+ /** @private
13453
+ * @type {Object.<string, Object>}
13454
+ */
13455
+ DataTable.prototype._clsSource = null;
13456
+ /** @private
13457
+ * @type {number}
13458
+ */
13459
+ DataTable.prototype._classifyingTimer = 0;
12602
13460
 
12603
13461
 
12604
13462
  /** @typedef {Function} DataTable~SortLogic
@@ -12627,8 +13485,17 @@ DataTable.prototype.dispose = function() {
12627
13485
  this.unlistenAll();
12628
13486
  this.clearAllData(true);
12629
13487
 
13488
+ if(this._classifyingTimer) {
13489
+ clearTimeout(this._classifyingTimer);
13490
+ this._classifyingTimer = 0;
13491
+ }
13492
+
12630
13493
  this._compMap = null; // Release user function that may be bound
12631
- this._segments = null;
13494
+ this._clsSource = null;
13495
+ if(this._segments) {
13496
+ this._segments.dispose();
13497
+ this._segments = null;
13498
+ }
12632
13499
  };
12633
13500
 
12634
13501
  /** {@link DataCache#getColumnData}
@@ -12746,7 +13613,7 @@ DataTable.prototype.setRowData = function(rid, values, eventArg) { // Data chang
12746
13613
  this._prevData[rid] = {};
12747
13614
  if(eventArg) {
12748
13615
  var nextRid = /** @type{string} */(eventArg["nextRid"]); // Used for insertion only
12749
- var rowIndex = (nextRid != null) ? this.getRowIndex(nextRid) : -1;
13616
+ var rowIndex = (nextRid) ? this.getRowIndex(nextRid) : -1;
12750
13617
  if(rowIndex < 0) {
12751
13618
  rowIndex = /** @type{number} */(eventArg["fallback"]);
12752
13619
  }
@@ -12778,6 +13645,7 @@ DataTable.prototype.setRowData = function(rid, values, eventArg) { // Data chang
12778
13645
  var segment = this._segments.getSegment(rid);
12779
13646
  if(segment) {
12780
13647
  if(this._segments.removeSegment(rid)) {
13648
+ // TODO: Handle sub segment removal
12781
13649
  segmentChanged = true;
12782
13650
  if(!this._segments.getSegmentCount()) {
12783
13651
  this._segments = null;
@@ -12785,12 +13653,7 @@ DataTable.prototype.setRowData = function(rid, values, eventArg) { // Data chang
12785
13653
  }
12786
13654
  }
12787
13655
  }
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
- }
13656
+ DataTable._removeArrayItem(this._rids, rid);
12794
13657
  dirty = true;
12795
13658
  }
12796
13659
  }
@@ -12809,7 +13672,7 @@ DataTable.prototype.setRowData = function(rid, values, eventArg) { // Data chang
12809
13672
  }
12810
13673
  this._dispatchDataChange(e);
12811
13674
  }
12812
-
13675
+ this.requestClassifying(); // TODO: Check if needFiring method should have an effect on this request
12813
13676
  }
12814
13677
  return dirty;
12815
13678
  };
@@ -13012,7 +13875,7 @@ DataTable.prototype.unshiftRow = function(opt_values, opt_rid) {
13012
13875
  return this.insertRow(0, opt_values, opt_rid);
13013
13876
  };
13014
13877
  /** @public
13015
- * @param {string|number|null=} rowRef
13878
+ * @param {(string|number|null)=} rowRef
13016
13879
  * @param {Object.<string, *>=} values Key/value pair object map
13017
13880
  * @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
13881
  * @return {string} Return Row id that has been inserted or changed
@@ -13021,11 +13884,13 @@ DataTable.prototype.unshiftRow = function(opt_values, opt_rid) {
13021
13884
  * @see {@link DataTable#removeRow}
13022
13885
  */
13023
13886
  DataTable.prototype.insertRow = function(rowRef, values, rid) {
13024
- var arg = {};
13887
+ var arg = null;
13025
13888
  if(typeof rowRef === "number") {
13889
+ arg = {};
13026
13890
  arg["nextRid"] = this._rids[rowRef];
13027
13891
  arg["fallback"] = rowRef; // Fallback index in case of no nextRid found
13028
- } else {
13892
+ } else if(rowRef) {
13893
+ arg = {};
13029
13894
  arg["nextRid"] = /** @type{string} */(rowRef);
13030
13895
  }
13031
13896
 
@@ -13110,12 +13975,34 @@ DataTable.prototype.removeRows = function(refs) {
13110
13975
  DataTable.prototype._removeRows = function(rid) {
13111
13976
  return !this._removedRows[rid];
13112
13977
  };
13978
+
13979
+ /** @private
13980
+ * @param {Array} ary
13981
+ * @param {*} item
13982
+ * @return {boolean}
13983
+ */
13984
+ DataTable._removeArrayItem = function(ary, item) {
13985
+ var at = ary.indexOf(item);
13986
+ if(at >= 0) {
13987
+ if(at >= ary.length) {
13988
+ ary.pop(); // Array.pop is 100 times faster than Array.splice
13989
+ } else {
13990
+ ary.splice(at, 1);
13991
+ }
13992
+ return true;
13993
+ }
13994
+ return false;
13995
+ };
13113
13996
  /** Remove all existing rows
13114
13997
  * @override
13115
13998
  */
13116
13999
  DataTable.prototype.clearAllData = function(suppressEvent) {
13117
14000
  DataTable.base(this, "clearAllData", true);
13118
14001
  this._prevData = {};
14002
+ // TODO: Clear all segments
14003
+ if(this._segments) {
14004
+ this._segments.removeAllSegmentChildren(); // This immediately remove all sub segments
14005
+ }
13119
14006
 
13120
14007
  if(this._rids.length) {
13121
14008
  this._rids.length = 0;
@@ -13422,6 +14309,7 @@ DataTable.prototype.setSegmentSeparator = function(rid, enabled) {
13422
14309
  if(enabled !== false) {
13423
14310
  if(!this._segments) {
13424
14311
  this._segments = new data_SegmentCollection();
14312
+ this._segments.addEventListener("subSegmentChanged", this._onSubSegmentChanged);
13425
14313
  }
13426
14314
  if(this._autoSegmentFilling) {
13427
14315
  var parentId = this._segments.getParentRowId(rid);
@@ -13494,6 +14382,29 @@ DataTable.prototype.isSegmentSeparator = function(rid) {
13494
14382
  }
13495
14383
  return false;
13496
14384
  };
14385
+ /** Get Segment object
14386
+ * @public
14387
+ * @param {string} rid Row id
14388
+ * @return {Segment} Return 0 if the given rid is not a segment
14389
+ */
14390
+ DataTable.prototype.getSegment = function(rid) {
14391
+ if(this._segments) {
14392
+ return this._segments.getSegment(rid);
14393
+ }
14394
+ return null;
14395
+ };
14396
+ /** Segment level starts from 1
14397
+ * @public
14398
+ * @param {string} rid
14399
+ * @return {number} Return 0 if the given rid is not a segment
14400
+ */
14401
+ DataTable.prototype.getSegmentLevel = function(rid) {
14402
+ var segment = this.getSegment(rid);
14403
+ if(segment) {
14404
+ return segment.getSegmentLevel() + 1;
14405
+ }
14406
+ return 0;
14407
+ };
13497
14408
  /**
13498
14409
  * @public
13499
14410
  * @param {string} rid
@@ -13567,6 +14478,7 @@ DataTable.prototype.fillSegment = function(segmentId) {
13567
14478
  if(this._segments) {
13568
14479
  this._segments.fillSegment(segmentId, this._rids);
13569
14480
  this.dispatchGlobalChange();
14481
+ this.requestClassifying();
13570
14482
  }
13571
14483
  };
13572
14484
  /** Remove all existing segment children in each segment and fill the segments with all contnet rows before the next segment separator
@@ -13578,6 +14490,7 @@ DataTable.prototype.fillSegments = function() {
13578
14490
  var dirty = this._segments.fillSegments(this._rids);
13579
14491
  if(dirty) {
13580
14492
  this.dispatchGlobalChange();
14493
+ this.requestClassifying();
13581
14494
  }
13582
14495
  return dirty;
13583
14496
  }
@@ -13586,15 +14499,17 @@ DataTable.prototype.fillSegments = function() {
13586
14499
  /** @public
13587
14500
  * @param {string} segmentId Row id
13588
14501
  * @param {string} rid Row id
14502
+ * @param {string=} dataId Row id for retrieving data
13589
14503
  * @return {boolean} Return true if there is any change
13590
14504
  */
13591
- DataTable.prototype.addSegmentChild = function(segmentId, rid) {
14505
+ DataTable.prototype.addSegmentChild = function(segmentId, rid, dataId) {
13592
14506
  if(this._segments) {
13593
- var dirty = this._segments.addSegmentChild(segmentId, rid);
14507
+ var dirty = this._segments.addSegmentChild(segmentId, rid, dataId);
13594
14508
  if(dirty) {
13595
14509
  if(this._sort(null)) {
13596
14510
  this._dispatchPositionChange();
13597
14511
  }
14512
+ this.requestClassifying();
13598
14513
  return true;
13599
14514
  }
13600
14515
  }
@@ -13612,6 +14527,7 @@ DataTable.prototype.addSegmentChildren = function(segmentId, rids) {
13612
14527
  if(this._sort(null)) {
13613
14528
  this._dispatchPositionChange();
13614
14529
  }
14530
+ this.requestClassifying();
13615
14531
  return true;
13616
14532
  }
13617
14533
  }
@@ -13627,6 +14543,7 @@ DataTable.prototype.removeSegmentChild = function(segmentId, rid) {
13627
14543
  var dirty = this._segments.removeSegmentChild(segmentId, rid);
13628
14544
  if(dirty) {
13629
14545
  this.dispatchGlobalChange();
14546
+ this.requestClassifying();
13630
14547
  }
13631
14548
  return dirty;
13632
14549
  }
@@ -13642,6 +14559,7 @@ DataTable.prototype.removeSegmentChildren = function(segmentId, rids) {
13642
14559
  var dirty = this._segments.removeSegmentChildren(segmentId, rids);
13643
14560
  if(dirty) {
13644
14561
  this.dispatchGlobalChange();
14562
+ this.requestClassifying();
13645
14563
  }
13646
14564
  return dirty;
13647
14565
  }
@@ -13652,7 +14570,7 @@ DataTable.prototype.removeSegmentChildren = function(segmentId, rids) {
13652
14570
  */
13653
14571
  DataTable.prototype.removeAllSegmentChildren = function() {
13654
14572
  if(this._segments) {
13655
- var dirty = this._segments.removeAllSegmentChildren();
14573
+ var dirty = this._segments.removeAllSegmentChildren(); // This immediately remove all sub segments
13656
14574
  if (dirty) {
13657
14575
  this.dispatchGlobalChange();
13658
14576
  }
@@ -13688,10 +14606,15 @@ DataTable.prototype.getSegmentChildIds = function(segmentId) {
13688
14606
  /** Sort all of existing segments by given compare function
13689
14607
  * @public
13690
14608
  * @param {Function} compare
14609
+ * @return {boolean}
13691
14610
  */
13692
14611
  DataTable.prototype.sortSegments = function (compare) {
13693
- if(!this._segments || typeof compare !== "function") {
13694
- return;
14612
+ if(!this._segments) {
14613
+ return false;
14614
+ }
14615
+ if(typeof compare !== "function") {
14616
+ this._segments.calcSegmentOrder(this._rids);
14617
+ return false;
13695
14618
  }
13696
14619
  var rids = this._rids;
13697
14620
  var segments = this._segments;
@@ -13735,7 +14658,9 @@ DataTable.prototype.sortSegments = function (compare) {
13735
14658
  this._segments.calcSegmentOrder(rids);
13736
14659
  this._sort(null);
13737
14660
  this._dispatchPositionChange();
14661
+ return true;
13738
14662
  }
14663
+ return false;
13739
14664
  };
13740
14665
  /** Sort all of existing segments by given compare function
13741
14666
  * @private
@@ -13750,6 +14675,112 @@ DataTable.prototype._bySegmentSeparator = function (segmentA, segmentB) {
13750
14675
  ));
13751
14676
  };
13752
14677
 
14678
+ /** A data source to be used with segment classification
14679
+ * @public
14680
+ * @param {DataCache} dc
14681
+ */
14682
+ DataTable.prototype.setClassificationSource = function(dc) {
14683
+ this._clsSource = null;
14684
+
14685
+ if(dc && dc._rows) {
14686
+ this._clsSource = dc._rows;
14687
+ }
14688
+ };
14689
+ /**
14690
+ * @public
14691
+ * @param {string} segmentId
14692
+ * @param {string|Array.<string>} fields
14693
+ * @return {boolean}
14694
+ */
14695
+ DataTable.prototype.setSegmentClassification = function(segmentId, fields) {
14696
+ if(this._segments) {
14697
+ var dirty = this._segments.setSegmentClassification(segmentId, fields);
14698
+ if(dirty) {
14699
+ return this.classifySegments();
14700
+ }
14701
+ }
14702
+ return false;
14703
+ };
14704
+ /** @public
14705
+ * @return {boolean}
14706
+ */
14707
+ DataTable.prototype.classifySegments = function() {
14708
+ if(this._segments) {
14709
+ if(this._rids.length) {
14710
+ return this._segments.classify(this._clsSource || this._rows);
14711
+ }
14712
+ }
14713
+ return false;
14714
+ };
14715
+
14716
+ /** @public
14717
+ */
14718
+ DataTable.prototype.requestClassifying = function() {
14719
+ if(this._segments && !this._classifyingTimer) {
14720
+ if(this._segments.hasClassification()) {
14721
+ this._classifyingTimer = setTimeout(this._onClassifyingTimer, 10);
14722
+ }
14723
+ }
14724
+ };
14725
+ /** @private
14726
+ */
14727
+ DataTable.prototype._onClassifyingTimer = function() {
14728
+ this._classifyingTimer = 0;
14729
+ this.classifySegments();
14730
+ };
14731
+ /** @private
14732
+ * @param {Object} e
14733
+ */
14734
+ DataTable.prototype._onSubSegmentChanged = function(e) {
14735
+ var insertionList = /** @type{Array.<Segment>} */(e["insertionList"]);
14736
+ var removalList = /** @type{Array.<string>} */(e["removalList"]);
14737
+
14738
+ var dirty = false;
14739
+ var rows = this._rows;
14740
+ var clsSource = this._clsSource || rows;
14741
+ var rids = this._rids;
14742
+ var prevData = this._prevData;
14743
+ var i;
14744
+
14745
+ var removalCount = removalList.length;
14746
+ var removedRows = {};
14747
+ for(i = 0; i < removalCount; i++) {
14748
+ var rid = removalList[i];
14749
+ if(rows[rid]) {
14750
+ removedRows[rid] = prevData[rid] = rows[rid];
14751
+ delete rows[rid];
14752
+ DataTable._removeArrayItem(rids, rid);
14753
+ dirty = true;
14754
+ // TODO: Remove classification source
14755
+ }
14756
+ }
14757
+
14758
+ var insertionCount = insertionList.length;
14759
+ for(i = 0; i < insertionCount; i++) {
14760
+ var segment = insertionList[i];
14761
+ var parentId = segment.getParentId();
14762
+ var segmentId = segment.getId();
14763
+
14764
+ if(!rows[segmentId]) {
14765
+ prevData[segmentId] = {};
14766
+ segment.setRowData(rows, clsSource);
14767
+
14768
+ var parentAt = rids.indexOf(parentId);
14769
+ if(parentAt < 0 || parentAt + 1 >= rids.length) {
14770
+ rids.push(segmentId);
14771
+ } else {
14772
+ rids.splice(parentAt + 1, 0, segmentId);
14773
+ }
14774
+ dirty = true;
14775
+ }
14776
+ }
14777
+ if(dirty) {
14778
+ e["removedRows"] = removedRows;
14779
+ this._dispatch("subSegmentChanged", e);
14780
+ this.dispatchGlobalChange(); // Rerender everything
14781
+ }
14782
+ };
14783
+
13753
14784
 
13754
14785
  /**
13755
14786
  * @public
@@ -16190,6 +17221,7 @@ Conflator.prototype.enable = function (opt_enabled) {
16190
17221
 
16191
17222
  // eslint-disable-line
16192
17223
 
17224
+ // eslint-disable-line
16193
17225
 
16194
17226
 
16195
17227
 
@@ -18534,6 +19566,22 @@ DataView.prototype.isSegmentSeparator = function(rid) {
18534
19566
  return this._dt.isSegmentSeparator(rid);
18535
19567
  };
18536
19568
 
19569
+ /** Get Segment object
19570
+ * @public
19571
+ * @param {string} rid Row id
19572
+ * @return {Segment} Return 0 if the given rid is not a segment
19573
+ */
19574
+ DataView.prototype.getSegment = function(rid) {
19575
+ return this._dt.getSegment(rid);
19576
+ };
19577
+ /** Segment level starts from 1
19578
+ * @public
19579
+ * @param {string} rid Row id
19580
+ * @return {number} Return 0 if the given rid is not a segment
19581
+ */
19582
+ DataView.prototype.getSegmentLevel = function(rid) {
19583
+ return this._dt.getSegmentLevel(rid);
19584
+ };
18537
19585
  /**
18538
19586
  * @public
18539
19587
  * @param {string} rid
@@ -18615,13 +19663,14 @@ DataView.prototype.fillSegments = function() {
18615
19663
  /** @public
18616
19664
  * @param {string|number} segmentRef Row id or row index
18617
19665
  * @param {string|number} rowRef Row id, row index
19666
+ * @param {string=} dataId Row id for retrieving data
18618
19667
  * @return {boolean} Return true if there is any change
18619
19668
  */
18620
- DataView.prototype.addSegmentChild = function(segmentRef, rowRef) {
19669
+ DataView.prototype.addSegmentChild = function(segmentRef, rowRef, dataId) {
18621
19670
  if(this._dt._getSegmentSeparators()) {
18622
19671
  var segmentId = this._toRowId(segmentRef);
18623
19672
  var rowId = this._toRowId(rowRef);
18624
- return this._dt.addSegmentChild(segmentId, rowId);
19673
+ return this._dt.addSegmentChild(segmentId, rowId, dataId);
18625
19674
  }
18626
19675
  return false;
18627
19676
  };
@@ -18693,6 +19742,16 @@ DataView.prototype.sortSegments = function (compare) {
18693
19742
  this._dt.sortSegments(compare);
18694
19743
  };
18695
19744
 
19745
+ /**
19746
+ * @public
19747
+ * @param {string|number} segmentRef Row id or row index
19748
+ * @param {string|Array.<string>} fields
19749
+ * @return {boolean}
19750
+ */
19751
+ DataView.prototype.setSegmentClassification = function(segmentRef, fields) {
19752
+ return this._dt.setSegmentClassification(this._toRowId(segmentRef), fields);
19753
+ };
19754
+
18696
19755
  /** @public
18697
19756
  * @ignore
18698
19757
  * @return {Object}
@@ -23149,7 +24208,7 @@ Core_Core.prototype._rowHeightTimerId = 0;
23149
24208
  * @return {string}
23150
24209
  */
23151
24210
  Core_Core.getVersion = function () {
23152
- return "5.1.20";
24211
+ return "5.1.27";
23153
24212
  };
23154
24213
  /** {@link ElementWrapper#dispose}
23155
24214
  * @override