@refinitiv-ui/efx-grid 6.0.126 → 6.0.128

Sign up to get free protection for your applications and to get access to all the features.
@@ -8621,8 +8621,7 @@ EventDispatcher_EventDispatcher._proto = EventDispatcher_EventDispatcher.prototy
8621
8621
 
8622
8622
 
8623
8623
 
8624
- /**
8625
- * Trigger when data within the table has been changed
8624
+ /** @description Trigger when data within the table has been changed
8626
8625
  * @event DataCache#dataChanged
8627
8626
  * @property {boolean} globalChange Indicates a big change. User should expect all data has been change
8628
8627
  * @property {string} type Type of changes. Possible values are "inserted", "removed", "updated", and undefined
@@ -8630,32 +8629,34 @@ EventDispatcher_EventDispatcher._proto = EventDispatcher_EventDispatcher.prototy
8630
8629
  * @property {Object.<string, *>} rowData Column values of the changed row in JSON object format
8631
8630
  */
8632
8631
 
8633
- /**
8634
- * Trigger before DataCache#dataChanged. Perform any data update during the event will NOT cause more dataChanged events
8632
+ /** @description Trigger before DataCache#dataChanged. Perform any data update during the event will NOT cause more dataChanged events
8635
8633
  * @event DataCache#dataComposed
8636
8634
  */
8637
8635
 
8638
- /**
8636
+ /** Class for caching data and firing event when data is changed
8639
8637
  * @constructor
8640
8638
  * @extends {EventDispatcher}
8641
8639
  */
8642
8640
  let DataCache = function () {
8643
- let _t = this;
8644
-
8645
- _t._rows = {};
8646
- _t._subs = {};
8647
- _t._onInsert = _t._onInsert.bind(_t);
8648
- _t._onUpdate = _t._onUpdate.bind(_t);
8649
- _t._onDelete = _t._onDelete.bind(_t);
8650
- _t._onQ2DataChanged = _t._onQ2DataChanged.bind(_t);
8651
- _t._onQ2SubAdded = _t._onQ2SubAdded.bind(_t);
8652
- _t._onQ2SubRemoved = _t._onQ2SubRemoved.bind(_t);
8641
+ this._rows = {};
8653
8642
 
8654
- _t._addEvent("dataComposed");
8655
- _t._addEvent("dataChanged");
8643
+ this._addEvent("dataComposed");
8644
+ this._addEvent("dataChanged");
8656
8645
  };
8657
8646
  es6_Ext.inherits(DataCache, event_EventDispatcher);
8658
8647
 
8648
+ /** @protected
8649
+ * @ignore
8650
+ * @type {!Object.<string, Object>}
8651
+ */
8652
+ DataCache.prototype._rows;
8653
+
8654
+ /** @protected
8655
+ * @ignore
8656
+ * @type {boolean}
8657
+ */
8658
+ DataCache.prototype._composing = false;
8659
+
8659
8660
  //#region Public
8660
8661
  /**
8661
8662
  * @public
@@ -8663,162 +8664,64 @@ es6_Ext.inherits(DataCache, event_EventDispatcher);
8663
8664
  DataCache.prototype.dispose = function () {
8664
8665
  this.unlistenAll();
8665
8666
  this.clearAllData(true);
8666
- this._quotes2 = null;
8667
8667
  };
8668
8668
 
8669
- /**
8670
- * Deprecated. Built-in Data Service is deprecated due to the lack of flexibility. This API supports only Quotes2's "Subscriptions" object.
8669
+ /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8671
8670
  * @public
8672
- * @param {Object} subs Subscriptions object from JET.Quotes2
8671
+ * @ignore
8673
8672
  */
8674
- DataCache.prototype.setSubscriptions = function (subs) {
8675
- if (this._quotes2) {
8676
- this._quotes2["removeEventListener"]("dataChanged", this._onQ2DataChanged);
8677
- this._quotes2["removeEventListener"]("subscriptionAdded", this._onQ2SubAdded);
8678
- this._quotes2["removeEventListener"]("subscriptionRemoved", this._onQ2SubRemoved);
8679
- }
8680
-
8681
- this._quotes2 = subs;
8682
-
8683
- if (this._quotes2) {
8684
- this._quotes2["addEventListener"]("dataChanged", this._onQ2DataChanged);
8685
- this._quotes2["addEventListener"]("subscriptionAdded", this._onQ2SubAdded);
8686
- this._quotes2["addEventListener"]("subscriptionRemoved", this._onQ2SubRemoved);
8687
- }
8688
- };
8673
+ DataCache.prototype.setSubscriptions = function () {};
8689
8674
 
8690
- /**
8691
- * Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.This API supports only Quotes2's
8692
- * "Subscriptions" object.
8675
+ /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8693
8676
  * @public
8694
- * @return {Object} subs Subscriptions object from JET.Quotes2
8677
+ * @ignore
8678
+ * @return {Object} Always returns null
8695
8679
  */
8696
- DataCache.prototype.getSubscriptions = function () {
8697
- return this._quotes2;
8698
- };
8680
+ DataCache.prototype.getSubscriptions = function () { return null; };
8699
8681
 
8700
- /**
8701
- * Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8682
+ /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8702
8683
  * @public
8703
- * @param {Object} sub Subscription object from JET.Quote
8704
- * @param {string=} opt_primaryRic Main RIC for creating Id or recalling subscription. This is because subscription
8705
- * object does not provide a way to access its data
8706
- * @param {Object=} opt_values Initial values
8684
+ * @ignore
8707
8685
  */
8708
- DataCache.prototype.addSubscription = function (sub, opt_primaryRic, opt_values) {
8709
- if (this.getSubscription(sub["id"])) {
8710
- return;
8711
- }
8712
-
8713
- let internalSub = {"s": sub, "rics": {}};
8714
-
8715
- this._subs[sub["id"]] = internalSub;
8686
+ DataCache.prototype.addSubscription = function () {};
8716
8687
 
8717
- if (!this._quotes2) {
8718
- sub["onNewRow"](this._onInsert);
8719
- sub["onUpdate"](this._onUpdate);
8720
- sub["onRemoveRow"](this._onDelete);
8721
- }
8722
-
8723
- if (opt_primaryRic) {
8724
- internalSub["primary"] = opt_primaryRic;
8725
-
8726
- if (!opt_values) {
8727
- opt_values = {};
8728
- }
8729
-
8730
- this._onInsert(sub, opt_primaryRic, opt_values);
8731
- }
8732
- };
8733
-
8734
- /**
8735
- * Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8688
+ /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8736
8689
  * @public
8737
- * @param {Object} sub Subscription object from JET.Quote
8690
+ * @ignore
8738
8691
  */
8739
- DataCache.prototype.removeSubscription = function (sub) { // All RICs associated to the subscription are removed
8740
- let subId = sub["id"];
8692
+ DataCache.prototype.removeSubscription = function () {};
8741
8693
 
8742
- if (!sub || !this._subs[subId]) {
8743
- return;
8744
- }
8745
-
8746
- if (!this._quotes2) {
8747
- sub["stop"]();
8748
- }
8749
-
8750
- let rics = this._subs[subId]["rics"];
8751
-
8752
- for (let ric in rics) {
8753
- this.setRowData(subId + ric, null); // No subscription attached
8754
- }
8755
-
8756
- delete this._subs[subId];
8757
- };
8758
-
8759
- /**
8760
- * Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8694
+ /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8761
8695
  * @public
8696
+ * @ignore
8762
8697
  */
8763
- DataCache.prototype.startAllSubscriptions = function () {
8764
- if (this._quotes2) {
8765
- this._quotes2["start"]();
8766
- } else {
8767
- for (let key in this._subs) {
8768
- this._subs[key]["s"]["start"]();
8769
- }
8770
- }
8771
- };
8698
+ DataCache.prototype.startAllSubscriptions = function () {};
8772
8699
 
8773
- /**
8774
- * Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8700
+ /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8775
8701
  * @public
8702
+ * @ignore
8776
8703
  */
8777
- DataCache.prototype.stopAllSubscriptions = function () {
8778
- if (this._quotes2) {
8779
- this._quotes2["stop"]();
8780
- } else {
8781
- for (let key in this._subs) {
8782
- this._subs[key]["s"]["stop"]();
8783
- }
8784
- }
8785
- };
8704
+ DataCache.prototype.stopAllSubscriptions = function () {};
8786
8705
 
8787
- /**
8706
+ /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8788
8707
  * @public
8789
- * @param {string} sub_id
8790
- * @return {Object} Subscription object from JET.Quote
8708
+ * @ignore
8709
+ * @return {Object} Always returns null
8791
8710
  */
8792
- DataCache.prototype.getSubscription = function (sub_id) {
8793
- return (this._subs[sub_id]) ? this._subs[sub_id]["s"] : null;
8794
- };
8711
+ DataCache.prototype.getSubscription = function () { return null; };
8795
8712
 
8796
- /**
8713
+ /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8797
8714
  * @public
8798
- * @param {string} sub_id
8799
- * @return {string} ric that has been input when calling addSubscription
8715
+ * @ignore
8716
+ * @return {string} Always returns empty string
8800
8717
  */
8801
- DataCache.prototype.getPrimaryRic = function (sub_id) {
8802
- let subDef = this._subs[sub_id];
8803
- if (subDef) {
8804
- return subDef["primary"];
8805
- }
8806
- return "";
8807
- };
8718
+ DataCache.prototype.getPrimaryRic = function () { return ""; };
8808
8719
 
8809
- /**
8810
- * @public
8720
+ /** @public
8811
8721
  * @param {boolean=} opt_suppressEvent
8812
8722
  * @fires DataCache#dataChanged
8813
8723
  */
