@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.
@@ -371,8 +371,6 @@ declare class Core extends ElementWrapper {
371
371
 
372
372
  public reserveRightSpace(size: number): boolean;
373
373
 
374
- public getHiddenInput(): Element|null;
375
-
376
374
  public focus(): void;
377
375
 
378
376
  public isBinding(): boolean;
@@ -391,6 +389,8 @@ declare class Core extends ElementWrapper {
391
389
 
392
390
  public isSelectedColumn(colIndex: number): boolean;
393
391
 
392
+ public updateColumnBounds(): void;
393
+
394
394
  public getColumnRect(startColIndex: number, endColIndex: number): any;
395
395
 
396
396
  public getRowRect(startRowIndex: number, endRowIndex: number): any;
@@ -52,6 +52,9 @@ import VirtualizedLayoutGrid from "./VirtualizedLayoutGrid.js";
52
52
  /** @event Core#preForcedUpdate
53
53
  * @ignore
54
54
  */
55
+ /** @event Core#tabNavigation
56
+ * @ignore
57
+ */
55
58
  //#endregion Events
56
59
 
57
60
  /** @private
@@ -62,6 +65,44 @@ import VirtualizedLayoutGrid from "./VirtualizedLayoutGrid.js";
62
65
  let ascNumberSorter = function (a, b) {
63
66
  return a - b;
64
67
  };
68
+ /** @private
69
+ * @return {!Element}
70
+ */
71
+ let _createHiddenInput = function () {
72
+ let hiddenInput = document.createElement("input");
73
+ let styleObj = hiddenInput.style;
74
+ styleObj.position = "absolute";
75
+ styleObj.width = styleObj.height = styleObj.padding = styleObj.border = "0";
76
+ hiddenInput.value = "0";
77
+ return hiddenInput;
78
+ };
79
+ /** @private
80
+ * @param {Object} e
81
+ * @return {boolean}
82
+ */
83
+ let _isTabCommand = function (e) {
84
+ if(e.keyCode === 9) {
85
+ return !e.ctrlKey && !e.altKey && !e.metaKey;
86
+ }
87
+ return false;
88
+ };
89
+ /** @private
90
+ * @param {Element} elem
91
+ * @return {Element}
92
+ */
93
+ let _getActiveElement = function (elem) {
94
+ if(elem) {
95
+ if(elem.getRootNode) {
96
+ let rootNode = elem.getRootNode(); // Get uncomposed root node
97
+ if(rootNode && rootNode !== elem) { // The root node could be the element itself, if it is not attached to the DOM tree
98
+ return rootNode.activeElement || null;
99
+ }
100
+ } else { // Older browser does not support getRootNode
101
+ return document.activeElement;
102
+ }
103
+ }
104
+ return null;
105
+ };
65
106
 
66
107
  /** @constructor
67
108
  * @param {Element=} opt_initializer this can be either element id (string) or DOM element.
@@ -85,6 +126,8 @@ let Core = function (opt_initializer) {
85
126
  _t._onMouseMove = _t._onMouseMove.bind(_t);
86
127
  _t._onRowHightlighted = _t._onRowHightlighted.bind(_t);
87
128
  _t._onGridClicked = _t._onGridClicked.bind(_t);
129
+ _t._onKeyDown = _t._onKeyDown.bind(_t);
130
+ _t._onKeyUp = _t._onKeyUp.bind(_t);
88
131
 
89
132
  _t._onWindowResize = _t._onWindowResize.bind(_t);
90
133
  _t._onSectionDataChanged = _t._onSectionDataChanged.bind(_t);
@@ -105,7 +148,7 @@ let Core = function (opt_initializer) {
105
148
  _t._onColInViewChanged = _t._onColInViewChanged.bind(_t);
106
149
 
107
150
  _t._updateVScrollbar = _t._updateVScrollbar.bind(_t);
108
- _t._updateColumnBounds = _t._updateColumnBounds.bind(_t);
151
+ _t.updateColumnBounds = _t.updateColumnBounds.bind(_t);
109
152
  _t._dispatchColumnPositionChanged = _t._dispatchColumnPositionChanged.bind(_t);
110
153
  _t._dispatchRowPositionChanged = _t._dispatchRowPositionChanged.bind(_t);
111
154
  _t._requestScrollbarUpdate = _t._requestScrollbarUpdate.bind(_t);
@@ -146,7 +189,7 @@ let Core = function (opt_initializer) {
146
189
  // Initialize vertical scrollbar
147
190
  _t._vscrollbar = new VScrollbar();
148
191
  _t._vscrollbar.disable();
149
- _t._vscrollbar.setParent(this.getParent() || this.getElement());
192
+ _t._vscrollbar.setParent(_t.getParent() || _t.getElement());
150
193
 
151
194
  _t._vscrollbar.listen("scroll", _t._onVScroll);
152
195
  _t._vscrollbar.listen("layoutChanged", _t._onVScroll);
@@ -159,25 +202,28 @@ let Core = function (opt_initializer) {
159
202
  // Initialize horizontal scrollbars
160
203
  _t._hscrollbar = new HScrollbar();
161
204
  _t._hscrollbar.disable();
162
- _t._hscrollbar.setParent(this.getParent() || this.getElement());
205
+ _t._hscrollbar.setParent(_t.getParent() || _t.getElement());
163
206
 
164
- _t._hscrollbar.listen("scroll", this._onHScroll);
165
- _t._hscrollbar.listen("layoutChanged", this._onHScroll);
166
- _t._hscrollbar.listen("activated", this.updateLayout);
167
- _t._hscrollbar.listen("deactivated", this.updateLayout);
207
+ _t._hscrollbar.listen("scroll", _t._onHScroll);
208
+ _t._hscrollbar.listen("layoutChanged", _t._onHScroll);
209
+ _t._hscrollbar.listen("activated", _t.updateLayout);
210
+ _t._hscrollbar.listen("deactivated", _t.updateLayout);
168
211
 
169
212
  // cross-reference scrollbars
170
213
  _t._hscrollbar.setOtherScrollbar(_t._vscrollbar);
171
214
  _t._vscrollbar.setOtherScrollbar(_t._hscrollbar);
172
215
 
216
+
217
+ _t._element.addEventListener("keydown", _t._onKeyDown);
218
+ _t._element.addEventListener("keyup", _t._onKeyUp);
173
219
  if (Util.isMobile || Util.isTouchDevice) {
174
- _t._element.addEventListener("touchmove", this._onMouseMove, false);
220
+ _t._element.addEventListener("touchmove", _t._onMouseMove, false);
175
221
  } else {
176
- _t._element.addEventListener("mousemove", this._onMouseMove, false);
222
+ _t._element.addEventListener("mousemove", _t._onMouseMove, false);
177
223
  }
178
224
 
179
225
  if(Util.isSafari){
180
- _t._element.addEventListener("click", this._onGridClicked);
226
+ _t._element.addEventListener("click", _t._onGridClicked);
181
227
  }
182
228
 
183
229
  window.addEventListener("resize", _t._onWindowResize, false); // Should be unlistened after destroyed
@@ -185,10 +231,17 @@ let Core = function (opt_initializer) {
185
231
  _t._colVirtualizer.listen("indexChanged", _t._onColInViewChanged);
186
232
  _t._rowHeightConflator = new Conflator(_t._onRowHeightChanged, 50);
187
233
  _t._vScrollbarConflator = new Conflator(_t._updateVScrollbar, 200);
188
- _t._columnBoundConflator = new Conflator(_t._updateColumnBounds, 10);
234
+ _t._columnBoundConflator = new Conflator(_t.updateColumnBounds, 10);
189
235
  _t._columnPositionConflator = new Conflator(_t._dispatchColumnPositionChanged, 10);
190
236
  _t._rowPositionConflator = new Conflator(_t._dispatchRowPositionChanged, 10);
191
237
 
238
+ _t._firstHiddenInput = _createHiddenInput();
239
+ _t._firstHiddenInput.className = "first-input";
240
+ _t._lastHiddenInput = _createHiddenInput();
241
+ _t._lastHiddenInput.className = "last-input";
242
+ _t._element.insertBefore(_t._firstHiddenInput, _t._element.firstChild);
243
+ _t._element.appendChild(_t._lastHiddenInput);
244
+
192
245
  // Initialize events for external users
193
246
  _t._addEvents(
194
247
  "sectionAdded",
@@ -217,7 +270,8 @@ let Core = function (opt_initializer) {
217
270
  "beforeColumnBoundUpdate",
218
271
  "beforeBatchOperation",
219
272
  "afterBatchOperation",
220
- "pinningChanged"
273
+ "pinningChanged",
274
+ "tabNavigation"
221
275
  );
222
276
 
223
277
  // For debugging in advanced optimization mode
@@ -226,9 +280,9 @@ let Core = function (opt_initializer) {
226
280
  map = {};
227
281
  Core["map"] = map;
228
282
  }
229
- let elem = _t._element;
230
- elem["_control"] = _t;
231
- let id = elem.id || elem.name;
283
+
284
+ _t._element["_control"] = _t;
285
+ let id = _t._element.id || _t._element.name;
232
286
  if(!id || map[id]) {
233
287
  id = "_grid" + Core._runningGridId;
234
288
  }
@@ -236,17 +290,6 @@ let Core = function (opt_initializer) {
236
290
  map[id] = _t;
237
291
  Core._runningGridId++;
238
292
 
239
- // init hiddenInput for retrieve copy and cut event
240
- let hiddenInput = document.createElement("input");
241
- hiddenInput.style.position = "absolute";
242
- hiddenInput.style.width = "0";
243
- hiddenInput.style.height = "0";
244
- hiddenInput.style.padding = "0";
245
- hiddenInput.style.border = "0";
246
- hiddenInput.value = "0";
247
- _t._hiddenInput = hiddenInput;
248
- elem.insertBefore(hiddenInput, elem.firstChild);
249
-
250
293
  // Ensure all affected plugins are loaded prior zoom plugin
251
294
  // use as entity to trigger updateLayout once zoom is changed
252
295
  Object.defineProperty(_t, "zoomFactor", {
@@ -526,11 +569,16 @@ Core.prototype._rowRefreshTimer = 0;
526
569
  * @private
527
570
  */
528
571
  Core.prototype._layoutUpdating = false;
529
- /** A Hidden input that allow to get cut and copy event when user perform cut, copy activities
530
- * @type {Element}
572
+ /** A hidden input that allows grid to receive keyboard input and focus
573
+ * @type {!Element}
574
+ * @private
575
+ */
576
+ Core.prototype._firstHiddenInput;
577
+ /** A hidden input that allows grid to receive keyboard input and focus
578
+ * @type {!Element}
531
579
  * @private
532
580
  */
533
- Core.prototype._hiddenInput;
581
+ Core.prototype._lastHiddenInput;
534
582
  /** @type {number}
535
583
  * @private
536
584
  */
@@ -574,7 +622,7 @@ Core.prototype._hasPendingRowChange = false;
574
622
  * @return {string}
575
623
  */
576
624
  Core.getVersion = function () {
577
- return "5.1.108";
625
+ return "5.1.110";
578
626
  };
579
627
  /** {@link ElementWrapper#dispose}
580
628
  * @override
@@ -635,11 +683,12 @@ Core.prototype.dispose = function () {
635
683
 
636
684
  // Clean Top node
637
685
  let elem = this._element;
638
- if (elem !== null) {
686
+ if (elem) {
639
687
  if (elem["_control"]) {
640
688
  delete elem["_control"];
641
689
  }
642
- elem.removeChild(this._hiddenInput);
690
+ elem.removeChild(this._firstHiddenInput);
691
+ elem.removeChild(this._lastHiddenInput);
643
692
  }
644
693
  this._dispose();
645
694
 
@@ -1804,7 +1853,7 @@ Core.prototype._moveColumn = function (fromCol, destCol) {
1804
1853
  this._colVirtualizer.update();
1805
1854
  }
1806
1855
  }
1807
- this._updateColumnBounds();
1856
+ this.updateColumnBounds();
1808
1857
  this._updateColumnSeparators();
1809
1858
  return true;
1810
1859
  };
@@ -4037,15 +4086,14 @@ Core.prototype.reserveRightSpace = function (size) {
4037
4086
  return false;
4038
4087
  };
4039
4088
 
4040
- /** Get hidden input in grid <br>
4041
- * this input for make grid can copy <br>
4042
- * normal user should not touch it <br>
4043
- * but sometime grid extension will have to use this element
4089
+ /** Get the hidden input. This input allows grid to receive keyboard input
4044
4090
  * @public
4045
- * @return {Element}
4091
+ * @ignore
4092
+ * @param {boolean} firstInput
4093
+ * @return {!Element}
4046
4094
  */
4047
- Core.prototype.getHiddenInput = function () {
4048
- return this._hiddenInput;
4095
+ Core.prototype.getHiddenInput = function (firstInput) {
4096
+ return firstInput ? this._firstHiddenInput : this._lastHiddenInput;
4049
4097
  };
4050
4098
 
4051
4099
  /** 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.
@@ -4054,8 +4102,8 @@ Core.prototype.getHiddenInput = function () {
4054
4102
  * @see {@link http://help.dottoro.com/ljqmdirr.php}
4055
4103
  */
4056
4104
  Core.prototype.focus = function () {
4057
- let elem = this._hiddenInput;
4058
- let activeElem = document.activeElement;
4105
+ let elem = this._lastHiddenInput;
4106
+ let activeElem = _getActiveElement(elem);
4059
4107
  if(elem && elem !== activeElem) {
4060
4108
  let x = window.pageXOffset;
4061
4109
  let y = window.pageYOffset;
@@ -4186,7 +4234,7 @@ Core.prototype.selectColumn = function (colIndex, selected) {
4186
4234
  for (let i = this._settings.length; --i >= 0; ) {
4187
4235
  this._settings[i].getSection().selectColumn(colIndex, selected);
4188
4236
  }
4189
- this._updateColumnBounds();
4237
+ this.updateColumnBounds();
4190
4238
  };
4191
4239
  /** @public
4192
4240
  * @param {number} colIndex
@@ -4200,9 +4248,9 @@ Core.prototype.isSelectedColumn = function (colIndex) {
4200
4248
  return false;
4201
4249
  };
4202
4250
 
4203
- /** @private
4251
+ /** @public
4204
4252
  */
4205
- Core.prototype._updateColumnBounds = function () {
4253
+ Core.prototype.updateColumnBounds = function () {
4206
4254
  if(this._columnBoundConflator.conflate()) {
4207
4255
  return;
4208
4256
  }
@@ -4689,14 +4737,14 @@ Core.prototype._newSection = function (opt_type, sectionName) {
4689
4737
  Core.prototype._putToLast = function(section) {
4690
4738
  let sectionCount = this._settings.length;
4691
4739
  if (sectionCount === 0) {
4692
- section.setParent(this._element, true);
4740
+ section.insertBefore(this._lastHiddenInput);
4693
4741
  } else {
4694
4742
  let lastGrid = this.getLastSection();
4695
4743
  let nextSibling = lastGrid.getElement().nextSibling;
4696
4744
  if (nextSibling !== null) {
4697
4745
  section.insertBefore(nextSibling);
4698
4746
  } else {
4699
- section.setParent(this._element);
4747
+ section.insertBefore(this._lastHiddenInput);
4700
4748
  }
4701
4749
  }
4702
4750
  };
@@ -5082,7 +5130,7 @@ Core.prototype._onVScroll = function (e) {
5082
5130
  Core.prototype._onHScroll = function (e) {
5083
5131
  let scrollVal = this._hscrollbar.getScrollLeft();
5084
5132
  this._colVirtualizer.setViewOffset(scrollVal); // Trigger virtualization event
5085
- this._updateColumnBounds();
5133
+ this.updateColumnBounds();
5086
5134
  this._dispatchColumnPositionChanged();
5087
5135
  };
5088
5136
  /** @private
@@ -5381,14 +5429,66 @@ Core.prototype._onMouseMove = function () {
5381
5429
  };
5382
5430
  /** @private */
5383
5431
  Core.prototype._onGridClicked = function () {
5384
- // research for dragging
5385
5432
  let selection = window.getSelection();
5386
- if(selection.toString()){
5433
+ if(!selection.toString()){
5434
+ if(!this._element.contains(_getActiveElement(this._element))){
5435
+ this.focus();
5436
+ }
5437
+ }
5438
+ };
5439
+
5440
+ /** @private
5441
+ * @param {Object} e
5442
+ */
5443
+ Core.prototype._onKeyDown = function (e) {
5444
+ if(!_isTabCommand(e)) {
5387
5445
  return;
5388
5446
  }
5389
- let activeElem = document.activeElement;
5390
- if(!this._element.contains(activeElem)){
5391
- this.focus();
5447
+ let activeElement = _getActiveElement(this._element);
5448
+ let onTheEdge = false;
5449
+ if(this._firstHiddenInput === activeElement) {
5450
+ onTheEdge = -1;
5451
+ } else if(this._lastHiddenInput === activeElement) {
5452
+ onTheEdge = 1;
5453
+ }
5454
+
5455
+ this._dispatch("tabNavigation", {
5456
+ "activeElement": activeElement,
5457
+ "firstHiddenInput": this._firstHiddenInput,
5458
+ "lastHiddenInput": this._lastHiddenInput,
5459
+ "onTheEdge": onTheEdge,
5460
+ "shiftKey": e.shiftKey,
5461
+ "event": e
5462
+ });
5463
+
5464
+ if(onTheEdge && !e.defaultPrevented) {
5465
+ if(onTheEdge > 0 && e.shiftKey) {
5466
+ this._firstHiddenInput.focus(); // jump to the top
5467
+ e.preventDefault();
5468
+ } else if(onTheEdge < 0 && !e.shiftKey) {
5469
+ this._lastHiddenInput.focus(); // skip to the end
5470
+ e.preventDefault();
5471
+ }
5472
+ }
5473
+ };
5474
+ /** @private
5475
+ * @param {Object} e
5476
+ */
5477
+ Core.prototype._onKeyUp = function (e) {
5478
+ if(!_isTabCommand(e)) {
5479
+ return;
5480
+ }
5481
+ var activeElem = _getActiveElement(this._element);
5482
+ if(e.shiftKey) {
5483
+ if(activeElem === this._lastHiddenInput) {
5484
+ this._firstHiddenInput.focus();
5485
+ e.preventDefault();
5486
+ }
5487
+ } else {
5488
+ if(activeElem === this._firstHiddenInput) {
5489
+ this._lastHiddenInput.focus();
5490
+ e.preventDefault();
5491
+ }
5392
5492
  }
5393
5493
  };
5394
5494
 
@@ -5571,6 +5671,7 @@ Core.prototype._onSectionCountChanged = function (opt_suppressLayout) {
5571
5671
 
5572
5672
  // Reinsert sections
5573
5673
  this._vscrollbar.setScrollContent(this, this._getAllSections(), this._startVScrollbarIndex);
5674
+ this._element.appendChild(this._lastHiddenInput); // Ensure that the hidden input is always at the last position
5574
5675
 
5575
5676
  if(!opt_suppressLayout) {
5576
5677
  this._updateScrollbarHeight(true, true);
@@ -5588,7 +5689,7 @@ Core.prototype._onColumnCountChanged = function () {
5588
5689
  let pinnedLeft = this._countPinnedLeftColumns();
5589
5690
  let pinnedRight = this._countPinnedRightColumns();
5590
5691
 
5591
- this._updateColumnBounds();
5692
+ this.updateColumnBounds();
5592
5693
  this._updateColumnSeparators();
5593
5694
 
5594
5695
  if (this._hScrollbarEnabled && pinnedLeft + pinnedRight < this.getColumnCount()) {
@@ -5884,7 +5985,7 @@ Core.prototype._syncLayoutToColumns = function (from, to, opt_forceDispatching)
5884
5985
  // TODO: Check if "to" should be greater than or equal to first pinnied right index
5885
5986
  let paneChanged = forceUpdate || (from < this.getHScrollStartIndex()) || (to > this.getFirstPinnedRightIndex());
5886
5987
  this._updateScrollbarWidth(paneChanged, true /* contentChanged */);
5887
- this._updateColumnBounds();
5988
+ this.updateColumnBounds();
5888
5989
  this._updateColumnSeparators();
5889
5990
  this._dispatchColumnPositionChanged();
5890
5991
 
@@ -838,7 +838,7 @@ Scrollbar.prototype._clearAllPanes = function() {
838
838
  */
839
839
  Scrollbar.prototype.disableKeyboardInput = function (opt_disabled) {
840
840
  if(opt_disabled === false) {
841
- this._element.setAttribute("tabindex", "0");
841
+ this._element.setAttribute("tabindex", "-1"); // tabindex makes the element focusable. The negative value exclude it from tab key navigation
842
842
  this._element.addEventListener("keydown", this._onKeyDown, false);
843
843
  } else {
844
844
  this._element.removeAttribute("tabindex");
@@ -19,6 +19,17 @@ import SimpleTickerFormatter from "./SimpleTickerFormatter.js";
19
19
  import SimpleToggleFormatter from "./SimpleToggleFormatter.js";
20
20
  import TextFormatter from "./TextFormatter.js";
21
21
 
22
+ import EFButtonFormatter from "./EFButtonFormatter.js";
23
+ import EFCheckboxFormatter from "./EFCheckboxFormatter.js";
24
+ import EFComboBoxFormatter from "./EFComboBoxFormatter.js";
25
+ import EFDateTimePickerFormatter from "./EFDateTimePickerFormatter.js";
26
+ import EFIconFormatter from "./EFIconFormatter.js";
27
+ import EFNumberFieldFormatter from "./EFNumberFieldFormatter.js";
28
+ import EFRadioButtonFormatter from "./EFRadioButtonFormatter.js";
29
+ import EFSelectFormatter from "./EFSelectFormatter.js";
30
+ import EFTextFieldFormatter from "./EFTextFieldFormatter.js";
31
+ import EFToggleFormatter from "./EFToggleFormatter.js";
32
+
22
33
 
23
34
 
24
35
  export {
@@ -39,5 +50,15 @@ export {
39
50
  SimpleLinkFormatter,
40
51
  SimpleTickerFormatter,
41
52
  SimpleToggleFormatter,
42
- TextFormatter
53
+ TextFormatter,
54
+ EFButtonFormatter,
55
+ EFCheckboxFormatter,
56
+ EFComboBoxFormatter,
57
+ EFDateTimePickerFormatter,
58
+ EFIconFormatter,
59
+ EFNumberFieldFormatter,
60
+ EFRadioButtonFormatter,
61
+ EFSelectFormatter,
62
+ EFTextFieldFormatter,
63
+ EFToggleFormatter
43
64
  };
@@ -19,6 +19,17 @@ import SimpleTickerFormatter from "./SimpleTickerFormatter.js";
19
19
  import SimpleToggleFormatter from "./SimpleToggleFormatter.js";
20
20
  import TextFormatter from "./TextFormatter.js";
21
21
 
22
+ import EFButtonFormatter from "./EFButtonFormatter.js";
23
+ import EFCheckboxFormatter from "./EFCheckboxFormatter.js";
24
+ import EFComboBoxFormatter from "./EFComboBoxFormatter.js";
25
+ import EFDateTimePickerFormatter from "./EFDateTimePickerFormatter.js";
26
+ import EFIconFormatter from "./EFIconFormatter.js";
27
+ import EFNumberFieldFormatter from "./EFNumberFieldFormatter.js";
28
+ import EFRadioButtonFormatter from "./EFRadioButtonFormatter.js";
29
+ import EFSelectFormatter from "./EFSelectFormatter.js";
30
+ import EFTextFieldFormatter from "./EFTextFieldFormatter.js";
31
+ import EFToggleFormatter from "./EFToggleFormatter.js";
32
+
22
33
  // tsd-disable
23
34
  var tr = window["tr"];
24
35
  if (!tr) {
@@ -63,5 +74,15 @@ export {
63
74
  SimpleLinkFormatter,
64
75
  SimpleTickerFormatter,
65
76
  SimpleToggleFormatter,
66
- TextFormatter
77
+ TextFormatter,
78
+ EFButtonFormatter,
79
+ EFCheckboxFormatter,
80
+ EFComboBoxFormatter,
81
+ EFDateTimePickerFormatter,
82
+ EFIconFormatter,
83
+ EFNumberFieldFormatter,
84
+ EFRadioButtonFormatter,
85
+ EFSelectFormatter,
86
+ EFTextFieldFormatter,
87
+ EFToggleFormatter
67
88
  };
package/lib/grid/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import {Grid} from "./lib/efx-grid.js";
2
2
  export {Grid}
3
- window.EFX_GRID = { version: "6.0.107" };
3
+ window.EFX_GRID = { version: "6.0.108" };