@refinitiv-ui/efx-grid 6.0.153 → 6.0.155

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.
@@ -9145,7 +9145,7 @@ DataCache.constructTable = function (dataset, opt_options, opt_rowIds) {
9145
9145
  */
9146
9146
  let Segment = function(rid, sharedObj) {
9147
9147
  this._rid = rid;
9148
- this._children = {};
9148
+ this._childIds = [];
9149
9149
  this._shared = sharedObj;
9150
9150
  if(sharedObj.defaultCollapsing) {
9151
9151
  this._collapsed = true;
@@ -9176,14 +9176,6 @@ Segment._subSegSortLogic = function(a, b) {
9176
9176
 
9177
9177
  return 0;
9178
9178
  };
9179
- /** @private
9180
- * @function
9181
- * @param {Segment} segment
9182
- * @param {number} idx
9183
- */
9184
- Segment._assignSubSegmentOrder = function(segment, idx) {
9185
- segment.setOrder(idx + 1);
9186
- };
9187
9179
 
9188
9180
  /** @type {Object}
9189
9181
  * @private
@@ -9194,14 +9186,14 @@ Segment.prototype._shared = null;
9194
9186
  * @private
9195
9187
  */
9196
9188
  Segment.prototype._rid;
9197
- /** @type {!Object}
9189
+ /** @type {!Array.<string>}
9198
9190
  * @private
9199
9191
  */
9200
- Segment.prototype._children;
9201
- /** @type {number}
9192
+ Segment.prototype._childIds;
9193
+ /** @type {Object}
9202
9194
  * @private
9203
9195
  */
9204
- Segment.prototype._childCount = 0;
9196
+ Segment.prototype._childDataIds = null;
9205
9197
  /** @type {boolean}
9206
9198
  * @private
9207
9199
  */
@@ -9210,6 +9202,14 @@ Segment.prototype._collapsed = false;
9210
9202
  * @private
9211
9203
  */
9212
9204
  Segment.prototype._order = 0;
9205
+ /** @type {number}
9206
+ * @private
9207
+ */
9208
+ Segment.prototype._offsetOrder = 0;
9209
+ /** @type {number}
9210
+ * @private
9211
+ */
9212
+ Segment.prototype._depth = 0;
9213
9213
  /** @type {boolean}
9214
9214
  * @private
9215
9215
  */
@@ -9219,10 +9219,10 @@ Segment.prototype._disposed = false;
9219
9219
  * @private
9220
9220
  */
9221
9221
  Segment.prototype._subSegDef = null;
9222
- /** @type {number}
9222
+ /** @type {boolean}
9223
9223
  * @private
9224
9224
  */
9225
- Segment.prototype._subSegLevel = 0;
9225
+ Segment.prototype._subSegment = false; // This indicates that the segment is autogenerated (subsegment)
9226
9226
  /** @type {Object.<string, Segment>}
9227
9227
  * @private
9228
9228
  */
@@ -9230,7 +9230,7 @@ Segment.prototype._subSegMap = null; // For immediate sub-segment children
9230
9230
  /** @type {Array.<string>}
9231
9231
  * @private
9232
9232
  */
9233
- Segment.prototype._subSegNames = null; // For immediate sub-segment child names
9233
+ Segment.prototype._subSegNames = null; // For immediate sub-segment child names/ids
9234
9234
  /** @type {string}
9235
9235
  * @private
9236
9236
  */
@@ -9239,10 +9239,6 @@ Segment.prototype._subSegName = "";
9239
9239
  * @private
9240
9240
  */
9241
9241
  Segment.prototype._subSegVal;
9242
- /** @type {Segment}
9243
- * @private
9244
- */
9245
- Segment.prototype._subSegParent = null;
9246
9242
 
9247
9243
 
9248
9244
  /** @public
@@ -9264,14 +9260,13 @@ Segment.prototype.dispose = function() {
9264
9260
  this._subSegMap = this._subSegNames = null;
9265
9261
  }
9266
9262
  if(this._collapsed) {
9267
- if(this._childCount || this._subSegDef) {
9268
- this._shared.dirtyCollapsingState = true;
9269
- }
9263
+ this.markCollapsingStateDirty();
9270
9264
  }
9271
9265
 
9272
- this._childCount = 0;
9266
+ this._childDataIds = null;
9267
+ this._childIds.length = 0;
9273
9268
  this._shared = null;
9274
- this._subSegParent = this._subSegDef = this._subSegVal = null;
9269
+ this._subSegDef = this._subSegVal = null;
9275
9270
  };
9276
9271
  /** @public
9277
9272
  * @return {string}
@@ -9283,10 +9278,17 @@ Segment.prototype.getId = function() {
9283
9278
  * @return {string}
9284
9279
  */
9285
9280
  Segment.prototype.getParentId = function() {
9286
- if(this._subSegParent) {
9287
- return this._subSegParent.getId();
9281
+ return this._shared.childToSegment[this._rid] || "";
9282
+ };
9283
+ /** @public
9284
+ * @return {Segment}
9285
+ */
9286
+ Segment.prototype.getParent = function() {
9287
+ let parentId = this.getParentId();
9288
+ if(parentId) {
9289
+ return this._shared.segments[parentId] || null;
9288
9290
  }
9289
- return "";
9291
+ return null;
9290
9292
  };
9291
9293
  /** @public
9292
9294
  * @param {Array.<string>=} out_ary
@@ -9314,21 +9316,43 @@ Segment.prototype.getSubSegmentIds = function(out_ary) {
9314
9316
  /** @public
9315
9317
  * @param {string} rid
9316
9318
  * @param {string=} dataId Row id for retrieving data
9317
- * @return {boolean}
9319
+ * @return {boolean} Returns true only a new child is added
9318
9320
  */
9319
9321
  Segment.prototype.addChild = function(rid, dataId) {
9320
- if(rid) {
9322
+ if(!rid) {
9323
+ return false;
9324
+ }
9325
+ let prevSegmentId = this._shared.childToSegment[rid];
9326
+ if(prevSegmentId) {
9327
+ if(prevSegmentId !== this._rid) {
9328
+ let prevSegment = this._shared.segments[prevSegmentId];
9329
+ if(prevSegment && !prevSegment.hasSubSegments()) { // Children of a classified segment always stick the root segment
9330
+ prevSegment.removeChild(rid);
9331
+ }
9332
+ this._shared.childToSegment[rid] = this._rid;
9333
+ }
9334
+ } else {
9321
9335
  this._shared.childToSegment[rid] = this._rid;
9322
- if(this._children[rid]) {
9323
- this._children[rid] = dataId || rid; // Update data id
9324
- } else {
9325
- if(this._collapsed) {
9326
- this._shared.dirtyCollapsingState = true; // TODO: Check if we need to update this only when new child is added
9336
+ }
9337
+
9338
+ if(dataId != null) { // Update data id
9339
+ if(dataId && dataId !== rid) {
9340
+ if(!this._childDataIds) {
9341
+ this._childDataIds = {};
9327
9342
  }
9328
- this._children[rid] = dataId || rid;
9329
- ++this._childCount;
9330
- return true;
9343
+ this._childDataIds[rid] = dataId;
9344
+ } else if(this._childDataIds) {
9345
+ delete this._childDataIds[rid];
9346
+ }
9347
+ }
9348
+
9349
+ let at = this._childIds.indexOf(rid);
9350
+ if(at < 0) {
9351
+ if(this._collapsed) {
9352
+ this._shared.dirtyCollapsingState = true; // TODO: Check if we need to update this only when new child is added
9331
9353
  }
9354
+ this._childIds.push(rid);
9355
+ return true;
9332
9356
  }
9333
9357
  return false;
9334
9358
  };
@@ -9338,8 +9362,15 @@ Segment.prototype.addChild = function(rid, dataId) {
9338
9362
  * @return {boolean}
9339
9363
  */
9340
9364
  Segment.prototype.addChildren = function(rids, dataIds) {
9365
+ if(!rids) {
9366
+ return false;
9367
+ }
9341
9368
  let rowIds = Array.isArray(rids) ? rids : [rids];
9342
9369
  let rowCount = rowIds.length;
9370
+ if(!rowCount) {
9371
+ return false;
9372
+ }
9373
+
9343
9374
  let dirty = 0;
9344
9375
  let i;
9345
9376
  if(dataIds != null) {
@@ -9359,27 +9390,35 @@ Segment.prototype.addChildren = function(rids, dataIds) {
9359
9390
  * @return {boolean}
9360
9391
  */
9361
9392
  Segment.prototype.containsChild = function(rid) {
9362
- return this._children[rid] ? true : false;
9393
+ return this._childIds.indexOf(rid) >= 0;
9394
+ };
9395
+ /** @public
9396
+ * @param {string} rid
9397
+ * @return {number}
9398
+ */
9399
+ Segment.prototype.getChildIndex = function(rid) {
9400
+ return this._childIds.indexOf(rid);
9363
9401
  };
9364
9402
  /** @public
9365
9403
  * @param {string} rid
9366
9404
  * @return {boolean}
9367
9405
  */
9368
9406
  Segment.prototype.removeChild = function(rid) {
9369
- if(this._subSegLevel) {
9407
+ if(this._subSegment) {
9370
9408
  return false; // Sub segments are not allowed to remove its children
9371
9409
  }
9372
- if(!this._childCount) {
9410
+ if(!this._childIds.length) {
9373
9411
  return false;
9374
9412
  }
9375
- if(!this._children[rid]) {
9413
+ let at = this._childIds.indexOf(rid);
9414
+ if(at < 0) {
9376
9415
  return false; // The specified rid is not a child of this segment
9377
9416
  }
9378
9417
 
9379
- let objMap = this._shared.childToSegment;
9380
- delete objMap[rid];
9381
- delete this._children[rid]; // Slow
9382
- --this._childCount;
9418
+ if(this._shared.childToSegment[rid] === this._rid) {
9419
+ delete this._shared.childToSegment[rid];
9420
+ }
9421
+ this._childIds.splice(at, 1); // Slow
9383
9422
 
9384
9423
  if(this._collapsed) {
9385
9424
  this._shared.dirtyCollapsingState = true;
@@ -9391,10 +9430,10 @@ Segment.prototype.removeChild = function(rid) {
9391
9430
  * @return {boolean}
9392
9431
  */
9393
9432
  Segment.prototype.removeChildren = function(rids) {
9394
- if(this._subSegLevel) {
9433
+ if(this._subSegment) {
9395
9434
  return false; // Sub segments are not allowed to remove its children
9396
9435
  }
9397
- if(!this._childCount) {
9436
+ if(!this._childIds.length) {
9398
9437
  return false;
9399
9438
  }
9400
9439
  let rowIds = Array.isArray(rids) ? rids : [rids];
@@ -9409,21 +9448,24 @@ Segment.prototype.removeChildren = function(rids) {
9409
9448
  * @return {boolean}
9410
9449
  */
9411
9450
  Segment.prototype.removeAllChildren = function() {
9412
- if(this._subSegLevel) {
9451
+ if(this._subSegment) {
9413
9452
  return false; // Sub segments are not allowed to remove its children
9414
9453
  }
9415
- if(!this._childCount) {
9454
+ let childCount = this._childIds.length;
9455
+ if(!this._childIds.length) {
9416
9456
  return false;
9417
9457
  }
9458
+ let segmentId = this._rid;
9418
9459
  let objMap = this._shared.childToSegment;
9419
- let chdr = this._children;
9420
- for(let rid in chdr) {
9421
- if(objMap[rid]) {
9422
- delete objMap[rid]; // TODO: Check if we need to do this
9460
+ let chdr = this._childIds;
9461
+ for(let i = 0; i < childCount; ++i) {
9462
+ let rid = chdr[i];
9463
+ if(objMap[rid] === segmentId) {
9464
+ delete objMap[rid];
9423
9465
  }
9424
9466
  }
9425
- this._children = {};
9426
- this._childCount = 0;
9467
+ this._childIds.length = 0;
9468
+ this._childDataIds = null;
9427
9469
 
9428
9470
  if(this._collapsed) {
9429
9471
  this._shared.dirtyCollapsingState = true;
@@ -9434,24 +9476,41 @@ Segment.prototype.removeAllChildren = function() {
9434
9476
  * @return {!Array.<string>}
9435
9477
  */
9436
9478
  Segment.prototype.getChildIds = function() {
9437
- return this._childCount ? Object.keys(this._children) : [];
9479
+ return this._childIds; // WARNING: Returns private members
9438
9480
  };
9439
9481
  /** @public
9440
9482
  * @return {!Object}
9441
9483
  */
9442
9484
  Segment.prototype.getChildren = function() {
9443
- return this._children;
9485
+ let obj = {};
9486
+ let chdr = this._childIds;
9487
+ let childCount = chdr.length;
9488
+ let dataIds = this._childDataIds || {};
9489
+ for(let i = 0; i < childCount; ++i) {
9490
+ let rid = chdr[i];
9491
+ obj[rid] = dataIds[rid] || rid;
9492
+ }
9493
+ return obj;
9444
9494
  };
9445
9495
  /** @public
9446
9496
  * @return {number}
9447
9497
  */
9448
9498
  Segment.prototype.getChildCount = function() {
9449
- return this._childCount;
9499
+ return this._childIds.length;
9500
+ };
9501
+ /** When a segment is not empty, the visibility of its content need to be updated.
9502
+ * @public
9503
+ */
9504
+ Segment.prototype.markCollapsingStateDirty = function() {
9505
+ // A segment can have a child and/or autogenerated segment (subsegment) to not be considered as empty.
9506
+ if(this._childIds.length || this._subSegDef) {
9507
+ this._shared.dirtyCollapsingState = true;
9508
+ }
9450
9509
  };
9451
9510
 
9452
9511
 
9453
9512
  /** @public
9454
- * @return {Array.<string>} fields
9513
+ * @return {Array.<string>}
9455
9514
  */
9456
9515
  Segment.prototype.getClassification = function() {
9457
9516
  if(this._subSegDef) {
@@ -9464,8 +9523,8 @@ Segment.prototype.getClassification = function() {
9464
9523
  * @return {boolean}
9465
9524
  */
9466
9525
  Segment.prototype.setClassification = function(fields) {
9467
- if(this._subSegLevel) {
9468
- return false; // non-root segment cannot be classified
9526
+ if(this._subSegment) {
9527
+ return false; // subsegment cannot be classified
9469
9528
  }
9470
9529
  let classifiers = null;
9471
9530
  if(this._subSegDef) {
@@ -9508,9 +9567,8 @@ Segment.prototype.setClassification = function(fields) {
9508
9567
  return true;
9509
9568
  } else if(classifiers) { // Remove existing ones
9510
9569
  this._subSegDef.classifiers = null;
9511
- this._subSegDef.subSegments = null;
9512
9570
  // this._subSegDef.classifierChanged = true;
9513
- this._subSegDef = null; // WARNING: All sub segments remain existing
9571
+ this._subSegDef = null; // WARNING: All subsegments remain existing
9514
9572
  return true;
9515
9573
  }
9516
9574
  return false;
@@ -9527,7 +9585,7 @@ Segment.prototype.classify = function(rows) {
9527
9585
  let segmentCount = segmentNames ? segmentNames.length : 0;
9528
9586
 
9529
9587
  if(!segmentCount) {
9530
- if(this._subSegLevel >= classifierCount) {
9588
+ if(this._depth >= classifierCount) {
9531
9589
  return false; // Current segment level is beyond existing classification level and this segment should already be removed
9532
9590
  }
9533
9591
  }
@@ -9537,7 +9595,7 @@ Segment.prototype.classify = function(rows) {
9537
9595
  sharedObj.dirtyCollapsingState = true;
9538
9596
  }
9539
9597
 
9540
- // Prepare existing sub segments for checking change in its members
9598
+ // Prepare existing subsegments for checking change in its members
9541
9599
  let i;
9542
9600
  let segmentName = "";
9543
9601
  let nonExistenceGroups = {};
@@ -9551,9 +9609,8 @@ Segment.prototype.classify = function(rows) {
9551
9609
  nonExistenceGroups[segmentName] = 1;
9552
9610
 
9553
9611
  segment = segmentMap[segmentName];
9554
- if(segment._childCount) { // Quick cleaning up
9555
- segment._children = {};
9556
- segment._childCount = 0;
9612
+ if(segment._childIds.length) { // Quick cleaning up
9613
+ segment._childIds.length = 0;
9557
9614
  }
9558
9615
  if(segment._collapsed) {
9559
9616
  sharedObj.dirtyCollapsingState = true;
@@ -9561,20 +9618,23 @@ Segment.prototype.classify = function(rows) {
9561
9618
  }
9562
9619
  }
9563
9620
 
9564
- // Loop through row children and assign them to their corresponding sub segment
9565
- let isRootSegment = !this._subSegLevel;
9621
+ // Loop through row children and assign them to their corresponding subsegment
9622
+ let rootSegment = !this._subSegment;
9623
+ let dataIds = this._childDataIds || {};
9566
9624
  let rid;
9567
- let children = this._children;
9568
- if(this._subSegLevel < classifierCount && rows) {
9625
+ let chdr = this._childIds;
9626
+ let childCount = chdr.length;
9627
+ if(this._depth < classifierCount && rows) {
9569
9628
  if(!segmentMap) {
9570
9629
  segmentMap = this._subSegMap = {};
9571
9630
  segmentNames = this._subSegNames = [];
9572
9631
  }
9573
9632
 
9574
- let classifier = classifiers[this._subSegLevel];
9633
+ let classifier = classifiers[this._depth];
9575
9634
 
9576
- for(rid in children) {
9577
- let dataId = children[rid];
9635
+ for(i = 0; i < childCount; ++i) {
9636
+ rid = chdr[i];
9637
+ let dataId = dataIds[rid] || rid;
9578
9638
  let record = rows[dataId];
9579
9639
  let val = record ? record[classifier] : null; // WARNING: row could already be removed
9580
9640
 
@@ -9591,31 +9651,34 @@ Segment.prototype.classify = function(rows) {
9591
9651
 
9592
9652
  segment = segmentMap[segmentName];
9593
9653
  if(!segment) { // New group is detected
9594
- segment = new Segment(this._rid + "/" + segmentName, sharedObj);
9654
+ let subSegId = this._rid + "/" + segmentName;
9655
+ segment = new Segment(subSegId, sharedObj);
9595
9656
  segment._subSegDef = this._subSegDef;
9596
- segment._subSegLevel = this._subSegLevel + 1;
9657
+ segment._subSegment = true; // this indicates that the segment is autogenerated (subsegment)
9658
+ segment._depth = this._depth + 1;
9597
9659
  segment._subSegName = segmentName;
9598
9660
  segment._subSegVal = val;
9599
- segment._subSegParent = this;
9661
+ sharedObj.childToSegment[subSegId] = this._rid; // WARNING: this will mix autogenerated rows with actual rows
9600
9662
 
9601
9663
  segmentMap[segmentName] = segment;
9602
9664
  segmentNames.push(segmentName);
9603
9665
 
9604
9666
  this._dispatch("subSegmentAdded", {
9605
- "rid": segment.getId(),
9667
+ "rid": subSegId,
9606
9668
  "segment": segment
9607
9669
  });
9608
9670
  }
9609
9671
 
9610
9672
  segment.addChild(rid, dataId);
9611
9673
  }
9612
- } else if(isRootSegment) { // In case of no classification
9613
- for(rid in children) {
9674
+ } else if(rootSegment) { // In case of no classification
9675
+ for(i = 0; i < childCount; ++i) {
9676
+ rid = chdr[i];
9614
9677
  sharedObj.childToSegment[rid] = this._rid; // Relocate child in case of it has been moved to a non existence group
9615
9678
  }
9616
9679
  }
9617
9680
 
9618
- // Remove all sub segments with no members
9681
+ // Remove all subsegments with no members
9619
9682
  if(removalCount > 0) {
9620
9683
  if(removalCount >= segmentNames.length) {
9621
9684
  segmentNames.length = 0;
@@ -9643,7 +9706,7 @@ Segment.prototype.classify = function(rows) {
9643
9706
  }
9644
9707
  }
9645
9708
 
9646
- // Sort and classify existing sub segments
9709
+ // Sort and classify existing subsegments
9647
9710
  segmentCount = segmentNames ? segmentNames.length : 0;
9648
9711
  if(segmentCount) {
9649
9712
  segmentNames.sort(Segment._subSegSortLogic);
@@ -9653,22 +9716,17 @@ Segment.prototype.classify = function(rows) {
9653
9716
  }
9654
9717
  }
9655
9718
 
9656
- // Collecting all sub segments including all descendants and reassigning segment order.
9657
- if(isRootSegment) { // If this is a root segment
9658
- if(this._subSegDef) {
9659
- if(segmentCount) {
9660
- let subSegments = this._subSegDef.subSegments = [];
9661
- this.getAllSubSegments(subSegments);
9662
- subSegments.forEach(Segment._assignSubSegmentOrder);
9663
- } else {
9664
- this._subSegDef.subSegments = null;
9665
- }
9666
- // this._subSegDef.classifierChanged = false;
9719
+ // Collecting all subsegments including all descendants and reassigning segment order.
9720
+ if(rootSegment && this._subSegDef) {
9721
+ if(segmentCount) {
9722
+ this.calcSubSegmentOrder(0);
9667
9723
  }
9724
+ // this._subSegDef.classifierChanged = false;
9668
9725
  }
9669
9726
  return true;
9670
9727
  };
9671
- /** @public
9728
+ /** SubSegment implies being classified
9729
+ * @public
9672
9730
  * @return {boolean}
9673
9731
  */
9674
9732
  Segment.prototype.hasSubSegments = function() {
@@ -9677,21 +9735,37 @@ Segment.prototype.hasSubSegments = function() {
9677
9735
  }
9678
9736
  return false;
9679
9737
  };
9680
- /** @public
9738
+ /** SubSegment implies autogenerated segment
9739
+ * @public
9681
9740
  * @return {boolean}
9682
9741
  */
9683
9742
  Segment.prototype.isSubSegment = function() {
9684
- return this._subSegLevel ? true : false;
9743
+ return this._subSegment;
9744
+ };
9745
+ /** @public
9746
+ * @return {boolean}
9747
+ */
9748
+ Segment.prototype.isRootSegment = function() {
9749
+ return this._shared.childToSegment[this._rid] ? false : true;
9685
9750
  };
9686
9751
  /** @public
9687
9752
  * @return {Segment}
9688
9753
  */
9689
9754
  Segment.prototype.getFirstAncestor = function() {
9690
- if(this._subSegLevel && this._subSegDef) {
9691
- let ancestor = this._subSegDef.root;
9692
- return /** @type{Segment} */(ancestor) || null;
9755
+ let ancestor = null;
9756
+ if(this._subSegment && this._subSegDef) { // Quick way to get root
9757
+ ancestor = this._subSegDef.root;
9758
+ } else { // Slow
9759
+ ancestor = this.getParent();
9760
+ if(ancestor) {
9761
+ let parentSeg = ancestor.getParent();
9762
+ while(parentSeg) { // This could cause infinite loop
9763
+ ancestor = parentSeg;
9764
+ parentSeg = ancestor.getParent();
9765
+ }
9766
+ }
9693
9767
  }
9694
- return null;
9768
+ return ancestor || null;
9695
9769
  };
9696
9770
  /** @public
9697
9771
  * @param {Array.<Segment>=} out_ary
@@ -9713,13 +9787,75 @@ Segment.prototype.getAllSubSegments = function(out_ary) {
9713
9787
  }
9714
9788
  return out_ary || null;
9715
9789
  };
9790
+ /** This method sets order, last order, and depth to entire tree structure in the segment, including the segment itself
9791
+ * @public
9792
+ * @param {number} counter
9793
+ * @return {number}
9794
+ */
9795
+ Segment.prototype.updateTreeStructure = function(counter) {
9796
+ if(!counter) {
9797
+ counter = 0;
9798
+ if(!this._subSegment) { // Subsegment's depth cannot be reset back to 0
9799
+ this._depth = 0; // WARNING: this assumes counter at 0 is the root segment
9800
+ }
9801
+ }
9802
+ if(this.hasSubSegments()) {
9803
+ return this.setLastOrder(counter); // Sub segments has already been calculated
9804
+ }
9805
+ let segmentSeparators = this._shared.segments;
9806
+ let childCount = this._childIds.length;
9807
+ let prevSeg = null;
9808
+ for(let i = 0; i < childCount; ++i) {
9809
+ let rid = this._childIds[i];
9810
+ let segment = segmentSeparators[rid];
9811
+ let segmentId = (segment) ? segment.getId() : "Uncategorized";
9812
+ if(prevSeg !== segmentId) {
9813
+ ++counter; // 0 become 1
9814
+ prevSeg = segmentId;
9815
+ }
9816
+ if(segment) {
9817
+ segment._depth = this._depth + 1;
9818
+ segment.setOrder(counter);
9819
+ counter = segment.updateTreeStructure(counter);
9820
+ }
9821
+ }
9822
+
9823
+ return this.setLastOrder(counter);
9824
+ };
9825
+ /** @public
9826
+ * @param {number} counter
9827
+ * @return {number}
9828
+ */
9829
+ Segment.prototype.calcSubSegmentOrder = function(counter) {
9830
+ if(!this.hasSubSegments()) {
9831
+ return this.setLastOrder(counter);
9832
+ }
9833
+
9834
+ let segmentMap = this._subSegMap;
9835
+ let childCount = this._subSegNames.length;
9836
+ let prevSeg = null;
9837
+ for(let i = 0; i < childCount; ++i) {
9838
+ let segmentName = this._subSegNames[i];
9839
+ let segment = segmentMap[segmentName];
9840
+ let segmentId = (segment) ? segment.getId() : "Uncategorized";
9841
+ if(prevSeg !== segmentId) {
9842
+ ++counter; // 0 become 1
9843
+ prevSeg = segmentId;
9844
+ }
9845
+ if(segment) {
9846
+ segment.setOrder(counter);
9847
+ counter = segment.calcSubSegmentOrder(counter);
9848
+ }
9849
+ }
9850
+ return this.setLastOrder(counter);
9851
+ };
9716
9852
  /** @public
9717
9853
  * @return {number}
9718
9854
  */
9719
9855
  Segment.prototype.getSegmentLevel = function() {
9720
- return this._subSegLevel;
9856
+ return this._depth;
9721
9857
  };
9722
- /** This method will be called on sub segments only
9858
+ /** This method will be called on subsegments only
9723
9859
  * @public
9724
9860
  * @param {Object=} rows
9725
9861
  * @param {Object=} clsSource
@@ -9744,7 +9880,7 @@ Segment.prototype.setRowData = function(rows, clsSource) {
9744
9880
  let segment = this;
9745
9881
  while(segment && segment.isSubSegment()) {
9746
9882
  segment.getSubSegmentName(row);
9747
- segment = segment._subSegParent;
9883
+ segment = segment.getParent();
9748
9884
  }
9749
9885
  };
9750
9886
  /** @public
@@ -9752,15 +9888,92 @@ Segment.prototype.setRowData = function(rows, clsSource) {
9752
9888
  * @return {string}
9753
9889
  */
9754
9890
  Segment.prototype.getSubSegmentName = function(row) {
9755
- if(row && this._subSegLevel) {
9891
+ if(row && this._subSegment) {
9756
9892
  let classifiers = this.getClassification();
9757
- let field = classifiers[this._subSegLevel - 1];
9893
+ let field = classifiers[this._depth - 1];
9758
9894
  if(field) {
9759
9895
  row[field] = this._subSegName;
9760
9896
  }
9761
9897
  }
9762
9898
  return this._subSegName;
9763
9899
  };
9900
+ /**
9901
+ * @private
9902
+ * @param {!Segment} segment
9903
+ * @returns {string}
9904
+ */
9905
+ let _toSegmentId = function(segment) {
9906
+ return segment.getId();
9907
+ };
9908
+ /**
9909
+ * @public
9910
+ * @param {!Function} comparer
9911
+ * @returns {boolean} Returns true if there is any change
9912
+ */
9913
+ Segment.prototype.sortSegments = function(comparer) {
9914
+ if(!comparer || this.hasSubSegments()) {
9915
+ return false;
9916
+ }
9917
+
9918
+ let segmentList = [];
9919
+ let rids = [];
9920
+ let childIds = this._childIds;
9921
+ let childCount = childIds.length;
9922
+ let segments = this._shared.segments;
9923
+ for(let i = 0; i < childCount; ++i) {
9924
+ let childId = childIds[i];
9925
+ let childSegment = segments[childId];
9926
+ if(childSegment) {
9927
+ segmentList.push(childSegment);
9928
+ } else {
9929
+ rids.push(childId);
9930
+ }
9931
+ }
9932
+ if(segmentList.length < 2) {
9933
+ return false;
9934
+ }
9935
+ segmentList.sort(comparer);
9936
+ this._childIds = rids.concat(segmentList.map(_toSegmentId));
9937
+ return true;
9938
+ };
9939
+ /** Get segment id and ids of children, including nested segments, but excluding sub segments
9940
+ * @public
9941
+ * @param {Array.<string>} ary
9942
+ * @return {!Array.<string>}
9943
+ */
9944
+ Segment.prototype.getFlattenTreeIds = function(ary) {
9945
+ if(!ary) {
9946
+ ary = [];
9947
+ }
9948
+
9949
+ if(!this._subSegment) { // Sub segments are excluded from tree
9950
+ ary.push(this._rid);
9951
+ }
9952
+ let i;
9953
+ let segmentNames = this._subSegNames;
9954
+ if(segmentNames) { // Classified segment
9955
+ let segmentCount = segmentNames.length;
9956
+ let segmentMap = this._subSegMap;
9957
+ for(i = 0; i < segmentCount; ++i) {
9958
+ segmentMap[segmentNames[i]].getFlattenTreeIds(ary);
9959
+ }
9960
+ } else {
9961
+ let childIds = this._childIds;
9962
+ let childCount = childIds.length;
9963
+ let segments = this._shared.segments;
9964
+ for(i = 0; i < childCount; ++i) {
9965
+ let childId = childIds[i];
9966
+ let childSegment = segments[childId];
9967
+ if(childSegment) {
9968
+ childSegment.getFlattenTreeIds(ary);
9969
+ } else {
9970
+ ary.push(childId);
9971
+ }
9972
+ }
9973
+ }
9974
+
9975
+ return ary;
9976
+ };
9764
9977
 
9765
9978
  /** @public
9766
9979
  * @param {boolean=} bool
@@ -9770,9 +9983,7 @@ Segment.prototype.collapse = function(bool) {
9770
9983
  bool = (bool !== false);
9771
9984
  if(this._collapsed !== bool) {
9772
9985
  this._collapsed = bool;
9773
- if(this._childCount || this._subSegDef) {
9774
- this._shared.dirtyCollapsingState = true;
9775
- }
9986
+ this.markCollapsingStateDirty();
9776
9987
  return true;
9777
9988
  }
9778
9989
  return false;
@@ -9790,82 +10001,87 @@ Segment.prototype.expand = function(bool) {
9790
10001
  Segment.prototype.isCollapsed = function() {
9791
10002
  return this._collapsed;
9792
10003
  };
9793
- /** @public
10004
+ /** Get all collapsing state from all children (subsegments and child segments), excluding the segment itself
10005
+ * @public
9794
10006
  * @param {Object=} objMap
9795
10007
  * @param {boolean=} parentState=false Collapsing state from parent segment
9796
10008
  * @return {boolean}
9797
10009
  */
9798
10010
  Segment.prototype.getCollapsingStates = function(objMap, parentState) {
9799
- let segmentNames = this._subSegNames;
9800
- if(!this._subSegLevel) { // Only root segment
9801
- if(!segmentNames) { // No sub segment
9802
- if(!this._collapsed) {
9803
- return false;
9804
- }
9805
- }
10011
+ let childList = this._subSegNames;
10012
+ let segmentMap = this._subSegMap;
10013
+ let subSegment = true; // Normal segments can have subsegments without being subsegment themselve
10014
+ if(!childList && this._shared) { // Ensure that segment has not been disposed
10015
+ childList = this._childIds;
10016
+ segmentMap = this._shared.segments;
10017
+ subSegment = false;
10018
+ }
10019
+ let childCount = childList ? childList.length : 0;
10020
+ if(!childCount) {
10021
+ return false;
9806
10022
  }
9807
10023
 
10024
+ let dirty = false;
10025
+ let childCollapsed = (parentState || this._collapsed) ? true : false;
10026
+
9808
10027
  if(!objMap) {
9809
10028
  objMap = {};
9810
10029
  }
9811
- let dirty = false;
9812
- if(this._subSegLevel) { // Sub segments are also subjected to collapsing
9813
- if(parentState) {
9814
- objMap[this._rid] = true;
10030
+ for(let i = 0; i < childCount; ++i) {
10031
+ let rid = "";
10032
+ let segment = null;
10033
+ if(subSegment) {
10034
+ segment = segmentMap[childList[i]]; // Use segment name to retrieve subsegment
10035
+ rid = segment.getId();
10036
+ } else {
10037
+ rid = childList[i];
10038
+ segment = segmentMap[rid]; // Use row id to retrieve segment from shared map
10039
+ }
10040
+ if(childCollapsed) {
10041
+ objMap[rid] = childCollapsed; // Collapsing states for all children is registered here
9815
10042
  dirty = true;
9816
10043
  }
9817
- }
9818
- if(this._childCount) {
9819
- let collapsed = parentState || this._collapsed;
9820
- if(segmentNames) {
9821
- let segmentMap = this._subSegMap;
9822
- let segmentCount = segmentNames.length;
9823
- for(let i = 0; i < segmentCount; ++i) {
9824
- let segment = segmentMap[segmentNames[i]];
9825
- objMap[segment.getId()] = !!parentState;
9826
- if(segment.getCollapsingStates(objMap, collapsed)) {
9827
- dirty = true;
9828
- }
9829
- }
9830
- } else if(collapsed) {
9831
- let chdr = this._children;
9832
- for(let rid in chdr) {
9833
- objMap[rid] = collapsed;
9834
- }
10044
+ if(segment && segment.getCollapsingStates(objMap, childCollapsed)) {
9835
10045
  dirty = true;
9836
10046
  }
9837
10047
  }
9838
10048
  return dirty;
9839
10049
  };
9840
10050
 
10051
+ /** @private
10052
+ * @return {number}
10053
+ */
10054
+ Segment.prototype._getOrder = function() {
10055
+ return this._order * 10000;
10056
+ };
10057
+ /** @private
10058
+ * @return {number}
10059
+ */
10060
+ Segment.prototype._getLastOrder = function() {
10061
+ return this._getOrder() + this._offsetOrder;
10062
+ };
9841
10063
  /** @public
9842
10064
  * @return {number}
9843
10065
  */
9844
10066
  Segment.prototype.getOrder = function() {
9845
- if(this._subSegLevel) {
9846
- let ancestor = this.getFirstAncestor();
9847
- if(ancestor) {
9848
- // WARNING: this._order cannot be greater than 9999
9849
- return ancestor.getOrder() + this._order;
9850
- }
10067
+ let ancestor = this.getFirstAncestor();
10068
+ if(ancestor) {
10069
+ // WARNING: this._order cannot be greater than 9999
10070
+ return ancestor._getOrder() + this._order;
9851
10071
  }
9852
- return this._order * 10000;
10072
+ return this._getOrder();
9853
10073
  };
9854
10074
  /** Get the last (highest) order from the entire tree regardless of the current position segment in the hierachy
9855
10075
  * @public
9856
10076
  * @return {number}
9857
10077
  */
9858
10078
  Segment.prototype.getLastOrder = function() {
9859
- if(this._subSegDef) {
9860
- let subSegments = this._subSegDef.subSegments;
9861
- if(subSegments) {
9862
- let lastSegment = subSegments[subSegments.length - 1];
9863
- if(lastSegment) {
9864
- return lastSegment.getOrder();
9865
- }
9866
- }
10079
+ let ancestor = this.getFirstAncestor();
10080
+ if(ancestor) {
10081
+ // WARNING: this._order cannot be greater than 9999
10082
+ return ancestor._getLastOrder();
9867
10083
  }
9868
- return this.getOrder();
10084
+ return this._getLastOrder();
9869
10085
  };
9870
10086
  /** @public
9871
10087
  * @param {number} val
@@ -9873,6 +10089,13 @@ Segment.prototype.getLastOrder = function() {
9873
10089
  Segment.prototype.setOrder = function(val) {
9874
10090
  this._order = val;
9875
10091
  };
10092
+ /** @public
10093
+ * @param {number} val
10094
+ * @returns {number} Returns the number set
10095
+ */
10096
+ Segment.prototype.setLastOrder = function(val) {
10097
+ return (this._offsetOrder = val);
10098
+ };
9876
10099
 
9877
10100
  /** @private
9878
10101
  * @type {Array.<string>}
@@ -9880,9 +10103,10 @@ Segment.prototype.setOrder = function(val) {
9880
10103
  Segment._tabs = null;
9881
10104
  /** @public
9882
10105
  * @param {Array.<string>=} lines
10106
+ * @param {number=} tabLevel
9883
10107
  * @return {!Array.<string>} lines
9884
10108
  */
9885
- Segment.prototype.log = function(lines) {
10109
+ Segment.prototype.log = function(lines, tabLevel) {
9886
10110
  if(!lines) {
9887
10111
  lines = [];
9888
10112
  }
@@ -9897,23 +10121,43 @@ Segment.prototype.log = function(lines) {
9897
10121
  tabCh += " ";
9898
10122
  }
9899
10123
  }
10124
+ if(!tabLevel) {
10125
+ tabLevel = 0;
10126
+ }
10127
+
9900
10128
  let collapsedCh = this._collapsed ? "+ " : "- ";
9901
- lines.push(tabs[this._subSegLevel] + collapsedCh + this._rid);
10129
+ lines.push(tabs[tabLevel] + collapsedCh + this._rid);
9902
10130
 
9903
- let segmentNames = this._subSegNames;
9904
- if(segmentNames) {
9905
- let segmentCount = segmentNames.length;
9906
- let segmentMap = this._subSegMap;
9907
- for(i = 0; i < segmentCount; ++i) {
9908
- segmentMap[segmentNames[i]].log(lines);
10131
+ let childLevel = tabLevel + 1;
10132
+ let childIndent = tabs[childLevel];
10133
+
10134
+ let childList = this._subSegNames;
10135
+ let segmentMap = this._subSegMap;
10136
+ let subSegment = true; // Normal segments can have subsegments without being subsegment themselve
10137
+ if(!childList && this._shared) { // Ensure that segment has not been disposed
10138
+ childList = this._childIds;
10139
+ segmentMap = this._shared.segments;
10140
+ subSegment = false;
10141
+ }
10142
+ let childCount = childList ? childList.length : 0;
10143
+
10144
+ for(i = 0; i < childCount; ++i) {
10145
+ let rid = "";
10146
+ let segment = null;
10147
+ if(subSegment) {
10148
+ segment = segmentMap[childList[i]]; // Use segment name to retrieve subsegment
10149
+ rid = segment.getId();
10150
+ } else {
10151
+ rid = childList[i];
10152
+ segment = segmentMap[rid]; // Use row id to retrieve segment from shared map
9909
10153
  }
9910
- } else if(this._childCount) {
9911
- let indent = tabs[this._subSegLevel + 1];
9912
- for(let rid in this._children) {
9913
- lines.push(indent + "- " + rid);
10154
+
10155
+ if(segment) {
10156
+ segment.log(lines, childLevel);
10157
+ } else {
10158
+ lines.push(childIndent + "- " + rid);
9914
10159
  }
9915
10160
  }
9916
-
9917
10161
  return lines;
9918
10162
  };
9919
10163
 
@@ -9938,6 +10182,7 @@ let SegmentCollection = function() {
9938
10182
  this._removalList = [];
9939
10183
 
9940
10184
  this._shared = {
10185
+ segments: this._segments,
9941
10186
  childToSegment: {}, // child Id to segment Id
9942
10187
  dirtyCollapsingState: false,
9943
10188
  defaultCollapsing: false
@@ -9998,10 +10243,6 @@ SegmentCollection.prototype.dispose = function() {
9998
10243
  */
9999
10244
  SegmentCollection.prototype.addSegment = function(rid, childRids) {
10000
10245
  if(rid && !this._segments[rid]) {
10001
- if(this.getParentRowId(rid)) {
10002
- console.log("child of a segment cannot be set as a segment separator");
10003
- return false;
10004
- }
10005
10246
  let segment = this._segments[rid] = new data_Segment(rid, this._shared);
10006
10247
  segment.addEventListener("subSegmentAdded", this._onSubSegmentAdded);
10007
10248
  segment.addEventListener("subSegmentRemoved", this._onSubSegmentRemoved);
@@ -10048,33 +10289,41 @@ SegmentCollection.prototype.getParentRowId = function(rid) {
10048
10289
  */
10049
10290
  SegmentCollection.prototype.removeSegment = function(rid) {
10050
10291
  let segment = this._segments[rid];
10051
- if(segment) {
10052
- if(this._segmentCount <= 1) {
10053
- return this.removeAllSegments();
10054
- }
10055
- if(segment.isSubSegment()) {
10056
- this._removalList.push(segment.getId());
10057
- }
10058
- let subSegIds = segment.getSubSegmentIds();
10059
- if(subSegIds) {
10060
- let len = subSegIds.length;
10061
- for(let i = 0; i < len; ++i) {
10062
- let subSegId = subSegIds[i];
10063
- if(this._segments[subSegId]) {
10064
- this._removalList.push(subSegId);
10065
- delete this._segments[subSegId]; // Slow
10066
- --this._segmentCount;
10067
- }
10292
+ if(!segment) {
10293
+ return false;
10294
+ }
10295
+
10296
+ if(this._segmentCount <= 1) {
10297
+ return this.removeAllSegments();
10298
+ }
10299
+ let subSegment = segment.isSubSegment();
10300
+ if(subSegment) {
10301
+ this._removalList.push(segment.getId());
10302
+ }
10303
+ let subSegIds = segment.getSubSegmentIds();
10304
+ if(subSegIds) {
10305
+ let len = subSegIds.length;
10306
+ for(let i = 0; i < len; ++i) {
10307
+ let subSegId = subSegIds[i];
10308
+ if(this._segments[subSegId]) {
10309
+ this._removalList.push(subSegId);
10310
+ delete this._segments[subSegId]; // Slow
10311
+ --this._segmentCount;
10068
10312
  }
10069
10313
  }
10070
- segment.removeAllChildren(); // This is important for updating childToSegment
10071
- segment.dispose();
10072
-
10073
- delete this._segments[rid]; // Slow
10074
- --this._segmentCount;
10075
- return true;
10076
10314
  }
10077
- return false;
10315
+ if(!subSegment) {
10316
+ let parentSeg = segment.getParent();
10317
+ if(parentSeg) { // Move existing children to its parent
10318
+ parentSeg.addChildren(segment.getChildIds()); // WARNING: passing private member
10319
+ }
10320
+ }
10321
+ segment.removeAllChildren(); // This is important for updating childToSegment
10322
+ segment.dispose();
10323
+
10324
+ delete this._segments[rid]; // Slow
10325
+ --this._segmentCount;
10326
+ return true;
10078
10327
  };
10079
10328
  /** @public
10080
10329
  * @return {boolean} Returns true if there is any change. Otherwise, returns false
@@ -10087,6 +10336,7 @@ SegmentCollection.prototype.removeAllSegments = function() {
10087
10336
  this._segments = {};
10088
10337
  this._segmentCount = 0;
10089
10338
  this._segmentList = null;
10339
+ this._shared.segments = this._segments;
10090
10340
  this._shared.childToSegment = {};
10091
10341
 
10092
10342
  this._classification = this._classifierChanged = false;
@@ -10131,6 +10381,23 @@ SegmentCollection.prototype.getSegments = function() {
10131
10381
  SegmentCollection.prototype.getSegmentIds = function() {
10132
10382
  return Object.keys(this._segments);
10133
10383
  };
10384
+ /** @public
10385
+ * @param {!Function} comparer
10386
+ * @return {!Array.<Segment>}
10387
+ */
10388
+ SegmentCollection.prototype.sortSegments = function(comparer) {
10389
+ let rootSegments = [];
10390
+ let segmentSeparators = this._segments;
10391
+ for(let rid in segmentSeparators) {
10392
+ let segment = segmentSeparators[rid];
10393
+ segment.sortSegments(comparer);
10394
+ if(segment.isRootSegment()) {
10395
+ rootSegments.push(segment);
10396
+ }
10397
+ }
10398
+ rootSegments.sort(comparer);
10399
+ return rootSegments;
10400
+ };
10134
10401
 
10135
10402
 
10136
10403
  /** @public
@@ -10212,7 +10479,7 @@ SegmentCollection.prototype.getCollapsedRows = function() {
10212
10479
  collapsedRids = {};
10213
10480
  for(let rid in segmentSeparators) {
10214
10481
  let segment = segmentSeparators[rid];
10215
- if(!segment.isSubSegment()) {
10482
+ if(segment.isRootSegment()) {
10216
10483
  if(segment.getCollapsingStates(collapsedRids)) {
10217
10484
  ++count;
10218
10485
  }
@@ -10224,6 +10491,31 @@ SegmentCollection.prototype.getCollapsedRows = function() {
10224
10491
  return this._collapsedRids;
10225
10492
  };
10226
10493
 
10494
+ /** Invalidate segment order cache, if the given row id is a segment separator
10495
+ * @private
10496
+ * @param {string|Array.<string>} segmentIds
10497
+ * @returns {boolean} Returns true if there is any change
10498
+ */
10499
+ SegmentCollection.prototype._invalidateSegmentOrder = function(segmentIds) {
10500
+ if(this._segmentList) {
10501
+ if(typeof segmentIds === "string") {
10502
+ if(this._segments[segmentIds]) {
10503
+ this._segmentList = null;
10504
+ return true;
10505
+ }
10506
+ } else if(Array.isArray(segmentIds)) {
10507
+ let len = segmentIds.length;
10508
+ for(let i = 0; i < len; ++i) {
10509
+ let segmentId = segmentIds[i];
10510
+ if(this._segments[segmentId]) {
10511
+ this._segmentList = null;
10512
+ return true;
10513
+ }
10514
+ }
10515
+ }
10516
+ }
10517
+ return false;
10518
+ };
10227
10519
  /** @public
10228
10520
  * @param {string} segmentId
10229
10521
  * @param {string} rid
@@ -10233,6 +10525,8 @@ SegmentCollection.prototype.getCollapsedRows = function() {
10233
10525
  SegmentCollection.prototype.addSegmentChild = function(segmentId, rid, dataId) {
10234
10526
  let segment = this._segments[segmentId];
10235
10527
  if(segment && !segment.isSubSegment()) {
10528
+ // If a segment becomes a child of other segment, then the segment order needs to be recalculated
10529
+ this._invalidateSegmentOrder(rid);
10236
10530
  return segment.addChild(rid, dataId);
10237
10531
  }
10238
10532
  return false;
@@ -10246,11 +10540,14 @@ SegmentCollection.prototype.addSegmentChild = function(segmentId, rid, dataId) {
10246
10540
  SegmentCollection.prototype.addSegmentChildren = function(segmentId, rids, dataIds) {
10247
10541
  let segment = this._segments[segmentId];
10248
10542
  if(segment && !segment.isSubSegment()) {
10543
+ // If a segment becomes a child of other segment, then the segment order needs to be recalculated
10544
+ this._invalidateSegmentOrder(rids);
10249
10545
  return segment.addChildren(rids, dataIds);
10250
10546
  }
10251
10547
  return false;
10252
10548
  };
10253
- /** @public
10549
+ /** This only works for immediate children of the specified segment
10550
+ * @public
10254
10551
  * @param {string} segmentId
10255
10552
  * @param {string} rid
10256
10553
  * @return {boolean} Returns true if there is any change. Otherwise, returns false
@@ -10270,6 +10567,7 @@ SegmentCollection.prototype.containsSegmentChild = function(segmentId, rid) {
10270
10567
  SegmentCollection.prototype.removeSegmentChild = function(segmentId, rid) {
10271
10568
  let segment = this._segments[segmentId];
10272
10569
  if(segment) {
10570
+ this._invalidateSegmentOrder(rid);
10273
10571
  return segment.removeChild(rid);
10274
10572
  }
10275
10573
  return false;
@@ -10282,6 +10580,7 @@ SegmentCollection.prototype.removeSegmentChild = function(segmentId, rid) {
10282
10580
  SegmentCollection.prototype.removeSegmentChildren = function(segmentId, rids) {
10283
10581
  let segment = this._segments[segmentId];
10284
10582
  if(segment) {
10583
+ this._invalidateSegmentOrder(rids);
10285
10584
  return segment.removeChildren(rids);
10286
10585
  }
10287
10586
  return false;
@@ -10301,6 +10600,7 @@ SegmentCollection.prototype.removeAllSegmentChildren = function() {
10301
10600
  }
10302
10601
 
10303
10602
  if(dirty) {
10603
+ this._segmentList = null; // WARNING: not optimized
10304
10604
  this.classify(null);
10305
10605
  }
10306
10606
 
@@ -10359,10 +10659,14 @@ SegmentCollection.prototype.fillSegments = function(rids) {
10359
10659
  };
10360
10660
  /** @public
10361
10661
  * @param {Array.<string>} rids
10662
+ * @param {boolean=} useCache=false If this is true, skip the calculation when there is already a cache for segment order
10362
10663
  */
10363
- SegmentCollection.prototype.calcSegmentOrder = function(rids) {
10664
+ SegmentCollection.prototype.calcSegmentOrder = function(rids, useCache) {
10364
10665
  let segmentList = this._segmentList;
10365
10666
  if(segmentList) {
10667
+ if(useCache) {
10668
+ return; // Use previous cache for segment order
10669
+ }
10366
10670
  segmentList.length = 0;
10367
10671
  } else {
10368
10672
  segmentList = this._segmentList = [];
@@ -10376,9 +10680,10 @@ SegmentCollection.prototype.calcSegmentOrder = function(rids) {
10376
10680
  let rid = rids[i];
10377
10681
  let segment = segmentSeparators[rid];
10378
10682
  if(segment) {
10379
- if(!segment.isSubSegment()) {
10683
+ if(segment.isRootSegment()) {
10380
10684
  this._segmentList.push(segment);
10381
10685
  segment.setOrder(++order); // WARNING: Segments and sub segments start with 1
10686
+ segment.updateTreeStructure(0);
10382
10687
  }
10383
10688
  if(--segmentCount <= 0) {
10384
10689
  break;
@@ -10402,7 +10707,7 @@ SegmentCollection.prototype.getSegmentValues = function(rids, partial) {
10402
10707
  let prevSegment = null;
10403
10708
  let segmentValues = new Array(rowCount);
10404
10709
  let segmentVal = 0;
10405
- let highestVal = -10;
10710
+ let highestVal = 0;
10406
10711
  let offset = 0;
10407
10712
  for(let r = 0; r < rowCount; ++r) {
10408
10713
  let rid = rids[r];
@@ -10410,7 +10715,7 @@ SegmentCollection.prototype.getSegmentValues = function(rids, partial) {
10410
10715
  if(curSegment) { // segment separator
10411
10716
  segmentVal = curSegment.getOrder() * 100;
10412
10717
  offset = 0;
10413
- if(!curSegment.isSubSegment()) {
10718
+ if(curSegment.isRootSegment()) {
10414
10719
  if(prevSegment !== curSegment) {
10415
10720
  prevSegment = curSegment;
10416
10721
  highestVal = curSegment.getLastOrder() * 100;
@@ -10422,12 +10727,14 @@ SegmentCollection.prototype.getSegmentValues = function(rids, partial) {
10422
10727
  curSegment = segmentSeparators[parentId];
10423
10728
  segmentVal = curSegment.getOrder() * 100;
10424
10729
  offset = 1;
10425
- if(partial) {
10730
+ if(partial) { // This fixes the out of order sub segment
10426
10731
  highestVal = curSegment.getLastOrder() * 100;
10427
10732
  }
10428
10733
  } else { // row outside of segments
10429
10734
  if(highestVal) {
10430
- segmentVal = highestVal;
10735
+ if(segmentVal < highestVal) {
10736
+ segmentVal = highestVal;
10737
+ }
10431
10738
  offset = 10;
10432
10739
  } else {
10433
10740
  segmentVal = offset = 0;
@@ -10451,7 +10758,10 @@ SegmentCollection.prototype.logStructure = function() {
10451
10758
  let segmentCount = segmentList.length;
10452
10759
  let lines = [];
10453
10760
  for(let i = 0; i < segmentCount; ++i) {
10454
- segmentList[i].log(lines);
10761
+ let segment = segmentList[i];
10762
+ if(segment.isRootSegment()) {
10763
+ segment.log(lines);
10764
+ }
10455
10765
  }
10456
10766
 
10457
10767
  return lines.join("\n");
@@ -10461,10 +10771,14 @@ SegmentCollection.prototype.logStructure = function() {
10461
10771
  */
10462
10772
  SegmentCollection.prototype.logRowIdMap = function() {
10463
10773
  let lines = [];
10774
+ let segmentSeparators = this._segments;
10464
10775
  let childToSegmentId = this._shared.childToSegment;
10465
10776
  for(let rid in childToSegmentId) {
10466
10777
  let segmentId = childToSegmentId[rid];
10467
- lines.push(rid + " > " + segmentId);
10778
+ let segment = segmentSeparators[segmentId];
10779
+ if(!segment || !segment.isSubSegment()) {
10780
+ lines.push(rid + " > " + segmentId);
10781
+ }
10468
10782
  }
10469
10783
 
10470
10784
  return lines.join("\n");
@@ -11491,7 +11805,7 @@ DataTable.prototype.getSortingLogics = function() {
11491
11805
  };
11492
11806
  /** @public
11493
11807
  * @param {string|Array.<string>} cid Column id
11494
- * @param {string|number|Array.<string|number>=} sortOrders "a"|"d"|"n"
11808
+ * @param {(string|number|Array.<string|number>)=} sortOrders "a"|"d"|"n"
11495
11809
  * @param {DataTable.SortLogic=} customComparer
11496
11810
  * @param {*=} contextObj Context object that will be provided as the forth parameter of the given comparer method
11497
11811
  * @return {boolean} Return true if there is any change, otherwise false
@@ -11596,64 +11910,65 @@ DataTable.prototype._initSegmentCollection = function() {
11596
11910
  this._segments.addEventListener("subSegmentChanged", this._onSubSegmentChanged);
11597
11911
  }
11598
11912
  };
11599
- /**
11913
+ /** Add or remove all segments from the given row ids
11600
11914
  * @public
11601
11915
  * @param {Array.<string>} rids
11602
11916
  * @param {boolean=} enabled
11603
11917
  * @return {boolean} Return true if there is any change
11604
11918
  */
11605
11919
  DataTable.prototype.setSegmentSeparators = function(rids, enabled) {
11606
- let change = false;
11607
- if (rids) {
11608
- let len = rids.length;
11609
- let segmentChanged = false;
11610
- for (let i = 0; i < len; i++) {
11611
- if(enabled !== false) {
11612
- let rid = rids[i];
11613
- this._initSegmentCollection();
11614
- if(this._autoSegmentFilling) {
11615
- let parentId = this._segments.getParentRowId(rid);
11616
- if(parentId) {
11617
- this._segments.removeSegmentChild(parentId, rid);
11618
- }
11920
+ if (!rids) {
11921
+ return false;
11922
+ }
11923
+ let adding = (enabled !== false);
11924
+ let segmentAdded = 0;
11925
+ let segmentRemoved = 0;
11926
+
11927
+ let len = rids.length;
11928
+ for (let i = 0; i < len; i++) {
11929
+ let rid = rids[i];
11930
+ if(adding) {
11931
+ this._initSegmentCollection();
11932
+ if(this._autoSegmentFilling) {
11933
+ let parentId = this._segments.getParentRowId(rid);
11934
+ if(parentId) {
11935
+ this._segments.removeSegmentChild(parentId, rid);
11619
11936
  }
11620
- segmentChanged = this._segments.addSegment(rid);
11621
- } else if (this._segments) { // remove case
11622
- let segment = this._segments.getSegment(rid);
11623
- if(segment) {
11624
- if(this._segments.removeSegment(rid)) {
11625
- change = true;
11626
- if(!this._segments.getSegmentCount()) {
11627
- this._segments = null;
11628
- }
11937
+ }
11938
+ segmentAdded |= this._segments.addSegment(rid);
11939
+ } else if (this._segments) { // Removing
11940
+ let segment = this._segments.getSegment(rid);
11941
+ if(segment) {
11942
+ if(this._segments.removeSegment(rid)) {
11943
+ segmentRemoved = 1;
11944
+ if(!this._segments.getSegmentCount()) {
11945
+ this._segments = null;
11629
11946
  }
11630
11947
  }
11631
11948
  }
11632
-
11633
- }
11634
- if (enabled !== false && segmentChanged) {
11635
- this._segments.calcSegmentOrder(this._rids);
11636
- change = true;
11637
- }
11638
- if(change) {
11639
- this.dispatchGlobalChange();
11640
11949
  }
11641
11950
  }
11642
- return change;
11643
-
11951
+ if (segmentAdded) {
11952
+ this._segments.calcSegmentOrder(this._rids);
11953
+ }
11954
+ let changed = segmentAdded || segmentRemoved;
11955
+ if(changed && this._needFiring()) {
11956
+ this.dispatchGlobalChange();
11957
+ }
11958
+ return changed ? true : false;
11644
11959
  };
11645
11960
 
11646
11961
  /**
11647
11962
  * @public
11648
11963
  * @param {string} rid
11649
- * @param {boolean=} enabled
11964
+ * @param {*=} options=null Segment options. If the value is false, segment separator will be stripped off from the given rid
11650
11965
  * @return {boolean} Return true if there is any change
11651
11966
  */
11652
- DataTable.prototype.setSegmentSeparator = function(rid, enabled) {
11967
+ DataTable.prototype.setSegmentSeparator = function(rid, options) {
11653
11968
  let change = false;
11654
11969
  let memberCount = 0;
11655
11970
  if(rid && typeof rid === "string") {
11656
- if(enabled !== false) {
11971
+ if(options !== false) {
11657
11972
  this._initSegmentCollection();
11658
11973
  if(this._autoSegmentFilling) {
11659
11974
  let parentId = this._segments.getParentRowId(rid);
@@ -11661,11 +11976,12 @@ DataTable.prototype.setSegmentSeparator = function(rid, enabled) {
11661
11976
  this._segments.removeSegmentChild(parentId, rid);
11662
11977
  }
11663
11978
  }
11664
- if(this._segments.addSegment(rid)) {
11979
+ let children = (options && options["children"]) ? options["children"] : null;
11980
+ if(this._segments.addSegment(rid, children)) {
11665
11981
  this._segments.calcSegmentOrder(this._rids);
11666
11982
  change = true;
11667
11983
  }
11668
- } else if(this._segments) { // mean remove separator
11984
+ } else if(this._segments) { // Remove the separator
11669
11985
  let segment = this._segments.getSegment(rid);
11670
11986
  if(segment) {
11671
11987
  memberCount = segment.getChildCount();
@@ -11860,6 +12176,20 @@ DataTable.prototype.fillSegments = function() {
11860
12176
  }
11861
12177
  return false;
11862
12178
  };
12179
+ /** @private
12180
+ * @param {boolean=} adding This indicates that segment is changed by adding a new child
12181
+ */
12182
+ DataTable.prototype._onSegmentChildChanged = function(adding) {
12183
+ if(this._segments) {
12184
+ this._segments.calcSegmentOrder(this._rids, true);
12185
+ }
12186
+ if(adding !== false) {
12187
+ this._sort(null);
12188
+ }
12189
+ this._dispatchPositionChange(); // Force rerendering, even if there is no position change
12190
+
12191
+ this.requestClassifying();
12192
+ };
11863
12193
  /** @public
11864
12194
  * @param {string} segmentId Row id
11865
12195
  * @param {string} rid Row id
@@ -11870,10 +12200,7 @@ DataTable.prototype.addSegmentChild = function(segmentId, rid, dataId) {
11870
12200
  if(this._segments) {
11871
12201
  let dirty = this._segments.addSegmentChild(segmentId, rid, dataId);
11872
12202
  if(dirty) {
11873
- this._sort(null);
11874
- this._dispatchPositionChange(); // Force rerendering, even if there is no position change
11875
-
11876
- this.requestClassifying();
12203
+ this._onSegmentChildChanged();
11877
12204
  return true;
11878
12205
  }
11879
12206
  }
@@ -11889,17 +12216,15 @@ DataTable.prototype.addSegmentChildren = function(segmentId, rids, dataIds) {
11889
12216
  if(this._segments) {
11890
12217
  let dirty = this._segments.addSegmentChildren(segmentId, rids, dataIds);
11891
12218
  if(dirty) {
11892
- this._sort(null);
11893
- this._dispatchPositionChange(); // Force rerendering, even if there is no position change
11894
-
11895
- this.requestClassifying();
12219
+ this._onSegmentChildChanged();
11896
12220
  return true;
11897
12221
  }
11898
12222
  }
11899
12223
  return false;
11900
12224
  };
11901
12225
 
11902
- /** @public
12226
+ /** Deprecated. Remove all existing children and add new children according to the give array
12227
+ * @public
11903
12228
  * @param {Array.<Object>} segmentArr Segment array that contain "segmentId", "rowIds" to set segment children
11904
12229
  * @return {boolean} Return true if there is any change
11905
12230
  */
@@ -11907,20 +12232,16 @@ DataTable.prototype.setSegmentChildren = function(segmentArr) {
11907
12232
  if(!this._segments) {
11908
12233
  return false;
11909
12234
  }
11910
- this.removeAllSegmentChildren();
12235
+ let dirty = this._segments.removeAllSegmentChildren();
11911
12236
  let len = segmentArr.length;
11912
- let dirty;
11913
12237
  for (let i = 0; i < len; i++) {
11914
12238
  let obj = segmentArr[i];
11915
- if(this._segments.addSegmentChildren(obj.segmentId, obj.rowIds)) {
12239
+ if(this._segments.addSegmentChildren(obj["segmentId"], obj["rowIds"])) {
11916
12240
  dirty = true;
11917
12241
  }
11918
12242
  }
11919
12243
  if(dirty) {
11920
- this._sort(null);
11921
- this._dispatchPositionChange(); // Force rerendering, even if there is no position change
11922
-
11923
- this.requestClassifying();
12244
+ this._onSegmentChildChanged();
11924
12245
  return true;
11925
12246
  }
11926
12247
 
@@ -11935,8 +12256,7 @@ DataTable.prototype.removeSegmentChild = function(segmentId, rid) {
11935
12256
  if(this._segments) {
11936
12257
  let dirty = this._segments.removeSegmentChild(segmentId, rid);
11937
12258
  if(dirty) {
11938
- this.dispatchGlobalChange();
11939
- this.requestClassifying();
12259
+ this._onSegmentChildChanged(false);
11940
12260
  }
11941
12261
  return dirty;
11942
12262
  }
@@ -11951,8 +12271,7 @@ DataTable.prototype.removeSegmentChildren = function(segmentId, rids) {
11951
12271
  if(this._segments) {
11952
12272
  let dirty = this._segments.removeSegmentChildren(segmentId, rids);
11953
12273
  if(dirty) {
11954
- this.dispatchGlobalChange();
11955
- this.requestClassifying();
12274
+ this._onSegmentChildChanged(false);
11956
12275
  }
11957
12276
  return dirty;
11958
12277
  }
@@ -11965,7 +12284,7 @@ DataTable.prototype.removeAllSegmentChildren = function() {
11965
12284
  if(this._segments) {
11966
12285
  let dirty = this._segments.removeAllSegmentChildren(); // This immediately remove all sub segments
11967
12286
  if (dirty) {
11968
- this.dispatchGlobalChange();
12287
+ this._onSegmentChildChanged(false);
11969
12288
  }
11970
12289
  return dirty;
11971
12290
  }
@@ -11996,50 +12315,51 @@ DataTable.prototype.getSegmentChildIds = function(segmentId) {
11996
12315
  }
11997
12316
  return null;
11998
12317
  };
12318
+ /**
12319
+ * @private
12320
+ * @param {(Array|number)} sortOrder
12321
+ * @param {*} context
12322
+ */
12323
+ DataTable.prototype._setSegmentSortContext = function (sortOrder, context) {
12324
+ this._segmentSortOrder = sortOrder;
12325
+ this._segmentSortContext = context;
12326
+ };
11999
12327
  /** Sort all of existing segments by multiple sort logics
12000
12328
  * @public
12001
12329
  * @param {Function|Array.<Function>|Object} sortLogics
12002
- * @param {Array.<number>=} sortOrders
12330
+ * @param {Array.<number|string>=} sortOrders
12003
12331
  * @param {Array.<string>=} cids
12004
12332
  * @return {boolean}
12005
12333
  */
12006
12334
  DataTable.prototype.sortSeparators = function (sortLogics, sortOrders, cids) {
12007
- let dirty = false;
12008
12335
  if(!this._segments){
12009
12336
  return false;
12010
12337
  }
12011
12338
  if(typeof sortLogics === "function"){
12339
+ this._setSegmentSortContext(DataTable._getSortOrder(sortOrders), cids);
12012
12340
  return this.sortSegments(sortLogics);
12013
12341
  }
12342
+ if(!cids) {
12343
+ return false;
12344
+ }
12014
12345
  let sortingDefs = DataTable._buildSortContext(
12015
12346
  [],
12016
12347
  cids,
12017
12348
  sortOrders,
12018
- sortLogics
12349
+ sortLogics || this._compMap
12019
12350
  );
12020
- let defCount = sortingDefs ? sortingDefs.length : 0;
12021
- if(!defCount){
12022
- return dirty;
12023
- }
12024
-
12025
- let sortOrder = 0;
12026
- let sortLogic, sortContext;
12351
+ let defCount = sortingDefs.length;
12352
+ let sortLogic = null;
12027
12353
  if(defCount > 1) {
12028
12354
  sortLogic = DataTable._multiColumnSeparatorCompareLogic;
12029
- sortContext = sortingDefs;
12030
- sortOrder = 1; // sortOrder is not used by _multiColumnSeparatorCompareLogic
12031
- } else { // Single level sorting
12355
+ this._setSegmentSortContext(1, sortingDefs);
12356
+ } else if(defCount === 1) { // Single level sorting
12032
12357
  sortLogic = DataTable._singleColumnSeparatorCompareLogic;
12033
- sortContext = sortingDefs[0];
12034
- sortOrder = /** @type{number} */(sortContext[3]);
12358
+ this._setSegmentSortContext(sortingDefs[0][3], sortingDefs[0]); // sortOrder and context
12359
+ } else {
12360
+ return false;
12035
12361
  }
12036
- this._segmentSortOrder = sortOrder;
12037
- this._segmentSortContext = sortContext;
12038
- dirty = this.sortSegments(sortLogic);
12039
- this._segmentSortOrder = 0;
12040
- this._segmentSortContext = null;
12041
-
12042
- return dirty;
12362
+ return this.sortSegments(sortLogic);
12043
12363
  };
12044
12364
  /** Sort all of existing segments by given compare function
12045
12365
  * @public
@@ -12054,40 +12374,33 @@ DataTable.prototype.sortSegments = function (compare) {
12054
12374
  this._segments.calcSegmentOrder(this._rids);
12055
12375
  return false;
12056
12376
  }
12057
- let rids = this._rids;
12058
- let segments = this._segments;
12059
- let segmentCount = segments.getSegmentCount();
12060
- let segmentList = [];
12061
- let origOrder = [];
12062
- let itemCount = 0;
12063
- let rowCount = rids.length;
12064
- let rid = "";
12065
- let segment = null;
12066
- let i;
12067
- for(i = 0; i < rowCount; ++i) {
12068
- rid = rids[i];
12069
- segment = segments.getSegment(rid);
12070
- if(segment) {
12071
- origOrder.push(i);
12072
- segmentList.push(segment);
12073
- if(++itemCount >= segmentCount) {
12074
- break;
12075
- }
12076
- }
12077
- }
12078
12377
 
12079
12378
  this._userSegmentComparer = compare;
12080
- segmentList.sort(this._bySegmentSeparator);
12379
+
12380
+ let segments = this._segments;
12381
+ let rootSegments = segments.sortSegments(this._bySegmentSeparator);
12382
+
12081
12383
  this._userSegmentComparer = null;
12384
+ this._setSegmentSortContext(0, null);
12385
+
12386
+ let rids = this._rids;
12387
+ let origRids = rids.slice();
12388
+ let rowCount = rids.length;
12389
+ rids.length = 0;
12082
12390
 
12391
+ let segmentCount = 0;
12083
12392
  let dirty = false;
12084
- for(i = 0; i < itemCount; ++i) {
12085
- let idx = origOrder[i];
12086
- rid = rids[idx];
12087
- segment = segmentList[i];
12088
- let newRid = segment.getId();
12089
- if(rid !== newRid) {
12090
- rids[idx] = newRid;
12393
+ for(let i = 0; i < rowCount; ++i) {
12394
+ let rid = origRids[i];
12395
+ let segment = segments.getSegment(rid);
12396
+ if(segment) {
12397
+ if(segment.isRootSegment()) {
12398
+ rootSegments[segmentCount++].getFlattenTreeIds(rids);
12399
+ }
12400
+ } else if(!segments.getParentRowId(rid)) {
12401
+ rids.push(rid);
12402
+ }
12403
+ if(rid !== rids[i]) {
12091
12404
  dirty = true;
12092
12405
  }
12093
12406
  }
@@ -12096,9 +12409,8 @@ DataTable.prototype.sortSegments = function (compare) {
12096
12409
  this._segments.calcSegmentOrder(rids);
12097
12410
  this._sort(null);
12098
12411
  this._dispatchPositionChange();
12099
- return true;
12100
12412
  }
12101
- return false;
12413
+ return dirty;
12102
12414
  };
12103
12415
  /** Sort all of existing segments by given compare function
12104
12416
  * @private
@@ -12381,7 +12693,7 @@ DataTable._positionChangeArg = {"globalChange": true, "positionChangeOnly": true
12381
12693
  * @function
12382
12694
  * @public
12383
12695
  * @ignore
12384
- * @param {Array.<Array>} out_defs Output object. Array is used to optimize property accessing time.
12696
+ * @param {!Array.<Array>} out_defs Output object. Array is used to optimize property accessing time.
12385
12697
  * @param {string|Array.<string>} cids
12386
12698
  * @param {string|number|Array.<string|number>=} sortOrders
12387
12699
  * @param {Function|Array.<Function>|Object.<string, DataTable.SortLogic>=} logics
@@ -31600,13 +31912,13 @@ DataView.prototype.setSegmentSeparators = function(rowIds, enabled) {
31600
31912
  }
31601
31913
  return false;
31602
31914
  };
31603
- /** Set visible row as segment separator (hidden or filtered rows cannot be a segment separator)
31915
+ /** Set visible row as a segment separator (hidden or filtered rows cannot be a segment separator)
31604
31916
  * @public
31605
31917
  * @param {string|number} rowRef Row id or row index
31606
- * @param {boolean=} enabled
31918
+ * @param {*=} options=null Segment options. If the value is false, segment separator will be stripped off from the given rid
31607
31919
  * @return {boolean} Return true if there is any change
31608
31920
  */
31609
- DataView.prototype.setSegmentSeparator = function(rowRef, enabled) {
31921
+ DataView.prototype.setSegmentSeparator = function(rowRef, options) {
31610
31922
  let rowId = "";
31611
31923
  if(typeof rowRef === "number") {
31612
31924
  rowId = this.getRowId(rowRef);
@@ -31615,12 +31927,11 @@ DataView.prototype.setSegmentSeparator = function(rowRef, enabled) {
31615
31927
  }
31616
31928
 
31617
31929
  if(rowId) {
31618
- enabled = enabled !== false;
31619
- if(enabled) {
31930
+ if(options !== false) { // undefined, null, object, or true value
31620
31931
  this.synchronizeRowOrder();
31621
31932
  }
31622
31933
  // TODO: Force expanding of segment before unsetting segment separator
31623
- return this._dt.setSegmentSeparator(rowId, enabled);
31934
+ return this._dt.setSegmentSeparator(rowId, options);
31624
31935
  }
31625
31936
  return false;
31626
31937
  };
@@ -31853,10 +32164,22 @@ DataView.prototype.getSegmentChildIds = function(segmentRef) {
31853
32164
  /** Sort all of existing segments by multiple sort logics
31854
32165
  * @public
31855
32166
  * @param {Function|Array.<Function>|Object} sortLogics
31856
- * @param {Array.<number>=} sortOrders
31857
- * @param {Array.<string>=} cids
32167
+ * @param {(number|Array.<number>)=} sortOrders
32168
+ * @param {(string|Array.<string>)=} cids
31858
32169
  */
31859
32170
  DataView.prototype.sortSeparators = function (sortLogics, sortOrders, cids) {
32171
+ let sortingDefs = this._sortingDefs;
32172
+ if(sortingDefs.length) {
32173
+ if(!cids) {
32174
+ cids = sortingDefs[0][0]; // field
32175
+ }
32176
+ if(!sortOrders) {
32177
+ sortOrders = sortingDefs[0][3];
32178
+ }
32179
+ } else if(!sortLogics) {
32180
+ return;
32181
+ }
32182
+
31860
32183
  this._dt.sortSeparators(sortLogics, sortOrders, cids);
31861
32184
  };
31862
32185
  /** Sort all of existing segments by given compare function
@@ -34807,7 +35130,6 @@ VirtualizedLayoutGrid.prototype.setWidth = function (px) {
34807
35130
  };
34808
35131
  /** @override */
34809
35132
  VirtualizedLayoutGrid.prototype.setHeight = function (px) {
34810
- console.log("unsupported");
34811
35133
  return false;
34812
35134
  };
34813
35135
  /** {@link ElementWrapper#show}
@@ -34986,7 +35308,6 @@ VirtualizedLayoutGrid.prototype.getMinimumRowHeight = function (index) {
34986
35308
  };
34987
35309
  /** @inheritDoc */
34988
35310
  VirtualizedLayoutGrid.prototype.setMinimumRowHeight = function (index, val) {
34989
- console.log("unsupported");
34990
35311
  return false;
34991
35312
  };
34992
35313
 
@@ -35062,7 +35383,6 @@ VirtualizedLayoutGrid.prototype.getRowScalability = function (indexY) {
35062
35383
  };
35063
35384
  /** @inheritDoc */
35064
35385
  VirtualizedLayoutGrid.prototype.setRowScalability = function (index, val) {
35065
- console.log("unsupported");
35066
35386
  return false;
35067
35387
  };
35068
35388
 
@@ -35208,17 +35528,15 @@ VirtualizedLayoutGrid.prototype.getRowHighlight = function () {
35208
35528
  /** @inheritDoc */
35209
35529
  VirtualizedLayoutGrid.prototype.setRowHighlight = function (rowIndex) {
35210
35530
  let prevIndex = this._grid.getRowHighlight();
35211
- if (prevIndex >= 0) { prevIndex += this._firstIndex; }
35212
35531
  this._grid.setRowHighlight(rowIndex - this._firstIndex);
35213
- //Check row highligh is in view
35214
- rowIndex = this._grid.getRowHighlight();
35215
- if (rowIndex >= 0) { rowIndex += this._firstIndex; }
35216
35532
 
35217
35533
  if (this._hasListener("rowHighlighted")) {
35218
- let e = {};
35219
- e["prevRowIndex"] = prevIndex;
35220
- e["rowIndex"] = rowIndex;
35221
- this._dispatch("rowHighlighted", e);
35534
+ rowIndex = this._grid.getRowHighlight();
35535
+
35536
+ this._dispatch("rowHighlighted", {
35537
+ "prevRowIndex": (prevIndex >= 0) ? prevIndex + this._firstIndex : prevIndex,
35538
+ "rowIndex": (rowIndex >= 0) ? rowIndex + this._firstIndex : rowIndex
35539
+ });
35222
35540
  }
35223
35541
  };
35224
35542
 
@@ -35969,6 +36287,7 @@ let _createHiddenInput = function () {
35969
36287
  styleObj.width = styleObj.height = styleObj.padding = styleObj.border = "0";
35970
36288
  hiddenInput.value = "0";
35971
36289
  hiddenInput.role = "grid";
36290
+ hiddenInput.readOnly = true;
35972
36291
  return hiddenInput;
35973
36292
  };
35974
36293
  /** @private
@@ -36515,7 +36834,7 @@ Core.prototype._hasPendingRowChange = false;
36515
36834
  * @return {string}
36516
36835
  */
36517
36836
  Core.getVersion = function () {
36518
- return "5.1.135";
36837
+ return "5.1.140";
36519
36838
  };
36520
36839
  /** {@link ElementWrapper#dispose}
36521
36840
  * @override
@@ -48877,16 +49196,17 @@ Grid_Grid.prototype._onFormulaDataRequired = function(e) {
48877
49196
  * @param {Object} e
48878
49197
  */
48879
49198
  Grid_Grid.prototype._onDataComposed = function(e) {
48880
- let values = e["changes"];
48881
- if(!values) {
49199
+ let changes = e["changes"];
49200
+ if(!changes) {
48882
49201
  if(e["initialChanges"]) {
48883
- values = e["changes"] = e["initialChanges"]; // Need to keep e["changes"] for backward compatibility.
49202
+ changes = e["changes"] = e["initialChanges"]; // Need to keep e["changes"] for backward compatibility.
48884
49203
  } else {
48885
49204
  return; // Cannot do data composition if there is no change in data
48886
49205
  }
48887
49206
  }
48888
49207
 
48889
- if(!e["rowData"]) {
49208
+ let rowData = e["rowData"];
49209
+ if(!rowData) {
48890
49210
  return; // Row could already be removed or global change event is sent
48891
49211
  }
48892
49212
 
@@ -48904,9 +49224,9 @@ Grid_Grid.prototype._onDataComposed = function(e) {
48904
49224
  }
48905
49225
 
48906
49226
  if(this._autoDateConversion) { // auto data conversion
48907
- let field, value, dataType, colDef;
48908
- for(field in values) {
48909
- colDef = this._getColumnDefinition(field);
49227
+ let dataType;
49228
+ for(let field in changes) {
49229
+ let colDef = this._getColumnDefinition(field);
48910
49230
  if(colDef) {
48911
49231
  dataType = colDef.getDataType();
48912
49232
  } else {
@@ -48914,7 +49234,7 @@ Grid_Grid.prototype._onDataComposed = function(e) {
48914
49234
  }
48915
49235
 
48916
49236
  if(dataType === "datetime") {
48917
- value = values[field];
49237
+ let value = rowData[field];
48918
49238
  rowDef.setData(field + "_RAW", value);
48919
49239
  value = DateTime.toDateObject(value);
48920
49240
  rowDef.setData(field, value); // TODO: Check if this trigger data change multiple times