@refinitiv-ui/efx-grid 6.0.98 → 6.0.100

Sign up to get free protection for your applications and to get access to all the features.
@@ -43,7 +43,8 @@ declare namespace ColumnDefinition {
43
43
  stationary?: boolean|null,
44
44
  leftPinned?: boolean|null,
45
45
  rightPinned?: boolean|null,
46
- info?: any
46
+ info?: any,
47
+ focusable: boolean
47
48
  };
48
49
 
49
50
  }
@@ -158,6 +159,8 @@ declare class ColumnDefinition {
158
159
 
159
160
  public getColumnInfo(): any;
160
161
 
162
+ public isFocusable(): boolean;
163
+
161
164
  }
162
165
 
163
166
  declare const COL_DEF: string;
@@ -50,6 +50,7 @@ import Engine from "../../tr-grid-util/es6/formula/Engine.js";
50
50
  * @property {boolean=} leftPinned=false If enabled, the column will not be part of the scrollable area and is pinned to the left side
51
51
  * @property {boolean=} rightPinned=false If enabled, the column will not be part of the scrollable area and is pinned to the right side
52
52
  * @property {Object=} info=null For storing any additional information to the column
53
+ * @property {boolean} focusable=false If enabled, the column will be used to find focusable element when pressing tab key
53
54
  */
54
55
 
55
56
  /** mapping of field type to javascript type
@@ -258,6 +259,10 @@ ColumnDefinition.prototype._info = null;
258
259
  * @private
259
260
  */
260
261
  ColumnDefinition.prototype._coreColDef = null;
262
+ /** @type {boolean}
263
+ * @private
264
+ */
265
+ ColumnDefinition.prototype._focusable = false;
261
266
  //#endregion Private Members
262
267
 
263
268
 
@@ -402,6 +407,11 @@ ColumnDefinition.prototype.initialize = function(columnOption) {
402
407
  this._sortable = val ? true : false;
403
408
  }
404
409
 
410
+ val = columnOption["focusable"];
411
+ if(val != null) {
412
+ this._focusable = val ? true : false;
413
+ }
414
+
405
415
  val = columnOption["className"] || columnOption["class"];
