@refinitiv-ui/efx-grid 6.0.99 → 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;
@@ -250,6 +250,8 @@ declare class Grid extends EventDispatcher {
250
250
 
251
251
  public setRicData(ric: string, values: any): void;
252
252
 
253
+ public getAllRics(): (string)[]|null;
254
+
253
255
  public setRowData(rowRef: Grid.RowReference|null, values: any): void;
254
256
 
255
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}
@@ -3067,6 +3088,13 @@ Grid.prototype.setRicData = function(ric, values) {
3067
3088
  }
3068
3089
  }
3069
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
+ };
3070
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.
3071
3099
  * @public
3072
3100
  * @param {Grid~RowReference} rowRef
@@ -4132,5 +4160,198 @@ Grid.prototype.getVScrollView = function () {
4132
4160
  return this._grid.getVScrollView();
4133
4161
  };
4134
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
+
4135
4356
  export { Grid };
4136
4357
  export default Grid;
@@ -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;
@@ -31,6 +31,8 @@ import { CoralItems } from "../../tr-grid-util/es6/CoralItems.js";
31
31
  * @property {Element=} autoSuggest=null Element of ef-autosuggest or atlas-autosuggest for handled with input cell
32
32
  * @property {boolean=} closingOnScroll=true If disabled, the editor will not be automatically closed when scrolling grid.
33
33
  * @property {boolean=} autoHiding=true If disabled, the editor will not be automatically closed when losing its focus.
34
+ * @property {boolean=} readonly=false If disabled, the editor will not be able to open, this property overwrite `editableContent` and `editableTitle`
35
+ * @property {(string|boolean)=} starterText=false if enable it, it will be show placeholder when no ric in grid, given string to overwrite wording
34
36
  */
35
37
 
36
38
  /** @typedef {Object} InCellEditingPlugin~Cache
@@ -171,6 +173,8 @@ let InCellEditingPlugin = function (options) {
171
173
  t._onMultiSelectionValueChanged = t._onMultiSelectionValueChanged.bind(t);
172
174
  t._onMultiSelectionEditorChanged = t._onMultiSelectionEditorChanged.bind(t);
173
175
  t._onAutoSuggestItemSelected = t._onAutoSuggestItemSelected.bind(t);
176
+ t._firstRendered = t._firstRendered.bind(t);
177
+ t._onGridKeyDown = t._onGridKeyDown.bind(t);
174
178
  t._hosts = [];
175
179
 
176
180
  if(options) {
@@ -341,10 +345,26 @@ InCellEditingPlugin.prototype._closingOnScroll = true;
341
345
  * @private
342
346
  */
343
347
  InCellEditingPlugin.prototype._autoHiding = true;
348
+ /** @type {boolean}
349
+ * @private
350
+ */
351
+ InCellEditingPlugin.prototype._readonly = false;
352
+ /** @type {string}
353
+ * @private
354
+ */
355
+ InCellEditingPlugin.prototype._starterText = "";
356
+ /** @type {Object}
357
+ * @private
358
+ */
359
+ InCellEditingPlugin.prototype._starterTextPopup = null;
344
360
  /** @type {number}
345
361
  * @private
346
362
  */
347
363
  InCellEditingPlugin.prototype._editorTimerId = 0;
364
+ /** @type {Object}
365
+ * @private
366
+ */
367
+ InCellEditingPlugin.prototype._rowSelectionPlugin = null;
348
368
  /** @type {boolean}
349
369
  * @private
350
370
  */
@@ -369,6 +389,11 @@ InCellEditingPlugin._styles = prettifyCss([
369
389
  ],
370
390
  ":host .cell.editing", [
371
391
  "z-index: 2;"
392
+ ],
393
+ ":host .starter-text", [
394
+ "padding: var(--grid-cell-padding,0 8px 0 8px);",
395
+ "pointer-events: none;",
396
+ "line-height: 28px" // WARNING: hardcode, it can be calculate with row height
372
397
  ]
373
398
  ]);