8814
- DataCache.prototype.clearAllData = function (opt_suppressEvent) { // All subscriptions are also removed
8815
- if (this._quotes2) {
8816
- this._quotes2["removeAllSubscriptions"]();
8817
- } else {
8818
- this.stopAllSubscriptions();
8819
- }
8820
-
8821
- this._subs = {};
8724
+ DataCache.prototype.clearAllData = function (opt_suppressEvent) {
8822
8725
  this._rows = {};
8823
8726
 
8824
8727
  if (!opt_suppressEvent) {
@@ -8862,28 +8765,12 @@ DataCache.prototype.getData = function (rid, cid) {
8862
8765
  return (row) ? row[cid] : null;
8863
8766
  };
8864
8767
 
8865
- /**
8866
- * Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8768
+ /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8867
8769
  * @public
8868
- * @return {Object.<string, Array.<string>>} Map of Array of subscription object
8770
+ * @ignore
8771
+ * @return {Object.<string, Array.<string>>} Always returns null
8869
8772
  */
8870
- DataCache.prototype.getAllRics = function () { // Slow
8871
- let ricMap = {};
8872
-
8873
- for (let subId in this._subs) {
8874
- let rics = this._subs[subId]["rics"];
8875
-
8876
- for (let ric in rics) {
8877
- if (!ricMap[ric]) {
8878
- ricMap[ric] = [];
8879
- }
8880
-
8881
- ricMap[ric].push(subId);
8882
- }
8883
- }
8884
-
8885
- return ricMap; // No duplicate ric
8886
- };
8773
+ DataCache.prototype.getAllRics = function () { return null; };
8887
8774
 
8888
8775
  /**
8889
8776
  * @public
@@ -9082,27 +8969,22 @@ DataCache.prototype.cloneRowData = function (rid) {
9082
8969
  /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
9083
8970
  * @public
9084
8971
  * @ignore
9085
- * @suppress {checkTypes}
9086
8972
  */
9087
8973
  DataCache.prototype.addStaticFields = function () {};
9088
8974
 
9089
- /**
9090
- * Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8975
+ /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
9091
8976
  * @public
9092
8977
  * @ignore
9093
- * @suppress {checkTypes}
9094
8978
  */
9095
8979
  DataCache.prototype.removeStaticFields = function () {};
9096
8980
 
9097
- /**
9098
- * Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8981
+ /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
9099
8982
  * @public
9100
8983
  * @ignore
9101
8984
  */
9102
8985
  DataCache.prototype.resetStaticFields = function () {};
9103
8986
 
9104
- /**
9105
- * Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
8987
+ /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
9106
8988
  * @public
9107
8989
  * @ignore
9108
8990
  */
@@ -9143,40 +9025,29 @@ DataCache.prototype.log = function (opt_options) {
9143
9025
  console.table(this.dump(opt_options));
9144
9026
  };
9145
9027
 
9146
- //#region ADC
9147
9028
  /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
9148
9029
  * @public
9149
9030
  * @ignore
9150
- * @param {string} userId
9151
- * @param {string} productId
9152
- * @param {string} url
9153
- * @param {string=} opt_lang
9154
9031
  */
9155
- DataCache.prototype.setDataCloudSettings = function (userId, productId, url, opt_lang) {};
9032
+ DataCache.prototype.setDataCloudSettings = function () {};
9156
9033
 
9157
- /**
9158
- * Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
9034
+ /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
9159
9035
  * @public
9160
9036
  * @ignore
9161
9037
  */
9162
9038
  DataCache.prototype.getDataCloudFields = function () {};
9163
9039
 
9164
- /**
9165
- * Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
9040
+ /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
9166
9041
  * @public
9167
9042
  * @ignore
9168
- * @param {Array.<string>|string} fields
9169
9043
  */
9170
- DataCache.prototype.addDataCloudFields = function (fields) {};
9044
+ DataCache.prototype.addDataCloudFields = function () {};
9171
9045
 
9172
- /**
9173
- * Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
9046
+ /** Deprecated. Built-in Data Service is deprecated due to the lack of flexibility.
9174
9047
  * @public
9175
9048
  * @ignore
9176
- * @param {string} field
9177
9049
  */
9178
- DataCache.prototype.removeDataCloudField = function (field) {};
9179
- //#endregion ADC
9050
+ DataCache.prototype.removeDataCloudField = function () {};
9180
9051
  //#endregion Public
9181
9052
 
9182
9053
  /**
@@ -9313,162 +9184,6 @@ DataCache.constructTable = function (dataset, opt_options, opt_rowIds) {
9313
9184
  };
9314
9185
 
9315
9186
 
9316
- //#region Private
9317
- /**
9318
- * For Quotes2 only
9319
- * @private
9320
- * @param {string} subId
9321
- * @param {string} ric
9322
- * @param {Object.<string, *>} values
9323
- */
9324
- DataCache.prototype._insertRic = function (subId, ric, values) {
9325
- // HACK: Some chain may have 0# symbol in there chain index (e.g. 0#CL:)
9326
- ric = ric.replace("0#", "");
9327
-
9328
- let rid = subId + ric;
9329
-
9330
- let rowData = this.getRowData(rid);
9331
- if (!rowData) { // Ensure that we have subscription id and ric from Quotes2
9332
- let tmp = values;
9333
-
9334
- values = {}; // Clone a new object for duplicated ric
9335
-
9336
- for (let key in tmp) { // Slow
9337
- values[key] = tmp[key];
9338
- }
9339
-
9340
- values["SUB_ID"] = subId;
9341
- values["RIC"] = ric;
9342
- } else {
9343
- let rowDef = rowData["ROW_DEF"];
9344
- if(rowDef && rowDef.isChain()){
9345
- values["SUB_ID"] = subId;
9346
- }
9347
- }
9348
-
9349
- this.setRowData(rid, values);
9350
- };
9351
-
9352
- /**
9353
- * @private
9354
- * @param {Object} e
9355
- */
9356
- DataCache.prototype._onQ2DataChanged = function (e) {
9357
- let subId = e["subId"];
9358
- let ric = e["ric"];
9359
- let values = /** @type{Object.<string, *>} */(e["values"]);
9360
-
9361
- if (values) {
9362
- this._insertRic(subId, ric, values);
9363
- } else { // Remove ric
9364
- delete this._subs[subId]["rics"][ric];
9365
-
9366
- this.setRowData(subId + ric, null);
9367
- }
9368
- };
9369
-
9370
- /**
9371
- * @private
9372
- * @param {Object} e
9373
- */
9374
- DataCache.prototype._onQ2SubAdded = function (e) {
9375
- let subs = e["subs"];
9376
- let len = subs.length;
9377
-
9378
- for (let i = 0; i < len; ++i) {
9379
- let sub = subs[i];
9380
-
9381
- // chain subId fires twice, one with "_ci_" and one without "_ci_"
9382
- // the subId with "_ci_" should be ignore
9383
- if(sub["id"].indexOf("_ci_") < 0){
9384
- this.addSubscription(sub, sub["ric"]);
9385
- }
9386
- }
9387
- };
9388
-
9389
- /**
9390
- * @private
9391
- * @param {Object} e
9392
- */
9393
- DataCache.prototype._onQ2SubRemoved = function (e) {
9394
- let subs = e["subs"];
9395
- let len = subs.length;
9396
-
9397
- for (let i = 0; i < len; ++i) {
9398
- let sub = subs[i];
9399
-
9400
- // chain subId fires twice, one with "_ci_" and one without "_ci_"
9401
- // the subId with "_ci_" should be ignore
9402
- if(sub["id"].indexOf("_ci_") < 0){
9403
- this.removeSubscription(sub);
9404
- }
9405
- }
9406
- };
9407
-
9408
- /**
9409
- * @private
9410
- * @param {Object} sub Subscription object from JET.Quote
9411
- * @param {string} ric
9412
- * @param {Object.<string, *>} values
9413
- */
9414
- DataCache.prototype._onInsert = function (sub, ric, values/*, rowN*/) {
9415
- let subId = sub["id"];
9416
-
9417
- if (this._quotes2) {
9418
- this._insertRic(subId, ric, values);
9419
- } else {
9420
- this.setRowData(subId + ric, values, {"subscription": sub, "ric": ric});
9421
- }
9422
- };
9423
-
9424
- /**
9425
- * @private
9426
- * @function
9427
- */
9428
- DataCache.prototype._onUpdate = DataCache.prototype._onInsert;
9429
-
9430
- /**
9431
- * This is a legacy code and should be deprecated
9432
- * @private
9433
- * @param {Object} sub Subscription object from JET.Quote
9434
- * @param {string} ric
9435
- * @param {Array.<string, *>} values
9436
- */
9437
- DataCache.prototype._onDelete = function (sub, ric, values/*, rowN*/) {
9438
- delete this._subs[sub["id"]]["rics"][ric];
9439
-
9440
- // We cannot cache event arguments because user may want to collect all the updates
9441
- this.setRowData(sub["id"] + ric, null, {"subscription": sub, "ric": ric});
9442
- };
9443
-
9444
- /** @protected
9445
- * @ignore
9446
- * @type {!Object.<string, Object>}
9447
- */
9448
- DataCache.prototype._rows;
9449
-
9450
- /**
9451
- * @private
9452
- * @type {!Object.<string, Object>}
9453
- */
9454
- DataCache.prototype._subs;
9455
-
9456
- /**
9457
- * @private
9458
- * @type {Object}
9459
- */
9460
- DataCache.prototype._quotes2 = null;
9461
-
9462
- /** @protected
9463
- * @ignore
9464
- * @type {boolean}
9465
- */
9466
- DataCache.prototype._composing = false;
9467
-
9468
- //#endregion Private
9469
-
9470
- DataCache._proto = DataCache.prototype;
9471
-
9472
9187
  /* harmony default export */ var data_DataCache = (DataCache);
9473
9188
 
9474
9189
 
@@ -12978,20 +12693,32 @@ const ROW_TYPES = {
12978
12693
  */
12979
12694
  const ROW_ID_PATTERN = /^_[^_]+_$/;
12980
12695
 
12696
+ /** @private
12697
+ * @function
12698
+ * @param {Object} obj
12699
+ * @returns {!Object} Always returns a new object
12700
+ */
12701
+ let _cloneObject = function(obj) {
12702
+ let newObj = {};
12703
+ for(let key in obj) {
12704
+ newObj[key] = obj[key];
12705
+ }
12706
+ return newObj;
12707
+ };
12708
+
12981
12709
  /** @constructor
12982
12710
  * @param {RowDefinition~Options=} rowOptions
12983
12711
  */
12984
12712
  let RowDefinition = function(rowOptions) {
12985
12713
  this._changes = {};
12986
- if(rowOptions && rowOptions["segmentId"]) { // This row will be classification header row
12987
- this._dataId = this._rowId = rowOptions["segmentId"];
12714
+ if(rowOptions && rowOptions["segmentId"]) { // This row will be classified header row (subsegment header row)
12715
+ this._rowId = rowOptions["segmentId"];
12988
12716
  this._autoGenerated = true;
12989
12717
  this._subSegment = true;
12990
12718
  return;
12991
12719
  }
12992
12720
 
12993
12721
  this._rowId = "_" + RowDefinition._runningId++ + "_";
12994
- this._dataId = this._rowId;
12995
12722
 
12996
12723
  if(rowOptions) {
12997
12724
  if(rowOptions["asConstituent"]) { // Create row definition as a constituent of a chain
@@ -13044,10 +12771,6 @@ RowDefinition.prototype._realTime = true;
13044
12771
  * @private
13045
12772
  */
13046
12773
  RowDefinition.prototype._rowId = ""; // Row Id must be unique
13047
- /** @type {string}
13048
- * @private
13049
- */
13050
- RowDefinition.prototype._dataId = ""; // Data id can be different from rowId for constituents of a chain
13051
12774
  /** @type {boolean}
13052
12775
  * @private
13053
12776
  */
@@ -13056,6 +12779,11 @@ RowDefinition.prototype._userId = false;
13056
12779
  * @private
13057
12780
  */
13058
12781
  RowDefinition.prototype._dc = null;
12782
+ /** Quotes2 subscription object
12783
+ * @type {Object}
12784
+ * @private
12785
+ */
12786
+ RowDefinition.prototype._subs = null;
13059
12787
  /** @type {DataView}
13060
12788
  * @private
13061
12789
  */
@@ -13131,22 +12859,20 @@ RowDefinition.prototype.dispose = function() {
13131
12859
  this._children = null;
13132
12860
  }
13133
12861
 
12862
+ if(this._dc) {
12863
+ this._dc.setRowData(this._rowId, null); // Clear all data held by this row def
12864
+ this._dc = null;
12865
+ }
13134
12866
  this._staticValues = null; // Static values contain user data
13135
12867
  this._parent = null; // WARNING: This does not impact children count of the parent. A child must be destroyed by its parent only
13136
12868
  this._depthLevel = 0;
13137
12869
  this.unsubscribeForUpdates();
13138
- if(this._dc) {
13139
- let rowData = this.getRowData();
13140
- if(rowData) {
13141
- rowData[ROW_DEF] = null;
13142
- }
13143
- this._dc = null;
13144
- }
13145
- if(this._view) {
13146
- this._view = null;
13147
- }
13148
- this._rowId = this._dataId = "";
12870
+ this._subs = null;
12871
+ this._view = null; // WARNING: This does not remove this row from the UI view
12872
+
12873
+ this._subId = this._rowId = "";
13149
12874
  this._userId = false;
12875
+ this._autoGenerated = false;
13150
12876
  this._userModel = null;
13151
12877
  };
13152
12878
  /** @public
@@ -13169,7 +12895,7 @@ RowDefinition.prototype.initialize = function(rowOptions) {
13169
12895
  if(userRowId.match(ROW_ID_PATTERN)) {
13170
12896
  console.warn("Please change the rowId format to avoid duplicated rows' id causing unexpected behavior.");
13171
12897
  } else {
13172
- this._rowId = this._dataId = userRowId;
12898
+ this._rowId = userRowId;
13173
12899
  this._userId = true;
13174
12900
  }
13175
12901
  }
@@ -13225,7 +12951,7 @@ RowDefinition.prototype.initialize = function(rowOptions) {
13225
12951
 
13226
12952
  let symbol = this._ric || this._chainRic;
13227
12953
  if(symbol || this._permId){
13228
- this.setContent(symbol, extractedOptions); // this._dataId is modified
12954
+ this.setContent(symbol, extractedOptions);
13229
12955
  }
13230
12956
 
13231
12957
  val = rowOptions["values"];
@@ -13234,28 +12960,20 @@ RowDefinition.prototype.initialize = function(rowOptions) {
13234
12960
  this.setStaticRowData(val, rowOptions["fields"]);
13235
12961
  }
13236
12962
  };
13237
- /** @private
12963
+ /** @description Constituents will have subscription id, but have no subscription. It's row id will be different from subscription id. It will have a reference to its parent. It cannot be generated by themselve -- always be autogenerated.
12964
+ * @private
13238
12965
  * @param {!Object} rowOptions
13239
12966
  */
13240
12967
  RowDefinition.prototype._initializeAsConstituent = function(rowOptions) {
13241
12968
  this._autoGenerated = true;
13242
12969
  let parentDef = /** @type{RowDefinition} */(rowOptions["parent"]);
13243
12970
  if(this.setParent(parentDef)) {
13244
- this._dataId = /** @type{string} */(rowOptions["dataId"]); // Constituent will have the same subId as its parent but with different ric
13245
12971
  this._ric = /** @type{string} */(rowOptions["ric"]);
13246
12972
  this._dc = parentDef._dc; // Parent chain must have data cache
13247
- if(this._dc) {
13248
- let rowData = this.getRowData(); // Do not trigger any data update
13249
- if(rowData) { // Row data from data cache must exist beforehand
13250
- rowData[ROW_DEF] = this; // This is for easy referencing from data streaming, also for preventing duplication
13251
- }
13252
- }
13253
- }
13254
- let val = rowOptions["values"];
13255
- // eslint-disable-next-line no-undefined
13256
- if(val !== undefined) {
13257
- this.setStaticRowData(val, rowOptions["fields"]);
12973
+ this._subId = parentDef._subId; // Child constituent uses the same subscription as its parent
13258
12974
  }
12975
+ this._staticValues = rowOptions["values"] || null;
12976
+ this.resetRowData();
13259
12977
  };
13260
12978
  /** @private
13261
12979
  * @param {DataView} view
@@ -13310,9 +13028,9 @@ RowDefinition.prototype.setContent = function(userInput, extractedOptions) {
13310
13028
  }
13311
13029
 
13312
13030
  let dirty = (this._userInput !== userInput);
13313
- let permId = extractedOptions["permId"];
13031
+ let permId = extractedOptions["permId"] || "";
13314
13032
  if(this._permId !== permId){
13315
- this._permId = permId || "";
13033
+ this._permId = permId;
13316
13034
  dirty = true;
13317
13035
  }
13318
13036
  if(!dirty) {
@@ -13329,10 +13047,7 @@ RowDefinition.prototype.setContent = function(userInput, extractedOptions) {
13329
13047
  let dv = this._view;
13330
13048
  let stalledSorting = _stallSorting(dv, realtimeRow && asChain, false); // To preserve current position of the segment/chain
13331
13049
 
13332
- if(!this.unsubscribeForUpdates()){
13333
- this._clearStaticData();
13334
- }
13335
- this.resetUpdates(); // Remove all previous data updates because a new content is just entered
13050
+ this.unsubscribeForUpdates(); // Static data remains intact
13336
13051
 
13337
13052
  this._userInput = userInput;
13338
13053
  let collapsed = extractedOptions["collapsed"];
@@ -13346,9 +13061,6 @@ RowDefinition.prototype.setContent = function(userInput, extractedOptions) {
13346
13061
  this._isChain = asChain != null ? asChain : null; // this could be null or undefined
13347
13062
  this._chainRic = chainRic || "";
13348
13063
  }
13349
- // A symbol can be either RIC or permId
13350
- // JET/RTK will generate data id to be rowId (given from this rowDef) + ric
13351
- this._dataId = this._rowId + this.getSymbol();
13352
13064
 
13353
13065
  if(dv) {
13354
13066
  let segmentId = dv.getSegmentParentRowId(this._rowId);
@@ -13367,27 +13079,18 @@ RowDefinition.prototype.setContent = function(userInput, extractedOptions) {
13367
13079
  dv.setSegmentSeparator(this._rowId, true);
13368
13080
  }
13369
13081
 
13370
- if(collapsed !== this.isChainCollapsed()) {
13082
+ if(collapsed !== this.isChainCollapsed()) { // WARNING: This is not optimizsed
13371
13083
  dv.collapseSegment(this._rowId, collapsed);
13372
13084
  }
13373
13085
  this._collapsed = null;
13374
13086
 
13375
13087
  _stallSorting(dv, false, stalledSorting);
13376
13088
  if(segmentId) { // If data id is changed and the row is a child of a segment, then segment child data id must be updated
13377
- dv.addSegmentChild(segmentId, this._rowId, this._dataId);
13089
+ dv.addSegmentChild(segmentId, this._rowId);
13378
13090
  }
13379
13091
  }
13380
13092
 
13381
- if(!this.subscribeForUpdates()) {
13382
- if(this._dc) {
13383
- // This will work for runtime ric modification, but not for first initilization.
13384
- // Avoid losing the ROW_DEF pointer.
13385
- let rowData = {};
13386
- rowData[ROW_DEF] = this; // Enable tracking back and updating data
13387
- rowData["X_RIC_NAME"] = this.getDisplayText();
13388
- this.setRowData(rowData);
13389
- }
13390
- }
13093
+ this.subscribeForUpdates();
13391
13094
  return true;
13392
13095
  };
13393
13096
  /** @public
@@ -13499,12 +13202,12 @@ RowDefinition.prototype.getConfigObject = function(rowOptions) {
13499
13202
 
13500
13203
  return obj;
13501
13204
  };
13502
- /** Since an index chain (e.g. .FTSE) can automatically produce rows for its constituent, we need to separate rowId and dataId, so that the constituents still use the same data Id as that of its parent.
13205
+ /** Data id is deprecated
13503
13206
  * @public
13504
- * @return {string} Data Id will never be empty string unless the row has been removed
13207
+ * @return {string} Always return empty string
13505
13208
  */
13506
13209
  RowDefinition.prototype.getDataId = function() {
13507
- return this._dataId;
13210
+ return "";
13508
13211
  };
13509
13212
  /** @public
13510
13213
  * @return {string}
@@ -13540,26 +13243,19 @@ RowDefinition.prototype.getType = function() {
13540
13243
  /** This method should always be called right after the initialization
13541
13244
  * @public
13542
13245
  * @param {DataCache} dataSource
13246
+ * @param {Object=} subs Quotes2 subscription object
13543
13247
  */
13544
- RowDefinition.prototype.setDataSource = function(dataSource) {
13248
+ RowDefinition.prototype.setDataSource = function(dataSource, subs) {
13545
13249
  this._dc = dataSource || null;
13546
- if(!this._dc) {
13547
- return;
13548
- }
13549
-
13550
- let rowData = this.getRowData();
13551
- if(!rowData) {
13552
- rowData = {};
13553
- rowData[ROW_DEF] = this; // Enable tracking back and updating data
13554
- rowData["X_RIC_NAME"] = this.getDisplayText();
13555
- this.setRowData(rowData); // TODO: This will dispatch dataChanged event and caused update to be added, which should not happen
13556
- }
13557
13250
 
13558
- // Add static value to the new source
13559
- if(this._staticValues) {
13560
- this.setRowData(this._staticValues);
13251
+ if(this._dc) {
13252
+ this.setRowData({}); // Trigger data change
13253
+ if(this._staticValues) {
13254
+ this.setRowData(this._staticValues); // Trigger dataComposed and add updates
13255
+ }
13561
13256
  }
13562
13257
 
13258
+ this._subs = subs || null;
13563
13259
  // This will work for runtime row insertion, but not for first initilization.
13564
13260
  this.subscribeForUpdates();
13565
13261
  };
@@ -13574,14 +13270,14 @@ RowDefinition.prototype.getDataSource = function() {
13574
13270
  * @return {Object} rowData
13575
13271
  */
13576
13272
  RowDefinition.prototype.getRowData = function() {
13577
- return this._dc ? this._dc.getRowData(this._dataId) : {};
13273
+ return this._dc ? this._dc.getRowData(this._rowId) : {};
13578
13274
  };
13579
13275
  /** @public
13580
13276
  * @param {string} field
13581
13277
  * @return {*} data
13582
13278
  */
13583
13279
  RowDefinition.prototype.getData = function(field) {
13584
- return this._dc ? this._dc.getData(this._dataId, field) : null;
13280
+ return this._dc ? this._dc.getData(this._rowId, field) : null;
13585
13281
  };
13586
13282
 
13587
13283
  /** This method replaces all existing static data by the given data -- all existing static data are removed.
@@ -13606,7 +13302,7 @@ RowDefinition.prototype.setStaticRowData = function(data, indexToFieldMap) {
13606
13302
  * @return {Object.<string, *>}
13607
13303
  */
13608
13304
  RowDefinition.prototype._cloneStaticRowData = function() {
13609
- return this._staticValues ? cloneObject(this._staticValues) : null;
13305
+ return this._staticValues ? _cloneObject(this._staticValues) : null;
13610
13306
  };
13611
13307
  /** @public
13612
13308
  * @param {string} field
@@ -13676,7 +13372,20 @@ RowDefinition.prototype.cloneRowData = function(obj, exceptionObj) {
13676
13372
  */
13677
13373
  RowDefinition.prototype.setRowData = function(data) {
13678
13374
  if(this._dc) {
13679
- this._dc.setRowData(this._dataId, data);
13375
+ this._dc.setRowData(this._rowId, data);
13376
+ }
13377
+ };
13378
+ /** @public
13379
+ */
13380
+ RowDefinition.prototype.resetRowData = function() {
13381
+ let dc = this._dc;
13382
+ if(dc) {
13383
+ let rowId = this._rowId;
13384
+ dc.setRowData(rowId, null);
13385
+ dc.setRowData(rowId, {}); // Row data is guaranteed to be existed
13386
+ if(this._staticValues) {
13387
+ dc.setRowData(rowId, this._staticValues); // Trigger dataComposed and add updates
13388
+ }
13680
13389
  }
13681
13390
  };
13682
13391
  /** @public
@@ -13685,18 +13394,20 @@ RowDefinition.prototype.setRowData = function(data) {
13685
13394
  */
13686
13395
  RowDefinition.prototype.setData = function(field, value) {
13687
13396
  if(this._dc) {
13688
- this._dc.setData(this._dataId, field, value);
13397
+ this._dc.setData(this._rowId, field, value);
13689
13398
  }
13690
13399
  };
13691
13400
  /** @private
13692
13401
  */
13693
13402
  RowDefinition.prototype._clearStaticData = function() {
13694
- if(this._staticValues) {
13695
- for(let key in this._staticValues) {
13696
- this._staticValues[key] = null;
13697
- }
13403
+ let staticValues = this._staticValues;
13404
+ if(staticValues) {
13698
13405
  if(this._dc) {
13699
- this._dc.setRowData(this._dataId, this._staticValues);
13406
+ let obj = {};
13407
+ for(let key in staticValues) {
13408
+ obj[key] = null;
13409
+ }
13410
+ this._dc.setRowData(this._rowId, obj);
13700
13411
  }
13701
13412
  this._staticValues = null;
13702
13413
  }
@@ -13734,7 +13445,7 @@ RowDefinition.prototype.getDisplayText = function() {
13734
13445
  return this._label;
13735
13446
  }
13736
13447
 
13737
- if(this._ric) {
13448
+ if(this._ric) { // Use chainRic instead if this is a chain
13738
13449
  return this._ric;
13739
13450
  }
13740
13451
 
@@ -13764,6 +13475,12 @@ RowDefinition.prototype.isChain = function() {
13764
13475
  return this._isChain;
13765
13476
  };
13766
13477
  /** @public
13478
+ * @return {boolean}
13479
+ */
13480
+ RowDefinition.prototype.isConstituent = function() {
13481
+ return (this._autoGenerated && this._subId && this._rowId !== this._subId) ? true : false;
13482
+ };
13483
+ /** @public
13767
13484
  * @function
13768
13485
  * @param {RowDefinition} rowDef
13769
13486
  * @return {boolean}
@@ -13822,19 +13539,23 @@ RowDefinition.prototype.isRealTimeRow = function() {
13822
13539
  };
13823
13540
 
13824
13541
  /** @public
13542
+ * @param {Object=} subs
13825
13543
  * @return {boolean} If a subscription is made, return true.
13826
13544
  */
13827
- RowDefinition.prototype.subscribeForUpdates = function() {
13828
- if(!this.isRealTimeRow() && !this.getPermId()) {
13829
- return false;
13545
+ RowDefinition.prototype.subscribeForUpdates = function(subs) {
13546
+ if(subs) {
13547
+ this._subs = subs;
13548
+ } else {
13549
+ subs = this._subs;
13830
13550
  }
13831
-
13832
- let subs = this._dc ? this._dc.getSubscriptions() : null;
13833
13551
  if(!subs) {
13834
13552
  return false;
13835
13553
  }
13554
+ if(!this.isRealTimeRow() && !this.getPermId()) {
13555
+ return false;
13556
+ }
13836
13557
  // TODO: Check if the same subscription is being made.
13837
- let prevRowData = this.unsubscribeForUpdates();
13558
+ this.unsubscribeForUpdates();
13838
13559
 
13839
13560
  if(this.isChain()) {
13840
13561
  let symbol = this._chainRic;
@@ -13852,57 +13573,51 @@ RowDefinition.prototype.subscribeForUpdates = function() {
13852
13573
  this._subId = subs["addRic"](this._ric, this._rowId);
13853
13574
  }
13854
13575
 
13855
- if(prevRowData) {
13856
- this._dc.setRowData(this._dataId, prevRowData); // TODO: We may need to create a new object instead of prevRowData for data correctness
13857
- } else {
13858
- this._dc.setRowData(this._dataId, {"X_RIC_NAME": this.getDisplayText(), "ROW_DEF": this}); // Trigger data update immediately
13859
- }
13576
+ let xRicName = this.getDisplayText(); // WARNING: This does not cover real-time X_RIC_NAME updates
13577
+ this.setRowData({"X_RIC_NAME": xRicName}); // Trigger data update immediately
13578
+
13860
13579
  return true;
13861
13580
  };
13862
- /** @public
13863
- * @returns {*}
13581
+ /** Unsubscribe existing real-time data service. Static data is maintained
13582
+ * @public
13583
+ * @returns {null} Always return null
13864
13584
  */
13865
13585
  RowDefinition.prototype.unsubscribeForUpdates = function() {
13866
- if(!this._subId) {
13867
- return;
13586
+ if(this.isSubscribing()) { // Only normal real-time rows and chains have both subId and subscription object
13587
+ this._subs["removeSubscription"](this._subId);
13588
+ this._subId = "";
13589
+ this.resetUpdates();
13590
+ this.resetRowData(); // Real-time data is removed while static data is maintained
13868
13591
  }
13869
-
13870
- let subs = this._dc.getSubscriptions();
13871
- let prevRowData = this.getRowData();
13872
-
13873
- subs["removeSubscription"](this._subId);
13874
- this._subId = "";
13875
- this.resetUpdates();
13876
- // TODO: Reset only if this is the last ric
13877
- this._dc.setRowData(this._dataId, null); // Trigger data update immediately
13878
- this._clearStaticData();
13879
- // eslint-disable-next-line consistent-return
13880
- return prevRowData;
13592
+ return null;
13881
13593
  };
13882
13594
  /** @public
13883
13595
  * @return {boolean}
13884
13596
  */
13885
13597
  RowDefinition.prototype.isSubscribing = function() {
13886
- return this._subId ? true : false;
13598
+ return (this._subId && this._subs) ? true : false;
13599
+ };
13600
+ /** @public
13601
+ * @return {string}
13602
+ */
13603
+ RowDefinition.prototype.getSubId = function() {
13604
+ return this._subId;
13887
13605
  };
13888
13606
 
13889
13607
  /** Take event argument from streaming update with "changes" array property
13890
13608
  * @public
13891
- * @param {Object} e Object with changes property
13609
+ * @param {Object} changes
13892
13610
  * @return {boolean} Returns true if there is any change
13893
13611
  */
13894
- RowDefinition.prototype.addUpdate = function(e) {
13895
- if(e) {
13896
- let changes = e["changes"];
13897
- if(changes) {
13898
- let dirty = 0;
13899
- for(let field in changes) {
13900
- this._changes[field] = dirty = 1;
13901
- }
13902
- if(dirty) {
13903
- ++this._updateCount;
13904
- return true;
13905
- }
13612
+ RowDefinition.prototype.addUpdate = function(changes) {
13613
+ if(changes) {
13614
+ let dirty = 0;
13615
+ for(let field in changes) {
13616
+ this._changes[field] = dirty = 1;
13617
+ }
13618
+ if(dirty) {
13619
+ ++this._updateCount;
13620
+ return true;
13906
13621
  }
13907
13622
  }
13908
13623
  return false;
@@ -13925,27 +13640,27 @@ RowDefinition.prototype.resetUpdates = function() {
13925
13640
 
13926
13641
  /** @public
13927
13642
  * @param {DataView} view
13928
- * @param {string=} destRowId Destination position where the row will be placed BEFORE the specified position.
13643
+ * @param {string=} destRowId Destination position where the row will be placed BEFORE the specified position
13644
+ * @returns {boolean} Returns true for successful registration
13929
13645
  */
13930
13646
  RowDefinition.prototype.registerToView = function(view, destRowId) {
13931
13647
  if(!view || this._view === view) {
13932
- return; // Already in the view
13648
+ return false; // Already in the view
13933
13649
  }
13934
- this._view = view;
13935
13650
 
13936
- let rowId = this.getRowId();
13937
- if(view.getRowData(rowId)) {
13938
- console.warn("Duplicated rows' id.");
13939
- return;
13651
+ this._view = view;
13652
+ let rowId = this._rowId;
13653
+ let rowData = view.getRowData(rowId);
13654
+ if(rowData && rowData[ROW_DEF]) {
13655
+ console.warn("Duplicate row id detected");
13656
+ return false;
13940
13657
  }
13941
13658
 
13942
- let rowData = null;
13943
13659
  if(this._subSegment) {
13944
- rowData = this._view.getRowData(this.getRowId());
13945
- if(rowData) {
13946
- rowData[ROW_DEF] = this; // no event trigger
13660
+ if(rowData) { // Row data for sub segment has been created by data view
13661
+ rowData[ROW_DEF] = this; // It only needs to register row def to the row data
13947
13662
  }
13948
- return;
13663
+ return true;
13949
13664
  }
13950
13665
 
13951
13666
  rowData = {};
@@ -13958,7 +13673,13 @@ RowDefinition.prototype.registerToView = function(view, destRowId) {
13958
13673
  if(parentRowId) {
13959
13674
  if(isSegment) { // A chain or a segment cannot be put inside another segment
13960
13675
  destRowId = _getEndOfSegmentRowId(view, destRowId);
13961
- } // else { // Normal row is inserted into a segment
13676
+ } else if(!this.isConstituent()) { // Normal row cannot be put inside another chain
13677
+ let parentRowDef = view.getData(parentRowId, ROW_DEF);
13678
+ if(parentRowDef.isChain()) {
13679
+ parentRowId = null;
13680
+ destRowId = _getEndOfSegmentRowId(view, destRowId);
13681
+ } // else { // Normal row is inserted into a segment
13682
+ } // Constituent can be inserted inside a chain
13962
13683
  }
13963
13684
  }
13964
13685
 
@@ -13973,8 +13694,10 @@ RowDefinition.prototype.registerToView = function(view, destRowId) {
13973
13694
  this._collapsed = null;
13974
13695
  }
13975
13696
  } else if(!this._parent && parentRowId) { // Constituent cannot be added to another segment
13976
- view.addSegmentChild(parentRowId, rowId, this._dataId);
13697
+ view.addSegmentChild(parentRowId, rowId);
13977
13698
  }
13699
+
13700
+ return true;
13978
13701
  };
13979
13702
  /** @private
13980
13703
  * @param {Array.<string>=} rowIds
@@ -13991,7 +13714,9 @@ RowDefinition.prototype._deregisterFromView = function(rowIds) {
13991
13714
  }
13992
13715
  return "";
13993
13716
  };
13994
- /** @public
13717
+ /** Deprecated.
13718
+ * @public
13719
+ * @ignore
13995
13720
  * @function
13996
13721
  * @param {Array.<string>} rowIds
13997
13722
  * @param {RowDefinition} rowDef
@@ -14008,77 +13733,74 @@ RowDefinition.deregisterFromView = function(rowIds, rowDef) {
14008
13733
  * @return {Object}
14009
13734
  */
14010
13735
  RowDefinition.prototype._getChildStaticRowData = function(ric) {
14011
- if(!this._staticValues) {
14012
- return null;
13736
+ if(this._staticValues) {
13737
+ let childValues = this._staticValues[RowDefinition._childDataField];
13738
+ if(childValues) {
13739
+ return childValues[ric] || null;
13740
+ }
14013
13741
  }
13742
+ return null;
13743
+ };
14014
13744
 
14015
- let childValues = this._staticValues[RowDefinition._childDataField];
14016
- if(!childValues) {
14017
- return null;
13745
+ /** @public
13746
+ * @ignore
13747
+ * @param {string} ric
13748
+ * @return {RowDefinition}
13749
+ */
13750
+ RowDefinition.prototype.getConstituent = function(ric) {
13751
+ if(this._children && ric) {
13752
+ for(let i = this._children.length; --i >= 0;) {
13753
+ if(this._children[i]._ric === ric) {
13754
+ return this._children[i];
13755
+ }
13756
+ }
14018
13757
  }
13758
+ return null;
13759
+ };
14019
13760
 
14020
- return childValues[ric] || null;
13761
+ /** Check whether the given ric can be a constituent of this row definition. WARNING: permId is not handled by this method
13762
+ * @public
13763
+ * @ignore
13764
+ * @param {string} ric
13765
+ * @return {boolean} Returns true if the given ric can be its constituent
13766
+ */
13767
+ RowDefinition.prototype.verifyConstituent = function(ric) {
13768
+ if(this._isChain && ric) { // A constituent must have a valid ric
13769
+ if(this._ric !== ric) { // A constituent cannot have the same ric as its parent
13770
+ if(this._ric !== ("0#" + ric)) { // Real-time service may return ric without 0#
13771
+ return this._ric !== ("/" + ric); // Real-time service may return ric with slash (delayed ric)
13772
+ }
13773
+ }
13774
+ }
13775
+ return false;
14021
13776
  };
14022
- /** @public
13777
+ /** verifyConstituent should be called before calling this method
13778
+ * @public
14023
13779
  * @ignore
14024
13780
  * @param {string} ric
14025
13781
  * @return {RowDefinition} Return newly created child definition, if success
14026
13782
  */
14027
13783
  RowDefinition.prototype.addConstituent = function(ric) {
14028
- if(!ric || this._ric === ric) { // Parent cannot have a child with no name or the same name as itself
14029
- return null;
14030
- }
14031
13784
  if(!(this._rowId && this._subId && this._isChain)) { // Chain must be alive (has not been disposed). Chain must be subscribed as chain
14032
13785
  return null;
14033
13786
  }
14034
13787
 
14035
- let childDef = null;
14036
- if(this._children) {
14037
- for(let i = this._children.length; --i >= 0;) {
14038
- if(this._children[i]._ric === ric) {
14039
- childDef = this._children[i]; // Constituent has already been added
14040
- break;
14041
- }
14042
- }
14043
- } else {
13788
+ if(!this._children) {
14044
13789
  this._children = [];
14045
13790
  }
14046
13791
 
14047
- let newChild = !childDef;
14048
- if(newChild) {
14049
- let rowOptions = {
14050
- "asConstituent": true,
14051
- "dataId": this._subId + ric,
14052
- "ric": ric,
14053
- "parent": this
14054
- };
14055
-
14056
- let staticData = this._getChildStaticRowData(ric);
14057
- if(staticData) {
14058
- rowOptions["values"] = staticData;
14059
- }
14060
-
14061
- childDef = new RowDefinition(rowOptions);
14062
- }
13792
+ let rowOptions = {
13793
+ "asConstituent": true,
13794
+ "ric": ric,
13795
+ "parent": this
13796
+ };
14063
13797
 
14064
- if(this._view) {
14065
- let rowId = this.getRowId();
14066
- // WARNING: insert position, we prioritize using CHILD_ORDER (From server) in dc first. If it does not exist, the last row of the segment will be pushed
14067
- let childOrder = childDef.getData("CHILD_ORDER");
14068
- let dt = this._view.getDataSource();
14069
-
14070
- let parentIndex = dt.getRowIndex(rowId);
14071
- let position = parentIndex + this.getChildCount(); // push the last position
14072
- if(childOrder != null) {
14073
- // Warning: We need to carry a value of 1 because the CHILD_ORDER starts with 0, and it will be added to the parentIndex. In case the parent rowIndex is not included.
14074
- position = parentIndex + childOrder + 1; // insert between segment
14075
- } // else {} it will be push in the last row of segment
14076
- childDef.registerToView(this._view, dt.getRowId(position));
14077
- // TODO: Handle nested children
14078
- this._view.addSegmentChild(rowId, childDef.getRowId(), childDef.getDataId());
13798
+ let staticData = this._getChildStaticRowData(ric); // TODO: Remove the child's static data from parent
13799
+ if(staticData) {
13800
+ rowOptions["values"] = staticData;
14079
13801
  }
14080
13802
 
14081
- return newChild ? childDef : null;
13803
+ return new RowDefinition(rowOptions); // childDef is added to this._children in the constructor
14082
13804
  };
14083
13805
 
14084
13806
  /** Used to convert autogenerated row to regular real-time row
@@ -14086,25 +13808,18 @@ RowDefinition.prototype.addConstituent = function(ric) {
14086
13808
  * @ignore
14087
13809
  */
14088
13810
  RowDefinition.prototype.toRealTimeRow = function() {
14089
- if(!this._ric) { // Empty row
14090
- return;
14091
- }
14092
- if(this.isRowHeader() || !this._parent) {
14093
- return; // If the row is already a normal row or row header, it cannot be converted
13811
+ if(!this.isConstituent()) {
13812
+ return; // Only a constituent can be converted to a real-time row
14094
13813
  }
14095
13814
 
13815
+ let subs = this._parent._subs;
14096
13816
  this._realTime = true;
14097
- this._dc.setRowData(this._dataId, null); // Remove existing data. WARNING: Trigger data update immediately
14098
- this._dataId = this._rowId + this._ric; // JET/RTK will generate data id to be rowId (given from this rowDef) + ric;
14099
-
14100
13817
  this._autoGenerated = false;
14101
13818
  this._parent = null;
14102
13819
  this._depthLevel = 0;
14103
13820
 
14104
- this.subscribeForUpdates();
14105
- if(this._staticValues) { // Add static value to the new allocated row
14106
- this.setRowData(this._staticValues);
14107
- }
13821
+ this.resetRowData(); // WARNING: existing real-time data is lost after this line
13822
+ this.subscribeForUpdates(subs); // Static data remains intact
14108
13823
  };
14109
13824
 
14110
13825
  /** @public
@@ -14114,11 +13829,7 @@ RowDefinition.prototype.unlinkChain = function() {
14114
13829
  return;
14115
13830
  }
14116
13831
 
14117
- let staticData = this._cloneStaticRowData();
14118
- this.unsubscribeForUpdates();
14119
-
14120
- // Restore static data
14121
- this.setStaticRowData(staticData);
13832
+ this.unsubscribeForUpdates(); // Static data remains intact
14122
13833
 
14123
13834
  let view = this._view;
14124
13835
  if(view) {
@@ -14233,6 +13944,22 @@ RowDefinition.prototype.getChildCount = function() {
14233
13944
  return (this._children) ? this._children.length : 0;
14234
13945
  };
14235
13946
  /** @public
13947
+ * @return {number}
13948
+ */
13949
+ RowDefinition.prototype.countChildInView = function() {
13950
+ if(this._children) {
13951
+ let viewCount = 0;
13952
+ let childCount = this._children.length;
13953
+ for(let i = 0; i < childCount; ++i) {
13954
+ if(this._children[i]._view) {
13955
+ ++viewCount;
13956
+ }
13957
+ }
13958
+ return viewCount;
13959
+ }
13960
+ return 0;
13961
+ };
13962
+ /** @public
14236
13963
  * @return {RowDefinition}
14237
13964
  */
14238
13965
  RowDefinition.prototype.getParent = function() {
@@ -24196,7 +23923,8 @@ HScrollbar.prototype.setScrollContent = function (grid, sections, startColIndex,
24196
23923
  column = /** @type{Column} */(section.getColumn(c));
24197
23924
  column.setScrollState(paneElem, null, false);
24198
23925
  }
24199
- pane.setParent(section.getColumnHost());
23926
+ let scrollHost = section.getColumnHost();
23927
+ pane.setParent(scrollHost);
24200
23928
  let columns = [];
24201
23929
  let content = [];
24202
23930
  for (c = startColIndex; c < endColIndex; ++c) {
@@ -24213,9 +23941,11 @@ HScrollbar.prototype.setScrollContent = function (grid, sections, startColIndex,
24213
23941
 
24214
23942
  let rs = section.getReservedSpace();
24215
23943
  if(rs) {
24216
- if(!this._pinnedRightColumnCount) {
23944
+ if(this.isActive() && !this._pinnedRightColumnCount) {
24217
23945
  paneSlider.addContent(rs);
24218
23946
  content.push(rs);
23947
+ } else {
23948
+ scrollHost.appendChild(rs);
24219
23949
  }
24220
23950
  section._updateRightSpaceStyle();
24221
23951
  }
@@ -36572,7 +36302,7 @@ Core.prototype._hasPendingRowChange = false;
36572
36302
  * @return {string}
36573
36303
  */
36574
36304
  Core.getVersion = function () {
36575
- return "5.1.121";
36305
+ return "5.1.125";
36576
36306
  };
36577
36307
  /** {@link ElementWrapper#dispose}
36578
36308
  * @override
@@ -39638,37 +39368,37 @@ Core.prototype.getYScrollVal = function (sectionRef, rowIndex, topOfView) {
39638
39368
  section = this.getSection(sectionRef);
39639
39369
  }
39640
39370
 
39371
+ let rowIndexOffset = (section) ? section.getRowOffset() : this._sectionStarts[this._startVScrollbarIndex];
39372
+ let heightOffset = this._layoutY.getLaneStart(this._startVScrollbarIndex);
39373
+
39641
39374
  let rowCount = this._layoutY.getLaneCount();
39642
39375
  if (rowIndex <= 0) { rowIndex = 0; }
39643
39376
  else if (rowIndex >= rowCount) { rowIndex = rowCount - 1; }
39644
39377
 
39378
+ if (topOfView) {
39379
+ return this._layoutY.getLaneStart(rowIndex + rowIndexOffset) - heightOffset;
39380
+ }
39381
+
39382
+ let bufferSize = 2; // for more appealing space
39645
39383
  let viewInfo = this.getVerticalViewInfo();
39646
39384
  let firstFullRow = viewInfo.firstFullRow; // TODO: Make it work in zooming mode
39647
-
39648
- let scrollIndex = -1;
39649
- if (topOfView) {
39650
- scrollIndex = rowIndex;
39651
- } else {
39652
- if(rowIndex < firstFullRow) { // Scroll up
39653
- scrollIndex = rowIndex - 3; // Have some spaces at the top for more appealing visual
39654
- if(scrollIndex < 0) {
39655
- scrollIndex = 0;
39656
- }
39657
- } else { // Scroll down
39658
- let lastFullRow = viewInfo.lastFullRow;
39659
- if (rowIndex > lastFullRow) {
39660
- let viewIndexSize = lastFullRow - firstFullRow;
39661
- scrollIndex = rowIndex - viewIndexSize + 3;
39662
- if(scrollIndex < 0) {
39663
- scrollIndex = 0;
39664
- }
39665
- }
39385
+ if(rowIndex < firstFullRow) { // Scroll up, as the target row is outside of view
39386
+ let targetIndex = rowIndex - bufferSize; // Have some spaces at the top for more appealing visual
39387
+ if(targetIndex < 0) {
39388
+ targetIndex = 0;
39666
39389
  }
39390
+
39391
+ return this._layoutY.getLaneStart(targetIndex + rowIndexOffset) - heightOffset;
39667
39392
  }
39668
39393
 
39669
- let rowIndexOffset = (section) ? section.getRowOffset() : this._sectionStarts[this._startVScrollbarIndex];
39670
- let heightOffset = this._layoutY.getLaneStart(this._startVScrollbarIndex);
39671
- return (scrollIndex >= 0) ? (this._layoutY.getLaneStart(scrollIndex + rowIndexOffset) - heightOffset) : null;
39394
+ let lastFullRow = viewInfo.lastFullRow;
39395
+ if (rowIndex > lastFullRow) { // Scroll down, as the target row is outside of view
39396
+ let targetScroll = this._layoutY.getLaneStart(rowIndex + rowIndexOffset + bufferSize + 1);
39397
+
39398
+ return targetScroll - viewInfo.viewHeight - heightOffset;
39399
+ }
39400
+
39401
+ return null;
39672
39402
  };
39673
39403
  /** Scroll up or down to make specified row visible in the view
39674
39404
  * @public
@@ -39693,7 +39423,12 @@ Core.prototype.getVerticalViewInfo = function() {
39693
39423
  let viewBottom = viewTop + viewHeight;
39694
39424
 
39695
39425
  let topRowIndex = this._layoutY.hitTest(viewTop) - rowIndexOffset;
39696
- let bottomRowIndex = this._layoutY.hitTest(viewBottom - 0.1) - rowIndexOffset;
39426
+ let bottomRowIndex = this._layoutY.hitTest(viewBottom - 0.1);
39427
+ if(bottomRowIndex < 0) { // view is larger than existing row count
39428
+ bottomRowIndex = this._layoutY.getLaneCount() - 1;
39429
+ }
39430
+ bottomRowIndex -= rowIndexOffset;
39431
+
39697
39432
  let laneTop = this._layoutY.getLaneStart(topRowIndex + rowIndexOffset);
39698
39433
  let laneBottom = this._layoutY.getLaneEnd(bottomRowIndex + rowIndexOffset);
39699
39434
 
@@ -39701,7 +39436,10 @@ Core.prototype.getVerticalViewInfo = function() {
39701
39436
  topRowIndex: topRowIndex,
39702
39437
  firstFullRow: (laneTop < viewTop) ? topRowIndex + 1 : topRowIndex,
39703
39438
  lastFullRow: (laneBottom > viewBottom) ? bottomRowIndex - 1 : bottomRowIndex,
39704
- bottomRowIndex: bottomRowIndex
39439
+ bottomRowIndex: bottomRowIndex,
39440
+ viewHeight: viewHeight,
39441
+ viewTop: viewTop,
39442
+ viewBottom: viewBottom
39705
39443
  };
39706
39444
  };
39707
39445
  /** @public
@@ -45049,12 +44787,6 @@ SortableTitlePlugin._proto = SortableTitlePlugin.prototype;
45049
44787
  * @description Fired only when a row will be removed through Grid's API and before occurring of the actual removal
45050
44788
  */
45051
44789
 
45052
- /** @type {string}
45053
- * @private
45054
- * @const
45055
- */
45056
- const SUB_ID = "SUB_ID";
45057
-
45058
44790
  /** @private
45059
44791
  * @param {RowDefinition} rowDef
45060
44792
  * @return {Object}
@@ -45189,10 +44921,10 @@ let Grid = function(placeholder, config) {
45189
44921
 
45190
44922
  t._onDataChanged = t._onDataChanged.bind(t);
45191
44923
  t._onQuote2PostUpdate = t._onQuote2PostUpdate.bind(t);
44924
+ t._onQ2DataChanged = t._onQ2DataChanged.bind(t);
45192
44925
  t._onDataComposed = t._onDataComposed.bind(t);
45193
44926
  t._onSubSegmentChanged = t._onSubSegmentChanged.bind(t);
45194
44927
  t._recalculateFormulas = t._recalculateFormulas.bind(t);
45195
- t._updateStreamingData = t._updateStreamingData.bind(t);
45196
44928
  t.updateColumnTitle = t.updateColumnTitle.bind(t);
45197
44929
  t._populateTimeSeriesChildren = t._populateTimeSeriesChildren.bind(t);
45198
44930
 
@@ -45204,7 +44936,7 @@ let Grid = function(placeholder, config) {
45204
44936
  t._updateRowData = t._updateRowData.bind(t);
45205
44937
  t._onFormulaDataChanged = t._onFormulaDataChanged.bind(t);
45206
44938
  t._onFormulaDataRequired = t._onFormulaDataRequired.bind(t);
45207
- t._addMemberOfChain = t._addMemberOfChain.bind(t);
44939
+ t._registerConstituents = t._registerConstituents.bind(t);
45208
44940
  t._onColumnAdded = t._onColumnAdded.bind(t);
45209
44941
  t._onRowExpansionBinding = t._onRowExpansionBinding.bind(t);
45210
44942
  t._onColumnHeaderBinding = t._onColumnHeaderBinding.bind(t);
@@ -45219,9 +44951,9 @@ let Grid = function(placeholder, config) {
45219
44951
  t._onVScroll = t._onVScroll.bind(t);
45220
44952
  t._selfScrollToRow = t._selfScrollToRow.bind(t);
45221
44953
 
45222
- t._streamingConflator = new Conflator(50, t._updateStreamingData);
44954
+ t._dcConflator = new Conflator(50, t._onDataChanged);
45223
44955
  t._formulaConflator = new Conflator(300, t._onFormulaDataChanged);
45224
- t._chainConflator = new Conflator(100, t._addMemberOfChain);
44956
+ t._chainConflator = new Conflator(100, t._registerConstituents);
45225
44957
  t._columnTitleConflator = new Conflator(0, t.updateColumnTitle);
45226
44958
  t._timeSeriesChildConflator = new Conflator(0, t._populateTimeSeriesChildren);
45227
44959
 
@@ -45358,7 +45090,7 @@ Grid.prototype._sharedDataSource = false;
45358
45090
  */
45359
45091
  Grid.prototype._sharedSorter = false;
45360
45092
 
45361
- /** JET.Quotes2 Subscription
45093
+ /** JET/RTK's Quotes2 subscription object
45362
45094
  * @type {Object}
45363
45095
  * @private
45364
45096
  */
@@ -45376,7 +45108,7 @@ Grid.prototype._columnSorter = null;
45376
45108
  /** @private
45377
45109
  * @type {Conflator}
45378
45110
  */
45379
- Grid.prototype._streamingConflator = null;
45111
+ Grid.prototype._dcConflator = null;
45380
45112
  /** @private
45381
45113
  * @type {SnapshotFiller}
45382
45114
  */
@@ -45399,10 +45131,6 @@ Grid.prototype._fnEngine = null;
45399
45131
  */
45400
45132
  Grid.prototype._formulaConflator = null;
45401
45133
 
45402
- /** @private
45403
- * @type {Object.<string, Object>}
45404
- */
45405
- Grid.prototype._chainMembers = null;
45406
45134
  /** @private
45407
45135
  * @type {Conflator}
45408
45136
  */
@@ -45511,7 +45239,15 @@ Grid.prototype.dispose = function() {
45511
45239
  this._grid.dispose();
45512
45240
  this._connector.reset();
45513
45241
 
45514
- if(!this._sharedDataSource) { // make sure that it is the final grid, and that it will be dispose data
45242
+ if(!this._sharedDataSource) { // Make sure that this is the final grid, and its data is disposed
45243
+ if(this._subs) {
45244
+ this._subs.removeEventListener("postUpdate", this._onQuote2PostUpdate);
45245
+ this._subs.removeEventListener("dataChanged", this._onQ2DataChanged);
45246
+ this._subs["dispose"]();
45247
+ }
45248
+ if(this._dc) {
45249
+ this._dc.dispose();
45250
+ }
45515
45251
  if(this._dt) {
45516
45252
  this._dt.dispose();
45517
45253
  }
@@ -45519,12 +45255,7 @@ Grid.prototype.dispose = function() {
45519
45255
  this._dv.dispose();
45520
45256
  }
45521
45257
  }
45522
- this._mainGrid = this._dt = this._dv = null;
45523
-
45524
- if(this._subs) {
45525
- this._subs["dispose"]();
45526
- this._subs = null;
45527
- }
45258
+ this._mainGrid = this._dc = this._dt = this._dv = this._subs = null;
45528
45259
 
45529
45260
  if(this._focusingArgs) {
45530
45261
  _clearTimeout(this._focusingArgs.id);
@@ -45553,7 +45284,11 @@ Grid.prototype.listen = Grid.prototype.addEventListener;
45553
45284
  /** @public
45554
45285
  */
45555
45286
  Grid.prototype.initSubscription = function() {
45556
- if(!this._dc || this._dc.getSubscriptions()) { // Subscription is already initialized
45287
+ if(this._subs) { // Subscription is already initialized
45288
+ return;
45289
+ }
45290
+ if(this._sharedDataSource) {
45291
+ this._subs = this._mainGrid._subs;
45557
45292
  return;
45558
45293
  }
45559
45294
 
@@ -45566,6 +45301,9 @@ Grid.prototype.initSubscription = function() {
45566
45301
  }
45567
45302
  if(q) {
45568
45303
  s = q["create"]();
45304
+ if(this._RTK && this._RTK.prefetchWorkaround) { // The workaround for RTK Quotes has a bug concerning the removal of the last row; it isn't removed.
45305
+ s.addRic("DUMMY.WORKAROUND", "DUMMY.WORKAROUND");
45306
+ }
45569
45307
  }
45570
45308
  if(!s) {
45571
45309
  return;
@@ -45576,8 +45314,8 @@ Grid.prototype.initSubscription = function() {
45576
45314
 
45577
45315
  this._subs = s;
45578
45316
  this._subs["start"]();
45579
- this._dc.setSubscriptions(s);
45580
45317
  this._subs.addEventListener("postUpdate", this._onQuote2PostUpdate);
45318
+ this._subs.addEventListener("dataChanged", this._onQ2DataChanged);
45581
45319
 
45582
45320
  // TODO: Subscriptions should be registered per row.
45583
45321
  // However, chain subscription cannot be integrated with DataConnector in this current implementation.
@@ -45586,7 +45324,7 @@ Grid.prototype.initSubscription = function() {
45586
45324
  for(let i = 0; i < len; ++i) {
45587
45325
  let rowDef = rowDefs[i];
45588
45326
  if(rowDef) {
45589
- rowDef.subscribeForUpdates();
45327
+ rowDef.subscribeForUpdates(s);
45590
45328
  }
45591
45329
  }
45592
45330
  };
@@ -47194,29 +46932,31 @@ Grid.prototype._initDuplicateRicData = function(rowDef) {
47194
46932
  };
47195
46933
 
47196
46934
  /** @private
47197
- * @param {Object} rowDef
47198
- * @param {Array<Object>} children
46935
+ * @param {Object} newRowDef
47199
46936
  */
47200
- Grid.prototype._cloneChain = function(rowDef) {
47201
- let rowDefs = this._connector.getRowDefByRic(rowDef.getSymbol());
46937
+ Grid.prototype._cloneChain = function(newRowDef) {
46938
+ let rowDefs = this._connector.getRowDefByRic(newRowDef.getSymbol());
47202
46939
  let firstRowDef = rowDefs ? rowDefs[0] : null;
47203
46940
  let constituents = firstRowDef ? firstRowDef.getChildren() : null;
47204
-
47205
- if(!constituents) {
47206
- return;
47207
- }
47208
- let count = constituents.length;
47209
- if(count < 0 ) {
46941
+ let count = constituents ? constituents.length : 0;
46942
+ if(count < 0) {
47210
46943
  return;
47211
46944
  }
47212
46945
 
47213
- let subId = rowDef.getData(SUB_ID);
46946
+ let subId = newRowDef.getSubId();
46947
+ if(!subId) {
46948
+ return; // A chain without subscription cannot have constituents
46949
+ }
46950
+ let evtArg = {
46951
+ "subId": subId
46952
+ };
47214
46953
  for (let i = 0; i < count; i++) {
47215
- let childRowDef = constituents[i];
47216
- let rowData = childRowDef.cloneRowData();
47217
- rowData["SUB_ID"] = subId;
47218
- let rid = subId + rowData["RIC"];
47219
- this._dc.setRowData(rid, rowData);
46954
+ let childRowDef = constituents[i]; // TODO: the constituents should be sorted by CHILD_ORDER first
46955
+ evtArg["ric"] = childRowDef.getRic();
46956
+ evtArg["values"] = childRowDef.cloneRowData();
46957
+ evtArg["values"]["SUB_ID"] = subId; // Imitate real-time service responses
46958
+
46959
+ this._onQ2DataChanged(evtArg); // WARNING: evtArg is shared across multiple calls
47220
46960
  }
47221
46961
  };
47222
46962
  /** @public
@@ -47242,10 +46982,10 @@ Grid.prototype.insertRow = function(rowOption, rowRef) {
47242
46982
  }
47243
46983
  }
47244
46984
  let rowDef = new RowDefinition(rowOption);
47245
- rowDef.setDataSource(this._dc); // This could also subscribe chain index/ric to JET/RTK
46985
+ rowDef.registerToView(this._dv, this._getRowId(rowRef));
46986
+ rowDef.setDataSource(this._dc, this._subs); // This could also subscribe chain index/ric to JET/RTK
47246
46987
  this._initDuplicateRicData(rowDef);
47247
46988
 
47248
- rowDef.registerToView(this._dv, this._getRowId(rowRef));
47249
46989
  if(rowOption && rowOption["hidden"]) {
47250
46990
  this._dv.hideRow(rowDef.getRowId()); // Try to obtain rowId in rowDef since rowId is not assigned when new rows are created.
47251
46991
  }
@@ -47554,17 +47294,16 @@ Grid.prototype.removeAllRows = function() {
47554
47294
  if(!this._dt.getRowCount()) {
47555
47295
  return;
47556
47296
  }
47297
+ // Data source is not shared at this point
47557
47298
  let rowDefs = this._getAllRowDefinitions();
47558
47299
 
47559
- if(!this._sharedDataSource) {
47560
- this._dc.clearAllData();
47561
- this._dt.clearAllData();
47562
- this._clearDataUpdates();
47563
- }
47300
+ this._dc.clearAllData();
47301
+ this._dt.clearAllData();
47302
+ this._clearDataUpdates();
47564
47303
 
47565
- rowDefs.forEach(RowDefinition.dispose);
47304
+ rowDefs.forEach(RowDefinition.dispose); // Each individual subscription is unsubscribed along with disposed rowDef
47566
47305
 
47567
- this._streamingConflator.reset();
47306
+ this._dcConflator.reset();
47568
47307
  this._formulaConflator.reset();
47569
47308
  this._chainConflator.reset();
47570
47309
  this._connector.removeAllRics();
@@ -48461,94 +48200,127 @@ Grid.prototype._onQuote2PostUpdate = function (e) {
48461
48200
  }
48462
48201
  };
48463
48202
 
48464
- /** @private
48465
- * @param {!Object} e
48466
- */
48467
- Grid.prototype._onDataChanged = function(e) {
48468
- let rowData = e["rowData"]; // Use rowData to retrieve corresponding subscription object
48469
- if (!rowData || this._unlinking) {
48470
- return; // This must be a global change
48203
+ /**
48204
+ * @private
48205
+ * @param {Object} e
48206
+ */
48207
+ Grid.prototype._onQ2DataChanged = function (e) {
48208
+ let subId = e["subId"];
48209
+ let rowDef = this._getRowDefinitionById(subId);
48210
+ if(!rowDef) {
48211
+ return; // WARNING: This should not be happened because row has been removed but the data is still received
48471
48212
  }
48472
- let rowDef = rowData[ROW_DEF];
48473
48213
 
48474
- if(rowDef) {
48475
- let rowId = rowDef.getRowId();
48476
- if(rowId) {
48477
- // e["rid"] could be from JET/RTK (rowId + ric) or static data update (rowId)
48478
- let curRowData = this._dc.getRowData(e["rid"]);
48479
- if (curRowData) {
48480
- if(rowDef.addUpdate(e)) { // This is the only place that update array can grow. It is used for blinking data.
48481
- this._dt._hasNewUpdates = true; // Mark data table for cleaning it up later
48214
+ let values = e["values"];
48215
+ if (values) {
48216
+ let ric = e["ric"];
48217
+ if(rowDef.verifyConstituent(ric)) {
48218
+ let parentDef = rowDef;
48219
+ let childDef = parentDef.getConstituent(ric);
48220
+ if(childDef) { // The constituent will share the same sub id as its parent
48221
+ rowDef = childDef;
48222
+ } else {
48223
+ rowDef = childDef = parentDef.addConstituent(ric);
48224
+ if(!childDef) {
48225
+ return; // Parent chain is not alive
48482
48226
  }
48483
- this._updateStreamingData();
48484
- } else if(rowDef.isAutoGenerated()) { // Subscription and its parent has been removed by Real-time provider
48485
- rowDef.setParent(null); // Manually remove child reference from its parent
48486
- this._removeRow(rowDef);
48227
+ this._connector.addRic(childDef); // TODO: JET/RTK should not re-subscribe this
48228
+ this._registerConstituents(childDef);
48487
48229
  }
48488
48230
  }
48489
- return;
48490
- }
48491
48231
 
48492
- // The new data update has no row definition, meaning that we have found a new constituent from a chain.
48493
- let subId = rowData[SUB_ID]; // The constituent will share the same sub id as its parent
48494
- if(subId) {
48495
- let parentDef = this._getRowDefinitionById(subId);
48496
- if(parentDef && parentDef.isChain() && parentDef.getRic() !== rowData["RIC"]) { // TODO: Check for delayed ric
48497
- if(!this._chainMembers) {
48498
- this._chainMembers = {};
48499
- }
48500
- if(!this._chainMembers[e["rid"]]) { // Prevent duplication
48501
- this._chainMembers[e["rid"]] = rowData;
48502
- this._addMemberOfChain(rowData);
48503
- }
48504
- }
48232
+ rowDef.setRowData(values); // Trigger data changes
48233
+ } else if(rowDef.isConstituent()) { // Subscription and its parent has been removed by Real-time provider
48234
+ rowDef.setParent(null); // Manually remove child reference from its parent
48235
+ this._removeRow(rowDef);
48505
48236
  }
48506
48237
  };
48238
+
48507
48239
  /** @private
48508
- * @param {!Object} rowData
48240
+ * @param {RowDefinition} rowDef
48509
48241
  */
48510
- Grid.prototype._addMemberOfChain = function(rowData) {
48511
- if(this._chainConflator.conflate(rowData)) {
48242
+ Grid.prototype._registerConstituents = function(rowDef) {
48243
+ if(this._chainConflator.conflate(rowDef)) {
48512
48244
  return;
48513
48245
  }
48246
+ let view = this._dv;
48247
+ let dt = view ? view.getDataSource() : null;
48248
+ if(!dt) {
48249
+ return;
48250
+ }
48251
+
48252
+ let childDefs = this._chainConflator.popAllData(); // This must have no duplication
48253
+ let childCount = childDefs ? childDefs.length : 0;
48514
48254
 
48515
- let rows = this._chainConflator.popAllData(); // This must have no duplication
48516
- let len = rows ? rows.length : 0;
48255
+ // Validate row definition and collect its info
48517
48256
  let i;
48257
+ let validDefs = [];
48258
+ let maxCountMap = {};
48259
+ for(i = 0; i < childCount; ++i) {
48260
+ let childDef = childDefs[i];
48261
+ let parentDef = childDef.getParent();
48262
+ if(!parentDef) {
48263
+ break; // A constituent without parent cannot be added to the view
48264
+ }
48265
+ let parentRowId = parentDef.getRowId();
48266
+ let maxCount = maxCountMap[parentRowId];
48267
+ if(maxCount == null) {
48268
+ maxCount = maxCountMap[parentRowId] = parentDef.countChildInView();
48269
+ }
48270
+ validDefs.push(childDef);
48271
+ }
48272
+
48273
+ childCount = validDefs.length;
48274
+ if(!childCount) {
48275
+ return;
48276
+ }
48518
48277
 
48519
48278
  let prevState = false;
48520
- if(len > 1) {
48279
+ if(childCount > 1) {
48521
48280
  prevState = this._dt.freeze(); // Avoid sorting for each insertion
48522
48281
  }
48523
- let childDefs = [];
48524
- for(i = 0; i < len; ++i) {
48525
- rowData = /** @type{!Object} */(rows[i]);
48526
- let subId = rowData[SUB_ID];
48527
- let parentDef = this._getRowDefinitionById(subId);
48528
- if(parentDef) {
48529
- let childDef = parentDef.addConstituent(/** @type{string} */(rowData["RIC"]), this._dt);
48530
- if(childDef) {
48531
- childDefs.push(childDef);
48532
- } // else { // childDef has already been added
48533
- }
48534
- }
48535
- this._chainMembers = null; // Clear all waiting chain members
48536
48282
 
48537
- let childCount = childDefs.length;
48538
- if(childCount) {
48539
- for(i = childCount; --i >= 0;) {
48540
- this._connector.addRic(childDefs[i]); // TODO: JET/RTK should not re-subscribe this
48283
+ for(i = 0; i < childCount; ++i) {
48284
+ let childDef = validDefs[i];
48285
+ let parentDef = childDef.getParent();
48286
+ let parentRowId = parentDef.getRowId();
48287
+ let maxCount = maxCountMap[parentRowId];
48288
+
48289
+ // TODO: Handle nested children
48290
+ view.addSegmentChild(parentRowId, childDef.getRowId());
48291
+
48292
+ // Added order and child order can be different
48293
+ // CHILD_ORDER value from real-time service indicates the order of constituents.
48294
+ let destIndex = dt.getRowIndex(parentRowId) + 1; // WARNING: Not checking for negative index
48295
+ let childOrder = childDef.getData("CHILD_ORDER"); // CHILD_ORDER starts from 0
48296
+ if(childOrder != null && childOrder < maxCount) {
48297
+ destIndex += childOrder;
48298
+ } else {
48299
+ destIndex += maxCount;
48541
48300
  }
48301
+ let destRowId = dt.getRowId(destIndex);
48302
+ childDef.registerToView(view, destRowId);
48303
+ maxCountMap[parentRowId] = maxCount + 1; // Since new child has been added to the view, maxCount has to be updated
48542
48304
  }
48543
- if(len > 1) {
48305
+ if(childCount > 1) {
48544
48306
  this._dt.freeze(prevState);
48545
48307
  }
48546
48308
  };
48547
48309
 
48548
48310
  /** @private
48311
+ * @param {Object} e
48549
48312
  */
48550
- Grid.prototype._updateStreamingData = function() {
48551
- if(this._streamingConflator.conflate()) {
48313
+ Grid.prototype._onDataChanged = function(e) {
48314
+ if(this._dt && e && e["rid"] && e["changes"]) {
48315
+ let rowDef = this._getRowDefinitionById(e["rid"]);
48316
+ if(rowDef) {
48317
+ if(rowDef.addUpdate(e["changes"])) { // This is the only place that update array can grow. It is used for blinking data.
48318
+ this._dt._hasNewUpdates = true; // Mark data table for cleaning it up later
48319
+ }
48320
+ }
48321
+ }
48322
+
48323
+ if(this._dcConflator.conflate()) {
48552
48324
  return;
48553
48325
  }
48554
48326
 
@@ -48785,12 +48557,9 @@ Grid.prototype._onDataComposed = function(e) {
48785
48557
  return; // Row could already be removed or global change event is sent
48786
48558
  }
48787
48559
 
48788
- let rowDef = rowData[ROW_DEF];
48560
+ let rowDef = this._getRowDefinitionById(e["rid"]);
48789
48561
  if(!rowDef) {
48790
- return;
48791
- }
48792
- if(!rowDef.getDataSource()) {
48793
- return; // Somehow, rowDef is invalid and doesn't have data source
48562
+ return; // Somehow the given row id is invalid
48794
48563
  }
48795
48564
 
48796
48565
  if(this._autoDateConversion) { // auto data conversion
@@ -48849,10 +48618,10 @@ Grid.prototype._onSubSegmentChanged = function(e) {
48849
48618
  // let parentId = segment.getParentId();
48850
48619
  let segmentId = segment.getId();
48851
48620
  rowDef = new RowDefinition({
48852
- "segmentId": segmentId
48621
+ "segmentId": segmentId // WARNING: This could cause row id duplication
48853
48622
  });
48854
- rowDef.setDataSource(this._dc);
48855
48623
  rowDef.registerToView(this._dv);
48624
+ rowDef.setDataSource(this._dc); // auto generated row does not require a subscription
48856
48625
  }
48857
48626
  };
48858
48627
 
@@ -52886,10 +52655,6 @@ CellPainter.prototype._scopes;
52886
52655
  * @private
52887
52656
  */
52888
52657
  CellPainter.prototype._columnStats = null;
52889
- /** @type {boolean}
52890
- * @private
52891
- */
52892
- CellPainter.prototype._levelColorDisabled = false;
52893
52658
  /** @type {number}
52894
52659
  * @private
52895
52660
  */
@@ -52945,6 +52710,10 @@ CellPainter.supportedStyles = CellPainter.bgStyles.concat(CellPainter.nonBgStyle
52945
52710
  * @public
52946
52711
  */
52947
52712
  CellPainter.themeReady = null;
52713
+ /** @type {Object}
52714
+ * @private
52715
+ */
52716
+ CellPainter._contrastColors = {};
52948
52717
 
52949
52718
  /** Deprecated in favor of ExpressionParser
52950
52719
  * @public
@@ -53538,7 +53307,7 @@ CellPainter.prototype._getStyles = function(rowData, min, max) {
53538
53307
  } else if(ret < 0) {
53539
53308
  curCond["cssClass"] = curCond["downClass"];
53540
53309
  } else {
53541
- curCond["cssClass"] = this._levelColorDisabled ? "" : curCond["levelClass"];
53310
+ curCond["cssClass"] = curCond["levelClass"];
53542
53311
  }
53543
53312
  curCond["cssClass"] = curCond["cssClass"] || "";
53544
53313
  return curCond;
@@ -53739,8 +53508,12 @@ CellPainter._clearBlinkTimer = function(scp, opt_restoreColor) {
53739
53508
  CellPainter.getOppositeColor = function (hexCode) {
53740
53509
  if(typeof hexCode === "string") {
53741
53510
  if(hexCode.charAt(0) === "#") {
53742
- let triplet = hex2Num(hexCode);
53743
- return getContrastColor(triplet);
53511
+ let contrastColor = CellPainter._contrastColors[hexCode];
53512
+ if (!contrastColor) {
53513
+ let triplet = hex2Num(hexCode);
53514
+ contrastColor = CellPainter._contrastColors[hexCode] = getContrastColor(triplet);
53515
+ }
53516
+ return contrastColor;
53744
53517
  }
53745
53518
  } else if(Array.isArray(hexCode)) {
53746
53519
  return getContrastColor(hexCode);
@@ -53834,67 +53607,48 @@ CellPainter.prototype._paintCell = function(cell, rowData, min, max) {
53834
53607
  };
53835
53608
 
53836
53609
  /**
53837
- * @public
53610
+ * @private
53838
53611
  * @param {tr.grid.Cell} cell
53839
- * @param {number} blinkSignal
53840
- * @param {Object} rowData to calculate original style e.g. { PCTCHNG: 0.53, CF_NETCHNG: 0.75 }
53612
+ * @return {Object}
53841
53613
  */
53842
- CellPainter.prototype.blink = function (cell, blinkSignal, rowData) {
53843
- this._blinkCell(cell, rowData, blinkSignal);
53844
- };
53614
+ CellPainter.prototype._prepareScope = function(cell) {
53615
+ let scope = cell["blinking"];
53616
+ if (!scope) {
53617
+ scope = {};
53618
+ scope["cell"] = cell;
53619
+ cell["blinking"] = scope;
53620
+
53621
+ this._scopes.push(scope);
53622
+ }
53845
53623
 
53846
- /**
53847
- * @public
53848
- * @param {tr.grid.Cell} cell
53849
- * @param {number} newValue
53850
- * @param {number} oldValue
53851
- * @param {Object} rowData e.g. { PCTCHNG: 0.53, CF_NETCHNG: 0.75 }
53852
- * @return {boolean}
53853
- */
53854
- CellPainter.prototype.blinkCell = function(cell, newValue, oldValue, rowData) {
53855
53624
  let bc = this._blinkCondition;
53856
- if (!bc) return false;
53625
+ if (scope["blinkId"] !== bc["blinkId"]) {
53626
+ scope["blinkId"] = bc["blinkId"];
53627
+ scope["field"] = bc["field"];
53628
+ let restorer = bc["border"] ? CellPainter._borderRestorer : CellPainter._cellRestorer;
53629
+ scope._restorer = restorer.bind(this, scope);
53630
+ }
53857
53631
 
53858
- let blinkSignal = this._blinkCondition._fn(newValue, oldValue);
53859
- return this._blinkCell(cell, rowData, blinkSignal);
53632
+ return scope;
53860
53633
  };
53861
53634
 
53862
- /** @private
53635
+ /**
53636
+ * @public
53863
53637
  * @param {tr.grid.Cell} cell
53864
- * @param {Object} rowData e.g. { PCTCHNG: 0.53, CF_NETCHNG: 0.75 }
53865
53638
  * @param {number} blinkSignal
53639
+ * @param {Object} rowData to calculate original style e.g. { PCTCHNG: 0.53, CF_NETCHNG: 0.75 }
53866
53640
  * @return {boolean}
53867
53641
  */
53868
- CellPainter.prototype._blinkCell = function(cell, rowData, blinkSignal) {
53642
+ CellPainter.prototype.blink = function (cell, blinkSignal, rowData) {
53869
53643
  if (!cell) return false;
53870
53644
 
53871
- if (this._levelColorDisabled) {
53872
- if(!blinkSignal) { // Disabled level color equivalent to no blinking for blink signal 0
53873
- return false;
53874
- }
53875
- }
53876
-
53877
53645
  let elem = cell.getElement();
53878
53646
  if (!elem) return false; // Cell has been disposed
53879
53647
 
53880
53648
  let bc = this._blinkCondition;
53881
53649
  if (!bc) return false;
53882
53650
 
53883
- let scope = cell["blinking"];
53884
- if (!scope) {
53885
- scope = {};
53886
- scope["cell"] = cell;
53887
- cell["blinking"] = scope;
53888
-
53889
- this._scopes.push(scope);
53890
- }
53891
-
53892
- if (scope["blinkId"] !== bc["blinkId"]) {
53893
- scope["blinkId"] = bc["blinkId"];
53894
- scope["field"] = bc["field"];
53895
- let restorer = bc["border"] ? CellPainter._borderRestorer : CellPainter._cellRestorer;
53896
- scope._restorer = restorer.bind(this, scope);
53897
- }
53651
+ let scope = this._prepareScope(cell);
53898
53652
 
53899
53653
  scope["rowData"] = rowData;
53900
53654
 
@@ -53910,9 +53664,47 @@ CellPainter.prototype._blinkCell = function(cell, rowData, blinkSignal) {
53910
53664
  contrastColor = bc["contrastLevelColor"];
53911
53665
  }
53912
53666
 
53667
+ return this._blink(scope, elem, blinkColor, contrastColor);
53668
+ };
53669
+
53670
+ /** Blink cell with specific color or theme's neutral movement color.
53671
+ * @public
53672
+ * @param {tr.grid.Cell} cell
53673
+ * @param {string|null} blinkColor
53674
+ * @param {Object} rowData to calculate original style e.g. { PCTCHNG: 0.53, CF_NETCHNG: 0.75 }
53675
+ * @return {boolean}
53676
+ */
53677
+ CellPainter.prototype.flash = function(cell, blinkColor, rowData) {
53678
+ if (!cell) return false;
53679
+
53680
+ let elem = cell.getElement();
53681
+ if (!elem) return false; // Cell has been disposed
53682
+
53683
+ if (!this._blinkCondition) return false;
53684
+
53685
+ let scope = this._prepareScope(cell);
53686
+
53687
+ scope["rowData"] = rowData;
53688
+
53689
+ if (typeof blinkColor !== "string") {
53690
+ blinkColor = ElfUtil.themeColors["level"];
53691
+ }
53692
+
53693
+ return this._blink(scope, elem, blinkColor, CellPainter.getOppositeColor(blinkColor));
53694
+ };
53695
+
53696
+ /**
53697
+ * @public
53698
+ * @param {Object} scope
53699
+ * @param {Element} elem
53700
+ * @param {string} blinkColor
53701
+ * @param {string} contrastColor
53702
+ * @return {boolean}
53703
+ */
53704
+ CellPainter.prototype._blink = function (scope, elem, blinkColor, contrastColor) {
53913
53705
  let bgBlinking = true;
53914
- // All conditions are met for blinking
53915
- if (bc["border"]) {
53706
+
53707
+ if (this._blinkCondition["border"]) {
53916
53708
  elem.style.border = "1px solid " + blinkColor;
53917
53709
  bgBlinking = false;
53918
53710
  } else {
@@ -53926,6 +53718,36 @@ CellPainter.prototype._blinkCell = function(cell, rowData, blinkSignal) {
53926
53718
  return bgBlinking;
53927
53719
  };
53928
53720
 
53721
+ /**
53722
+ * @public
53723
+ * @param {tr.grid.Cell} cell
53724
+ * @param {number} newValue
53725
+ * @param {number} oldValue
53726
+ * @param {Object} rowData e.g. { PCTCHNG: 0.53, CF_NETCHNG: 0.75 }
53727
+ * @return {boolean}
53728
+ */
53729
+ CellPainter.prototype.blinkCell = function(cell, newValue, oldValue, rowData) {
53730
+ let bc = this._blinkCondition;
53731
+ if (!bc) return false;
53732
+
53733
+ let blinkSignal = this._blinkCondition._fn(newValue, oldValue);
53734
+ return this.blink(cell, blinkSignal, rowData);
53735
+ };
53736
+
53737
+ /**
53738
+ * @public
53739
+ * @ignore
53740
+ * @param {number} newValue
53741
+ * @param {number} oldValue
53742
+ * @return {number}
53743
+ */
53744
+ CellPainter.prototype.calcBlinkSignal = function(newValue, oldValue) {
53745
+ if (this._blinkCondition) {
53746
+ return this._blinkCondition._fn(newValue, oldValue);
53747
+ }
53748
+ return 0;
53749
+ };
53750
+
53929
53751
  /**
53930
53752
  * @public
53931
53753
  * @param {tr.grid.Cell} cell
@@ -53942,13 +53764,12 @@ CellPainter.prototype.verifyBlinking = function(cell, rowData) {
53942
53764
  }
53943
53765
  }
53944
53766
  };
53945
- /**
53767
+ /** Deprecated, the state has been moved out to support prioritization.
53946
53768
  * @public
53769
+ * @deprecated
53947
53770
  * @param {boolean=} disabled
53948
53771
  */
53949
- CellPainter.prototype.disableLevelColor = function(disabled) {
53950
- this._levelColorDisabled = disabled !== false;
53951
- };
53772
+ CellPainter.prototype.disableLevelColor = function(disabled) {};
53952
53773
  /**
53953
53774
  * @public
53954
53775
  * @param {number} duration