406
416
  if(typeof val === "string") {
407
417
  this._classes = val.split(" ");
@@ -785,6 +795,10 @@ ColumnDefinition.prototype.getConfigObject = function(colOptions) {
785
795
  obj["autoGenerated"] = this._autoGenerated;
786
796
  }
787
797
 
798
+ if(this._focusable) {
799
+ obj["focusable"] = true;
800
+ }
801
+
788
802
  let core = this._eventArg["core"];
789
803
  let grid = this._eventArg["grid"];
790
804
  let colIndex = grid.getColumnIndex(this);
@@ -1149,6 +1163,12 @@ ColumnDefinition.prototype._setCoreColumnDef = function(obj) {
1149
1163
  this._coreColDef = obj || null;
1150
1164
  };
1151
1165
 
1166
+ /** @public
1167
+ * @return {boolean}
1168
+ */
1169
+ ColumnDefinition.prototype.isFocusable = function() {
1170
+ return this._focusable;
1171
+ };
1152
1172
 
1153
1173
  export {ColumnDefinition, COL_DEF};
1154
1174
  export default ColumnDefinition;
@@ -184,6 +184,8 @@ declare class Grid extends EventDispatcher {
184
184
 
185
185
  public insertRow(rowOption?: (RowDefinition.Options|string)|null, rowRef?: Grid.RowReference|null): RowDefinition|null;
186
186
 
187
+ public insertSegmentSeparator(rowOption?: RowDefinition.Options|null, rowRef?: Grid.RowReference|null): RowDefinition|null;
188
+
187
189
  public insertRows(rowOptions: (RowDefinition.Options|string)[]|null, rowRef?: Grid.RowReference|null, opt_fields?: (string)[]|null): void;
188
190
 
189
191
  public addStaticDataRows(dataRows: any[]|null, fields?: (string)[]|null): void;
@@ -248,6 +250,8 @@ declare class Grid extends EventDispatcher {
248
250
 
249
251
  public setRicData(ric: string, values: any): void;
250
252
 
253
+ public getAllRics(): (string)[]|null;
254
+
251
255
  public setRowData(rowRef: Grid.RowReference|null, values: any): void;
252
256
 
253
257
  public setStaticRowData(rowRef: Grid.RowReference|null, values: any): void;
@@ -343,6 +343,11 @@ let Grid = function(placeholder, config) {
343
343
  t._snapshotFillerDataChanged = t._snapshotFillerDataChanged.bind(t);
344
344
  t._onPollingInterval = t._onPollingInterval.bind(t);
345
345
 
346
+ t._onKeyDown = t._onKeyDown.bind(t);
347
+ t._requestScroll = t._requestScroll.bind(t);
348
+ t._onVScroll = t._onVScroll.bind(t);
349
+ t._selfScrollToRow = t._selfScrollToRow.bind(t);
350
+
346
351
  t._streamingConflator = new Conflator(50, t._updateStreamingData);
347
352
  t._formulaConflator = new Conflator(300, t._onFormulaDataChanged);
348
353
  t._chainConflator = new Conflator(100, t._addMemberOfChain);
@@ -422,6 +427,10 @@ let Grid = function(placeholder, config) {
422
427
  t._grid.listen("postSectionDataBinding", t._onPostSectionDataBinding);
423
428
  t._grid.listen("firstRendered", t._dispatch.bind(t, "firstRendered"));
424
429
  t._grid.listen("afterContentBinding", t._dispatch.bind(t, "afterContentBinding"));
430
+ t._grid.listen("keydown", t._onKeyDown);
431
+
432
+ t._grid.getVScrollbar().listen("scroll", t._onVScroll);
433
+ t._hiddenInput = t._grid.getHiddenInput();
425
434
 
426
435
  t._grid.enableRowHighlighting(true);
427
436
 
@@ -607,7 +616,14 @@ Grid.prototype._childDataField = "";
607
616
  * @private
608
617
  */
609
618
  Grid.prototype._topSection = true;
610
-
619
+ /** @type {Object}
620
+ * @private
621
+ */
622
+ Grid.prototype._focusingArgs = null;
623
+ /** @type {number}
624
+ * @private
625
+ */
626
+ Grid.prototype._scrolledRow = -1;
611
627
  /** @public
612
628
  */
613
629
  Grid.prototype.dispose = function() {
@@ -640,6 +656,11 @@ Grid.prototype.dispose = function() {
640
656
  this._subs["dispose"]();
641
657
  this._subs = null;
642
658
  }
659
+
660
+ if(this._focusingArgs && this._focusingArgs.id) {
661
+ clearTimeout(this._focusingArgs.id);
662
+ this._focusingArgs = null;
663
+ }
643
664
  };
644
665
  /** @public
645
666
  * @return {Element}
@@ -2321,6 +2342,22 @@ Grid.prototype.insertRow = function(rowOption, rowRef) {
2321
2342
  this._connector.addRic(rowDef);
2322
2343
  return rowDef;
2323
2344
  };
2345
+ /** Insert a row as a segment separator
2346
+ * @public
2347
+ * @param {RowDefinition~Options=} rowOption
2348
+ * @param {Grid~RowReference=} rowRef Reference (i.e. row index, row id, or row definition) of the insert position
2349
+ * @returns {RowDefinition}
2350
+ */
2351
+ Grid.prototype.insertSegmentSeparator = function(rowOption, rowRef) {
2352
+ if(!rowOption) {
2353
+ rowOption = {};
2354
+ }
2355
+ if(typeof rowOption === "object") {
2356
+ rowOption.asSegment = true;
2357
+ return this.insertRow(rowOption, rowRef);
2358
+ }
2359
+ return null;
2360
+ };
2324
2361
  /** @public
2325
2362
  * @param {Array.<RowDefinition~Options|string>} rowOptions Array of row option object
2326
2363
  * @param {Grid~RowReference=} rowRef Reference (i.e. row index, row id, or row definition) of the insert position
@@ -3051,6 +3088,13 @@ Grid.prototype.setRicData = function(ric, values) {
3051
3088
  }
3052
3089
  }
3053
3090
  };
3091
+ /** Retrieve all RIC subscriptions. This method is not dependent on the number of rows, the RIC can vary from the current row in the grid.
3092
+ * @public
3093
+ * @return {Array.<string>}
3094
+ */
3095
+ Grid.prototype.getAllRics = function() {
3096
+ return this._connector.getAllRics();
3097
+ };
3054
3098
  /** A shorthand to set row data based on index of the specified row. It is better to keep rowDefinition object for updating data directly as row index can be changed by sorting and filtering.
3055
3099
  * @public
3056
3100
  * @param {Grid~RowReference} rowRef
@@ -4116,5 +4160,198 @@ Grid.prototype.getVScrollView = function () {
4116
4160
  return this._grid.getVScrollView();
4117
4161
  };
4118
4162
 
4163
+ /** @private
4164
+ * @param {Element} el
4165
+ * @return {boolean}
4166
+ */
4167
+ function isValidInput(el) {
4168
+ return el && el.tagName !== "SPAN" && !el.disabled;
4169
+ }
4170
+ /** @private
4171
+ * @param {Element} el
4172
+ * @param {Element} hiddenInput
4173
+ * @return {boolean}
4174
+ */
4175
+ function isValidTarget(el, hiddenInput) {
4176
+ return !el.classList.contains("valigner") && el !== hiddenInput;
4177
+ }
4178
+ /** @private
4179
+ * @param {Object} cell
4180
+ * @return {boolean}
4181
+ */
4182
+ function focusCell(cell) {
4183
+ if(cell) {
4184
+ let cellContent = cell.getContent();
4185
+ if(cellContent && isValidInput(cellContent)) {
4186
+ cellContent.focus();
4187
+ return true;
4188
+ }
4189
+ }
4190
+ return false;
4191
+ }
4192
+ /** @private
4193
+ */
4194
+ Grid.prototype._onVScroll = function() {
4195
+ let args = this._focusingArgs;
4196
+ if(!args) { return; }
4197
+
4198
+ this._focusingArgs = null;
4199
+ let event = args.event;
4200
+ let cell = args.section.getCell(args.colIndex, args.rowIndex);
4201
+ if(focusCell(cell)) {
4202
+ event.preventDefault();
4203
+ } else {
4204
+ if(event.shiftKey) {
4205
+ this._findPrevFocusableCell(event, args.colIndex, args.rowIndex, args.focusableColIndices);
4206
+ } else {
4207
+ this._findNextFocusableCell(event, args.colIndex, args.rowIndex, args.focusableColIndices);
4208
+ }
4209
+ }
4210
+ };
4211
+ /** @private
4212
+ */
4213
+ Grid.prototype._selfScrollToRow = function() {
4214
+ let args = this._focusingArgs;
4215
+ if(!args) { return; }
4216
+ args.id = 0;
4217
+ this.scrollToRow(args.rowIndex);
4218
+ };
4219
+ /** @private
4220
+ * @param {Object} e
4221
+ * @param {number} colIndex
4222
+ * @param {number} rowIndex
4223
+ * @param {Array} focusableColIndices
4224
+ * @param {Object} section
4225
+ */
4226
+ Grid.prototype._requestScroll = function(e, colIndex, rowIndex, focusableColIndices, section) {
4227
+ let args = this._focusingArgs;
4228
+ if(args) { return; }
4229
+ if(this._scrolledRow === rowIndex) { return; } // Avoid infinite loop
4230
+
4231
+ this._scrolledRow = rowIndex;
4232
+ args = this._focusingArgs = {
4233
+ event: e,
4234
+ colIndex: colIndex,
4235
+ rowIndex: rowIndex,
4236
+ focusableColIndices: focusableColIndices,
4237
+ section: section
4238
+ };
4239
+
4240
+ args.id = setTimeout(this._selfScrollToRow); // Avoid event loop protection
4241
+ };
4242
+ /** @private
4243
+ * @param {Object} e
4244
+ * @param {number} colIndex
4245
+ * @param {number} rowIndex
4246
+ * @param {Array} focusableColIndices
4247
+ * @param {Element=} content
4248
+ */
4249
+ Grid.prototype._findNextFocusableCell = function(e, colIndex, rowIndex, focusableColIndices, content) {
4250
+ let startIdx = focusableColIndices.indexOf(colIndex);
4251
+
4252
+ // Calculate starting row and column index
4253
+ if(!isValidTarget(e.target, this._hiddenInput) || startIdx < 0) {
4254
+ rowIndex = 0;
4255
+ startIdx = 0;
4256
+ } else if(isValidInput(content) && startIdx >= 0) {
4257
+ startIdx++;
4258
+ }
4259
+ let grid = this._grid;
4260
+ let section = grid.getSection("content");
4261
+ let viewInfo = grid.getVerticalViewInfo();
4262
+ let bottomRowIndex = viewInfo.bottomRowIndex;
4263
+ let rowCount = this.getRowCount();
4264
+ for(let r = rowIndex; r < rowCount; r++) {
4265
+ for(let i = startIdx; i < focusableColIndices.length; i++) {
4266
+ let c = focusableColIndices[i];
4267
+ if(r > bottomRowIndex) {
4268
+ this._requestScroll(e, c, r, focusableColIndices, section);
4269
+ return;
4270
+ } else {
4271
+ let cell = section.getCell(c, r);
4272
+ if(focusCell(cell)) {
4273
+ e.preventDefault();
4274
+ return;
4275
+ }
4276
+ }
4277
+ }
4278
+ startIdx = 0;
4279
+ }
4280
+ };
4281
+ /** @private
4282
+ * @param {Object} e
4283
+ * @param {number} colIndex
4284
+ * @param {number} rowIndex
4285
+ * @param {Array} focusableColIndices
4286
+ * @param {Element=} content
4287
+ */
4288
+ Grid.prototype._findPrevFocusableCell = function(e, colIndex, rowIndex, focusableColIndices, content) {
4289
+ let startIdx = focusableColIndices.indexOf(colIndex);
4290
+ let len = focusableColIndices.length;
4291
+
4292
+ // Calculate starting row and column index
4293
+ if(!isValidTarget(e.target, this._hiddenInput) || startIdx < 0) {
4294
+ rowIndex = 0;
4295
+ startIdx = 0;
4296
+ } else if(isValidInput(content) && startIdx >= 0) {
4297
+ startIdx--;
4298
+ }
4299
+
4300
+ let grid = this._grid;
4301
+ let section = grid.getSection("content");
4302
+ let viewInfo = grid.getVerticalViewInfo();
4303
+ let topRowIndex = viewInfo.topRowIndex;
4304
+ for(let r = rowIndex; r >= 0; r--) {
4305
+ for(let i = startIdx; i >= 0; i--) {
4306
+ let c = focusableColIndices[i];
4307
+ if(r < topRowIndex) {
4308
+ this._requestScroll(e, c, r, focusableColIndices, section);
4309
+ return;
4310
+ } else {
4311
+ let cell = section.getCell(c, r);
4312
+ if(focusCell(cell)) {
4313
+ e.preventDefault();
4314
+ return;
4315
+ }
4316
+ }
4317
+ }
4318
+ startIdx = len - 1;
4319
+ }
4320
+ };
4321
+
4322
+ /** @private
4323
+ * @param {Object} e
4324
+ */
4325
+ Grid.prototype._onKeyDown = function(e) {
4326
+ if (e.keyCode !== 9 || e.ctrlKey || e.altKey || e.metaKey) {
4327
+ return;
4328
+ }
4329
+
4330
+ // Find next focusable cell
4331
+ let colDefs = this.getColumnDefinitions();
4332
+ let colCount = colDefs.length;
4333
+
4334
+ let focusableColIndices = [];
4335
+ for(let c = 0; c < colCount; c++) {
4336
+ if(colDefs[c].isFocusable()) {
4337
+ focusableColIndices.push(c);
4338
+ }
4339
+ }
4340
+
4341
+ if(!focusableColIndices.length) {
4342
+ return;
4343
+ }
4344
+
4345
+ this._scrolledRow = -1; // Reset the scroll loop protector
4346
+ let pos = this.getRelativePosition(e);
4347
+ let content = pos["cell"] ? pos["cell"].getContent() : null;
4348
+
4349
+ if(e.shiftKey) {
4350
+ this._findPrevFocusableCell(e, pos["colIndex"], pos["rowIndex"], focusableColIndices, content);
4351
+ } else {
4352
+ this._findNextFocusableCell(e, pos["colIndex"], pos["rowIndex"], focusableColIndices, content);
4353
+ }
4354
+ };
4355
+
4119
4356
  export { Grid };
4120
4357
  export default Grid;
@@ -142,7 +142,5 @@ declare const ROW_DEF: string;
142
142
 
143
143
  declare const ROW_TYPES: RowDefinition.RowTypes;
144
144
 
145
- declare function rowData(userInput: string, extractedOptions: any): boolean;
146
-
147
145
  export {RowDefinition, ROW_DEF, ROW_TYPES};
148
146
  export default RowDefinition;
@@ -12,7 +12,7 @@ import { DataTable } from "../../core/es6/data/DataTable.js";
12
12
  * @property {Array.<string>=} fields=null Field that corresponds to the given static values
13
13
  * @property {boolean=} asChain=false The given ric will be treated as a chain
14
14
  * @property {string=} chainRic="" RIC to be used for chain request (overiding ric property)
15
- * @property {boolean=} collapsed=true Chain is collapsed by default
15
+ * @property {boolean=} collapsed=true Chain or segment is collapsed by default
16
16
  * @property {(string|null)=} label=null
17
17
  * @property {boolean=} hidden=true When this row is hidden
18
18
  * @property {boolean=} realTime=true Realtime row, able to request for JET/RTK
@@ -104,6 +104,10 @@ RowDefinition.prototype._isChain = null;
104
104
  /** @type {boolean}
105
105
  * @private
106
106
  */
107
+ RowDefinition.prototype._asSegment = false;
108
+ /** @type {boolean}
109
+ * @private
110
+ */
107
111
  RowDefinition.prototype._realTime = true;
108
112
 
109
113
  /** @type {string}
@@ -258,8 +262,8 @@ RowDefinition.prototype.initialize = function(rowOptions) {
258
262
  }
259
263
 
260
264
  val = extractedOptions["asChain"];
261
- if(val !== null) {
262
- this._isChain = val;
265
+ if(val != null) {
266
+ this._isChain = val ? true : false;
263
267
  }
264
268
 
265
269
  val = rowOptions["realTime"];
@@ -272,6 +276,12 @@ RowDefinition.prototype.initialize = function(rowOptions) {
272
276
  if(val != null || !collapsed){
273
277
  this._expanded = !collapsed;
274
278
  }
279
+
280
+ val = rowOptions["asSegment"];
281
+ if(val != null) {
282
+ this._asSegment = val ? true : false;
283
+ }
284
+
275
285
  val = rowOptions["keepModel"];
276
286
  if(val) {
277
287
  this._userModel = rowOptions;
@@ -315,6 +325,41 @@ RowDefinition.prototype._initializeAsConstituent = function(rowOptions) {
315
325
  this.setStaticRowData(val, rowOptions["fields"]);
316
326
  }
317
327
  };
328
+ /** @private
329
+ * @param {DataView} view
330
+ * @param {string} rowId
331
+ * @returns {string}
332
+ */
333
+ let _getEndOfSegmentRowId = function(view, rowId) {
334
+ let rowIndex = view.getRowIndex(rowId);
335
+ do {
336
+ rowId = view.getRowId(++rowIndex);
337
+ if(rowId && !view.getSegmentParentRowId(rowId)) {
338
+ break;
339
+ }
340
+ } while(rowId);
341
+ return rowId;
342
+ };
343
+
344
+ /** @private
345
+ * @param {DataView} view
346
+ * @param {boolean} newState
347
+ * @param {boolean} prevState
348
+ * @returns {boolean} Current state
349
+ */
350
+ let _stallSorting = function(view, newState, prevState) {
351
+ if(view && view.isSorting()) {
352
+ newState = newState ? true : false;
353
+ if(newState !== prevState) {
354
+ if(newState) {
355
+ view.synchronizeRowOrder();
356
+ }
357
+ view.stallSorting(newState);
358
+ }
359
+ return newState;
360
+ }
361
+ return false;
362
+ };
318
363
  /** @public
319
364
  * @ignore
320
365
  * @param {string} userInput RIC
@@ -342,44 +387,53 @@ RowDefinition.prototype.setContent = function(userInput, extractedOptions) {
342
387
  return false;
343
388
  }
344
389
 
390
+ let asChain = extractedOptions["asChain"];
391
+ let realtimeRow = true;
392
+ if(userInput.charAt(0) === "'") { // Single quote is used as a marker for non realtime row
393
+ realtimeRow = false;
394
+ this._ric = this._chainRic = ""; // No ric for realtime request
395
+ }
396
+
397
+ let dv = this._view;
398
+ let stalledSorting = _stallSorting(dv, realtimeRow && asChain, false); // To preserve current position of the segment/chain
399
+
345
400
  if(!this.unsubscribeForUpdates()){
346
401
  this._clearStaticData();
347
402
  }
348
403
  this.resetUpdates(); // Remove all previous data updates because a new content is just entered
349
404
 
350
405
  this._userInput = userInput;
351
- if(this._userInput.charAt(0) === "'") { // This is a row header
352
- this._ric = this._chainRic = ""; // No ric for realtime request
353
- } else {
354
- let asChain = extractedOptions["asChain"];
406
+ if(realtimeRow) {
355
407
  let expanded = !extractedOptions["collapsed"];
356
408
  let chainRic = extractedOptions["chainRic"];
357
409
  if(asChain === true){
358
- this._ric = expanded === false ? this._userInput : this._userInput.replace("0#", "");
410
+ this._ric = expanded === false ? userInput : userInput.replace("0#", "");
359
411
  this._expanded = expanded; // Only chain can be expanded by 0#
360
412
  } else {
361
- this._ric = this._userInput;
413
+ this._ric = userInput;
362
414
  }
363
415
  this._isChain = asChain != null ? asChain : null; // this could be null or undefined
364
416
  this._chainRic = chainRic || "";
365
417
  }
418
+ // A symbol can be either RIC or permId
419
+ // JET/RTK will generate data id to be rowId (given from this rowDef) + ric
420
+ this._dataId = this._rowId + this.getSymbol();
366
421
 
367
- let segmentId = "";
368
- if(this._view) {
369
- segmentId = this._view.getSegmentParentRowId(this._rowId);
422
+ if(dv) {
423
+ let segmentId = dv.getSegmentParentRowId(this._rowId);
370
424
  if(segmentId) {
371
425
  if(this._isChain){ // If the row was a normal row and has been changed to a chain, remove it from existing segment
372
- let targetRowId = _getEndOfSegmentRowId(this._view, this._rowId);
373
- this._view.removeSegmentChild(segmentId, this._rowId);
374
- this._view.moveRow(this._rowId, targetRowId);
426
+ let targetRowId = _getEndOfSegmentRowId(dv, this._rowId);
427
+ dv.removeSegmentChild(segmentId, this._rowId);
428
+ dv.moveRow(this._rowId, targetRowId);
375
429
 
376
430
  segmentId = "";
377
431
  }
378
- } else if(this._view.getSegment(this._rowId)) {
379
- this._view.setSegmentSeparator(this._rowId, false); // Remove existing segment
432
+ } else if(dv.getSegment(this._rowId)) {
433
+ dv.setSegmentSeparator(this._rowId, false); // Remove existing segment
380
434
  }
381
435
  if(this._isChain) {
382
- this._view.setSegmentSeparator(this._rowId, true);
436
+ dv.setSegmentSeparator(this._rowId, true);
383
437
  }
384
438
  if(this.isChainCollapsed()) {
385
439
  if(this._expanded){
@@ -390,11 +444,10 @@ RowDefinition.prototype.setContent = function(userInput, extractedOptions) {
390
444
  this.collapseChain();
391
445
  }
392
446
  }
393
- }
394
-
395
- this._dataId = this._rowId + this.getSymbol(); // JET/RTK will generate data id to be rowId (given from this rowDef) + ric
396
- if(segmentId) { // If data id is changed and the row is a child of a segment, then segment child data id must be updated
397
- this._view.addSegmentChild(segmentId, this._rowId, this._dataId);
447
+ _stallSorting(dv, false, stalledSorting);
448
+ if(segmentId) { // If data id is changed and the row is a child of a segment, then segment child data id must be updated
449
+ dv.addSegmentChild(segmentId, this._rowId, this._dataId);
450
+ }
398
451
  }
399
452
 
400
453
  if(!this.subscribeForUpdates()) {
@@ -903,22 +956,6 @@ RowDefinition.prototype.resetUpdates = function() {
903
956
  }
904
957
  };
905
958
 
906
- /** @private
907
- * @param {DataView} view
908
- * @param {string} rowId
909
- * @returns {string}
910
- */
911
- let _getEndOfSegmentRowId = function(view, rowId) {
912
- let rowIndex = view.getRowIndex(rowId);
913
- do {
914
- rowId = view.getRowId(++rowIndex);
915
- if(rowId && !view.getSegmentParentRowId(rowId)) {
916
- break;
917
- }
918
- } while(rowId);
919
- return rowId;
920
- };
921
-
922
959
  /** @public
923
960
  * @param {DataView} view
924
961
  * @param {string=} rowId
@@ -942,28 +979,32 @@ RowDefinition.prototype.registerToView = function(view, rowId) {
942
979
  rowData[ROW_DEF] = this;
943
980
 
944
981
  let parentRowId = "";
982
+ let isSegment = this._isChain || this._asSegment;
945
983
  if(rowId) {
946
984
  parentRowId = view.getSegmentParentRowId(rowId);
947
985
  if(parentRowId) {
948
- if(this._isChain) { // A chain cannot be put inside another segment
986
+ if(isSegment) { // A chain or a segment cannot be put inside another segment
949
987
  rowId = _getEndOfSegmentRowId(view, rowId);
950
988
  } // else { // Normal row is inserted into a segment
951
989
  }
952
990
  }
953
991
 
992
+ let stalledSorting = _stallSorting(view, isSegment, false);
993
+
954
994
  let newRowId = view.insertRow(rowId, rowData, this.getRowId());
955
995
  if(newRowId !== this._rowId) {
956
996
  this._rowId = newRowId; // In case there is some duplicate row id
957
997
  this._userId = false;
958
998
  }
959
999
 
960
- if(this._isChain) {
961
- view.setSegmentSeparator(this._rowId);
1000
+ if(isSegment) {
1001
+ view.setSegmentSeparator(newRowId);
1002
+ _stallSorting(view, false, stalledSorting);
962
1003
  if(!this._expanded) {
963
- this.collapseChain();
1004
+ view.collapseSegment(newRowId);
964
1005
  }
965
1006
  } else if(!this._parent && parentRowId) { // Constituent cannot be added to another segment
966
- view.addSegmentChild(parentRowId, this._rowId, this._dataId);
1007
+ view.addSegmentChild(parentRowId, newRowId, this._dataId);
967
1008
  }
968
1009
  };
969
1010
  /** @private
@@ -1093,7 +1093,18 @@ ColumnGroupingPlugin.prototype._onBeforeColumnBoundUpdate = function (e) {
1093
1093
  }
1094
1094
  }
1095
1095
  }
1096
- e.topBoundRowIndex = topBoundRowIndex;
1096
+
1097
+ // Find maximum spanned row count
1098
+ var section = this._hosts[0].getSection("title");
1099
+ var minRowSpanCount = 0;
1100
+ var bottomRowIndex = this._maxDepth;
1101
+ for (i = 0; i < selectedColumns.length; i++) {
1102
+ var rowSpanCount = section.getCellRowSpan(selectedColumns[i], bottomRowIndex);
1103
+ if (rowSpanCount < minRowSpanCount) {
1104
+ minRowSpanCount = rowSpanCount;
1105
+ }
1106
+ }
1107
+ e.topBoundRowIndex = bottomRowIndex + minRowSpanCount;
1097
1108
  };
1098
1109
  /** Deprecated. Column should be directly added through grid APIs.
1099
1110
  * @deprecated
@@ -31,7 +31,9 @@ declare namespace InCellEditingPlugin {
31
31
  rowEditorClosed?: ((...params: any[]) => any)|null,
32
32
  autoSuggest?: Element|null,
33
33
  closingOnScroll?: boolean|null,
34
- autoHiding?: boolean|null
34
+ autoHiding?: boolean|null,
35
+ readonly?: boolean|null,
36
+ starterText?: (string|boolean)|null
35
37
  };
36
38
 
37
39
  type Cache = {
@@ -81,6 +83,8 @@ declare class InCellEditingPlugin extends GridPlugin {
81
83
 
82
84
  public disableDblClick(opt_disabled?: boolean|null): void;
83
85
 
86
+ public showStarterText(bool?: boolean|null): void;
87
+
84
88
  public isEditing(): boolean;
85
89
 
86
90
  public getTextBox(columnIndex?: number|null, grid?: any): Element|null;
@@ -99,6 +103,10 @@ declare class InCellEditingPlugin extends GridPlugin {
99
103
 
100
104
  public isColumnEditable(colIndex: number): boolean;
101
105
 
106
+ public enableReadonly(bool: boolean): void;
107
+
108
+ public disableReadonly(bool: boolean): void;
109
+
102
110
  public openRowEditor(rowIndex: number, grid?: any): void;
103
111
 
104
112
  public closeRowEditor(isCommit?: boolean|null): void;