@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
@@ -1,11 +1,54 @@
1
+ import Ext from "../../../tr-grid-util/es6/Ext.js";
2
+ import EventDispatcher from "../../../tr-grid-util/es6/EventDispatcher.js";
3
+
1
4
  /** @constructor
5
+ * @extends {EventDispatcher}
2
6
  * @param {string} rid
7
+ * @param {!Object} sharedObj
3
8
  */
4
- var Segment = function(rid) {
9
+ var Segment = function(rid, sharedObj) {
5
10
  this._rid = rid;
6
11
  this._children = {};
12
+ this._shared = sharedObj;
7
13
  };
14
+ Ext.inherits(Segment, EventDispatcher);
15
+
16
+ /** @private
17
+ * @function
18
+ * @param {string} a
19
+ * @param {string} b
20
+ * @return {number}
21
+ */
22
+ Segment._subSegSortLogic = function(a, b) {
23
+ if(a === "Uncategorized") {
24
+ return 1;
25
+ }
26
+ if(b === "Uncategorized") {
27
+ return -1;
28
+ }
8
29
 
30
+ if(a < b) {
31
+ return -1;
32
+ }
33
+ if(b < a) {
34
+ return 1;
35
+ }
36
+
37
+ return 0;
38
+ };
39
+ /** @private
40
+ * @function
41
+ * @param {Segment} segment
42
+ * @param {number} idx
43
+ */
44
+ Segment._assignSubSegmentOrder = function(segment, idx) {
45
+ segment.setOrder(idx + 1);
46
+ };
47
+
48
+ /** @type {Object}
49
+ * @private
50
+ */
51
+ Segment.prototype._shared = null;
9
52
 
10
53
  /** @type {string}
11
54
  * @private
@@ -26,13 +69,67 @@ Segment.prototype._collapsed = false;
26
69
  /** @type {number}
27
70
  * @private
28
71
  */
29
- Segment.prototype._value = 0;
72
+ Segment.prototype._order = 0;
73
+ /** @type {boolean}
74
+ * @private
75
+ */
76
+ Segment.prototype._disposed = false;
77
+
78
+ /** @type {Object}
79
+ * @private
80
+ */
81
+ Segment.prototype._subSegDef = null;
30
82
  /** @type {number}
31
83
  * @private
32
84
  */
33
- Segment.prototype._order = 0;
85
+ Segment.prototype._subSegLevel = 0;
86
+ /** @type {Object.<string, Segment>}
87
+ * @private
88
+ */
89
+ Segment.prototype._subSegMap = null; // For immediate sub-segment children
90
+ /** @type {Array.<string>}
91
+ * @private
92
+ */
93
+ Segment.prototype._subSegNames = null; // For immediate sub-segment child names
94
+ /** @type {string}
95
+ * @private
96
+ */
97
+ Segment.prototype._subSegName = "";
98
+ /** @type {*}
99
+ * @private
100
+ */
101
+ Segment.prototype._subSegVal;
102
+ /** @type {Segment}
103
+ * @private
104
+ */
105
+ Segment.prototype._subSegParent = null;
34
106
 
35
107
 
108
+ /** @public
109
+ */
110
+ Segment.prototype.dispose = function() {
111
+ if(this._disposed) {
112
+ return;
113
+ }
114
+ this._disposed = true;
115
+
116
+ this.removeAllEventListeners();
117
+ var segmentNames = this._subSegNames;
118
+ if(segmentNames) {
119
+ var segmentCount = segmentNames.length;
120
+ var segmentMap = this._subSegMap;
121
+ for(var i = 0; i < segmentCount; ++i) {
122
+ segmentMap[segmentNames[i]].dispose();
123
+ }
124
+ this._subSegMap = this._subSegNames = null;
125
+ }
126
+ if(this._collapsed) {
127
+ this._shared.dirtyCollapsingState = true;
128
+ }
129
+
130
+ this._shared = null;
131
+ this._subSegParent = this._subSegDef = this._subSegVal = null;
132
+ };
36
133
  /** @public
37
134
  * @return {string}
38
135
  */
@@ -40,32 +137,66 @@ Segment.prototype.getId = function() {
40
137
  return this._rid;
41
138
  };
42
139
  /** @public
140
+ * @return {string}
141
+ */
142
+ Segment.prototype.getParentId = function() {
143
+ if(this._subSegParent) {
144
+ return this._subSegParent.getId();
145
+ }
146
+ return "";
147
+ };
148
+ /** @public
149
+ * @param {Array.<string>=} out_ary
150
+ * @return {Array.<string>}
151
+ */
152
+ Segment.prototype.getSubSegmentIds = function(out_ary) {
153
+ var segmentNames = this._subSegNames;
154
+ if(segmentNames) {
155
+ if(!out_ary) {
156
+ out_ary = [];
157
+ }
158
+ var segmentCount = segmentNames.length;
159
+ var segmentMap = this._subSegMap;
160
+ for(var i = 0; i < segmentCount; ++i) {
161
+ var segmentName = segmentNames[i];
162
+ var segment = segmentMap[segmentName];
163
+ out_ary.push(segment.getId());
164
+ segment.getSubSegmentIds(out_ary);
165
+ }
166
+
167
+ return out_ary;
168
+ }
169
+ return null;
170
+ };
171
+ /** @public
43
172
  * @param {string} rid
44
- * @param {Object=} objMap
173
+ * @param {string=} dataId Row id for retrieving data
45
174
  * @return {boolean}
46
175
  */
47
- Segment.prototype.addChild = function(rid, objMap) {
48
- if(rid && !this._children[rid]) {
49
- if(objMap) {
50
- objMap[rid] = this._rid;
176
+ Segment.prototype.addChild = function(rid, dataId) {
177
+ if(rid) {
178
+ this._shared.childToSegment[rid] = this._rid;
179
+ if(this._collapsed) {
180
+ this._shared.dirtyCollapsingState = true; // TODO: Check if we need to update this only when new child is added
181
+ }
182
+ if(!this._children[rid]) {
183
+ this._children[rid] = dataId || rid;
184
+ ++this._childCount;
185
+ return true;
51
186
  }
52
- this._children[rid] = 1;
53
- ++this._childCount;
54
- return true;
55
187
  }
56
188
  return false;
57
189
  };
58
190
  /** @public
59
191
  * @param {Array.<string>} rids
60
- * @param {Object=} objMap
61
192
  * @return {boolean}
62
193
  */
63
- Segment.prototype.addChildren = function(rids, objMap) {
194
+ Segment.prototype.addChildren = function(rids) {
64
195
  var rowIds = Array.isArray(rids) ? rids : [rids];
65
196
  var rowCount = rowIds.length;
66
197
  var dirty = 0;
67
198
  for(var i = 0; i < rowCount; ++i) {
68
- dirty |= this.addChild(rowIds[i], objMap);
199
+ dirty |= this.addChild(rowIds[i]);
69
200
  }
70
201
  return dirty ? true : false;
71
202
  };
@@ -78,26 +209,37 @@ Segment.prototype.containsChild = function(rid) {
78
209
  };
79
210
  /** @public
80
211
  * @param {string} rid
81
- * @param {Object=} objMap
82
212
  * @return {boolean}
83
213
  */
84
- Segment.prototype.removeChild = function(rid, objMap) {
85
- if(this._childCount && this._children[rid]) {
86
- if(objMap) {
87
- delete objMap[rid];
88
- }
89
- delete this._children[rid]; // Slow
90
- --this._childCount;
91
- return true;
214
+ Segment.prototype.removeChild = function(rid) {
215
+ if(this._subSegLevel) {
216
+ return false; // Sub segments are not allowed to remove its children
92
217
  }
93
- return false;
218
+ if(!this._childCount) {
219
+ return false;
220
+ }
221
+ if(!this._children[rid]) {
222
+ return false; // The specified rid is not a child of this segment
223
+ }
224
+
225
+ var objMap = this._shared.childToSegment;
226
+ delete objMap[rid];
227
+ delete this._children[rid]; // Slow
228
+ --this._childCount;
229
+
230
+ if(this._collapsed) {
231
+ this._shared.dirtyCollapsingState = true;
232
+ }
233
+ return true;
94
234
  };
95
235
  /** @public
96
236
  * @param {Array.<string>} rids
97
- * @param {Object=} objMap
98
237
  * @return {boolean}
99
238
  */
100
- Segment.prototype.removeChildren = function(rids, objMap) {
239
+ Segment.prototype.removeChildren = function(rids) {
240
+ if(this._subSegLevel) {
241
+ return false; // Sub segments are not allowed to remove its children
242
+ }
101
243
  if(!this._childCount) {
102
244
  return false;
103
245
  }
@@ -105,29 +247,34 @@ Segment.prototype.removeChildren = function(rids, objMap) {
105
247
  var rowCount = rowIds.length;
106
248
  var dirty = 0;
107
249
  for(var i = 0; i < rowCount; ++i) {
108
- dirty |= this.removeChild(rowIds[i], objMap);
250
+ dirty |= this.removeChild(rowIds[i]);
109
251
  }
110
252
  return dirty ? true : false;
111
253
  };
112
254
  /** @public
113
- * @param {Object=} objMap
114
255
  * @return {boolean}
115
256
  */
116
- Segment.prototype.removeAllChildren = function(objMap) {
117
- if(this._childCount) {
118
- if(objMap) {
119
- var chdr = this._children;
120
- for(var rid in chdr) {
121
- if(objMap[rid]) {
122
- delete objMap[rid];
123
- }
124
- }
257
+ Segment.prototype.removeAllChildren = function() {
258
+ if(this._subSegLevel) {
259
+ return false; // Sub segments are not allowed to remove its children
260
+ }
261
+ if(!this._childCount) {
262
+ return false;
263
+ }
264
+ var objMap = this._shared.childToSegment;
265
+ var chdr = this._children;
266
+ for(var rid in chdr) {
267
+ if(objMap[rid]) {
268
+ delete objMap[rid]; // TODO: Check if we need to do this
125
269
  }
126
- this._children = {};
127
- this._childCount = 0;
128
- return true;
129
270
  }
130
- return false;
271
+ this._children = {};
272
+ this._childCount = 0;
273
+
274
+ if(this._collapsed) {
275
+ this._shared.dirtyCollapsingState = true;
276
+ }
277
+ return true;
131
278
  };
132
279
  /** @public
133
280
  * @return {!Array.<string>}
@@ -143,6 +290,317 @@ Segment.prototype.getChildCount = function() {
143
290
  };
144
291
 
145
292
 
293
+ /** @public
294
+ * @return {Array.<string>} fields
295
+ */
296
+ Segment.prototype.getClassification = function() {
297
+ if(this._subSegDef) {
298
+ return this._subSegDef.classifiers || null;
299
+ }
300
+ return null;
301
+ };
302
+ /** @public
303
+ * @param {string|Array.<string>} fields
304
+ * @return {boolean}
305
+ */
306
+ Segment.prototype.setClassification = function(fields) {
307
+ if(this._subSegLevel) {
308
+ return false; // non-root segment cannot be classified
309
+ }
310
+ var classifiers = null;
311
+ if(this._subSegDef) {
312
+ classifiers = this._subSegDef.classifiers;
313
+ }
314
+
315
+ var newClassifiers = null;
316
+ if(fields) {
317
+ if(typeof fields === "string") {
318
+ newClassifiers = [fields];
319
+ } else if(Array.isArray(fields)) {
320
+ newClassifiers = fields;
321
+ }
322
+ }
323
+ var i;
324
+ var fieldCount = newClassifiers ? newClassifiers.length : 0;
325
+
326
+ if(fieldCount) {
327
+ var curCount = classifiers ? classifiers.length : 0;
328
+ if(curCount === fieldCount) { // Check duplication
329
+ for(i = 0; i < fieldCount; ++i) {
330
+ if(newClassifiers[i] !== classifiers[i]) {
331
+ break;
332
+ }
333
+ }
334
+ if(i >= fieldCount) {
335
+ return false; // nothing has change
336
+ }
337
+ }
338
+
339
+ if(!this._subSegDef) {
340
+ this._subSegDef = {
341
+ root: this,
342
+ subSegments: null
343
+ };
344
+ }
345
+
346
+ this._subSegDef.classifiers = newClassifiers;
347
+ // this._subSegDef.classifierChanged = true;
348
+ return true;
349
+ } else if(classifiers) { // Remove existing ones
350
+ this._subSegDef.classifiers = null;
351
+ this._subSegDef.subSegments = null;
352
+ // this._subSegDef.classifierChanged = true;
353
+ this._subSegDef = null; // WARNING: All sub segments remain existing
354
+ return true;
355
+ }
356
+ return false;
357
+ };
358
+ /** @public
359
+ * @param {Object.<string, Object>=} rows Object maps between row id and its record
360
+ * @return {boolean}
361
+ */
362
+ Segment.prototype.classify = function(rows) {
363
+ var classifiers = this._subSegDef ? this._subSegDef.classifiers : null;
364
+ var classifierCount = classifiers ? classifiers.length : 0;
365
+
366
+ var segmentNames = this._subSegNames;
367
+ var segmentCount = segmentNames ? segmentNames.length : 0;
368
+
369
+ if(!segmentCount) {
370
+ if(this._subSegLevel >= classifierCount) {
371
+ return false; // Current segment level is beyond existing classification level and this segment should already be removed
372
+ }
373
+ }
374
+
375
+ var sharedObj = this._shared;
376
+ if(this._collapsed) {
377
+ sharedObj.dirtyCollapsingState = true;
378
+ }
379
+
380
+ // Prepare existing sub segments for checking change in its members
381
+ var i;
382
+ var segmentName = "";
383
+ var nonExistenceGroups = {};
384
+ var removalCount = 0;
385
+ var segmentMap = this._subSegMap;
386
+ var segment = null;
387
+ if(segmentCount) {
388
+ removalCount = segmentCount;
389
+ for(i = 0; i < removalCount; ++i) {
390
+ segmentName = segmentNames[i];
391
+ nonExistenceGroups[segmentName] = 1;
392
+
393
+ segment = segmentMap[segmentName];
394
+ if(segment._childCount) { // Quick cleaning up
395
+ segment._children = {};
396
+ segment._childCount = 0;
397
+ }
398
+ if(segment._collapsed) {
399
+ sharedObj.dirtyCollapsingState = true;
400
+ }
401
+ }
402
+ }
403
+
404
+ // Loop through row children and assign them to their corresponding sub segment
405
+ var isRootSegment = !this._subSegLevel;
406
+ var rid;
407
+ var children = this._children;
408
+ if(this._subSegLevel < classifierCount && rows) {
409
+ if(!segmentMap) {
410
+ segmentMap = this._subSegMap = {};
411
+ segmentNames = this._subSegNames = [];
412
+ }
413
+
414
+ var classifier = classifiers[this._subSegLevel];
415
+
416
+ for(rid in children) {
417
+ var dataId = children[rid];
418
+ var record = rows[dataId];
419
+ var val = record ? record[classifier] : null; // WARNING: row could already be removed
420
+
421
+ sharedObj.childToSegment[rid] = this._rid; // Relocate child in case of it has been moved to a non existence group
422
+
423
+ segmentName = "Uncategorized";
424
+ if(val || val === 0 || val === false) { // Check for null, undefined, "", and NaN value
425
+ segmentName = val + "";
426
+ }
427
+ if(nonExistenceGroups[segmentName]) {
428
+ nonExistenceGroups[segmentName] = 0;
429
+ --removalCount;
430
+ }
431
+
432
+ segment = segmentMap[segmentName];
433
+ if(!segment) { // New group is detected
434
+ segment = new Segment(this._rid + "/" + segmentName, sharedObj);
435
+ segment._subSegDef = this._subSegDef;
436
+ segment._subSegLevel = this._subSegLevel + 1;
437
+ segment._subSegName = segmentName;
438
+ segment._subSegVal = val;
439
+ segment._subSegParent = this;
440
+
441
+ segmentMap[segmentName] = segment;
442
+ segmentNames.push(segmentName);
443
+
444
+ this._dispatch("subSegmentAdded", {
445
+ "rid": segment.getId(),
446
+ "segment": segment
447
+ });
448
+ }
449
+
450
+ segment.addChild(rid, dataId);
451
+ }
452
+ } else if(isRootSegment) { // In case of no classification
453
+ for(rid in children) {
454
+ sharedObj.childToSegment[rid] = this._rid; // Relocate child in case of it has been moved to a non existence group
455
+ }
456
+ }
457
+
458
+ // Remove all sub segments with no members
459
+ if(removalCount > 0) {
460
+ if(removalCount >= segmentNames.length) {
461
+ segmentNames.length = 0;
462
+ }
463
+ for(segmentName in nonExistenceGroups) {
464
+ if(nonExistenceGroups[segmentName]) {
465
+ segment = segmentMap[segmentName];
466
+ delete segmentMap[segmentName];
467
+ // TODO: Slow
468
+ var at = segmentNames.indexOf(segmentName);
469
+ if(at >= 0) {
470
+ segmentNames.splice(at, 1);
471
+ }
472
+
473
+ this._dispatch("subSegmentRemoved", {
474
+ "rid": segment.getId(),
475
+ "segment": segment
476
+ });
477
+
478
+ // segment.dispose(); Already done by segment collection
479
+ }
480
+ }
481
+ if(!segmentNames.length) {
482
+ segmentNames = this._subSegMap = this._subSegNames = null;
483
+ }
484
+ }
485
+
486
+ // Sort and classify existing sub segments
487
+ segmentCount = segmentNames ? segmentNames.length : 0;
488
+ if(segmentCount) {
489
+ segmentNames.sort(Segment._subSegSortLogic);
490
+ for(i = 0; i < segmentCount; ++i) {
491
+ segment = segmentMap[segmentNames[i]];
492
+ segment.classify(rows);
493
+ }
494
+ }
495
+
496
+ // Collecting all sub segments including all descendants and reassigning segment order.
497
+ if(isRootSegment) { // If this is a root segment
498
+ if(this._subSegDef) {
499
+ if(segmentCount) {
500
+ var subSegments = this._subSegDef.subSegments = [];
501
+ this.getAllSubSegments(subSegments);
502
+ subSegments.forEach(Segment._assignSubSegmentOrder);
503
+ } else {
504
+ this._subSegDef.subSegments = null;
505
+ }
506
+ // this._subSegDef.classifierChanged = false;
507
+ }
508
+ }
509
+ return true;
510
+ };
511
+ /** @public
512
+ * @return {boolean}
513
+ */
514
+ Segment.prototype.hasSubSegments = function() {
515
+ if(this._subSegNames) {
516
+ return this._subSegNames.length ? true : false;
517
+ }
518
+ return false;
519
+ };
520
+ /** @public
521
+ * @return {boolean}
522
+ */
523
+ Segment.prototype.isSubSegment = function() {
524
+ return this._subSegLevel ? true : false;
525
+ };
526
+ /** @public
527
+ * @return {Segment}
528
+ */
529
+ Segment.prototype.getFirstAncestor = function() {
530
+ if(this._subSegLevel && this._subSegDef) {
531
+ var ancestor = this._subSegDef.root;
532
+ return /** @type{Segment} */(ancestor) || null;
533
+ }
534
+ return null;
535
+ };
536
+ /** @public
537
+ * @param {Array.<Segment>=} out_ary
538
+ * @return {Array.<Segment>}
539
+ */
540
+ Segment.prototype.getAllSubSegments = function(out_ary) {
541
+ var segmentNames = this._subSegNames;
542
+ if(segmentNames) {
543
+ if(!out_ary) {
544
+ out_ary = [];
545
+ }
546
+ var segmentMap = this._subSegMap;
547
+ var segmentCount = segmentNames.length;
548
+ for(var i = 0; i < segmentCount; ++i) {
549
+ var segment = segmentMap[segmentNames[i]];
550
+ out_ary.push(segment);
551
+ segment.getAllSubSegments(out_ary);
552
+ }
553
+ }
554
+ return out_ary || null;
555
+ };
556
+ /** @public
557
+ * @return {number}
558
+ */
559
+ Segment.prototype.getSegmentLevel = function() {
560
+ return this._subSegLevel;
561
+ };
562
+ /** This method will be called on sub segments only
563
+ * @public
564
+ * @param {Object=} rows
565
+ * @param {Object=} clsSource
566
+ */
567
+ Segment.prototype.setRowData = function(rows, clsSource) {
568
+ if(!rows) {
569
+ return;
570
+ }
571
+ var row = rows[this._rid];
572
+ if(!row) {
573
+ row = rows[this._rid] = {};
574
+ }
575
+
576
+ if(!clsSource) {
577
+ clsSource = rows;
578
+ }
579
+ row = clsSource[this._rid];
580
+ if(!row) {
581
+ row = clsSource[this._rid] = {};
582
+ }
583
+
584
+ var segment = this;
585
+ while(segment && segment.isSubSegment()) {
586
+ segment.getSubSegmentName(row);
587
+ segment = segment._subSegParent;
588
+ }
589
+ };
590
+ /** @public
591
+ * @param {Object=} row
592
+ * @return {string}
593
+ */
594
+ Segment.prototype.getSubSegmentName = function(row) {
595
+ if(row && this._subSegLevel) {
596
+ var classifiers = this.getClassification();
597
+ var field = classifiers[this._subSegLevel - 1];
598
+ if(field) {
599
+ row[field] = this._subSegName;
600
+ }
601
+ }
602
+ return this._subSegName;
603
+ };
146
604
 
147
605
  /** @public
148
606
  * @param {boolean=} bool
@@ -152,6 +610,7 @@ Segment.prototype.collapse = function(bool) {
152
610
  bool = (bool !== false);
153
611
  if(this._collapsed !== bool) {
154
612
  this._collapsed = bool;
613
+ this._shared.dirtyCollapsingState = true;
155
614
  return true;
156
615
  }
157
616
  return false;
@@ -171,44 +630,109 @@ Segment.prototype.isCollapsed = function() {
171
630
  };
172
631
  /** @public
173
632
  * @param {Object=} objMap
174
- * @return {!Object}
633
+ * @param {boolean=} parentState=false Collapsing state from parent segment
634
+ * @return {boolean}
175
635
  */
176
- Segment.prototype.getCollapsingStates = function(objMap) {
636
+ Segment.prototype.getCollapsingStates = function(objMap, parentState) {
637
+ var segmentNames = this._subSegNames;
638
+ if(!this._subSegLevel) { // Only root segment
639
+ if(!segmentNames) { // No sub segment
640
+ if(!this._collapsed) {
641
+ return false;
642
+ }
643
+ }
644
+ }
645
+
177
646
  if(!objMap) {
178
647
  objMap = {};
179
648
  }
649
+ var dirty = false;
650
+ if(this._subSegLevel) { // Sub segments are also subjected to collapsing
651
+ if(parentState) {
652
+ objMap[this._rid] = true;
653
+ dirty = true;
654
+ }
655
+ }
180
656
  if(this._childCount) {
181
- var chdr = this._children;
182
- var collapsed = this._collapsed;
183
- for(var rid in chdr) {
184
- objMap[rid] = collapsed;
657
+ var collapsed = parentState || this._collapsed;
658
+ if(segmentNames) {
659
+ var segmentMap = this._subSegMap;
660
+ var segmentCount = segmentNames.length;
661
+ for(var i = 0; i < segmentCount; ++i) {
662
+ var segment = segmentMap[segmentNames[i]];
663
+ objMap[segment.getId()] = !!parentState;
664
+ if(segment.getCollapsingStates(objMap, collapsed)) {
665
+ dirty = true;
666
+ }
667
+ }
668
+ } else if(collapsed) {
669
+ var chdr = this._children;
670
+ for(var rid in chdr) {
671
+ objMap[rid] = collapsed;
672
+ }
673
+ dirty = true;
185
674
  }
186
675
  }
187
- return objMap;
676
+ return dirty;
188
677
  };
678
+
189
679
  /** @public
190
680
  * @return {number}
191
681
  */
192
- Segment.prototype.getValue = function() {
193
- return this._value;
682
+ Segment.prototype.getOrder = function() {
683
+ if(this._subSegLevel) {
684
+ var ancestor = this.getFirstAncestor();
685
+ if(ancestor) {
686
+ // WARNING: this._order cannot be greater than 9999
687
+ return ancestor.getOrder() + this._order;
688
+ }
689
+ }
690
+ return this._order * 10000;
194
691
  };
195
692
  /** @public
196
693
  * @param {number} val
197
694
  */
198
- Segment.prototype.setValue = function(val) {
199
- this._value = val;
695
+ Segment.prototype.setOrder = function(val) {
696
+ this._order = val;
200
697
  };
201
- /** @public
202
- * @return {number}
698
+
699
+ /** @private
700
+ * @type {Array.<string>}
203
701
  */
204
- Segment.prototype.getOrder = function() {
205
- return this._order;
206
- };
702
+ Segment._tabs = null;
207
703
  /** @public
208
- * @param {number} val
704
+ * @param {Array.<string>} lines
705
+ * @return {Array.<string>} lines
209
706
  */
210
- Segment.prototype.setOrder = function(val) {
211
- this._order = val;
707
+ Segment.prototype.log = function(lines) {
708
+ var i;
709
+ var tabs = Segment._tabs;
710
+ if(!tabs) {
711
+ tabs = Segment._tabs = [];
712
+ var tabCh = "";
713
+ for(i = 0; i < 11; ++i) {
714
+ tabs[i] = tabCh;
715
+ tabCh += " ";
716
+ }
717
+ }
718
+ var collapsedCh = this._collapsed ? "+ " : "- ";
719
+ lines.push(tabs[this._subSegLevel] + collapsedCh + this._rid);
720
+
721
+ var segmentNames = this._subSegNames;
722
+ if(segmentNames) {
723
+ var segmentCount = segmentNames.length;
724
+ var segmentMap = this._subSegMap;
725
+ for(i = 0; i < segmentCount; ++i) {
726
+ segmentMap[segmentNames[i]].log(lines);
727
+ }
728
+ } else if(this._childCount) {
729
+ var indent = tabs[this._subSegLevel + 1];
730
+ for(var rid in this._children) {
731
+ lines.push(indent + "- " + rid);
732
+ }
733
+ }
734
+
735
+ return lines;
212
736
  };
213
737
 
214
738