@refinitiv-ui/efx-grid 6.0.153 → 6.0.155

Sign up to get free protection for your applications and to get access to all the features.
@@ -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