374
399
 
@@ -551,6 +576,9 @@ InCellEditingPlugin.prototype.initialize = function (host, options) {
551
576
  }
552
577
 
553
578
  host.listen("columnAdded", this._onColumnAdded);
579
+ host.listen("firstRendered", this._firstRendered);
580
+ host.listen("keydown", this._onGridKeyDown);
581
+
554
582
  host.getVScrollbar().listen("scroll", this._onScroll);
555
583
  host.getHScrollbar().listen("scroll", this._onScroll);
556
584
 
@@ -604,6 +632,14 @@ InCellEditingPlugin.prototype._afterInit = function () {
604
632
  this._elfVersion = ElfUtil.getElfVersion();
605
633
  };
606
634
 
635
+ /** @private
636
+ */
637
+ InCellEditingPlugin.prototype._firstRendered = function () {
638
+ if(!this._readonly && this._starterText) {
639
+ this.showStarterText();
640
+ }
641
+ };
642
+
607
643
  /** @public
608
644
  * @param {Object=} options
609
645
  */
@@ -679,6 +715,16 @@ InCellEditingPlugin.prototype.config = function(options) {
679
715
  if(pluginOption["autoHiding"] == false) {
680
716
  t._autoHiding = false;
681
717
  }
718
+ if(pluginOption["readonly"] == true) {
719
+ t._readonly = true;
720
+ }
721
+ if(pluginOption["starterText"] !== null) {
722
+ if(typeof pluginOption["starterText"] === "string") {
723
+ t._starterText = pluginOption["starterText"];
724
+ } else {
725
+ t._starterText = pluginOption["starterText"] ? "Type to add" : false;
726
+ }
727
+ }
682
728
 
683
729
  // event callback
684
730
  t.addListener(pluginOption, "preEditorOpening");
@@ -773,6 +819,15 @@ InCellEditingPlugin.prototype.getConfigObject = function (out_obj) {
773
819
  dirty |= _setBooleanOption(extOptions, "uiBlocking", this._uiBlocking, false);
774
820
  dirty |= _setBooleanOption(extOptions, "closingOnScroll", this._closingOnScroll, true);
775
821
  dirty |= _setBooleanOption(extOptions, "autoHiding", this._autoHiding, true);
822
+ dirty |= _setBooleanOption(extOptions, "readonly", this._readonly, false);
823
+
824
+ if(this._starterText) {
825
+ if(this._starterText === "Type to add") {
826
+ extOptions["starterText"] = true;
827
+ } else {
828
+ extOptions["starterText"] = this._starterText;
829
+ }
830
+ }
776
831
 
777
832
  if(this._contentSource !== "textContent") {
778
833
  dirty = 1;
@@ -831,6 +886,9 @@ InCellEditingPlugin.prototype.unload = function (host) {
831
886
  window.removeEventListener("scroll", this._onScroll);
832
887
  }
833
888
 
889
+ if(this._starterTextPopup) {
890
+ this._starterTextPopup.dispose();
891
+ }
834
892
  this._dispose();
835
893
  };
836
894
 
@@ -848,6 +906,9 @@ InCellEditingPlugin.prototype.openEditor = function (colIndex, rowIndex, section
848
906
  return;
849
907
  }
850
908
  }
909
+ if(this._readonly) {
910
+ return;
911
+ }
851
912
 
852
913
  let sectionSettings = grid.getSectionSettings(sectionRef || "content");
853
914
  let activePos = this._activePos;
@@ -937,6 +998,114 @@ InCellEditingPlugin.prototype.disableDblClick = function (opt_disabled) {
937
998
  }
938
999
  };
939
1000
 
