@refinitiv-ui/efx-grid 6.0.108 → 6.0.110

Sign up to get free protection for your applications and to get access to all the features.
@@ -14857,6 +14857,7 @@ PredefinedFormula.remove = function(field) {
14857
14857
  * @property {boolean=} rightPinned=false If enabled, the column will not be part of the scrollable area and is pinned to the right side
14858
14858
  * @property {Object=} info=null For storing any additional information to the column
14859
14859
  * @property {boolean=} focusable=false If enabled, the column will be used to find focusable element when pressing tab key
14860
+ * @property {string=} backgroundColor CSS color value
14860
14861
  */
14861
14862
 
14862
14863
  /** mapping of field type to javascript type
@@ -15975,6 +15976,24 @@ ColumnDefinition.prototype._setCoreColumnDef = function(obj) {
15975
15976
  ColumnDefinition.prototype.isFocusable = function() {
15976
15977
  return this._focusable;
15977
15978
  };
15979
+ /** @public
15980
+ * @return {string}
15981
+ */
15982
+ ColumnDefinition.prototype.getBackgroundColor = function() {
15983
+ let core = this._eventArg["core"];
15984
+ let grid = this._eventArg["grid"];
15985
+ let colIndex = grid.getColumnIndex(this);
15986
+ return core.getColumnBackgroundColor(colIndex);
15987
+ };
15988
+ /** @public
15989
+ * @param {string} color
15990
+ */
15991
+ ColumnDefinition.prototype.setBackgroundColor = function(color) {
15992
+ let core = this._eventArg["core"];
15993
+ let grid = this._eventArg["grid"];
15994
+ let colIndex = grid.getColumnIndex(this);
15995
+ core.setColumnBackgroundColor(colIndex, color);
15996
+ };
15978
15997
 
15979
15998
 
15980
15999
  /* harmony default export */ var js_ColumnDefinition = (ColumnDefinition);
@@ -16915,9 +16934,9 @@ GroupDefinitions.prototype.setGroup = function (groupId, groupDef) {
16915
16934
  if(curDef) { // Replace
16916
16935
  this.removeAllChildren(groupId);
16917
16936
  }
16918
- let parentDef = this._childToParent[groupId];
16919
- if(parentDef) {
16920
- newDef.parentId = parentDef.id;
16937
+ let parentId = this._childToParent[groupId];
16938
+ if(parentId) {
16939
+ newDef.parentId = parentId;
16921
16940
  }
16922
16941
  this._groupMap[groupId] = newDef;
16923
16942
 
@@ -23251,7 +23270,7 @@ Scrollbar.prototype._clearAllPanes = function() {
23251
23270
  */
23252
23271
  Scrollbar.prototype.disableKeyboardInput = function (opt_disabled) {
23253
23272
  if(opt_disabled === false) {
23254
- this._element.setAttribute("tabindex", "0");
23273
+ this._element.setAttribute("tabindex", "-1"); // tabindex makes the element focusable. The negative value exclude it from tab key navigation
23255
23274
  this._element.addEventListener("keydown", this._onKeyDown, false);
23256
23275
  } else {
23257
23276
  this._element.removeAttribute("tabindex");
@@ -35706,6 +35725,9 @@ VirtualizedLayoutGrid._proto = VirtualizedLayoutGrid.prototype;
35706
35725
  /** @event Core#preForcedUpdate
35707
35726
  * @ignore
35708
35727
  */
35728
+ /** @event Core#tabNavigation
35729
+ * @ignore
35730
+ */
35709
35731
  //#endregion Events
35710
35732
 
35711
35733
  /** @private
@@ -35716,6 +35738,44 @@ VirtualizedLayoutGrid._proto = VirtualizedLayoutGrid.prototype;
35716
35738
  let ascNumberSorter = function (a, b) {
35717
35739
  return a - b;
35718
35740
  };
35741
+ /** @private
35742
+ * @return {!Element}
35743
+ */
35744
+ let _createHiddenInput = function () {
35745
+ let hiddenInput = document.createElement("input");
35746
+ let styleObj = hiddenInput.style;
35747
+ styleObj.position = "absolute";
35748
+ styleObj.width = styleObj.height = styleObj.padding = styleObj.border = "0";
35749
+ hiddenInput.value = "0";
35750
+ return hiddenInput;
35751
+ };
35752
+ /** @private
35753
+ * @param {Object} e
35754
+ * @return {boolean}
35755
+ */
35756
+ let _isTabCommand = function (e) {
35757
+ if(e.keyCode === 9) {
35758
+ return !e.ctrlKey && !e.altKey && !e.metaKey;
35759
+ }
35760
+ return false;
35761
+ };
35762
+ /** @private
35763
+ * @param {Element} elem
35764
+ * @return {Element}
35765
+ */
35766
+ let _getActiveElement = function (elem) {
35767
+ if(elem) {
35768
+ if(elem.getRootNode) {
35769
+ let rootNode = elem.getRootNode(); // Get uncomposed root node
35770
+ if(rootNode && rootNode !== elem) { // The root node could be the element itself, if it is not attached to the DOM tree
35771
+ return rootNode.activeElement || null;
35772
+ }
35773
+ } else { // Older browser does not support getRootNode
35774
+ return document.activeElement;
35775
+ }
35776
+ }
35777
+ return null;
35778
+ };
35719
35779
 
35720
35780
  /** @constructor
35721
35781
  * @param {Element=} opt_initializer this can be either element id (string) or DOM element.
@@ -35739,6 +35799,7 @@ let Core = function (opt_initializer) {
35739
35799
  _t._onMouseMove = _t._onMouseMove.bind(_t);
35740
35800
  _t._onRowHightlighted = _t._onRowHightlighted.bind(_t);
35741
35801
  _t._onGridClicked = _t._onGridClicked.bind(_t);
35802
+ _t._onKeyDown = _t._onKeyDown.bind(_t);
35742
35803
 
35743
35804
  _t._onWindowResize = _t._onWindowResize.bind(_t);
35744
35805
  _t._onSectionDataChanged = _t._onSectionDataChanged.bind(_t);
@@ -35759,7 +35820,7 @@ let Core = function (opt_initializer) {
35759
35820
  _t._onColInViewChanged = _t._onColInViewChanged.bind(_t);
35760
35821
 
35761
35822
  _t._updateVScrollbar = _t._updateVScrollbar.bind(_t);
35762
- _t._updateColumnBounds = _t._updateColumnBounds.bind(_t);
35823
+ _t.updateColumnBounds = _t.updateColumnBounds.bind(_t);
35763
35824
  _t._dispatchColumnPositionChanged = _t._dispatchColumnPositionChanged.bind(_t);
35764
35825
  _t._dispatchRowPositionChanged = _t._dispatchRowPositionChanged.bind(_t);
35765
35826
  _t._requestScrollbarUpdate = _t._requestScrollbarUpdate.bind(_t);
@@ -35800,7 +35861,7 @@ let Core = function (opt_initializer) {
35800
35861
  // Initialize vertical scrollbar
35801
35862
  _t._vscrollbar = new components_VScrollbar();
35802
35863
  _t._vscrollbar.disable();
35803
- _t._vscrollbar.setParent(this.getParent() || this.getElement());
35864
+ _t._vscrollbar.setParent(_t.getParent() || _t.getElement());
35804
35865
 
35805
35866
  _t._vscrollbar.listen("scroll", _t._onVScroll);
35806
35867
  _t._vscrollbar.listen("layoutChanged", _t._onVScroll);
@@ -35813,25 +35874,27 @@ let Core = function (opt_initializer) {
35813
35874
  // Initialize horizontal scrollbars
35814
35875
  _t._hscrollbar = new components_HScrollbar();
35815
35876
  _t._hscrollbar.disable();
35816
- _t._hscrollbar.setParent(this.getParent() || this.getElement());
35877
+ _t._hscrollbar.setParent(_t.getParent() || _t.getElement());
35817
35878
 
35818
- _t._hscrollbar.listen("scroll", this._onHScroll);
35819
- _t._hscrollbar.listen("layoutChanged", this._onHScroll);
35820
- _t._hscrollbar.listen("activated", this.updateLayout);
35821
- _t._hscrollbar.listen("deactivated", this.updateLayout);
35879
+ _t._hscrollbar.listen("scroll", _t._onHScroll);
35880
+ _t._hscrollbar.listen("layoutChanged", _t._onHScroll);
35881
+ _t._hscrollbar.listen("activated", _t.updateLayout);
35882
+ _t._hscrollbar.listen("deactivated", _t.updateLayout);
35822
35883
 
35823
35884
  // cross-reference scrollbars
35824
35885
  _t._hscrollbar.setOtherScrollbar(_t._vscrollbar);
35825
35886
  _t._vscrollbar.setOtherScrollbar(_t._hscrollbar);
35826
35887
 
35888
+
35889
+ _t._element.addEventListener("keydown", _t._onKeyDown);
35827
35890
  if (util.isMobile || util.isTouchDevice) {
35828
- _t._element.addEventListener("touchmove", this._onMouseMove, false);
35891
+ _t._element.addEventListener("touchmove", _t._onMouseMove, false);
35829
35892
  } else {
35830
- _t._element.addEventListener("mousemove", this._onMouseMove, false);
35893
+ _t._element.addEventListener("mousemove", _t._onMouseMove, false);
35831
35894
  }
35832
35895
 
35833
35896
  if(util.isSafari){
35834
- _t._element.addEventListener("click", this._onGridClicked);
35897
+ _t._element.addEventListener("click", _t._onGridClicked);
35835
35898
  }
35836
35899
 
35837
35900
  window.addEventListener("resize", _t._onWindowResize, false); // Should be unlistened after destroyed
@@ -35839,10 +35902,17 @@ let Core = function (opt_initializer) {
35839
35902
  _t._colVirtualizer.listen("indexChanged", _t._onColInViewChanged);
35840
35903
  _t._rowHeightConflator = new util_Conflator(_t._onRowHeightChanged, 50);
35841
35904
  _t._vScrollbarConflator = new util_Conflator(_t._updateVScrollbar, 200);
35842
- _t._columnBoundConflator = new util_Conflator(_t._updateColumnBounds, 10);
35905
+ _t._columnBoundConflator = new util_Conflator(_t.updateColumnBounds, 10);
35843
35906
  _t._columnPositionConflator = new util_Conflator(_t._dispatchColumnPositionChanged, 10);
35844
35907
  _t._rowPositionConflator = new util_Conflator(_t._dispatchRowPositionChanged, 10);
35845
35908
 
35909
+ _t._firstHiddenInput = _createHiddenInput();
35910
+ _t._firstHiddenInput.className = "first-input";
35911
+ _t._lastHiddenInput = _createHiddenInput();
35912
+ _t._lastHiddenInput.className = "last-input";
35913
+ _t._element.insertBefore(_t._firstHiddenInput, _t._element.firstChild);
35914
+ _t._element.appendChild(_t._lastHiddenInput);
35915
+
35846
35916
  // Initialize events for external users
35847
35917
  _t._addEvents(
35848
35918
  "sectionAdded",
@@ -35871,7 +35941,8 @@ let Core = function (opt_initializer) {
35871
35941
  "beforeColumnBoundUpdate",
35872
35942
  "beforeBatchOperation",
35873
35943
  "afterBatchOperation",
35874
- "pinningChanged"
35944
+ "pinningChanged",
35945
+ "tabNavigation"
35875
35946
  );
35876
35947
 
35877
35948
  // For debugging in advanced optimization mode
@@ -35880,9 +35951,9 @@ let Core = function (opt_initializer) {
35880
35951
  map = {};
35881
35952
  Core["map"] = map;
35882
35953
  }
35883
- let elem = _t._element;
35884
- elem["_control"] = _t;
35885
- let id = elem.id || elem.name;
35954
+
35955
+ _t._element["_control"] = _t;
35956
+ let id = _t._element.id || _t._element.name;
35886
35957
  if(!id || map[id]) {
35887
35958
  id = "_grid" + Core._runningGridId;
35888
35959
  }
@@ -35890,17 +35961,6 @@ let Core = function (opt_initializer) {
35890
35961
  map[id] = _t;
35891
35962
  Core._runningGridId++;
35892
35963
 
35893
- // init hiddenInput for retrieve copy and cut event
35894
- let hiddenInput = document.createElement("input");
35895
- hiddenInput.style.position = "absolute";
35896
- hiddenInput.style.width = "0";
35897
- hiddenInput.style.height = "0";
35898
- hiddenInput.style.padding = "0";
35899
- hiddenInput.style.border = "0";
35900
- hiddenInput.value = "0";
35901
- _t._hiddenInput = hiddenInput;
35902
- elem.insertBefore(hiddenInput, elem.firstChild);
35903
-
35904
35964
  // Ensure all affected plugins are loaded prior zoom plugin
35905
35965
  // use as entity to trigger updateLayout once zoom is changed
35906
35966
  Object.defineProperty(_t, "zoomFactor", {
@@ -36180,11 +36240,16 @@ Core.prototype._rowRefreshTimer = 0;
36180
36240
  * @private
36181
36241
  */
36182
36242
  Core.prototype._layoutUpdating = false;
36183
- /** A Hidden input that allow to get cut and copy event when user perform cut, copy activities
36184
- * @type {Element}
36243
+ /** A hidden input that allows grid to receive keyboard input and focus
36244
+ * @type {!Element}
36245
+ * @private
36246
+ */
36247
+ Core.prototype._firstHiddenInput;
36248
+ /** A hidden input that allows grid to receive keyboard input and focus
36249
+ * @type {!Element}
36185
36250
  * @private
36186
36251
  */
36187
- Core.prototype._hiddenInput;
36252
+ Core.prototype._lastHiddenInput;
36188
36253
  /** @type {number}
36189
36254
  * @private
36190
36255
  */
@@ -36228,7 +36293,7 @@ Core.prototype._hasPendingRowChange = false;
36228
36293
  * @return {string}
36229
36294
  */
36230
36295
  Core.getVersion = function () {
36231
- return "5.1.108";
36296
+ return "5.1.112";
36232
36297
  };
36233
36298
  /** {@link ElementWrapper#dispose}
36234
36299
  * @override
@@ -36289,11 +36354,12 @@ Core.prototype.dispose = function () {
36289
36354
 
36290
36355
  // Clean Top node
36291
36356
  let elem = this._element;
36292
- if (elem !== null) {
36357
+ if (elem) {
36293
36358
  if (elem["_control"]) {
36294
36359
  delete elem["_control"];
36295
36360
  }
36296
- elem.removeChild(this._hiddenInput);
36361
+ elem.removeChild(this._firstHiddenInput);
36362
+ elem.removeChild(this._lastHiddenInput);
36297
36363
  }
36298
36364
  this._dispose();
36299
36365
 
@@ -36370,6 +36436,9 @@ Core.prototype.getConfigObject = function (gridOptions) {
36370
36436
  if (columnDef["rightPinned"]) {
36371
36437
  column["rightPinned"] = columnDef["rightPinned"];
36372
36438
  }
36439
+ if (columnDef["backgroundColor"]) {
36440
+ column["backgroundColor"] = columnDef["backgroundColor"];
36441
+ }
36373
36442
  }
36374
36443
 
36375
36444
  // It will be overwrite in rt-grid or atlas-blotter
@@ -37458,7 +37527,7 @@ Core.prototype._moveColumn = function (fromCol, destCol) {
37458
37527
  this._colVirtualizer.update();
37459
37528
  }
37460
37529
  }
37461
- this._updateColumnBounds();
37530
+ this.updateColumnBounds();
37462
37531
  this._updateColumnSeparators();
37463
37532
  return true;
37464
37533
  };
@@ -37658,6 +37727,10 @@ Core.prototype._deserializeColumn = function (index, jsonObj) {
37658
37727
  if (value != null) {
37659
37728
  colDef["rightPinned"] = value ? true : false;
37660
37729
  }
37730
+ value = jsonObj["backgroundColor"];
37731
+ if (value != null) {
37732
+ this.setColumnBackgroundColor(index, value);
37733
+ }
37661
37734
 
37662
37735
  this.setColumnRenderingHandler(index, jsonObj["renderingHandler"]);
37663
37736
  this.setColumnDataBindingHandler(index, jsonObj["dataBindingHandler"]);
@@ -37917,6 +37990,56 @@ Core.prototype.setColumnStyle = function (colIndex, style, value, opt_type) {
37917
37990
  }
37918
37991
  };
37919
37992
 
37993
+ /** @public
37994
+ * @param {number} colIndex
37995
+ * @return {string}
37996
+ */
37997
+ Core.prototype.getColumnBackgroundColor = function(colIndex) {
37998
+ let colDef = this._getColumnDef(colIndex);
37999
+ return colDef["backgroundColor"] || "";
38000
+ };
38001
+ /** @public
38002
+ * @param {number} colIndex
38003
+ * @param {string=} color
38004
+ */
38005
+ Core.prototype.setColumnBackgroundColor = function(colIndex, color) {
38006
+ if(colIndex == null || typeof colIndex !== "number") {
38007
+ return;
38008
+ }
38009
+
38010
+ let colDef = this._getColumnDef(colIndex);
38011
+ if(colDef["backgroundColor"] === color) {
38012
+ return;
38013
+ }
38014
+
38015
+ colDef["backgroundColor"] = color;
38016
+ color = color != null ? color : "";
38017
+
38018
+ let sectionCount = this._settings.length;
38019
+ for(let i = 0; i < sectionCount; ++i) {
38020
+ let settings = this._settings[i];
38021
+ let section = settings.getSection();
38022
+ if(!section) {
38023
+ continue;
38024
+ }
38025
+
38026
+ if(settings.getType() !== "content") {
38027
+ let rowCount = section.getRowCount();
38028
+ for(let r = 0; r < rowCount; r++) {
38029
+ let cellSpan = section.getCellColSpan(colIndex, r);
38030
+ if(cellSpan > 1) { continue; }
38031
+ let cell = section.getCell(colIndex, r);
38032
+ if(cell) {
38033
+ cell.setStyle("backgroundColor", color);
38034
+ }
38035
+ }
38036
+ } else {
38037
+ let column = section.getColumn(colIndex);
38038
+ column.setStyle("backgroundColor", color);
38039
+ }
38040
+ }
38041
+ };
38042
+
37920
38043
  /** @public
37921
38044
  * @param {number} colIndex
37922
38045
  * @param {string} clsName
@@ -39691,15 +39814,14 @@ Core.prototype.reserveRightSpace = function (size) {
39691
39814
  return false;
39692
39815
  };
39693
39816
 
39694
- /** Get hidden input in grid <br>
39695
- * this input for make grid can copy <br>
39696
- * normal user should not touch it <br>
39697
- * but sometime grid extension will have to use this element
39817
+ /** Get the hidden input. This input allows grid to receive keyboard input
39698
39818
  * @public
39699
- * @return {Element}
39819
+ * @ignore
39820
+ * @param {boolean} firstInput
39821
+ * @return {!Element}
39700
39822
  */
39701
- Core.prototype.getHiddenInput = function () {
39702
- return this._hiddenInput;
39823
+ Core.prototype.getHiddenInput = function (firstInput) {
39824
+ return firstInput ? this._firstHiddenInput : this._lastHiddenInput;
39703
39825
  };
39704
39826
 
39705
39827
  /** Focus grid element without bringing grid into window's view. This is useful when grid is very wide or tall, since window can be scrolled to focused element by default in some browsers.
@@ -39708,8 +39830,8 @@ Core.prototype.getHiddenInput = function () {
39708
39830
  * @see {@link http://help.dottoro.com/ljqmdirr.php}
39709
39831
  */
39710
39832
  Core.prototype.focus = function () {
39711
- let elem = this._hiddenInput;
39712
- let activeElem = document.activeElement;
39833
+ let elem = this._lastHiddenInput;
39834
+ let activeElem = _getActiveElement(elem);
39713
39835
  if(elem && elem !== activeElem) {
39714
39836
  let x = window.pageXOffset;
39715
39837
  let y = window.pageYOffset;
@@ -39840,7 +39962,7 @@ Core.prototype.selectColumn = function (colIndex, selected) {
39840
39962
  for (let i = this._settings.length; --i >= 0; ) {
39841
39963
  this._settings[i].getSection().selectColumn(colIndex, selected);
39842
39964
  }
39843
- this._updateColumnBounds();
39965
+ this.updateColumnBounds();
39844
39966
  };
39845
39967
  /** @public
39846
39968
  * @param {number} colIndex
@@ -39854,9 +39976,9 @@ Core.prototype.isSelectedColumn = function (colIndex) {
39854
39976
  return false;
39855
39977
  };
39856
39978
 
39857
- /** @private
39979
+ /** @public
39858
39980
  */
39859
- Core.prototype._updateColumnBounds = function () {
39981
+ Core.prototype.updateColumnBounds = function () {
39860
39982
  if(this._columnBoundConflator.conflate()) {
39861
39983
  return;
39862
39984
  }
@@ -40343,14 +40465,14 @@ Core.prototype._newSection = function (opt_type, sectionName) {
40343
40465
  Core.prototype._putToLast = function(section) {
40344
40466
  let sectionCount = this._settings.length;
40345
40467
  if (sectionCount === 0) {
40346
- section.setParent(this._element, true);
40468
+ section.insertBefore(this._lastHiddenInput);
40347
40469
  } else {
40348
40470
  let lastGrid = this.getLastSection();
40349
40471
  let nextSibling = lastGrid.getElement().nextSibling;
40350
40472
  if (nextSibling !== null) {
40351
40473
  section.insertBefore(nextSibling);
40352
40474
  } else {
40353
- section.setParent(this._element);
40475
+ section.insertBefore(this._lastHiddenInput);
40354
40476
  }
40355
40477
  }
40356
40478
  };
@@ -40736,7 +40858,7 @@ Core.prototype._onVScroll = function (e) {
40736
40858
  Core.prototype._onHScroll = function (e) {
40737
40859
  let scrollVal = this._hscrollbar.getScrollLeft();
40738
40860
  this._colVirtualizer.setViewOffset(scrollVal); // Trigger virtualization event
40739
- this._updateColumnBounds();
40861
+ this.updateColumnBounds();
40740
40862
  this._dispatchColumnPositionChanged();
40741
40863
  };
40742
40864
  /** @private
@@ -41035,14 +41157,44 @@ Core.prototype._onMouseMove = function () {
41035
41157
  };
41036
41158
  /** @private */
41037
41159
  Core.prototype._onGridClicked = function () {
41038
- // research for dragging
41039
41160
  let selection = window.getSelection();
41040
- if(selection.toString()){
41161
+ if(!selection.toString()){
41162
+ if(!this._element.contains(_getActiveElement(this._element))){
41163
+ this.focus();
41164
+ }
41165
+ }
41166
+ };
41167
+
41168
+ /** @private
41169
+ * @param {Object} e
41170
+ */
41171
+ Core.prototype._onKeyDown = function (e) {
41172
+ if(!_isTabCommand(e)) {
41041
41173
  return;
41042
41174
  }
41043
- let activeElem = document.activeElement;
41044
- if(!this._element.contains(activeElem)){
41045
- this.focus();
41175
+ let activeElement = _getActiveElement(this._element);
41176
+ let onTheEdge = false;
41177
+ if(this._firstHiddenInput === activeElement) {
41178
+ onTheEdge = -1;
41179
+ } else if(this._lastHiddenInput === activeElement) {
41180
+ onTheEdge = 1;
41181
+ }
41182
+
41183
+ this._dispatch("tabNavigation", {
41184
+ "activeElement": activeElement,
41185
+ "firstHiddenInput": this._firstHiddenInput,
41186
+ "lastHiddenInput": this._lastHiddenInput,
41187
+ "onTheEdge": onTheEdge,
41188
+ "shiftKey": e.shiftKey,
41189
+ "event": e
41190
+ });
41191
+
41192
+ if(onTheEdge && !e.defaultPrevented) {
41193
+ if(onTheEdge > 0 && e.shiftKey) {
41194
+ this._firstHiddenInput.focus(); // jump to the top and move out of grid
41195
+ } else if(onTheEdge < 0 && !e.shiftKey) {
41196
+ this._lastHiddenInput.focus(); // skip to the end and move out of grid
41197
+ }
41046
41198
  }
41047
41199
  };
41048
41200
 
@@ -41225,6 +41377,7 @@ Core.prototype._onSectionCountChanged = function (opt_suppressLayout) {
41225
41377
 
41226
41378
  // Reinsert sections
41227
41379
  this._vscrollbar.setScrollContent(this, this._getAllSections(), this._startVScrollbarIndex);
41380
+ this._element.appendChild(this._lastHiddenInput); // Ensure that the hidden input is always at the last position
41228
41381
 
41229
41382
  if(!opt_suppressLayout) {
41230
41383
  this._updateScrollbarHeight(true, true);
@@ -41242,7 +41395,7 @@ Core.prototype._onColumnCountChanged = function () {
41242
41395
  let pinnedLeft = this._countPinnedLeftColumns();
41243
41396
  let pinnedRight = this._countPinnedRightColumns();
41244
41397
 
41245
- this._updateColumnBounds();
41398
+ this.updateColumnBounds();
41246
41399
  this._updateColumnSeparators();
41247
41400
 
41248
41401
  if (this._hScrollbarEnabled && pinnedLeft + pinnedRight < this.getColumnCount()) {
@@ -41538,7 +41691,7 @@ Core.prototype._syncLayoutToColumns = function (from, to, opt_forceDispatching)
41538
41691
  // TODO: Check if "to" should be greater than or equal to first pinnied right index
41539
41692
  let paneChanged = forceUpdate || (from < this.getHScrollStartIndex()) || (to > this.getFirstPinnedRightIndex());
41540
41693
  this._updateScrollbarWidth(paneChanged, true /* contentChanged */);
41541
- this._updateColumnBounds();
41694
+ this.updateColumnBounds();
41542
41695
  this._updateColumnSeparators();
41543
41696
  this._dispatchColumnPositionChanged();
41544
41697
 
@@ -44728,7 +44881,7 @@ let Grid = function(placeholder, config) {
44728
44881
  t._snapshotFillerDataChanged = t._snapshotFillerDataChanged.bind(t);
44729
44882
  t._onPollingInterval = t._onPollingInterval.bind(t);
44730
44883
 
44731
- t._onKeyDown = t._onKeyDown.bind(t);
44884
+ t._onTabNavigation = t._onTabNavigation.bind(t);
44732
44885
  t._requestScroll = t._requestScroll.bind(t);
44733
44886
  t._onVScroll = t._onVScroll.bind(t);
44734
44887
  t._selfScrollToRow = t._selfScrollToRow.bind(t);
@@ -44811,10 +44964,9 @@ let Grid = function(placeholder, config) {
44811
44964
  t._grid.listen("postSectionDataBinding", t._onPostSectionDataBinding);
44812
44965
  t._grid.listen("firstRendered", t._dispatch.bind(t, "firstRendered"));
44813
44966
  t._grid.listen("afterContentBinding", t._dispatch.bind(t, "afterContentBinding"));
44814
- t._grid.listen("keydown", t._onKeyDown);
44967
+ t._grid.listen("tabNavigation", t._onTabNavigation);
44815
44968
 
44816
44969
  t._grid.getVScrollbar().listen("scroll", t._onVScroll);
44817
- t._hiddenInput = t._grid.getHiddenInput();
44818
44970
 
44819
44971
  t._grid.enableRowHighlighting(true);
44820
44972
 
@@ -45041,8 +45193,10 @@ Grid.prototype.dispose = function() {
45041
45193
  this._subs = null;
45042
45194
  }
45043
45195
 
45044
- if(this._focusingArgs && this._focusingArgs.id) {
45045
- clearTimeout(this._focusingArgs.id);
45196
+ if(this._focusingArgs) {
45197
+ if(this._focusingArgs.id) {
45198
+ clearTimeout(this._focusingArgs.id);
45199
+ }
45046
45200
  this._focusingArgs = null;
45047
45201
  }
45048
45202
  };
@@ -46576,6 +46730,27 @@ Grid.prototype.setColumnName = function(colIndex, str) {
46576
46730
  };
46577
46731
  /** @public
46578
46732
  * @param {Grid~ColumnReference} colRef
46733
+ * @return {string}
46734
+ */
46735
+ Grid.prototype.getColumnBackgroundColor = function(colRef) {
46736
+ let colDef = this.getColumnDefinition(colRef);
46737
+ if(colDef) {
46738
+ return colDef.getBackgroundColor();
46739
+ }
46740
+ return "";
46741
+ };
46742
+ /** @public
46743
+ * @param {Grid~ColumnReference} colRef
46744
+ * @param {string} color
46745
+ */
46746
+ Grid.prototype.setColumnBackgroundColor = function(colRef, color) {
46747
+ let colDef = this.getColumnDefinition(colRef);
46748
+ if(colDef) {
46749
+ colDef.setBackgroundColor(color);
46750
+ }
46751
+ };
46752
+ /** @public
46753
+ * @param {Grid~ColumnReference} colRef
46579
46754
  * @param {Function=} func
46580
46755
  */
46581
46756
  Grid.prototype.setColumnRenderer = function(colRef, func) {
@@ -48530,16 +48705,11 @@ Grid.prototype.getVScrollView = function () {
48530
48705
  * @param {Element} el
48531
48706
  * @return {boolean}
48532
48707
  */
48533
- function isValidInput(el) {
48534
- return el && el.tagName !== "SPAN" && !el.disabled;
48535
- }
48536
- /** @private
48537
- * @param {Element} el
48538
- * @param {Element} hiddenInput
48539
- * @return {boolean}
48540
- */
48541
- function isValidTarget(el, hiddenInput) {
48542
- return !el.classList.contains("valigner") && el !== hiddenInput;
48708
+ function isFocusableContent(el) {
48709
+ if(el) {
48710
+ return (el.tagName !== "SPAN" && !el.disabled);
48711
+ }
48712
+ return false;
48543
48713
  }
48544
48714
  /** @private
48545
48715
  * @param {Object} cell
@@ -48548,7 +48718,7 @@ function isValidTarget(el, hiddenInput) {
48548
48718
  function focusCell(cell) {
48549
48719
  if(cell) {
48550
48720
  let cellContent = cell.getContent();
48551
- if(cellContent && isValidInput(cellContent)) {
48721
+ if(cellContent && isFocusableContent(cellContent)) {
48552
48722
  cellContent.focus();
48553
48723
  return true;
48554
48724
  }
@@ -48559,18 +48729,15 @@ function focusCell(cell) {
48559
48729
  */
48560
48730
  Grid.prototype._onVScroll = function() {
48561
48731
  let args = this._focusingArgs;
48562
- if(!args) { return; }
48563
-
48564
- this._focusingArgs = null;
48565
- let event = args.event;
48566
- let cell = args.section.getCell(args.colIndex, args.rowIndex);
48567
- if(focusCell(cell)) {
48568
- event.preventDefault();
48569
- } else {
48570
- if(event.shiftKey) {
48571
- this._findPrevFocusableCell(event, args.colIndex, args.rowIndex, args.focusableColIndices);
48572
- } else {
48573
- this._findNextFocusableCell(event, args.colIndex, args.rowIndex, args.focusableColIndices);
48732
+ if(args) {
48733
+ this._focusingArgs = null;
48734
+ let cell = this._grid.getCell("content", args.colIndex, args.rowIndex);
48735
+ if(!focusCell(cell)) {
48736
+ if(args.shiftKey) {
48737
+ this._focusPrevCellContent(args);
48738
+ } else {
48739
+ this._focusNextCellContent(args);
48740
+ }
48574
48741
  }
48575
48742
  }
48576
48743
  };
@@ -48578,89 +48745,108 @@ Grid.prototype._onVScroll = function() {
48578
48745
  */
48579
48746
  Grid.prototype._selfScrollToRow = function() {
48580
48747
  let args = this._focusingArgs;
48581
- if(!args) { return; }
48582
- args.id = 0;
48583
- this.scrollToRow(args.rowIndex);
48748
+ if(args) {
48749
+ args.id = 0;
48750
+ this.scrollToRow(args.rowIndex);
48751
+ }
48584
48752
  };
48585
48753
  /** @private
48586
- * @param {Object} e
48754
+ * @param {Object} args
48587
48755
  * @param {number} colIndex
48588
48756
  * @param {number} rowIndex
48589
- * @param {Array} focusableColIndices
48590
- * @param {Object} section
48591
48757
  */
48592
- Grid.prototype._requestScroll = function(e, colIndex, rowIndex, focusableColIndices, section) {
48593
- let args = this._focusingArgs;
48594
- if(args) { return; }
48595
- if(this._scrolledRow === rowIndex) { return; } // Avoid infinite loop
48596
-
48597
- this._scrolledRow = rowIndex;
48598
- args = this._focusingArgs = {
48599
- event: e,
48600
- colIndex: colIndex,
48601
- rowIndex: rowIndex,
48602
- focusableColIndices: focusableColIndices,
48603
- section: section
48604
- };
48758
+ Grid.prototype._requestScroll = function(args, colIndex, rowIndex) {
48759
+ if(this._focusingArgs || this._scrolledRow === args.rowIndex) {
48760
+ return; // Avoid infinite loop
48761
+ }
48605
48762
 
48763
+ this._scrolledRow = args.rowIndex;
48764
+ this._focusingArgs = args;
48765
+ args.colIndex = colIndex;
48766
+ args.rowIndex = rowIndex;
48767
+ args.event = null; // The event is invalid after the scroll
48606
48768
  args.id = setTimeout(this._selfScrollToRow); // Avoid event loop protection
48607
48769
  };
48608
48770
  /** @private
48609
- * @param {Object} e
48610
- * @param {number} colIndex
48611
- * @param {number} rowIndex
48612
- * @param {Array} focusableColIndices
48613
- * @param {Element=} content
48771
+ * @param {Object} args
48614
48772
  */
48615
- Grid.prototype._findNextFocusableCell = function(e, colIndex, rowIndex, focusableColIndices, content) {
48616
- let startIdx = focusableColIndices.indexOf(colIndex);
48773
+ Grid.prototype._focusNextCellContent = function(args) {
48774
+ let colIndex = args.colIndex;
48775
+ let rowIndex = args.rowIndex;
48776
+ if(rowIndex < 0 || rowIndex == null) {
48777
+ return;
48778
+ }
48617
48779
 
48618
- // Calculate starting row and column index
48619
- if(!isValidTarget(e.target, this._hiddenInput) || startIdx < 0) {
48620
- rowIndex = 0;
48621
- startIdx = 0;
48622
- } else if(isValidInput(content) && startIdx >= 0) {
48780
+ let focusableColIndices = args.focusableColIndices;
48781
+ let len = focusableColIndices.length;
48782
+ let startIdx = 0;
48783
+ let i;
48784
+ if(colIndex >= 0) {
48785
+ for(i = 1; i < len; i++) {
48786
+ if(colIndex < focusableColIndices[i]) {
48787
+ break;
48788
+ }
48789
+ startIdx = i;
48790
+ }
48791
+ }
48792
+ // If the current focus is on a valid content, starts on the next cell
48793
+ if(args.event && args.validContent) {
48623
48794
  startIdx++;
48624
48795
  }
48796
+
48625
48797
  let grid = this._grid;
48626
48798
  let section = grid.getSection("content");
48627
48799
  let viewInfo = grid.getVerticalViewInfo();
48628
48800
  let bottomRowIndex = viewInfo.bottomRowIndex;
48629
48801
  let rowCount = this.getRowCount();
48630
48802
  for(let r = rowIndex; r < rowCount; r++) {
48631
- for(let i = startIdx; i < focusableColIndices.length; i++) {
48803
+ for(i = startIdx; i < len; i++) {
48632
48804
  let c = focusableColIndices[i];
48633
48805
  if(r > bottomRowIndex) {
48634
- this._requestScroll(e, c, r, focusableColIndices, section);
48806
+ this._requestScroll(args, c, r);
48635
48807
  return;
48636
48808
  } else {
48637
48809
  let cell = section.getCell(c, r);
48638
48810
  if(focusCell(cell)) {
48639
- e.preventDefault();
48811
+ if(args.event) {
48812
+ args.event.preventDefault();
48813
+ }
48640
48814
  return;
48641
48815
  }
48642
48816
  }
48643
48817
  }
48644
48818
  startIdx = 0;
48645
48819
  }
48820
+
48821
+ if(args.validContent) { // The current focus on the last focusable content
48822
+ this._grid.getHiddenInput().focus();
48823
+ }
48646
48824
  };
48647
48825
  /** @private
48648
- * @param {Object} e
48649
- * @param {number} colIndex
48650
- * @param {number} rowIndex
48651
- * @param {Array} focusableColIndices
48652
- * @param {Element=} content
48826
+ * @param {Object} args
48653
48827
  */
48654
- Grid.prototype._findPrevFocusableCell = function(e, colIndex, rowIndex, focusableColIndices, content) {
48655
- let startIdx = focusableColIndices.indexOf(colIndex);
48656
- let len = focusableColIndices.length;
48828
+ Grid.prototype._focusPrevCellContent = function(args) {
48829
+ let colIndex = args.colIndex;
48830
+ let rowIndex = args.rowIndex;
48831
+ if(rowIndex < 0 || rowIndex == null) {
48832
+ return;
48833
+ }
48657
48834
 
48658
- // Calculate starting row and column index
48659
- if(!isValidTarget(e.target, this._hiddenInput) || startIdx < 0) {
48660
- rowIndex = 0;
48661
- startIdx = 0;
48662
- } else if(isValidInput(content) && startIdx >= 0) {
48663
- startIdx--;
48835
+ let focusableColIndices = args.focusableColIndices;
48836
+ let len = focusableColIndices.length;
48837
+ let startIdx = len - 1;
48838
+ let i;
48839
+ if(colIndex >= 0) {
48840
+ for(i = len - 1; --i >= 0;) {
48841
+ if(colIndex > focusableColIndices[i]) {
48842
+ break;
48843
+ }
48844
+ startIdx = i;
48845
+ }
48846
+ }
48847
+ // If the current focus is on a valid content, starts on the next cell
48848
+ if(args.event && args.validContent) {
48849
+ --startIdx;
48664
48850
  }
48665
48851
 
48666
48852
  let grid = this._grid;
@@ -48668,32 +48854,33 @@ Grid.prototype._findPrevFocusableCell = function(e, colIndex, rowIndex, focusabl
48668
48854
  let viewInfo = grid.getVerticalViewInfo();
48669
48855
  let topRowIndex = viewInfo.topRowIndex;
48670
48856
  for(let r = rowIndex; r >= 0; r--) {
48671
- for(let i = startIdx; i >= 0; i--) {
48857
+ for(i = startIdx; i >= 0; i--) {
48672
48858
  let c = focusableColIndices[i];
48673
48859
  if(r < topRowIndex) {
48674
- this._requestScroll(e, c, r, focusableColIndices, section);
48860
+ this._requestScroll(args, c, r);
48675
48861
  return;
48676
48862
  } else {
48677
48863
  let cell = section.getCell(c, r);
48678
48864
  if(focusCell(cell)) {
48679
- e.preventDefault();
48865
+ if(args.event) {
48866
+ args.event.preventDefault();
48867
+ }
48680
48868
  return;
48681
48869
  }
48682
48870
  }
48683
48871
  }
48684
48872
  startIdx = len - 1;
48685
48873
  }
48874
+
48875
+ if(args.validContent) { // The current focus on the last focusable content
48876
+ this._grid.getHiddenInput(true).focus();
48877
+ }
48686
48878
  };
48687
48879
 
48688
48880
  /** @private
48689
48881
  * @param {Object} e
48690
48882
  */
48691
- Grid.prototype._onKeyDown = function(e) {
48692
- if (e.keyCode !== 9 || e.ctrlKey || e.altKey || e.metaKey) {
48693
- return;
48694
- }
48695
-
48696
- // Find next focusable cell
48883
+ Grid.prototype._onTabNavigation = function(e) {
48697
48884
  let colDefs = this.getColumnDefinitions();
48698
48885
  let colCount = colDefs.length;
48699
48886
 
@@ -48709,13 +48896,36 @@ Grid.prototype._onKeyDown = function(e) {
48709
48896
  }
48710
48897
 
48711
48898
  this._scrolledRow = -1; // Reset the scroll loop protector
48712
- let pos = this.getRelativePosition(e);
48713
- let content = pos["cell"] ? pos["cell"].getContent() : null;
48899
+ let keyEvt = e.event;
48900
+ let pos = this.getRelativePosition(keyEvt);
48901
+ let validContent = true;
48902
+ let activeElement = e.activeElement;
48903
+ if(activeElement) {
48904
+ validContent = !activeElement.classList.contains("valigner");
48905
+ }
48906
+
48907
+ if(validContent) {
48908
+ let content = pos["cell"] ? pos["cell"].getContent() : null;
48909
+ validContent = isFocusableContent(content);
48910
+ }
48911
+ let startingRowIndex = pos["rowIndex"];
48912
+ if(e.onTheEdge) {
48913
+ let viewInfo = this._grid.getVScrollView();
48914
+ startingRowIndex = keyEvt.shiftKey ? viewInfo.lastFullRow : viewInfo.firstFullRow;
48915
+ }
48916
+ let args = {
48917
+ event: keyEvt,
48918
+ shiftKey: keyEvt.shiftKey,
48919
+ colIndex: pos["colIndex"],
48920
+ rowIndex: startingRowIndex,
48921
+ focusableColIndices: focusableColIndices,
48922
+ validContent: validContent
48923
+ };
48714
48924
 
48715
- if(e.shiftKey) {
48716
- this._findPrevFocusableCell(e, pos["colIndex"], pos["rowIndex"], focusableColIndices, content);
48925
+ if(keyEvt.shiftKey) {
48926
+ this._focusPrevCellContent(args);
48717
48927
  } else {
48718
- this._findNextFocusableCell(e, pos["colIndex"], pos["rowIndex"], focusableColIndices, content);
48928
+ this._focusNextCellContent(args);
48719
48929
  }
48720
48930
  };
48721
48931