@refinitiv-ui/efx-grid 6.0.107 → 6.0.109

Sign up to get free protection for your applications and to get access to all the features.
@@ -6854,7 +6854,7 @@ Scrollbar.prototype._clearAllPanes = function() {
6854
6854
  */
6855
6855
  Scrollbar.prototype.disableKeyboardInput = function (opt_disabled) {
6856
6856
  if(opt_disabled === false) {
6857
- this._element.setAttribute("tabindex", "0");
6857
+ this._element.setAttribute("tabindex", "-1"); // tabindex makes the element focusable. The negative value exclude it from tab key navigation
6858
6858
  this._element.addEventListener("keydown", this._onKeyDown, false);
6859
6859
  } else {
6860
6860
  this._element.removeAttribute("tabindex");
@@ -25142,6 +25142,9 @@ VirtualizedLayoutGrid._proto = VirtualizedLayoutGrid.prototype;
25142
25142
  /** @event Core#preForcedUpdate
25143
25143
  * @ignore
25144
25144
  */
25145
+ /** @event Core#tabNavigation
25146
+ * @ignore
25147
+ */
25145
25148
  //#endregion Events
25146
25149
 
25147
25150
  /** @private
@@ -25152,6 +25155,44 @@ VirtualizedLayoutGrid._proto = VirtualizedLayoutGrid.prototype;
25152
25155
  let ascNumberSorter = function (a, b) {
25153
25156
  return a - b;
25154
25157
  };
25158
+ /** @private
25159
+ * @return {!Element}
25160
+ */
25161
+ let _createHiddenInput = function () {
25162
+ let hiddenInput = document.createElement("input");
25163
+ let styleObj = hiddenInput.style;
25164
+ styleObj.position = "absolute";
25165
+ styleObj.width = styleObj.height = styleObj.padding = styleObj.border = "0";
25166
+ hiddenInput.value = "0";
25167
+ return hiddenInput;
25168
+ };
25169
+ /** @private
25170
+ * @param {Object} e
25171
+ * @return {boolean}
25172
+ */
25173
+ let _isTabCommand = function (e) {
25174
+ if(e.keyCode === 9) {
25175
+ return !e.ctrlKey && !e.altKey && !e.metaKey;
25176
+ }
25177
+ return false;
25178
+ };
25179
+ /** @private
25180
+ * @param {Element} elem
25181
+ * @return {Element}
25182
+ */
25183
+ let _getActiveElement = function (elem) {
25184
+ if(elem) {
25185
+ if(elem.getRootNode) {
25186
+ let rootNode = elem.getRootNode(); // Get uncomposed root node
25187
+ if(rootNode && rootNode !== elem) { // The root node could be the element itself, if it is not attached to the DOM tree
25188
+ return rootNode.activeElement || null;
25189
+ }
25190
+ } else { // Older browser does not support getRootNode
25191
+ return document.activeElement;
25192
+ }
25193
+ }
25194
+ return null;
25195
+ };
25155
25196
 
25156
25197
  /** @constructor
25157
25198
  * @param {Element=} opt_initializer this can be either element id (string) or DOM element.
@@ -25175,6 +25216,7 @@ let Core_Core = function (opt_initializer) {
25175
25216
  _t._onMouseMove = _t._onMouseMove.bind(_t);
25176
25217
  _t._onRowHightlighted = _t._onRowHightlighted.bind(_t);
25177
25218
  _t._onGridClicked = _t._onGridClicked.bind(_t);
25219
+ _t._onKeyDown = _t._onKeyDown.bind(_t);
25178
25220
 
25179
25221
  _t._onWindowResize = _t._onWindowResize.bind(_t);
25180
25222
  _t._onSectionDataChanged = _t._onSectionDataChanged.bind(_t);
@@ -25195,7 +25237,7 @@ let Core_Core = function (opt_initializer) {
25195
25237
  _t._onColInViewChanged = _t._onColInViewChanged.bind(_t);
25196
25238
 
25197
25239
  _t._updateVScrollbar = _t._updateVScrollbar.bind(_t);
25198
- _t._updateColumnBounds = _t._updateColumnBounds.bind(_t);
25240
+ _t.updateColumnBounds = _t.updateColumnBounds.bind(_t);
25199
25241
  _t._dispatchColumnPositionChanged = _t._dispatchColumnPositionChanged.bind(_t);
25200
25242
  _t._dispatchRowPositionChanged = _t._dispatchRowPositionChanged.bind(_t);
25201
25243
  _t._requestScrollbarUpdate = _t._requestScrollbarUpdate.bind(_t);
@@ -25236,7 +25278,7 @@ let Core_Core = function (opt_initializer) {
25236
25278
  // Initialize vertical scrollbar
25237
25279
  _t._vscrollbar = new components_VScrollbar();
25238
25280
  _t._vscrollbar.disable();
25239
- _t._vscrollbar.setParent(this.getParent() || this.getElement());
25281
+ _t._vscrollbar.setParent(_t.getParent() || _t.getElement());
25240
25282
 
25241
25283
  _t._vscrollbar.listen("scroll", _t._onVScroll);
25242
25284
  _t._vscrollbar.listen("layoutChanged", _t._onVScroll);
@@ -25249,25 +25291,27 @@ let Core_Core = function (opt_initializer) {
25249
25291
  // Initialize horizontal scrollbars
25250
25292
  _t._hscrollbar = new components_HScrollbar();
25251
25293
  _t._hscrollbar.disable();
25252
- _t._hscrollbar.setParent(this.getParent() || this.getElement());
25294
+ _t._hscrollbar.setParent(_t.getParent() || _t.getElement());
25253
25295
 
25254
- _t._hscrollbar.listen("scroll", this._onHScroll);
25255
- _t._hscrollbar.listen("layoutChanged", this._onHScroll);
25256
- _t._hscrollbar.listen("activated", this.updateLayout);
25257
- _t._hscrollbar.listen("deactivated", this.updateLayout);
25296
+ _t._hscrollbar.listen("scroll", _t._onHScroll);
25297
+ _t._hscrollbar.listen("layoutChanged", _t._onHScroll);
25298
+ _t._hscrollbar.listen("activated", _t.updateLayout);
25299
+ _t._hscrollbar.listen("deactivated", _t.updateLayout);
25258
25300
 
25259
25301
  // cross-reference scrollbars
25260
25302
  _t._hscrollbar.setOtherScrollbar(_t._vscrollbar);
25261
25303
  _t._vscrollbar.setOtherScrollbar(_t._hscrollbar);
25262
25304
 
25305
+
25306
+ _t._element.addEventListener("keydown", _t._onKeyDown);
25263
25307
  if (util.isMobile || util.isTouchDevice) {
25264
- _t._element.addEventListener("touchmove", this._onMouseMove, false);
25308
+ _t._element.addEventListener("touchmove", _t._onMouseMove, false);
25265
25309
  } else {
25266
- _t._element.addEventListener("mousemove", this._onMouseMove, false);
25310
+ _t._element.addEventListener("mousemove", _t._onMouseMove, false);
25267
25311
  }
25268
25312
 
25269
25313
  if(util.isSafari){
25270
- _t._element.addEventListener("click", this._onGridClicked);
25314
+ _t._element.addEventListener("click", _t._onGridClicked);
25271
25315
  }
25272
25316
 
25273
25317
  window.addEventListener("resize", _t._onWindowResize, false); // Should be unlistened after destroyed
@@ -25275,10 +25319,17 @@ let Core_Core = function (opt_initializer) {
25275
25319
  _t._colVirtualizer.listen("indexChanged", _t._onColInViewChanged);
25276
25320
  _t._rowHeightConflator = new util_Conflator(_t._onRowHeightChanged, 50);
25277
25321
  _t._vScrollbarConflator = new util_Conflator(_t._updateVScrollbar, 200);
25278
- _t._columnBoundConflator = new util_Conflator(_t._updateColumnBounds, 10);
25322
+ _t._columnBoundConflator = new util_Conflator(_t.updateColumnBounds, 10);
25279
25323
  _t._columnPositionConflator = new util_Conflator(_t._dispatchColumnPositionChanged, 10);
25280
25324
  _t._rowPositionConflator = new util_Conflator(_t._dispatchRowPositionChanged, 10);
25281
25325
 
25326
+ _t._firstHiddenInput = _createHiddenInput();
25327
+ _t._firstHiddenInput.className = "first-input";
25328
+ _t._lastHiddenInput = _createHiddenInput();
25329
+ _t._lastHiddenInput.className = "last-input";
25330
+ _t._element.insertBefore(_t._firstHiddenInput, _t._element.firstChild);
25331
+ _t._element.appendChild(_t._lastHiddenInput);
25332
+
25282
25333
  // Initialize events for external users
25283
25334
  _t._addEvents(
25284
25335
  "sectionAdded",
@@ -25307,7 +25358,8 @@ let Core_Core = function (opt_initializer) {
25307
25358
  "beforeColumnBoundUpdate",
25308
25359
  "beforeBatchOperation",
25309
25360
  "afterBatchOperation",
25310
- "pinningChanged"
25361
+ "pinningChanged",
25362
+ "tabNavigation"
25311
25363
  );
25312
25364
 
25313
25365
  // For debugging in advanced optimization mode
@@ -25316,9 +25368,9 @@ let Core_Core = function (opt_initializer) {
25316
25368
  map = {};
25317
25369
  Core_Core["map"] = map;
25318
25370
  }
25319
- let elem = _t._element;
25320
- elem["_control"] = _t;
25321
- let id = elem.id || elem.name;
25371
+
25372
+ _t._element["_control"] = _t;
25373
+ let id = _t._element.id || _t._element.name;
25322
25374
  if(!id || map[id]) {
25323
25375
  id = "_grid" + Core_Core._runningGridId;
25324
25376
  }
@@ -25326,17 +25378,6 @@ let Core_Core = function (opt_initializer) {
25326
25378
  map[id] = _t;
25327
25379
  Core_Core._runningGridId++;
25328
25380
 
25329
- // init hiddenInput for retrieve copy and cut event
25330
- let hiddenInput = document.createElement("input");
25331
- hiddenInput.style.position = "absolute";
25332
- hiddenInput.style.width = "0";
25333
- hiddenInput.style.height = "0";
25334
- hiddenInput.style.padding = "0";
25335
- hiddenInput.style.border = "0";
25336
- hiddenInput.value = "0";
25337
- _t._hiddenInput = hiddenInput;
25338
- elem.insertBefore(hiddenInput, elem.firstChild);
25339
-
25340
25381
  // Ensure all affected plugins are loaded prior zoom plugin
25341
25382
  // use as entity to trigger updateLayout once zoom is changed
25342
25383
  Object.defineProperty(_t, "zoomFactor", {
@@ -25616,11 +25657,16 @@ Core_Core.prototype._rowRefreshTimer = 0;
25616
25657
  * @private
25617
25658
  */
25618
25659
  Core_Core.prototype._layoutUpdating = false;
25619
- /** A Hidden input that allow to get cut and copy event when user perform cut, copy activities
25620
- * @type {Element}
25660
+ /** A hidden input that allows grid to receive keyboard input and focus
25661
+ * @type {!Element}
25662
+ * @private
25663
+ */
25664
+ Core_Core.prototype._firstHiddenInput;
25665
+ /** A hidden input that allows grid to receive keyboard input and focus
25666
+ * @type {!Element}
25621
25667
  * @private
25622
25668
  */
25623
- Core_Core.prototype._hiddenInput;
25669
+ Core_Core.prototype._lastHiddenInput;
25624
25670
  /** @type {number}
25625
25671
  * @private
25626
25672
  */
@@ -25664,7 +25710,7 @@ Core_Core.prototype._hasPendingRowChange = false;
25664
25710
  * @return {string}
25665
25711
  */
25666
25712
  Core_Core.getVersion = function () {
25667
- return "5.1.108";
25713
+ return "5.1.111";
25668
25714
  };
25669
25715
  /** {@link ElementWrapper#dispose}
25670
25716
  * @override
@@ -25725,11 +25771,12 @@ Core_Core.prototype.dispose = function () {
25725
25771
 
25726
25772
  // Clean Top node
25727
25773
  let elem = this._element;
25728
- if (elem !== null) {
25774
+ if (elem) {
25729
25775
  if (elem["_control"]) {
25730
25776
  delete elem["_control"];
25731
25777
  }
25732
- elem.removeChild(this._hiddenInput);
25778
+ elem.removeChild(this._firstHiddenInput);
25779
+ elem.removeChild(this._lastHiddenInput);
25733
25780
  }
25734
25781
  this._dispose();
25735
25782
 
@@ -26894,7 +26941,7 @@ Core_Core.prototype._moveColumn = function (fromCol, destCol) {
26894
26941
  this._colVirtualizer.update();
26895
26942
  }
26896
26943
  }
26897
- this._updateColumnBounds();
26944
+ this.updateColumnBounds();
26898
26945
  this._updateColumnSeparators();
26899
26946
  return true;
26900
26947
  };
@@ -29127,15 +29174,14 @@ Core_Core.prototype.reserveRightSpace = function (size) {
29127
29174
  return false;
29128
29175
  };
29129
29176
 
29130
- /** Get hidden input in grid <br>
29131
- * this input for make grid can copy <br>
29132
- * normal user should not touch it <br>
29133
- * but sometime grid extension will have to use this element
29177
+ /** Get the hidden input. This input allows grid to receive keyboard input
29134
29178
  * @public
29135
- * @return {Element}
29179
+ * @ignore
29180
+ * @param {boolean} firstInput
29181
+ * @return {!Element}
29136
29182
  */
29137
- Core_Core.prototype.getHiddenInput = function () {
29138
- return this._hiddenInput;
29183
+ Core_Core.prototype.getHiddenInput = function (firstInput) {
29184
+ return firstInput ? this._firstHiddenInput : this._lastHiddenInput;
29139
29185
  };
29140
29186
 
29141
29187
  /** 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.
@@ -29144,8 +29190,8 @@ Core_Core.prototype.getHiddenInput = function () {
29144
29190
  * @see {@link http://help.dottoro.com/ljqmdirr.php}
29145
29191
  */
29146
29192
  Core_Core.prototype.focus = function () {
29147
- let elem = this._hiddenInput;
29148
- let activeElem = document.activeElement;
29193
+ let elem = this._lastHiddenInput;
29194
+ let activeElem = _getActiveElement(elem);
29149
29195
  if(elem && elem !== activeElem) {
29150
29196
  let x = window.pageXOffset;
29151
29197
  let y = window.pageYOffset;
@@ -29276,7 +29322,7 @@ Core_Core.prototype.selectColumn = function (colIndex, selected) {
29276
29322
  for (let i = this._settings.length; --i >= 0; ) {
29277
29323
  this._settings[i].getSection().selectColumn(colIndex, selected);
29278
29324
  }
29279
- this._updateColumnBounds();
29325
+ this.updateColumnBounds();
29280
29326
  };
29281
29327
  /** @public
29282
29328
  * @param {number} colIndex
@@ -29290,9 +29336,9 @@ Core_Core.prototype.isSelectedColumn = function (colIndex) {
29290
29336
  return false;
29291
29337
  };
29292
29338
 
29293
- /** @private
29339
+ /** @public
29294
29340
  */
29295
- Core_Core.prototype._updateColumnBounds = function () {
29341
+ Core_Core.prototype.updateColumnBounds = function () {
29296
29342
  if(this._columnBoundConflator.conflate()) {
29297
29343
  return;
29298
29344
  }
@@ -29779,14 +29825,14 @@ Core_Core.prototype._newSection = function (opt_type, sectionName) {
29779
29825
  Core_Core.prototype._putToLast = function(section) {
29780
29826
  let sectionCount = this._settings.length;
29781
29827
  if (sectionCount === 0) {
29782
- section.setParent(this._element, true);
29828
+ section.insertBefore(this._lastHiddenInput);
29783
29829
  } else {
29784
29830
  let lastGrid = this.getLastSection();
29785
29831
  let nextSibling = lastGrid.getElement().nextSibling;
29786
29832
  if (nextSibling !== null) {
29787
29833
  section.insertBefore(nextSibling);
29788
29834
  } else {
29789
- section.setParent(this._element);
29835
+ section.insertBefore(this._lastHiddenInput);
29790
29836
  }
29791
29837
  }
29792
29838
  };
@@ -30172,7 +30218,7 @@ Core_Core.prototype._onVScroll = function (e) {
30172
30218
  Core_Core.prototype._onHScroll = function (e) {
30173
30219
  let scrollVal = this._hscrollbar.getScrollLeft();
30174
30220
  this._colVirtualizer.setViewOffset(scrollVal); // Trigger virtualization event
30175
- this._updateColumnBounds();
30221
+ this.updateColumnBounds();
30176
30222
  this._dispatchColumnPositionChanged();
30177
30223
  };
30178
30224
  /** @private
@@ -30471,14 +30517,44 @@ Core_Core.prototype._onMouseMove = function () {
30471
30517
  };
30472
30518
  /** @private */
30473
30519
  Core_Core.prototype._onGridClicked = function () {
30474
- // research for dragging
30475
30520
  let selection = window.getSelection();
30476
- if(selection.toString()){
30521
+ if(!selection.toString()){
30522
+ if(!this._element.contains(_getActiveElement(this._element))){
30523
+ this.focus();
30524
+ }
30525
+ }
30526
+ };
30527
+
30528
+ /** @private
30529
+ * @param {Object} e
30530
+ */
30531
+ Core_Core.prototype._onKeyDown = function (e) {
30532
+ if(!_isTabCommand(e)) {
30477
30533
  return;
30478
30534
  }
30479
- let activeElem = document.activeElement;
30480
- if(!this._element.contains(activeElem)){
30481
- this.focus();
30535
+ let activeElement = _getActiveElement(this._element);
30536
+ let onTheEdge = false;
30537
+ if(this._firstHiddenInput === activeElement) {
30538
+ onTheEdge = -1;
30539
+ } else if(this._lastHiddenInput === activeElement) {
30540
+ onTheEdge = 1;
30541
+ }
30542
+
30543
+ this._dispatch("tabNavigation", {
30544
+ "activeElement": activeElement,
30545
+ "firstHiddenInput": this._firstHiddenInput,
30546
+ "lastHiddenInput": this._lastHiddenInput,
30547
+ "onTheEdge": onTheEdge,
30548
+ "shiftKey": e.shiftKey,
30549
+ "event": e
30550
+ });
30551
+
30552
+ if(onTheEdge && !e.defaultPrevented) {
30553
+ if(onTheEdge > 0 && e.shiftKey) {
30554
+ this._firstHiddenInput.focus(); // jump to the top and move out of grid
30555
+ } else if(onTheEdge < 0 && !e.shiftKey) {
30556
+ this._lastHiddenInput.focus(); // skip to the end and move out of grid
30557
+ }
30482
30558
  }
30483
30559
  };
30484
30560
 
@@ -30661,6 +30737,7 @@ Core_Core.prototype._onSectionCountChanged = function (opt_suppressLayout) {
30661
30737
 
30662
30738
  // Reinsert sections
30663
30739
  this._vscrollbar.setScrollContent(this, this._getAllSections(), this._startVScrollbarIndex);
30740
+ this._element.appendChild(this._lastHiddenInput); // Ensure that the hidden input is always at the last position
30664
30741
 
30665
30742
  if(!opt_suppressLayout) {
30666
30743
  this._updateScrollbarHeight(true, true);
@@ -30678,7 +30755,7 @@ Core_Core.prototype._onColumnCountChanged = function () {
30678
30755
  let pinnedLeft = this._countPinnedLeftColumns();
30679
30756
  let pinnedRight = this._countPinnedRightColumns();
30680
30757
 
30681
- this._updateColumnBounds();
30758
+ this.updateColumnBounds();
30682
30759
  this._updateColumnSeparators();
30683
30760
 
30684
30761
  if (this._hScrollbarEnabled && pinnedLeft + pinnedRight < this.getColumnCount()) {
@@ -30974,7 +31051,7 @@ Core_Core.prototype._syncLayoutToColumns = function (from, to, opt_forceDispatch
30974
31051
  // TODO: Check if "to" should be greater than or equal to first pinnied right index
30975
31052
  let paneChanged = forceUpdate || (from < this.getHScrollStartIndex()) || (to > this.getFirstPinnedRightIndex());
30976
31053
  this._updateScrollbarWidth(paneChanged, true /* contentChanged */);
30977
- this._updateColumnBounds();
31054
+ this.updateColumnBounds();
30978
31055
  this._updateColumnSeparators();
30979
31056
  this._dispatchColumnPositionChanged();
30980
31057