1001
+ /** @private
1002
+ * @param {Object} e
1003
+ */
1004
+ InCellEditingPlugin.prototype._onGridKeyDown = function (e) {
1005
+ if (e.key.length !== 1) { // Special character
1006
+ return;
1007
+ }
1008
+ if(this._starterText && this._starterTextPopup.isShown()) {
1009
+ let rsp = this._getPlugin("RowSelectionPlugin");
1010
+ if(rsp && rsp.getSelectedRowCount() > 0) {
1011
+ return;
1012
+ }
1013
+ let grid = this._hosts[0];
1014
+ grid.scrollToRow("content", 0, true);
1015
+ if(!this.isEditing()) {
1016
+ let firstEditableCol = this._getFirstEditableColumnIndex();
1017
+ if(firstEditableCol === 0) {
1018
+ return;
1019
+ }
1020
+ let cell = grid.getCell("content", firstEditableCol, 0);
1021
+ this._openEditor(cell, grid);
1022
+ }
1023
+ }
1024
+ };
1025
+
1026
+ /**
1027
+ * @description Show starter text when the grid is no ric
1028
+ * @public
1029
+ * @param {boolean=} bool
1030
+ */
1031
+ InCellEditingPlugin.prototype.showStarterText = function (bool) {
1032
+ setTimeout(this._showStarterText.bind(this, bool), 0); // Need to delay to wait scrollbar or editor closed
1033
+ };
1034
+
1035
+
1036
+ /**
1037
+ * @private
1038
+ * @param {boolean=} bool
1039
+ */
1040
+ InCellEditingPlugin.prototype._showStarterText = function (bool) {
1041
+ if(!this._realTimeGrid || !this._starterText) {
1042
+ return;
1043
+ }
1044
+ let allRics = this._realTimeGrid.getAllRics();
1045
+ if(allRics.length > 0) {
1046
+ return;
1047
+ }
1048
+ let popupElem;
1049
+ if(!this._starterTextPopup) {
1050
+ popupElem = this._starterTextPopup = this._createStaterTextElement();
1051
+ } else {
1052
+ popupElem = this._starterTextPopup;
1053
+ }
1054
+ if(bool === false) {
1055
+ popupElem.hide();
1056
+ return;
1057
+ }
1058
+ let grid = this._hosts[0];
1059
+
1060
+ let editableColIndex = this._getFirstEditableColumnIndex();
1061
+ if(editableColIndex < 0) { // not editable
1062
+ return;
1063
+ }
1064
+ grid.scrollToRow("content", 0, true);
1065
+ let editableCell = grid.getCell("content", editableColIndex, 0);
1066
+ popupElem.attachTo(editableCell.getElement());
1067
+ popupElem.show(bool, grid.getElement().parentElement);
1068
+ };
1069
+
1070
+ /** @private
1071
+ * @return {number}
1072
+ */
1073
+ InCellEditingPlugin.prototype._getFirstEditableColumnIndex = function () {
1074
+ if(this._readonly || !this._editableContent) {
1075
+ return -1;
1076
+ }
1077
+
1078
+ let colCount = this.getColumnCount();
1079
+ for (let i = 0; i < colCount; i++) {
1080
+ let editableCol = this.isColumnEditable(i);
1081
+ if(editableCol) {
1082
+ return i;
1083
+ }
1084
+ }
1085
+ return -1;
1086
+ };
1087
+
1088
+ /** @private
1089
+ * @return {Object}
1090
+ */
1091
+ InCellEditingPlugin.prototype._createStaterTextElement = function () {
1092
+ let container = document.createElement("div");
1093
+ container.textContent = this._starterText;
1094
+ container.className = "starter-text";
1095
+ let popup = new Popup(container, { positioning: "over"});
1096
+ popup.disableAutoHiding(true);
1097
+ popup.disableHideOnScroll(true);
1098
+ return popup;
1099
+ };
1100
+
1101
+ /** @public
1102
+ * @description This is for testing purpose to compare element
1103
+ * @ignore
1104
+ * @return {Object}
1105
+ */
1106
+ InCellEditingPlugin.prototype.getStarterTextelement = function () {
1107
+ return this._starterTextPopup;
1108
+ };
940
1109
  /** Checking Editing is in process.
941
1110
  * @public
942
1111
  * @return {boolean}
@@ -1090,9 +1259,27 @@ InCellEditingPlugin.prototype.enableAutoCommitText = function (opt_enable) {
1090
1259
  * @return {boolean}
1091
1260
  */
