@refinitiv-ui/efx-grid 6.0.107 → 6.0.108

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,8 @@ 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);
25220
+ _t._onKeyUp = _t._onKeyUp.bind(_t);
25178
25221
 
25179
25222
  _t._onWindowResize = _t._onWindowResize.bind(_t);
25180
25223
  _t._onSectionDataChanged = _t._onSectionDataChanged.bind(_t);
@@ -25195,7 +25238,7 @@ let Core_Core = function (opt_initializer) {
25195
25238
  _t._onColInViewChanged = _t._onColInViewChanged.bind(_t);
25196
25239
 
25197
25240
  _t._updateVScrollbar = _t._updateVScrollbar.bind(_t);
25198
- _t._updateColumnBounds = _t._updateColumnBounds.bind(_t);
25241
+ _t.updateColumnBounds = _t.updateColumnBounds.bind(_t);
25199
25242
  _t._dispatchColumnPositionChanged = _t._dispatchColumnPositionChanged.bind(_t);
25200
25243
  _t._dispatchRowPositionChanged = _t._dispatchRowPositionChanged.bind(_t);
25201
25244
  _t._requestScrollbarUpdate = _t._requestScrollbarUpdate.bind(_t);
@@ -25236,7 +25279,7 @@ let Core_Core = function (opt_initializer) {
25236
25279
  // Initialize vertical scrollbar
25237
25280
  _t._vscrollbar = new components_VScrollbar();
25238
25281
  _t._vscrollbar.disable();
25239
- _t._vscrollbar.setParent(this.getParent() || this.getElement());
25282
+ _t._vscrollbar.setParent(_t.getParent() || _t.getElement());
25240
25283
 
25241
25284
  _t._vscrollbar.listen("scroll", _t._onVScroll);
25242
25285
  _t._vscrollbar.listen("layoutChanged", _t._onVScroll);
@@ -25249,25 +25292,28 @@ let Core_Core = function (opt_initializer) {
25249
25292
  // Initialize horizontal scrollbars
25250
25293
  _t._hscrollbar = new components_HScrollbar();
25251
25294
  _t._hscrollbar.disable();
25252
- _t._hscrollbar.setParent(this.getParent() || this.getElement());
25295
+ _t._hscrollbar.setParent(_t.getParent() || _t.getElement());
25253
25296
 
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);
25297
+ _t._hscrollbar.listen("scroll", _t._onHScroll);
25298
+ _t._hscrollbar.listen("layoutChanged", _t._onHScroll);
25299
+ _t._hscrollbar.listen("activated", _t.updateLayout);
25300
+ _t._hscrollbar.listen("deactivated", _t.updateLayout);
25258
25301
 
25259
25302
  // cross-reference scrollbars
25260
25303
  _t._hscrollbar.setOtherScrollbar(_t._vscrollbar);
25261
25304
  _t._vscrollbar.setOtherScrollbar(_t._hscrollbar);
25262
25305
 
25306
+
25307
+ _t._element.addEventListener("keydown", _t._onKeyDown);
25308
+ _t._element.addEventListener("keyup", _t._onKeyUp);
25263
25309
  if (util.isMobile || util.isTouchDevice) {
25264
- _t._element.addEventListener("touchmove", this._onMouseMove, false);
25310
+ _t._element.addEventListener("touchmove", _t._onMouseMove, false);
25265
25311
  } else {
25266
- _t._element.addEventListener("mousemove", this._onMouseMove, false);
25312
+ _t._element.addEventListener("mousemove", _t._onMouseMove, false);
25267
25313
  }
25268
25314
 
25269
25315
  if(util.isSafari){
25270
- _t._element.addEventListener("click", this._onGridClicked);
25316
+ _t._element.addEventListener("click", _t._onGridClicked);
25271
25317
  }
25272
25318
 
25273
25319
  window.addEventListener("resize", _t._onWindowResize, false); // Should be unlistened after destroyed
@@ -25275,10 +25321,17 @@ let Core_Core = function (opt_initializer) {
25275
25321
  _t._colVirtualizer.listen("indexChanged", _t._onColInViewChanged);
25276
25322
  _t._rowHeightConflator = new util_Conflator(_t._onRowHeightChanged, 50);
25277
25323
  _t._vScrollbarConflator = new util_Conflator(_t._updateVScrollbar, 200);
25278
- _t._columnBoundConflator = new util_Conflator(_t._updateColumnBounds, 10);
25324
+ _t._columnBoundConflator = new util_Conflator(_t.updateColumnBounds, 10);
25279
25325
  _t._columnPositionConflator = new util_Conflator(_t._dispatchColumnPositionChanged, 10);
25280
25326
  _t._rowPositionConflator = new util_Conflator(_t._dispatchRowPositionChanged, 10);
25281
25327
 
25328
+ _t._firstHiddenInput = _createHiddenInput();
25329
+ _t._firstHiddenInput.className = "first-input";
25330
+ _t._lastHiddenInput = _createHiddenInput();
25331
+ _t._lastHiddenInput.className = "last-input";
25332
+ _t._element.insertBefore(_t._firstHiddenInput, _t._element.firstChild);
25333
+ _t._element.appendChild(_t._lastHiddenInput);
25334
+
25282
25335
  // Initialize events for external users
25283
25336
  _t._addEvents(
25284
25337
  "sectionAdded",
@@ -25307,7 +25360,8 @@ let Core_Core = function (opt_initializer) {
25307
25360
  "beforeColumnBoundUpdate",
25308
25361
  "beforeBatchOperation",
25309
25362
  "afterBatchOperation",
25310
- "pinningChanged"
25363
+ "pinningChanged",
25364
+ "tabNavigation"
25311
25365
  );
25312
25366
 
25313
25367
  // For debugging in advanced optimization mode
@@ -25316,9 +25370,9 @@ let Core_Core = function (opt_initializer) {
25316
25370
  map = {};
25317
25371
  Core_Core["map"] = map;
25318
25372
  }
25319
- let elem = _t._element;
25320
- elem["_control"] = _t;
25321
- let id = elem.id || elem.name;
25373
+
25374
+ _t._element["_control"] = _t;
25375
+ let id = _t._element.id || _t._element.name;
25322
25376
  if(!id || map[id]) {
25323
25377
  id = "_grid" + Core_Core._runningGridId;
25324
25378
  }
@@ -25326,17 +25380,6 @@ let Core_Core = function (opt_initializer) {
25326
25380
  map[id] = _t;
25327
25381
  Core_Core._runningGridId++;
25328
25382
 
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
25383
  // Ensure all affected plugins are loaded prior zoom plugin
25341
25384
  // use as entity to trigger updateLayout once zoom is changed
25342
25385
  Object.defineProperty(_t, "zoomFactor", {
@@ -25616,11 +25659,16 @@ Core_Core.prototype._rowRefreshTimer = 0;
25616
25659
  * @private
25617
25660
  */
25618
25661
  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}
25662
+ /** A hidden input that allows grid to receive keyboard input and focus
25663
+ * @type {!Element}
25621
25664
  * @private
25622
25665
  */
25623
- Core_Core.prototype._hiddenInput;
25666
+ Core_Core.prototype._firstHiddenInput;
25667
+ /** A hidden input that allows grid to receive keyboard input and focus
25668
+ * @type {!Element}
25669
+ * @private
25670
+ */
25671
+ Core_Core.prototype._lastHiddenInput;
25624
25672
  /** @type {number}
25625
25673
  * @private
25626
25674
  */
@@ -25664,7 +25712,7 @@ Core_Core.prototype._hasPendingRowChange = false;
25664
25712
  * @return {string}
25665
25713
  */
25666
25714
  Core_Core.getVersion = function () {
25667
- return "5.1.108";
25715
+ return "5.1.110";
25668
25716
  };
25669
25717
  /** {@link ElementWrapper#dispose}
25670
25718
  * @override
@@ -25725,11 +25773,12 @@ Core_Core.prototype.dispose = function () {
25725
25773
 
25726
25774
  // Clean Top node
25727
25775
  let elem = this._element;
25728
- if (elem !== null) {
25776
+ if (elem) {
25729
25777
  if (elem["_control"]) {
25730
25778
  delete elem["_control"];
25731
25779
  }
25732
- elem.removeChild(this._hiddenInput);
25780
+ elem.removeChild(this._firstHiddenInput);
25781
+ elem.removeChild(this._lastHiddenInput);
25733
25782
  }
25734
25783
  this._dispose();
25735
25784
 
@@ -26894,7 +26943,7 @@ Core_Core.prototype._moveColumn = function (fromCol, destCol) {
26894
26943
  this._colVirtualizer.update();
26895
26944
  }
26896
26945
  }
26897
- this._updateColumnBounds();
26946
+ this.updateColumnBounds();
26898
26947
  this._updateColumnSeparators();
26899
26948
  return true;
26900
26949
  };
@@ -29127,15 +29176,14 @@ Core_Core.prototype.reserveRightSpace = function (size) {
29127
29176
  return false;
29128
29177
  };
29129
29178
 
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
29179
+ /** Get the hidden input. This input allows grid to receive keyboard input
29134
29180
  * @public
29135
- * @return {Element}
29181
+ * @ignore
29182
+ * @param {boolean} firstInput
29183
+ * @return {!Element}
29136
29184
  */
29137
- Core_Core.prototype.getHiddenInput = function () {
29138
- return this._hiddenInput;
29185
+ Core_Core.prototype.getHiddenInput = function (firstInput) {
29186
+ return firstInput ? this._firstHiddenInput : this._lastHiddenInput;
29139
29187
  };
29140
29188
 
29141
29189
  /** 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 +29192,8 @@ Core_Core.prototype.getHiddenInput = function () {
29144
29192
  * @see {@link http://help.dottoro.com/ljqmdirr.php}
29145
29193
  */
29146
29194
  Core_Core.prototype.focus = function () {
29147
- let elem = this._hiddenInput;
29148
- let activeElem = document.activeElement;
29195
+ let elem = this._lastHiddenInput;
29196
+ let activeElem = _getActiveElement(elem);
29149
29197
  if(elem && elem !== activeElem) {
29150
29198
  let x = window.pageXOffset;
29151
29199
  let y = window.pageYOffset;
@@ -29276,7 +29324,7 @@ Core_Core.prototype.selectColumn = function (colIndex, selected) {
29276
29324
  for (let i = this._settings.length; --i >= 0; ) {
29277
29325
  this._settings[i].getSection().selectColumn(colIndex, selected);
29278
29326
  }
29279
- this._updateColumnBounds();
29327
+ this.updateColumnBounds();
29280
29328
  };
29281
29329
  /** @public
29282
29330
  * @param {number} colIndex
@@ -29290,9 +29338,9 @@ Core_Core.prototype.isSelectedColumn = function (colIndex) {
29290
29338
  return false;
29291
29339
  };
29292
29340
 
29293
- /** @private
29341
+ /** @public
29294
29342
  */
29295
- Core_Core.prototype._updateColumnBounds = function () {
29343
+ Core_Core.prototype.updateColumnBounds = function () {
29296
29344
  if(this._columnBoundConflator.conflate()) {
29297
29345
  return;
29298
29346
  }
@@ -29779,14 +29827,14 @@ Core_Core.prototype._newSection = function (opt_type, sectionName) {
29779
29827
  Core_Core.prototype._putToLast = function(section) {
29780
29828
  let sectionCount = this._settings.length;
29781
29829
  if (sectionCount === 0) {
29782
- section.setParent(this._element, true);
29830
+ section.insertBefore(this._lastHiddenInput);
29783
29831
  } else {
29784
29832
  let lastGrid = this.getLastSection();
29785
29833
  let nextSibling = lastGrid.getElement().nextSibling;
29786
29834
  if (nextSibling !== null) {
29787
29835
  section.insertBefore(nextSibling);
29788
29836
  } else {
29789
- section.setParent(this._element);
29837
+ section.insertBefore(this._lastHiddenInput);
29790
29838
  }
29791
29839
  }
29792
29840
  };
@@ -30172,7 +30220,7 @@ Core_Core.prototype._onVScroll = function (e) {
30172
30220
  Core_Core.prototype._onHScroll = function (e) {
30173
30221
  let scrollVal = this._hscrollbar.getScrollLeft();
30174
30222
  this._colVirtualizer.setViewOffset(scrollVal); // Trigger virtualization event
30175
- this._updateColumnBounds();
30223
+ this.updateColumnBounds();
30176
30224
  this._dispatchColumnPositionChanged();
30177
30225
  };
30178
30226
  /** @private
@@ -30471,14 +30519,66 @@ Core_Core.prototype._onMouseMove = function () {
30471
30519
  };
30472
30520
  /** @private */
30473
30521
  Core_Core.prototype._onGridClicked = function () {
30474
- // research for dragging
30475
30522
  let selection = window.getSelection();
30476
- if(selection.toString()){
30523
+ if(!selection.toString()){
30524
+ if(!this._element.contains(_getActiveElement(this._element))){
30525
+ this.focus();
30526
+ }
30527
+ }
30528
+ };
30529
+
30530
+ /** @private
30531
+ * @param {Object} e
30532
+ */
30533
+ Core_Core.prototype._onKeyDown = function (e) {
30534
+ if(!_isTabCommand(e)) {
30477
30535
  return;
30478
30536
  }
30479
- let activeElem = document.activeElement;
30480
- if(!this._element.contains(activeElem)){
30481
- this.focus();
30537
+ let activeElement = _getActiveElement(this._element);
30538
+ let onTheEdge = false;
30539
+ if(this._firstHiddenInput === activeElement) {
30540
+ onTheEdge = -1;
30541
+ } else if(this._lastHiddenInput === activeElement) {
30542
+ onTheEdge = 1;
30543
+ }
30544
+
30545
+ this._dispatch("tabNavigation", {
30546
+ "activeElement": activeElement,
30547
+ "firstHiddenInput": this._firstHiddenInput,
30548
+ "lastHiddenInput": this._lastHiddenInput,
30549
+ "onTheEdge": onTheEdge,
30550
+ "shiftKey": e.shiftKey,
30551
+ "event": e
30552
+ });
30553
+
30554
+ if(onTheEdge && !e.defaultPrevented) {
30555
+ if(onTheEdge > 0 && e.shiftKey) {
30556
+ this._firstHiddenInput.focus(); // jump to the top
30557
+ e.preventDefault();
30558
+ } else if(onTheEdge < 0 && !e.shiftKey) {
30559
+ this._lastHiddenInput.focus(); // skip to the end
30560
+ e.preventDefault();
30561
+ }
30562
+ }
30563
+ };
30564
+ /** @private
30565
+ * @param {Object} e
30566
+ */
30567
+ Core_Core.prototype._onKeyUp = function (e) {
30568
+ if(!_isTabCommand(e)) {
30569
+ return;
30570
+ }
30571
+ var activeElem = _getActiveElement(this._element);
30572
+ if(e.shiftKey) {
30573
+ if(activeElem === this._lastHiddenInput) {
30574
+ this._firstHiddenInput.focus();
30575
+ e.preventDefault();
30576
+ }
30577
+ } else {
30578
+ if(activeElem === this._firstHiddenInput) {
30579
+ this._lastHiddenInput.focus();
30580
+ e.preventDefault();
30581
+ }
30482
30582
  }
30483
30583
  };
30484
30584
 
@@ -30661,6 +30761,7 @@ Core_Core.prototype._onSectionCountChanged = function (opt_suppressLayout) {
30661
30761
 
30662
30762
  // Reinsert sections
30663
30763
  this._vscrollbar.setScrollContent(this, this._getAllSections(), this._startVScrollbarIndex);
30764
+ this._element.appendChild(this._lastHiddenInput); // Ensure that the hidden input is always at the last position
30664
30765
 
30665
30766
  if(!opt_suppressLayout) {
30666
30767
  this._updateScrollbarHeight(true, true);
@@ -30678,7 +30779,7 @@ Core_Core.prototype._onColumnCountChanged = function () {
30678
30779
  let pinnedLeft = this._countPinnedLeftColumns();
30679
30780
  let pinnedRight = this._countPinnedRightColumns();
30680
30781
 
30681
- this._updateColumnBounds();
30782
+ this.updateColumnBounds();
30682
30783
  this._updateColumnSeparators();
30683
30784
 
30684
30785
  if (this._hScrollbarEnabled && pinnedLeft + pinnedRight < this.getColumnCount()) {
@@ -30974,7 +31075,7 @@ Core_Core.prototype._syncLayoutToColumns = function (from, to, opt_forceDispatch
30974
31075
  // TODO: Check if "to" should be greater than or equal to first pinnied right index
30975
31076
  let paneChanged = forceUpdate || (from < this.getHScrollStartIndex()) || (to > this.getFirstPinnedRightIndex());
30976
31077
  this._updateScrollbarWidth(paneChanged, true /* contentChanged */);
30977
- this._updateColumnBounds();
31078
+ this.updateColumnBounds();
30978
31079
  this._updateColumnSeparators();
30979
31080
  this._dispatchColumnPositionChanged();
30980
31081