1092
1261
  InCellEditingPlugin.prototype.isColumnEditable = function (colIndex) {
1262
+ if(this._readonly) {
1263
+ return false;
1264
+ }
1093
1265
  let val = this._getColumnOption(colIndex, "editableContent");
1094
1266
  return val == null ? this._editableContent : val;
1095
1267
  };
1268
+
1269
+ /**
1270
+ * @public
1271
+ * @param {boolean} bool
1272
+ */
1273
+ InCellEditingPlugin.prototype.enableReadonly = function (bool) {
1274
+ this._readonly = bool !== false;
1275
+ };
1276
+ /**
1277
+ * @public
1278
+ * @param {boolean} bool
1279
+ */
1280
+ InCellEditingPlugin.prototype.disableReadonly = function () {
1281
+ this.enableReadonly(false);
1282
+ };
1096
1283
  /** @public
1097
1284
  * @description Supply an keyboard input. This is for testing purpose.
1098
1285
  * @ignore
@@ -1105,6 +1292,16 @@ InCellEditingPlugin.prototype.supplyKey = function(keyName, context) {
1105
1292
  this._onTextKeyUp(eventObj);
1106
1293
  };
1107
1294
  /** @public
1295
+ * @description Supply an keyboard input. This is for testing purpose.
1296
+ * @ignore
1297
+ * @param {string} keyName
1298
+ * @param {Object=} context
1299
+ */
1300
+ InCellEditingPlugin.prototype.supplyGridKeydown = function(keyName, context) {
1301
+ let eventObj = this._mockKeyboardEvent(keyName, context);
1302
+ this._onGridKeyDown(eventObj);
1303
+ };
1304
+ /** @public
1108
1305
  * @description Supply an double click event. This is for testing purpose.
1109
1306
  * @ignore
1110
1307
  * @param {number} colIndex
@@ -1122,6 +1319,9 @@ InCellEditingPlugin.prototype.mockDoubleClick = function(colIndex, rowIndex, con
1122
1319
  */
1123
1320
  InCellEditingPlugin.prototype._onDoubleClick = function (e, opt_host) {
1124
1321
  let t = this;
1322
+ if(t._readonly) {
1323
+ return;
1324
+ }
1125
1325
  let host = opt_host || t.getRelativeGrid(e);
1126
1326
  if(t.isEditing() || !host) { return; }
1127
1327
 
@@ -1318,6 +1518,7 @@ InCellEditingPlugin.prototype._openEditor = function (e, host, arg) {
1318
1518
 
1319
1519
  // Dispatch an event for user to setup stuff
1320
1520
  t._dispatch("editorOpened", arg); // User may modify the editor
1521
+ t.showStarterText(false);
1321
1522
 
1322
1523
  inputElement.focus();
1323
1524
  if(typeof inputElement.select === "function") {
@@ -1337,7 +1538,7 @@ InCellEditingPlugin.prototype.openRowEditor = function (rowIndex, grid) {
1337
1538
  let t = this;
1338
1539
  grid = grid || t._hosts[0];
1339
1540
  // if open same row we will do nothing
1340
- if(t._getRowIndex(t._activeRowId) === rowIndex || !grid) { return; }
1541
+ if(t._getRowIndex(t._activeRowId) === rowIndex || !grid || t._readonly) { return; }
1341
1542
 
1342
1543
  // close all open editor
1343
1544
  t.closeRowEditor(false, grid);
@@ -1835,6 +2036,7 @@ InCellEditingPlugin.prototype._commitText = function (committed, suggestionDetai
1835
2036
  Dom.removeParent(t._customElement);
1836
2037
 
1837
2038
  let grid = arg["grid"];
2039
+ this.showStarterText();
1838
2040
  if(grid) {
1839
2041
  t._freezeScrolling(grid, false);
1840
2042
  grid.focus();