UNPKG

60.9 kBJavaScriptView Raw
1"use strict";
2
3exports.__esModule = true;
4require("core-js/modules/es.error.cause.js");
5require("core-js/modules/es.array.push.js");
6var _element = require("./helpers/dom/element");
7var _eventManager = _interopRequireDefault(require("./eventManager"));
8var _event = require("./helpers/dom/event");
9var _src = _interopRequireDefault(require("./3rdparty/walkontable/src"));
10var _mouseEventHandler = require("./selection/mouseEventHandler");
11var _rootInstance = require("./utils/rootInstance");
12var _a11y = require("./helpers/a11y");
13function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); }
15function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); }
16function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
17function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
18function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
19function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
20function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
21function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }
22function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
23/**
24 * @class TableView
25 * @private
26 */
27var _columnHeadersCount = /*#__PURE__*/new WeakMap();
28var _rowHeadersCount = /*#__PURE__*/new WeakMap();
29var _selectionMouseDown = /*#__PURE__*/new WeakMap();
30var _mouseDown = /*#__PURE__*/new WeakMap();
31var _table = /*#__PURE__*/new WeakMap();
32var _lastWidth = /*#__PURE__*/new WeakMap();
33var _lastHeight = /*#__PURE__*/new WeakMap();
34var _TableView_brand = /*#__PURE__*/new WeakSet();
35class TableView {
36 /**
37 * @param {Hanstontable} hotInstance Instance of {@link Handsontable}.
38 */
39 constructor(hotInstance) {
40 /**
41 * Return the value of the `aria-colcount` attribute.
42 *
43 * @returns {number} The value of the `aria-colcount` attribute.
44 */
45 _classPrivateMethodInitSpec(this, _TableView_brand);
46 /**
47 * Instance of {@link Handsontable}.
48 *
49 * @private
50 * @type {Handsontable}
51 */
52 _defineProperty(this, "hot", void 0);
53 /**
54 * Instance of {@link EventManager}.
55 *
56 * @private
57 * @type {EventManager}
58 */
59 _defineProperty(this, "eventManager", void 0);
60 /**
61 * Current Handsontable's GridSettings object.
62 *
63 * @private
64 * @type {GridSettings}
65 */
66 _defineProperty(this, "settings", void 0);
67 /**
68 * Main <THEAD> element.
69 *
70 * @private
71 * @type {HTMLTableSectionElement}
72 */
73 _defineProperty(this, "THEAD", void 0);
74 /**
75 * Main <TBODY> element.
76 *
77 * @private
78 * @type {HTMLTableSectionElement}
79 */
80 _defineProperty(this, "TBODY", void 0);
81 /**
82 * Main Walkontable instance.
83 *
84 * @private
85 * @type {Walkontable}
86 */
87 _defineProperty(this, "_wt", void 0);
88 /**
89 * Main Walkontable instance.
90 *
91 * @type {Walkontable}
92 */
93 _defineProperty(this, "activeWt", void 0);
94 /**
95 * The total number of the column header renderers applied to the table through the
96 * `afterGetColumnHeaderRenderers` hook.
97 *
98 * @type {number}
99 */
100 _classPrivateFieldInitSpec(this, _columnHeadersCount, 0);
101 /**
102 * The total number of the row header renderers applied to the table through the
103 * `afterGetRowHeaderRenderers` hook.
104 *
105 * @type {number}
106 */
107 _classPrivateFieldInitSpec(this, _rowHeadersCount, 0);
108 /**
109 * The flag determines if the `adjustElementsSize` method call was made during
110 * the render suspending. If true, the method has to be triggered once after render
111 * resuming.
112 *
113 * @private
114 * @type {boolean}
115 */
116 _defineProperty(this, "postponedAdjustElementsSize", false);
117 /**
118 * Defines if the text should be selected during mousemove.
119 *
120 * @type {boolean}
121 */
122 _classPrivateFieldInitSpec(this, _selectionMouseDown, false);
123 /**
124 * @type {boolean}
125 */
126 _classPrivateFieldInitSpec(this, _mouseDown, void 0);
127 /**
128 * Main <TABLE> element.
129 *
130 * @type {HTMLTableElement}
131 */
132 _classPrivateFieldInitSpec(this, _table, void 0);
133 /**
134 * Cached width of the rootElement.
135 *
136 * @type {number}
137 */
138 _classPrivateFieldInitSpec(this, _lastWidth, 0);
139 /**
140 * Cached height of the rootElement.
141 *
142 * @type {number}
143 */
144 _classPrivateFieldInitSpec(this, _lastHeight, 0);
145 this.hot = hotInstance;
146 this.eventManager = new _eventManager.default(this.hot);
147 this.settings = this.hot.getSettings();
148 this.createElements();
149 this.registerEvents();
150 this.initializeWalkontable();
151 }
152
153 /**
154 * Renders WalkontableUI.
155 */
156 render() {
157 if (!this.hot.isRenderSuspended()) {
158 this.hot.runHooks('beforeRender', this.hot.forceFullRender);
159 if (this.postponedAdjustElementsSize) {
160 this.postponedAdjustElementsSize = false;
161 this.adjustElementsSize(true);
162 }
163 this._wt.draw(!this.hot.forceFullRender);
164 this.hot.runHooks('afterRender', this.hot.forceFullRender);
165 this.hot.forceFullRender = false;
166 this.hot.renderCall = false;
167 }
168 }
169
170 /**
171 * Adjust overlays elements size and master table size.
172 */
173 adjustElementsSize() {
174 if (this.hot.isRenderSuspended()) {
175 this.postponedAdjustElementsSize = true;
176 } else {
177 this._wt.wtOverlays.adjustElementsSize();
178 }
179 }
180
181 /**
182 * Returns td object given coordinates.
183 *
184 * @param {CellCoords} coords Renderable cell coordinates.
185 * @param {boolean} topmost Indicates whether the cell should be calculated from the topmost.
186 * @returns {HTMLTableCellElement|null}
187 */
188 getCellAtCoords(coords, topmost) {
189 const td = this._wt.getCell(coords, topmost);
190 if (td < 0) {
191 // there was an exit code (cell is out of bounds)
192 return null;
193 }
194 return td;
195 }
196
197 /**
198 * Scroll viewport to a cell.
199 *
200 * @param {CellCoords} coords Renderable cell coordinates.
201 * @param {boolean} [snapToTop] If `true`, viewport is scrolled to show the cell on the top of the table.
202 * @param {boolean} [snapToRight] If `true`, viewport is scrolled to show the cell on the right side of the table.
203 * @param {boolean} [snapToBottom] If `true`, viewport is scrolled to show the cell on the bottom side of the table.
204 * @param {boolean} [snapToLeft] If `true`, viewport is scrolled to show the cell on the left side of the table.
205 * @returns {boolean}
206 */
207 scrollViewport(coords, snapToTop, snapToRight, snapToBottom, snapToLeft) {
208 return this._wt.scrollViewport(coords, snapToTop, snapToRight, snapToBottom, snapToLeft);
209 }
210
211 /**
212 * Scroll viewport to a column.
213 *
214 * @param {number} column Renderable column index.
215 * @param {boolean} [snapToRight] If `true`, viewport is scrolled to show the cell on the right side of the table.
216 * @param {boolean} [snapToLeft] If `true`, viewport is scrolled to show the cell on the left side of the table.
217 * @returns {boolean}
218 */
219 scrollViewportHorizontally(column, snapToRight, snapToLeft) {
220 return this._wt.scrollViewportHorizontally(column, snapToRight, snapToLeft);
221 }
222
223 /**
224 * Scroll viewport to a row.
225 *
226 * @param {number} row Renderable row index.
227 * @param {boolean} [snapToTop] If `true`, viewport is scrolled to show the cell on the top of the table.
228 * @param {boolean} [snapToBottom] If `true`, viewport is scrolled to show the cell on the bottom side of the table.
229 * @returns {boolean}
230 */
231 scrollViewportVertically(row, snapToTop, snapToBottom) {
232 return this._wt.scrollViewportVertically(row, snapToTop, snapToBottom);
233 }
234
235 /**
236 * Prepares DOMElements and adds correct className to the root element.
237 *
238 * @private
239 */
240 createElements() {
241 const {
242 rootElement,
243 rootDocument
244 } = this.hot;
245 const originalStyle = rootElement.getAttribute('style');
246 if (originalStyle) {
247 rootElement.setAttribute('data-originalstyle', originalStyle); // needed to retrieve original style in jsFiddle link generator in HT examples. may be removed in future versions
248 }
249 (0, _element.addClass)(rootElement, 'handsontable');
250 _classPrivateFieldSet(_table, this, rootDocument.createElement('TABLE'));
251 (0, _element.addClass)(_classPrivateFieldGet(_table, this), 'htCore');
252 if (this.hot.getSettings().tableClassName) {
253 (0, _element.addClass)(_classPrivateFieldGet(_table, this), this.hot.getSettings().tableClassName);
254 }
255 if (this.settings.ariaTags) {
256 (0, _element.setAttribute)(_classPrivateFieldGet(_table, this), [(0, _a11y.A11Y_PRESENTATION)()]);
257 (0, _element.setAttribute)(rootElement, [(0, _a11y.A11Y_TREEGRID)(), (0, _a11y.A11Y_ROWCOUNT)(-1), (0, _a11y.A11Y_COLCOUNT)(this.hot.countCols()), (0, _a11y.A11Y_MULTISELECTABLE)()]);
258 }
259 this.THEAD = rootDocument.createElement('THEAD');
260 _classPrivateFieldGet(_table, this).appendChild(this.THEAD);
261 this.TBODY = rootDocument.createElement('TBODY');
262 _classPrivateFieldGet(_table, this).appendChild(this.TBODY);
263 this.hot.table = _classPrivateFieldGet(_table, this);
264 this.hot.container.insertBefore(_classPrivateFieldGet(_table, this), this.hot.container.firstChild);
265 }
266
267 /**
268 * Attaches necessary listeners.
269 *
270 * @private
271 */
272 registerEvents() {
273 const {
274 rootElement,
275 rootDocument,
276 selection,
277 rootWindow
278 } = this.hot;
279 const documentElement = rootDocument.documentElement;
280 this.eventManager.addEventListener(rootElement, 'mousedown', event => {
281 _classPrivateFieldSet(_selectionMouseDown, this, true);
282 if (!this.isTextSelectionAllowed(event.target)) {
283 (0, _element.clearTextSelection)(rootWindow);
284 event.preventDefault();
285 rootWindow.focus(); // make sure that window that contains HOT is active. Important when HOT is in iframe.
286 }
287 });
288 this.eventManager.addEventListener(rootElement, 'mouseup', () => {
289 _classPrivateFieldSet(_selectionMouseDown, this, false);
290 });
291 this.eventManager.addEventListener(rootElement, 'mousemove', event => {
292 if (_classPrivateFieldGet(_selectionMouseDown, this) && !this.isTextSelectionAllowed(event.target)) {
293 // Clear selection only when fragmentSelection is enabled, otherwise clearing selection breaks the IME editor.
294 if (this.settings.fragmentSelection) {
295 (0, _element.clearTextSelection)(rootWindow);
296 }
297 event.preventDefault();
298 }
299 });
300 this.eventManager.addEventListener(documentElement, 'keyup', event => {
301 // TODO: is it the best place and way to finish cell selection?
302 if (selection.isInProgress() && !event.shiftKey) {
303 selection.finish();
304 }
305 });
306 this.eventManager.addEventListener(documentElement, 'mouseup', event => {
307 if (selection.isInProgress() && (0, _event.isLeftClick)(event)) {
308 selection.finish();
309 }
310 _classPrivateFieldSet(_mouseDown, this, false);
311 const isOutsideInputElement = (0, _element.isOutsideInput)(rootDocument.activeElement);
312 if ((0, _element.isInput)(rootDocument.activeElement) && !isOutsideInputElement) {
313 return;
314 }
315 if (isOutsideInputElement || !selection.isSelected() && !selection.isSelectedByAnyHeader() && !rootElement.contains(event.target) && !(0, _event.isRightClick)(event)) {
316 this.hot.unlisten();
317 }
318 });
319 this.eventManager.addEventListener(documentElement, 'contextmenu', event => {
320 if (selection.isInProgress() && (0, _event.isRightClick)(event)) {
321 selection.finish();
322 _classPrivateFieldSet(_mouseDown, this, false);
323 }
324 });
325 this.eventManager.addEventListener(documentElement, 'touchend', () => {
326 if (selection.isInProgress()) {
327 selection.finish();
328 }
329 _classPrivateFieldSet(_mouseDown, this, false);
330 });
331 this.eventManager.addEventListener(documentElement, 'mousedown', event => {
332 const originalTarget = event.target;
333 const eventX = event.x || event.clientX;
334 const eventY = event.y || event.clientY;
335 let next = event.target;
336 if (_classPrivateFieldGet(_mouseDown, this) || !rootElement || !this.hot.view) {
337 return; // it must have been started in a cell
338 }
339
340 // immediate click on "holder" means click on the right side of vertical scrollbar
341 const {
342 holder
343 } = this._wt.wtTable;
344 if (next === holder) {
345 const scrollbarWidth = (0, _element.getScrollbarWidth)(rootDocument);
346 if (rootDocument.elementFromPoint(eventX + scrollbarWidth, eventY) !== holder || rootDocument.elementFromPoint(eventX, eventY + scrollbarWidth) !== holder) {
347 return;
348 }
349 } else {
350 while (next !== documentElement) {
351 if (next === null) {
352 if (event.isTargetWebComponent) {
353 break;
354 }
355
356 // click on something that was a row but now is detached (possibly because your click triggered a rerender)
357 return;
358 }
359 if (next === rootElement) {
360 // click inside container
361 return;
362 }
363 next = next.parentNode;
364 }
365 }
366
367 // function did not return until here, we have an outside click!
368 const outsideClickDeselects = typeof this.settings.outsideClickDeselects === 'function' ? this.settings.outsideClickDeselects(originalTarget) : this.settings.outsideClickDeselects;
369 if (outsideClickDeselects) {
370 this.hot.deselectCell();
371 } else {
372 this.hot.destroyEditor(false, false);
373 }
374 });
375 let parentWindow = (0, _element.getParentWindow)(rootWindow);
376 while (parentWindow !== null) {
377 this.eventManager.addEventListener(parentWindow.document.documentElement, 'click', () => {
378 this.hot.unlisten();
379 });
380 parentWindow = (0, _element.getParentWindow)(parentWindow);
381 }
382 this.eventManager.addEventListener(_classPrivateFieldGet(_table, this), 'selectstart', event => {
383 if (this.settings.fragmentSelection || (0, _element.isInput)(event.target)) {
384 return;
385 }
386 // https://github.com/handsontable/handsontable/issues/160
387 // Prevent text from being selected when performing drag down.
388 event.preventDefault();
389 });
390 }
391
392 /**
393 * Translate renderable cell coordinates to visual coordinates.
394 *
395 * @param {CellCoords} coords The cell coordinates.
396 * @returns {CellCoords}
397 */
398 translateFromRenderableToVisualCoords(_ref) {
399 let {
400 row,
401 col
402 } = _ref;
403 // TODO: To consider an idea to reusing the CellCoords instance instead creating new one.
404 return this.hot._createCellCoords(...this.translateFromRenderableToVisualIndex(row, col));
405 }
406
407 /**
408 * Translate renderable row and column indexes to visual row and column indexes.
409 *
410 * @param {number} renderableRow Renderable row index.
411 * @param {number} renderableColumn Renderable columnIndex.
412 * @returns {number[]}
413 */
414 translateFromRenderableToVisualIndex(renderableRow, renderableColumn) {
415 // TODO: Some helper may be needed.
416 // We perform translation for indexes (without headers).
417 let visualRow = renderableRow >= 0 ? this.hot.rowIndexMapper.getVisualFromRenderableIndex(renderableRow) : renderableRow;
418 let visualColumn = renderableColumn >= 0 ? this.hot.columnIndexMapper.getVisualFromRenderableIndex(renderableColumn) : renderableColumn;
419 if (visualRow === null) {
420 visualRow = renderableRow;
421 }
422 if (visualColumn === null) {
423 visualColumn = renderableColumn;
424 }
425 return [visualRow, visualColumn];
426 }
427
428 /**
429 * Returns the number of renderable indexes.
430 *
431 * @private
432 * @param {IndexMapper} indexMapper The IndexMapper instance for specific axis.
433 * @param {number} maxElements Maximum number of elements (rows or columns).
434 *
435 * @returns {number|*}
436 */
437 countRenderableIndexes(indexMapper, maxElements) {
438 const consideredElements = Math.min(indexMapper.getNotTrimmedIndexesLength(), maxElements);
439 // Don't take hidden indexes into account. We are looking just for renderable indexes.
440 const firstNotHiddenIndex = indexMapper.getNearestNotHiddenIndex(consideredElements - 1, -1);
441
442 // There are no renderable indexes.
443 if (firstNotHiddenIndex === null) {
444 return 0;
445 }
446 return indexMapper.getRenderableFromVisualIndex(firstNotHiddenIndex) + 1;
447 }
448
449 /**
450 * Returns the number of renderable columns.
451 *
452 * @returns {number}
453 */
454 countRenderableColumns() {
455 return this.countRenderableIndexes(this.hot.columnIndexMapper, this.settings.maxCols);
456 }
457
458 /**
459 * Returns the number of renderable rows.
460 *
461 * @returns {number}
462 */
463 countRenderableRows() {
464 return this.countRenderableIndexes(this.hot.rowIndexMapper, this.settings.maxRows);
465 }
466
467 /**
468 * Returns number of not hidden row indexes counting from the passed starting index.
469 * The counting direction can be controlled by `incrementBy` argument.
470 *
471 * @param {number} visualIndex The visual index from which the counting begins.
472 * @param {number} incrementBy If `-1` then counting is backwards or forward when `1`.
473 * @returns {number}
474 */
475 countNotHiddenRowIndexes(visualIndex, incrementBy) {
476 return this.countNotHiddenIndexes(visualIndex, incrementBy, this.hot.rowIndexMapper, this.countRenderableRows());
477 }
478
479 /**
480 * Returns number of not hidden column indexes counting from the passed starting index.
481 * The counting direction can be controlled by `incrementBy` argument.
482 *
483 * @param {number} visualIndex The visual index from which the counting begins.
484 * @param {number} incrementBy If `-1` then counting is backwards or forward when `1`.
485 * @returns {number}
486 */
487 countNotHiddenColumnIndexes(visualIndex, incrementBy) {
488 return this.countNotHiddenIndexes(visualIndex, incrementBy, this.hot.columnIndexMapper, this.countRenderableColumns());
489 }
490
491 /**
492 * Returns number of not hidden indexes counting from the passed starting index.
493 * The counting direction can be controlled by `incrementBy` argument.
494 *
495 * @param {number} visualIndex The visual index from which the counting begins.
496 * @param {number} incrementBy If `-1` then counting is backwards or forward when `1`.
497 * @param {IndexMapper} indexMapper The IndexMapper instance for specific axis.
498 * @param {number} renderableIndexesCount Total count of renderable indexes for specific axis.
499 * @returns {number}
500 */
501 countNotHiddenIndexes(visualIndex, incrementBy, indexMapper, renderableIndexesCount) {
502 if (isNaN(visualIndex) || visualIndex < 0) {
503 return 0;
504 }
505 const firstVisibleIndex = indexMapper.getNearestNotHiddenIndex(visualIndex, incrementBy);
506 const renderableIndex = indexMapper.getRenderableFromVisualIndex(firstVisibleIndex);
507 if (!Number.isInteger(renderableIndex)) {
508 return 0;
509 }
510 let notHiddenIndexes = 0;
511 if (incrementBy < 0) {
512 // Zero-based numbering for renderable indexes corresponds to a number of not hidden indexes.
513 notHiddenIndexes = renderableIndex + 1;
514 } else if (incrementBy > 0) {
515 notHiddenIndexes = renderableIndexesCount - renderableIndex;
516 }
517 return notHiddenIndexes;
518 }
519
520 /**
521 * The function returns the number of not hidden column indexes that fit between the first and
522 * last fixed column in the left (or right in RTL mode) overlay.
523 *
524 * @returns {number}
525 */
526 countNotHiddenFixedColumnsStart() {
527 const countCols = this.hot.countCols();
528 const visualFixedColumnsStart = Math.min(parseInt(this.settings.fixedColumnsStart, 10), countCols) - 1;
529 return this.countNotHiddenColumnIndexes(visualFixedColumnsStart, -1);
530 }
531
532 /**
533 * The function returns the number of not hidden row indexes that fit between the first and
534 * last fixed row in the top overlay.
535 *
536 * @returns {number}
537 */
538 countNotHiddenFixedRowsTop() {
539 const countRows = this.hot.countRows();
540 const visualFixedRowsTop = Math.min(parseInt(this.settings.fixedRowsTop, 10), countRows) - 1;
541 return this.countNotHiddenRowIndexes(visualFixedRowsTop, -1);
542 }
543
544 /**
545 * The function returns the number of not hidden row indexes that fit between the first and
546 * last fixed row in the bottom overlay.
547 *
548 * @returns {number}
549 */
550 countNotHiddenFixedRowsBottom() {
551 const countRows = this.hot.countRows();
552 const visualFixedRowsBottom = Math.max(countRows - parseInt(this.settings.fixedRowsBottom, 10), 0);
553 return this.countNotHiddenRowIndexes(visualFixedRowsBottom, 1);
554 }
555
556 /**
557 * The function returns the number of renderable column indexes within the passed range of the visual indexes.
558 *
559 * @param {number} columnStart The column visual start index.
560 * @param {number} columnEnd The column visual end index.
561 * @returns {number}
562 */
563 countRenderableColumnsInRange(columnStart, columnEnd) {
564 let count = 0;
565 for (let column = columnStart; column <= columnEnd; column++) {
566 if (this.hot.columnIndexMapper.getRenderableFromVisualIndex(column) !== null) {
567 count += 1;
568 }
569 }
570 return count;
571 }
572
573 /**
574 * The function returns the number of renderable row indexes within the passed range of the visual indexes.
575 *
576 * @param {number} rowStart The row visual start index.
577 * @param {number} rowEnd The row visual end index.
578 * @returns {number}
579 */
580 countRenderableRowsInRange(rowStart, rowEnd) {
581 let count = 0;
582 for (let row = rowStart; row <= rowEnd; row++) {
583 if (this.hot.rowIndexMapper.getRenderableFromVisualIndex(row) !== null) {
584 count += 1;
585 }
586 }
587 return count;
588 }
589
590 /**
591 * Checks if at least one cell than belongs to the main table is not covered by the top, left or
592 * bottom overlay.
593 *
594 * @returns {boolean}
595 */
596 isMainTableNotFullyCoveredByOverlays() {
597 const fixedAllRows = this.countNotHiddenFixedRowsTop() + this.countNotHiddenFixedRowsBottom();
598 const fixedAllColumns = this.countNotHiddenFixedColumnsStart();
599 return this.hot.countRenderedRows() > fixedAllRows && this.hot.countRenderedCols() > fixedAllColumns;
600 }
601
602 /**
603 * Defines default configuration and initializes WalkOnTable instance.
604 *
605 * @private
606 */
607 initializeWalkontable() {
608 const walkontableConfig = {
609 ariaTags: this.settings.ariaTags,
610 rtlMode: this.hot.isRtl(),
611 externalRowCalculator: this.hot.getPlugin('autoRowSize') && this.hot.getPlugin('autoRowSize').isEnabled(),
612 table: _classPrivateFieldGet(_table, this),
613 isDataViewInstance: () => (0, _rootInstance.isRootInstance)(this.hot),
614 preventOverflow: () => this.settings.preventOverflow,
615 preventWheel: () => this.settings.preventWheel,
616 stretchH: () => this.settings.stretchH,
617 data: (renderableRow, renderableColumn) => {
618 return this.hot.getDataAtCell(...this.translateFromRenderableToVisualIndex(renderableRow, renderableColumn));
619 },
620 totalRows: () => this.countRenderableRows(),
621 totalColumns: () => this.countRenderableColumns(),
622 // Number of renderable columns for the left overlay.
623 fixedColumnsStart: () => this.countNotHiddenFixedColumnsStart(),
624 // Number of renderable rows for the top overlay.
625 fixedRowsTop: () => this.countNotHiddenFixedRowsTop(),
626 // Number of renderable rows for the bottom overlay.
627 fixedRowsBottom: () => this.countNotHiddenFixedRowsBottom(),
628 // Enable the inline start overlay when conditions are met.
629 shouldRenderInlineStartOverlay: () => {
630 return this.settings.fixedColumnsStart > 0 || walkontableConfig.rowHeaders().length > 0;
631 },
632 // Enable the top overlay when conditions are met.
633 shouldRenderTopOverlay: () => {
634 return this.settings.fixedRowsTop > 0 || walkontableConfig.columnHeaders().length > 0;
635 },
636 // Enable the bottom overlay when conditions are met.
637 shouldRenderBottomOverlay: () => {
638 return this.settings.fixedRowsBottom > 0;
639 },
640 minSpareRows: () => this.settings.minSpareRows,
641 renderAllRows: this.settings.renderAllRows,
642 renderAllColumns: this.settings.renderAllColumns,
643 rowHeaders: () => {
644 const headerRenderers = [];
645 if (this.hot.hasRowHeaders()) {
646 headerRenderers.push((renderableRowIndex, TH) => {
647 // TODO: Some helper may be needed.
648 // We perform translation for row indexes (without row headers).
649 const visualRowIndex = renderableRowIndex >= 0 ? this.hot.rowIndexMapper.getVisualFromRenderableIndex(renderableRowIndex) : renderableRowIndex;
650 this.appendRowHeader(visualRowIndex, TH);
651 });
652 }
653 this.hot.runHooks('afterGetRowHeaderRenderers', headerRenderers);
654 _classPrivateFieldSet(_rowHeadersCount, this, headerRenderers.length);
655 if (this.hot.getSettings().ariaTags) {
656 // Update the aria-colcount attribute.
657 // Only needs to be done once after initialization/data update.
658 if (_assertClassBrand(_TableView_brand, this, _getAriaColcount).call(this) === this.hot.countCols()) {
659 _assertClassBrand(_TableView_brand, this, _updateAriaColcount).call(this, _classPrivateFieldGet(_rowHeadersCount, this));
660 }
661 }
662 return headerRenderers;
663 },
664 columnHeaders: () => {
665 const headerRenderers = [];
666 if (this.hot.hasColHeaders()) {
667 headerRenderers.push((renderedColumnIndex, TH) => {
668 // TODO: Some helper may be needed.
669 // We perform translation for columns indexes (without column headers).
670 const visualColumnsIndex = renderedColumnIndex >= 0 ? this.hot.columnIndexMapper.getVisualFromRenderableIndex(renderedColumnIndex) : renderedColumnIndex;
671 this.appendColHeader(visualColumnsIndex, TH);
672 });
673 }
674 this.hot.runHooks('afterGetColumnHeaderRenderers', headerRenderers);
675 _classPrivateFieldSet(_columnHeadersCount, this, headerRenderers.length);
676 return headerRenderers;
677 },
678 columnWidth: renderedColumnIndex => {
679 const visualIndex = this.hot.columnIndexMapper.getVisualFromRenderableIndex(renderedColumnIndex);
680
681 // It's not a bug that we can't find visual index for some handled by method indexes. The function is called also
682 // for indexes that are not displayed (indexes that are beyond the grid's boundaries), i.e. when `fixedColumnsStart` > `startCols` (wrong config?) or
683 // scrolling and dataset is empty (scroll should handle that?).
684 return this.hot.getColWidth(visualIndex === null ? renderedColumnIndex : visualIndex);
685 },
686 rowHeight: renderedRowIndex => {
687 const visualIndex = this.hot.rowIndexMapper.getVisualFromRenderableIndex(renderedRowIndex);
688 return this.hot.getRowHeight(visualIndex === null ? renderedRowIndex : visualIndex);
689 },
690 rowHeightByOverlayName: (renderedRowIndex, overlayType) => {
691 const visualIndex = this.hot.rowIndexMapper.getVisualFromRenderableIndex(renderedRowIndex);
692 const visualRowIndex = visualIndex === null ? renderedRowIndex : visualIndex;
693 return this.hot.runHooks('modifyRowHeightByOverlayName', this.hot.getRowHeight(visualRowIndex), visualRowIndex, overlayType);
694 },
695 cellRenderer: (renderedRowIndex, renderedColumnIndex, TD) => {
696 const [visualRowIndex, visualColumnIndex] = this.translateFromRenderableToVisualIndex(renderedRowIndex, renderedColumnIndex);
697
698 // Coords may be modified. For example, by the `MergeCells` plugin. It should affect cell value and cell meta.
699 const modifiedCellCoords = this.hot.runHooks('modifyGetCellCoords', visualRowIndex, visualColumnIndex);
700 let visualRowToCheck = visualRowIndex;
701 let visualColumnToCheck = visualColumnIndex;
702 if (Array.isArray(modifiedCellCoords)) {
703 [visualRowToCheck, visualColumnToCheck] = modifiedCellCoords;
704 }
705 const cellProperties = this.hot.getCellMeta(visualRowToCheck, visualColumnToCheck);
706 const prop = this.hot.colToProp(visualColumnToCheck);
707 let value = this.hot.getDataAtRowProp(visualRowToCheck, prop);
708 if (this.hot.hasHook('beforeValueRender')) {
709 value = this.hot.runHooks('beforeValueRender', value, cellProperties);
710 }
711 this.hot.runHooks('beforeRenderer', TD, visualRowIndex, visualColumnIndex, prop, value, cellProperties);
712 this.hot.getCellRenderer(cellProperties)(this.hot, TD, visualRowIndex, visualColumnIndex, prop, value, cellProperties);
713 this.hot.runHooks('afterRenderer', TD, visualRowIndex, visualColumnIndex, prop, value, cellProperties);
714 },
715 selections: this.hot.selection.highlight,
716 hideBorderOnMouseDownOver: () => this.settings.fragmentSelection,
717 onWindowResize: () => {
718 if (this.hot && !this.hot.isDestroyed) {
719 this.hot.refreshDimensions();
720 }
721 },
722 onContainerElementResize: () => {
723 if (this.hot && !this.hot.isDestroyed && (0, _element.isVisible)(this.hot.rootElement)) {
724 this.hot.refreshDimensions();
725 }
726 },
727 onCellMouseDown: (event, coords, TD, wt) => {
728 const visualCoords = this.translateFromRenderableToVisualCoords(coords);
729 const controller = {
730 row: false,
731 column: false,
732 cell: false
733 };
734 this.hot.listen();
735 this.activeWt = wt;
736 _classPrivateFieldSet(_mouseDown, this, true);
737 this.hot.runHooks('beforeOnCellMouseDown', event, visualCoords, TD, controller);
738 if ((0, _event.isImmediatePropagationStopped)(event)) {
739 return;
740 }
741 (0, _mouseEventHandler.handleMouseEvent)(event, {
742 coords: visualCoords,
743 selection: this.hot.selection,
744 controller,
745 cellCoordsFactory: (row, column) => this.hot._createCellCoords(row, column)
746 });
747 this.hot.runHooks('afterOnCellMouseDown', event, visualCoords, TD);
748 this.activeWt = this._wt;
749 },
750 onCellContextMenu: (event, coords, TD, wt) => {
751 const visualCoords = this.translateFromRenderableToVisualCoords(coords);
752 this.activeWt = wt;
753 _classPrivateFieldSet(_mouseDown, this, false);
754 if (this.hot.selection.isInProgress()) {
755 this.hot.selection.finish();
756 }
757 this.hot.runHooks('beforeOnCellContextMenu', event, visualCoords, TD);
758 if ((0, _event.isImmediatePropagationStopped)(event)) {
759 return;
760 }
761 this.hot.runHooks('afterOnCellContextMenu', event, visualCoords, TD);
762 this.activeWt = this._wt;
763 },
764 onCellMouseOut: (event, coords, TD, wt) => {
765 const visualCoords = this.translateFromRenderableToVisualCoords(coords);
766 this.activeWt = wt;
767 this.hot.runHooks('beforeOnCellMouseOut', event, visualCoords, TD);
768 if ((0, _event.isImmediatePropagationStopped)(event)) {
769 return;
770 }
771 this.hot.runHooks('afterOnCellMouseOut', event, visualCoords, TD);
772 this.activeWt = this._wt;
773 },
774 onCellMouseOver: (event, coords, TD, wt) => {
775 const visualCoords = this.translateFromRenderableToVisualCoords(coords);
776 const controller = {
777 row: false,
778 column: false,
779 cell: false
780 };
781 this.activeWt = wt;
782 this.hot.runHooks('beforeOnCellMouseOver', event, visualCoords, TD, controller);
783 if ((0, _event.isImmediatePropagationStopped)(event)) {
784 return;
785 }
786 if (_classPrivateFieldGet(_mouseDown, this)) {
787 (0, _mouseEventHandler.handleMouseEvent)(event, {
788 coords: visualCoords,
789 selection: this.hot.selection,
790 controller,
791 cellCoordsFactory: (row, column) => this.hot._createCellCoords(row, column)
792 });
793 }
794 this.hot.runHooks('afterOnCellMouseOver', event, visualCoords, TD);
795 this.activeWt = this._wt;
796 },
797 onCellMouseUp: (event, coords, TD, wt) => {
798 const visualCoords = this.translateFromRenderableToVisualCoords(coords);
799 this.activeWt = wt;
800 this.hot.runHooks('beforeOnCellMouseUp', event, visualCoords, TD);
801
802 // TODO: The second condition check is a workaround. Callback corresponding the method `updateSettings`
803 // disable plugin and enable it again. Disabling plugin closes the menu. Thus, calling the
804 // `updateSettings` in a body of any callback executed right after some context-menu action
805 // breaks the table (#7231).
806 if ((0, _event.isImmediatePropagationStopped)(event) || this.hot.isDestroyed) {
807 return;
808 }
809 this.hot.runHooks('afterOnCellMouseUp', event, visualCoords, TD);
810 this.activeWt = this._wt;
811 },
812 onCellCornerMouseDown: event => {
813 event.preventDefault();
814 this.hot.runHooks('afterOnCellCornerMouseDown', event);
815 },
816 onCellCornerDblClick: event => {
817 event.preventDefault();
818 this.hot.runHooks('afterOnCellCornerDblClick', event);
819 },
820 beforeDraw: (force, skipRender) => this.beforeRender(force, skipRender),
821 onDraw: force => this.afterRender(force),
822 onBeforeViewportScrollVertically: renderableRow => {
823 const rowMapper = this.hot.rowIndexMapper;
824 const areColumnHeadersSelected = renderableRow < 0;
825 let visualRow = renderableRow;
826 if (!areColumnHeadersSelected) {
827 visualRow = rowMapper.getVisualFromRenderableIndex(renderableRow);
828
829 // for an empty data return index as is
830 if (visualRow === null) {
831 return renderableRow;
832 }
833 }
834 visualRow = this.hot.runHooks('beforeViewportScrollVertically', visualRow);
835 this.hot.runHooks('beforeViewportScroll');
836 if (!areColumnHeadersSelected) {
837 return rowMapper.getRenderableFromVisualIndex(visualRow);
838 }
839 return visualRow;
840 },
841 onBeforeViewportScrollHorizontally: renderableColumn => {
842 const columnMapper = this.hot.columnIndexMapper;
843 const areRowHeadersSelected = renderableColumn < 0;
844 let visualColumn = renderableColumn;
845 if (!areRowHeadersSelected) {
846 visualColumn = columnMapper.getVisualFromRenderableIndex(renderableColumn);
847
848 // for an empty data return index as is
849 if (visualColumn === null) {
850 return renderableColumn;
851 }
852 }
853 visualColumn = this.hot.runHooks('beforeViewportScrollHorizontally', visualColumn);
854 this.hot.runHooks('beforeViewportScroll');
855 if (!areRowHeadersSelected) {
856 return columnMapper.getRenderableFromVisualIndex(visualColumn);
857 }
858 return visualColumn;
859 },
860 onScrollVertically: () => {
861 this.hot.runHooks('afterScrollVertically');
862 this.hot.runHooks('afterScroll');
863 },
864 onScrollHorizontally: () => {
865 this.hot.runHooks('afterScrollHorizontally');
866 this.hot.runHooks('afterScroll');
867 },
868 onBeforeRemoveCellClassNames: () => this.hot.runHooks('beforeRemoveCellClassNames'),
869 onBeforeHighlightingRowHeader: (renderableRow, headerLevel, highlightMeta) => {
870 const rowMapper = this.hot.rowIndexMapper;
871 const areColumnHeadersSelected = renderableRow < 0;
872 let visualRow = renderableRow;
873 if (!areColumnHeadersSelected) {
874 visualRow = rowMapper.getVisualFromRenderableIndex(renderableRow);
875 }
876 const newVisualRow = this.hot.runHooks('beforeHighlightingRowHeader', visualRow, headerLevel, highlightMeta);
877 if (!areColumnHeadersSelected) {
878 return rowMapper.getRenderableFromVisualIndex(rowMapper.getNearestNotHiddenIndex(newVisualRow, 1));
879 }
880 return newVisualRow;
881 },
882 onBeforeHighlightingColumnHeader: (renderableColumn, headerLevel, highlightMeta) => {
883 const columnMapper = this.hot.columnIndexMapper;
884 const areRowHeadersSelected = renderableColumn < 0;
885 let visualColumn = renderableColumn;
886 if (!areRowHeadersSelected) {
887 visualColumn = columnMapper.getVisualFromRenderableIndex(renderableColumn);
888 }
889 const newVisualColumn = this.hot.runHooks('beforeHighlightingColumnHeader', visualColumn, headerLevel, highlightMeta);
890 if (!areRowHeadersSelected) {
891 return columnMapper.getRenderableFromVisualIndex(columnMapper.getNearestNotHiddenIndex(newVisualColumn, 1));
892 }
893 return newVisualColumn;
894 },
895 onAfterDrawSelection: (currentRow, currentColumn, layerLevel) => {
896 let cornersOfSelection;
897 const [visualRowIndex, visualColumnIndex] = this.translateFromRenderableToVisualIndex(currentRow, currentColumn);
898 const selectedRange = this.hot.selection.getSelectedRange();
899 const selectionRangeSize = selectedRange.size();
900 if (selectionRangeSize > 0) {
901 const selectionForLayer = selectedRange.peekByIndex(layerLevel !== null && layerLevel !== void 0 ? layerLevel : 0);
902 cornersOfSelection = [selectionForLayer.from.row, selectionForLayer.from.col, selectionForLayer.to.row, selectionForLayer.to.col];
903 }
904 return this.hot.runHooks('afterDrawSelection', visualRowIndex, visualColumnIndex, cornersOfSelection, layerLevel);
905 },
906 onBeforeDrawBorders: (corners, borderClassName) => {
907 const [startRenderableRow, startRenderableColumn, endRenderableRow, endRenderableColumn] = corners;
908 const visualCorners = [this.hot.rowIndexMapper.getVisualFromRenderableIndex(startRenderableRow), this.hot.columnIndexMapper.getVisualFromRenderableIndex(startRenderableColumn), this.hot.rowIndexMapper.getVisualFromRenderableIndex(endRenderableRow), this.hot.columnIndexMapper.getVisualFromRenderableIndex(endRenderableColumn)];
909 return this.hot.runHooks('beforeDrawBorders', visualCorners, borderClassName);
910 },
911 onBeforeTouchScroll: () => this.hot.runHooks('beforeTouchScroll'),
912 onAfterMomentumScroll: () => this.hot.runHooks('afterMomentumScroll'),
913 onBeforeStretchingColumnWidth: (stretchedWidth, renderedColumnIndex) => {
914 const visualColumnIndex = this.hot.columnIndexMapper.getVisualFromRenderableIndex(renderedColumnIndex);
915 return this.hot.runHooks('beforeStretchingColumnWidth', stretchedWidth, visualColumnIndex);
916 },
917 onModifyRowHeaderWidth: rowHeaderWidth => this.hot.runHooks('modifyRowHeaderWidth', rowHeaderWidth),
918 onModifyGetCellCoords: (renderableRowIndex, renderableColumnIndex, topmost) => {
919 const rowMapper = this.hot.rowIndexMapper;
920 const columnMapper = this.hot.columnIndexMapper;
921
922 // Callback handle also headers. We shouldn't translate them.
923 const visualColumnIndex = renderableColumnIndex >= 0 ? columnMapper.getVisualFromRenderableIndex(renderableColumnIndex) : renderableColumnIndex;
924 const visualRowIndex = renderableRowIndex >= 0 ? rowMapper.getVisualFromRenderableIndex(renderableRowIndex) : renderableRowIndex;
925 const visualIndexes = this.hot.runHooks('modifyGetCellCoords', visualRowIndex, visualColumnIndex, topmost);
926 if (Array.isArray(visualIndexes)) {
927 const [visualRowFrom, visualColumnFrom, visualRowTo, visualColumnTo] = visualIndexes;
928
929 // Result of the hook is handled by the Walkontable (renderable indexes).
930 return [visualRowFrom >= 0 ? rowMapper.getRenderableFromVisualIndex(rowMapper.getNearestNotHiddenIndex(visualRowFrom, 1)) : visualRowFrom, visualColumnFrom >= 0 ? columnMapper.getRenderableFromVisualIndex(columnMapper.getNearestNotHiddenIndex(visualColumnFrom, 1)) : visualColumnFrom, visualRowTo >= 0 ? rowMapper.getRenderableFromVisualIndex(rowMapper.getNearestNotHiddenIndex(visualRowTo, -1)) : visualRowTo, visualColumnTo >= 0 ? columnMapper.getRenderableFromVisualIndex(columnMapper.getNearestNotHiddenIndex(visualColumnTo, -1)) : visualColumnTo];
931 }
932 },
933 viewportRowCalculatorOverride: calc => {
934 let viewportOffset = this.settings.viewportRowRenderingOffset;
935 if (viewportOffset === 'auto' && this.settings.fixedRowsTop) {
936 viewportOffset = 10;
937 }
938 if (viewportOffset > 0 || viewportOffset === 'auto') {
939 const renderableRows = this.countRenderableRows();
940 const firstRenderedRow = calc.startRow;
941 const lastRenderedRow = calc.endRow;
942 if (typeof viewportOffset === 'number') {
943 calc.startRow = Math.max(firstRenderedRow - viewportOffset, 0);
944 calc.endRow = Math.min(lastRenderedRow + viewportOffset, renderableRows - 1);
945 } else if (viewportOffset === 'auto') {
946 const offset = Math.ceil(lastRenderedRow / renderableRows * 12);
947 calc.startRow = Math.max(firstRenderedRow - offset, 0);
948 calc.endRow = Math.min(lastRenderedRow + offset, renderableRows - 1);
949 }
950 }
951 this.hot.runHooks('afterViewportRowCalculatorOverride', calc);
952 },
953 viewportColumnCalculatorOverride: calc => {
954 let viewportOffset = this.settings.viewportColumnRenderingOffset;
955 if (viewportOffset === 'auto' && this.settings.fixedColumnsStart) {
956 viewportOffset = 10;
957 }
958 if (viewportOffset > 0 || viewportOffset === 'auto') {
959 const renderableColumns = this.countRenderableColumns();
960 const firstRenderedColumn = calc.startColumn;
961 const lastRenderedColumn = calc.endColumn;
962 if (typeof viewportOffset === 'number') {
963 calc.startColumn = Math.max(firstRenderedColumn - viewportOffset, 0);
964 calc.endColumn = Math.min(lastRenderedColumn + viewportOffset, renderableColumns - 1);
965 }
966 if (viewportOffset === 'auto') {
967 const offset = Math.ceil(lastRenderedColumn / renderableColumns * 6);
968 calc.startColumn = Math.max(firstRenderedColumn - offset, 0);
969 calc.endColumn = Math.min(lastRenderedColumn + offset, renderableColumns - 1);
970 }
971 }
972 this.hot.runHooks('afterViewportColumnCalculatorOverride', calc);
973 },
974 rowHeaderWidth: () => this.settings.rowHeaderWidth,
975 columnHeaderHeight: () => {
976 const columnHeaderHeight = this.hot.runHooks('modifyColumnHeaderHeight');
977 return this.settings.columnHeaderHeight || columnHeaderHeight;
978 }
979 };
980 this.hot.runHooks('beforeInitWalkontable', walkontableConfig);
981 this._wt = new _src.default(walkontableConfig);
982 this.activeWt = this._wt;
983 const spreader = this._wt.wtTable.spreader;
984 // We have to cache width and height after Walkontable initialization.
985 const {
986 width,
987 height
988 } = this.hot.rootElement.getBoundingClientRect();
989 this.setLastSize(width, height);
990 this.eventManager.addEventListener(spreader, 'mousedown', event => {
991 // right mouse button exactly on spreader means right click on the right hand side of vertical scrollbar
992 if (event.target === spreader && event.which === 3) {
993 event.stopPropagation();
994 }
995 });
996 this.eventManager.addEventListener(spreader, 'contextmenu', event => {
997 // right mouse button exactly on spreader means right click on the right hand side of vertical scrollbar
998 if (event.target === spreader && event.which === 3) {
999 event.stopPropagation();
1000 }
1001 });
1002 this.eventManager.addEventListener(this.hot.rootDocument.documentElement, 'click', () => {
1003 if (this.settings.observeDOMVisibility) {
1004 if (this._wt.drawInterrupted) {
1005 this.hot.forceFullRender = true;
1006 this.render();
1007 }
1008 }
1009 });
1010 }
1011
1012 /**
1013 * Checks if it's possible to create text selection in element.
1014 *
1015 * @private
1016 * @param {HTMLElement} el The element to check.
1017 * @returns {boolean}
1018 */
1019 isTextSelectionAllowed(el) {
1020 if ((0, _element.isInput)(el)) {
1021 return true;
1022 }
1023 const isChildOfTableBody = (0, _element.isChildOf)(el, this._wt.wtTable.spreader);
1024 if (this.settings.fragmentSelection === true && isChildOfTableBody) {
1025 return true;
1026 }
1027 if (this.settings.fragmentSelection === 'cell' && this.isSelectedOnlyCell() && isChildOfTableBody) {
1028 return true;
1029 }
1030 if (!this.settings.fragmentSelection && this.isCellEdited() && this.isSelectedOnlyCell()) {
1031 return true;
1032 }
1033 return false;
1034 }
1035
1036 /**
1037 * Checks if user's been called mousedown.
1038 *
1039 * @private
1040 * @returns {boolean}
1041 */
1042 isMouseDown() {
1043 return _classPrivateFieldGet(_mouseDown, this);
1044 }
1045
1046 /**
1047 * Check if selected only one cell.
1048 *
1049 * @private
1050 * @returns {boolean}
1051 */
1052 isSelectedOnlyCell() {
1053 var _this$hot$getSelected, _this$hot$getSelected2;
1054 return (_this$hot$getSelected = (_this$hot$getSelected2 = this.hot.getSelectedRangeLast()) === null || _this$hot$getSelected2 === void 0 ? void 0 : _this$hot$getSelected2.isSingleCell()) !== null && _this$hot$getSelected !== void 0 ? _this$hot$getSelected : false;
1055 }
1056
1057 /**
1058 * Checks if active cell is editing.
1059 *
1060 * @private
1061 * @returns {boolean}
1062 */
1063 isCellEdited() {
1064 const activeEditor = this.hot.getActiveEditor();
1065 return activeEditor && activeEditor.isOpened();
1066 }
1067
1068 /**
1069 * `beforeDraw` callback.
1070 *
1071 * @private
1072 * @param {boolean} force If `true` rendering was triggered by a change of settings or data or `false` if
1073 * rendering was triggered by scrolling or moving selection.
1074 * @param {object} skipRender Object with `skipRender` property, if it is set to `true ` the next rendering
1075 * cycle will be skipped.
1076 */
1077 beforeRender(force, skipRender) {
1078 if (force) {
1079 // this.hot.forceFullRender = did Handsontable request full render?
1080 this.hot.runHooks('beforeViewRender', this.hot.forceFullRender, skipRender);
1081 }
1082 }
1083
1084 /**
1085 * `afterRender` callback.
1086 *
1087 * @private
1088 * @param {boolean} force If `true` rendering was triggered by a change of settings or data or `false` if
1089 * rendering was triggered by scrolling or moving selection.
1090 */
1091 afterRender(force) {
1092 if (force) {
1093 // this.hot.forceFullRender = did Handsontable request full render?
1094 this.hot.runHooks('afterViewRender', this.hot.forceFullRender);
1095 }
1096 }
1097
1098 /**
1099 * Append row header to a TH element.
1100 *
1101 * @private
1102 * @param {number} visualRowIndex The visual row index.
1103 * @param {HTMLTableHeaderCellElement} TH The table header element.
1104 */
1105 appendRowHeader(visualRowIndex, TH) {
1106 if (TH.firstChild) {
1107 const container = TH.firstChild;
1108 if (!(0, _element.hasClass)(container, 'relative')) {
1109 (0, _element.empty)(TH);
1110 this.appendRowHeader(visualRowIndex, TH);
1111 return;
1112 }
1113 this.updateCellHeader(container.querySelector('.rowHeader'), visualRowIndex, this.hot.getRowHeader);
1114 } else {
1115 const {
1116 rootDocument,
1117 getRowHeader
1118 } = this.hot;
1119 const div = rootDocument.createElement('div');
1120 const span = rootDocument.createElement('span');
1121 div.className = 'relative';
1122 span.className = 'rowHeader';
1123 this.updateCellHeader(span, visualRowIndex, getRowHeader);
1124 div.appendChild(span);
1125 TH.appendChild(div);
1126 }
1127 this.hot.runHooks('afterGetRowHeader', visualRowIndex, TH);
1128 }
1129
1130 /**
1131 * Append column header to a TH element.
1132 *
1133 * @private
1134 * @param {number} visualColumnIndex Visual column index.
1135 * @param {HTMLTableCellElement} TH The table header element.
1136 * @param {Function} [label] The function that returns the header label.
1137 * @param {number} [headerLevel=0] The index of header level counting from the top (positive
1138 * values counting from 0 to N).
1139 */
1140 appendColHeader(visualColumnIndex, TH) {
1141 let label = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.hot.getColHeader;
1142 let headerLevel = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
1143 const getColumnHeaderClassNames = () => {
1144 const metaHeaderClassNames = visualColumnIndex >= 0 ? this.hot.getColumnMeta(visualColumnIndex).headerClassName : null;
1145 return metaHeaderClassNames ? metaHeaderClassNames.split(' ') : [];
1146 };
1147 if (TH.firstChild) {
1148 const container = TH.firstChild;
1149 if ((0, _element.hasClass)(container, 'relative')) {
1150 this.updateCellHeader(container.querySelector('.colHeader'), visualColumnIndex, label, headerLevel);
1151 container.className = '';
1152 (0, _element.addClass)(container, ['relative', ...getColumnHeaderClassNames()]);
1153 } else {
1154 (0, _element.empty)(TH);
1155 this.appendColHeader(visualColumnIndex, TH, label, headerLevel);
1156 }
1157 } else {
1158 const {
1159 rootDocument
1160 } = this.hot;
1161 const div = rootDocument.createElement('div');
1162 const span = rootDocument.createElement('span');
1163 const classNames = getColumnHeaderClassNames();
1164 div.classList.add('relative', ...classNames);
1165 span.className = 'colHeader';
1166 if (this.settings.ariaTags) {
1167 (0, _element.setAttribute)(div, ...(0, _a11y.A11Y_PRESENTATION)());
1168 (0, _element.setAttribute)(span, ...(0, _a11y.A11Y_PRESENTATION)());
1169 }
1170 this.updateCellHeader(span, visualColumnIndex, label, headerLevel);
1171 div.appendChild(span);
1172 TH.appendChild(div);
1173 }
1174 this.hot.runHooks('afterGetColHeader', visualColumnIndex, TH, headerLevel);
1175 }
1176
1177 /**
1178 * Updates header cell content.
1179 *
1180 * @private
1181 * @param {HTMLElement} element Element to update.
1182 * @param {number} index Row index or column index.
1183 * @param {Function} content Function which should be returns content for this cell.
1184 * @param {number} [headerLevel=0] The index of header level counting from the top (positive
1185 * values counting from 0 to N).
1186 */
1187 updateCellHeader(element, index, content) {
1188 let headerLevel = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
1189 let renderedIndex = index;
1190 const parentOverlay = this._wt.wtOverlays.getParentOverlay(element) || this._wt;
1191
1192 // prevent wrong calculations from SampleGenerator
1193 if (element.parentNode) {
1194 if ((0, _element.hasClass)(element, 'colHeader')) {
1195 renderedIndex = parentOverlay.wtTable.columnFilter.sourceToRendered(index);
1196 } else if ((0, _element.hasClass)(element, 'rowHeader')) {
1197 renderedIndex = parentOverlay.wtTable.rowFilter.sourceToRendered(index);
1198 }
1199 }
1200 if (renderedIndex > -1) {
1201 (0, _element.fastInnerHTML)(element, content(index, headerLevel));
1202 } else {
1203 // workaround for https://github.com/handsontable/handsontable/issues/1946
1204 (0, _element.fastInnerText)(element, String.fromCharCode(160));
1205 (0, _element.addClass)(element, 'cornerHeader');
1206 }
1207 }
1208
1209 /**
1210 * Given a element's left (or right in RTL mode) position relative to the viewport, returns maximum
1211 * element width until the right (or left) edge of the viewport (before scrollbar).
1212 *
1213 * @private
1214 * @param {number} inlineOffset The left (or right in RTL mode) offset.
1215 * @returns {number}
1216 */
1217 maximumVisibleElementWidth(inlineOffset) {
1218 const workspaceWidth = this._wt.wtViewport.getWorkspaceWidth();
1219 const maxWidth = workspaceWidth - inlineOffset;
1220 return maxWidth > 0 ? maxWidth : 0;
1221 }
1222
1223 /**
1224 * Given a element's top position relative to the viewport, returns maximum element height until the bottom
1225 * edge of the viewport (before scrollbar).
1226 *
1227 * @private
1228 * @param {number} topOffset The top offset.
1229 * @returns {number}
1230 */
1231 maximumVisibleElementHeight(topOffset) {
1232 const workspaceHeight = this._wt.wtViewport.getWorkspaceHeight();
1233 const maxHeight = workspaceHeight - topOffset;
1234 return maxHeight > 0 ? maxHeight : 0;
1235 }
1236
1237 /**
1238 * Sets new dimensions of the container.
1239 *
1240 * @param {number} width The table width.
1241 * @param {number} height The table height.
1242 */
1243 setLastSize(width, height) {
1244 _classPrivateFieldSet(_lastWidth, this, width);
1245 _classPrivateFieldSet(_lastHeight, this, height);
1246 }
1247
1248 /**
1249 * Returns cached dimensions.
1250 *
1251 * @returns {object}
1252 */
1253 getLastSize() {
1254 return {
1255 width: _classPrivateFieldGet(_lastWidth, this),
1256 height: _classPrivateFieldGet(_lastHeight, this)
1257 };
1258 }
1259
1260 /**
1261 * Returns the first rendered row in the DOM (usually is not visible in the table's viewport).
1262 *
1263 * @returns {number | null}
1264 */
1265 getFirstRenderedVisibleRow() {
1266 if (!this._wt.wtViewport.rowsRenderCalculator) {
1267 return null;
1268 }
1269 return this.hot.rowIndexMapper.getNearestNotHiddenIndex(this._wt.wtTable.getFirstRenderedRow(), 1);
1270 }
1271
1272 /**
1273 * Returns the last rendered row in the DOM (usually is not visible in the table's viewport).
1274 *
1275 * @returns {number | null}
1276 */
1277 getLastRenderedVisibleRow() {
1278 if (!this._wt.wtViewport.rowsRenderCalculator) {
1279 return null;
1280 }
1281 return this.hot.rowIndexMapper.getNearestNotHiddenIndex(this._wt.wtTable.getLastRenderedRow(), -1);
1282 }
1283
1284 /**
1285 * Returns the first rendered column in the DOM (usually is not visible in the table's viewport).
1286 *
1287 * @returns {number | null}
1288 */
1289 getFirstRenderedVisibleColumn() {
1290 if (!this._wt.wtViewport.columnsRenderCalculator) {
1291 return null;
1292 }
1293 return this.hot.columnIndexMapper.getNearestNotHiddenIndex(this._wt.wtTable.getFirstRenderedColumn(), 1);
1294 }
1295
1296 /**
1297 * Returns the last rendered column in the DOM (usually is not visible in the table's viewport).
1298 *
1299 * @returns {number | null}
1300 */
1301 getLastRenderedVisibleColumn() {
1302 if (!this._wt.wtViewport.columnsRenderCalculator) {
1303 return null;
1304 }
1305 return this.hot.columnIndexMapper.getNearestNotHiddenIndex(this._wt.wtTable.getLastRenderedColumn(), -1);
1306 }
1307
1308 /**
1309 * Returns the first fully visible row in the table viewport. When the table has overlays the method returns
1310 * the first row of the master table that is not overlapped by overlay.
1311 *
1312 * @returns {number}
1313 */
1314 getFirstFullyVisibleRow() {
1315 return this.hot.rowIndexMapper.getVisualFromRenderableIndex(this._wt.wtScroll.getFirstVisibleRow());
1316 }
1317
1318 /**
1319 * Returns the last fully visible row in the table viewport. When the table has overlays the method returns
1320 * the first row of the master table that is not overlapped by overlay.
1321 *
1322 * @returns {number}
1323 */
1324 getLastFullyVisibleRow() {
1325 return this.hot.rowIndexMapper.getVisualFromRenderableIndex(this._wt.wtScroll.getLastVisibleRow());
1326 }
1327
1328 /**
1329 * Returns the first fully visible column in the table viewport. When the table has overlays the method returns
1330 * the first row of the master table that is not overlapped by overlay.
1331 *
1332 * @returns {number}
1333 */
1334 getFirstFullyVisibleColumn() {
1335 return this.hot.columnIndexMapper.getVisualFromRenderableIndex(this._wt.wtScroll.getFirstVisibleColumn());
1336 }
1337
1338 /**
1339 * Returns the last fully visible column in the table viewport. When the table has overlays the method returns
1340 * the first row of the master table that is not overlapped by overlay.
1341 *
1342 * @returns {number}
1343 */
1344 getLastFullyVisibleColumn() {
1345 return this.hot.columnIndexMapper.getVisualFromRenderableIndex(this._wt.wtScroll.getLastVisibleColumn());
1346 }
1347
1348 /**
1349 * Returns the first partially visible row in the table viewport. When the table has overlays the method returns
1350 * the first row of the master table that is not overlapped by overlay.
1351 *
1352 * @returns {number}
1353 */
1354 getFirstPartiallyVisibleRow() {
1355 return this.hot.rowIndexMapper.getVisualFromRenderableIndex(this._wt.wtScroll.getFirstPartiallyVisibleRow());
1356 }
1357
1358 /**
1359 * Returns the last partially visible row in the table viewport. When the table has overlays the method returns
1360 * the first row of the master table that is not overlapped by overlay.
1361 *
1362 * @returns {number}
1363 */
1364 getLastPartiallyVisibleRow() {
1365 return this.hot.rowIndexMapper.getVisualFromRenderableIndex(this._wt.wtScroll.getLastPartiallyVisibleRow());
1366 }
1367
1368 /**
1369 * Returns the first partially visible column in the table viewport. When the table has overlays the method returns
1370 * the first row of the master table that is not overlapped by overlay.
1371 *
1372 * @returns {number}
1373 */
1374 getFirstPartiallyVisibleColumn() {
1375 return this.hot.columnIndexMapper.getVisualFromRenderableIndex(this._wt.wtScroll.getFirstPartiallyVisibleColumn());
1376 }
1377
1378 /**
1379 * Returns the last partially visible column in the table viewport. When the table has overlays the method returns
1380 * the first row of the master table that is not overlapped by overlay.
1381 *
1382 * @returns {number}
1383 */
1384 getLastPartiallyVisibleColumn() {
1385 return this.hot.columnIndexMapper.getVisualFromRenderableIndex(this._wt.wtScroll.getLastPartiallyVisibleColumn());
1386 }
1387
1388 /**
1389 * Returns the total count of the rendered column headers.
1390 *
1391 * @returns {number}
1392 */
1393 getColumnHeadersCount() {
1394 return _classPrivateFieldGet(_columnHeadersCount, this);
1395 }
1396
1397 /**
1398 * Returns the total count of the rendered row headers.
1399 *
1400 * @returns {number}
1401 */
1402 getRowHeadersCount() {
1403 return _classPrivateFieldGet(_rowHeadersCount, this);
1404 }
1405
1406 /**
1407 * Returns the table's viewport width. When the table has defined the size of the container,
1408 * and the columns do not fill the entire viewport, the viewport width is equal to the sum of
1409 * the columns' widths.
1410 *
1411 * @returns {number}
1412 */
1413 getViewportWidth() {
1414 return this._wt.wtViewport.getViewportWidth();
1415 }
1416
1417 /**
1418 * Returns the table's total width including the scrollbar width.
1419 *
1420 * @returns {number}
1421 */
1422 getWorkspaceWidth() {
1423 return this._wt.wtViewport.getWorkspaceWidth();
1424 }
1425
1426 /**
1427 * Returns the table's viewport height. When the table has defined the size of the container,
1428 * and the rows do not fill the entire viewport, the viewport height is equal to the sum of
1429 * the rows' heights.
1430 *
1431 * @returns {number}
1432 */
1433 getViewportHeight() {
1434 return this._wt.wtViewport.getViewportHeight();
1435 }
1436
1437 /**
1438 * Returns the table's total height including the scrollbar height.
1439 *
1440 * @returns {number}
1441 */
1442 getWorkspaceHeight() {
1443 return this._wt.wtViewport.getWorkspaceHeight();
1444 }
1445
1446 /**
1447 * Checks to what overlay the provided element belongs.
1448 *
1449 * @param {HTMLElement} element The DOM element to check.
1450 * @returns {'master'|'inline_start'|'top'|'top_inline_start_corner'|'bottom'|'bottom_inline_start_corner'}
1451 */
1452 getElementOverlayName(element) {
1453 var _this$_wt$wtOverlays$;
1454 return ((_this$_wt$wtOverlays$ = this._wt.wtOverlays.getParentOverlay(element)) !== null && _this$_wt$wtOverlays$ !== void 0 ? _this$_wt$wtOverlays$ : this._wt).wtTable.name;
1455 }
1456
1457 /**
1458 * Gets the overlay instance by its name.
1459 *
1460 * @param {'inline_start'|'top'|'top_inline_start_corner'|'bottom'|'bottom_inline_start_corner'} overlayName The overlay name.
1461 * @returns {Overlay | null}
1462 */
1463 getOverlayByName(overlayName) {
1464 return this._wt.getOverlayByName(overlayName);
1465 }
1466
1467 /**
1468 * Checks if the table is visible or not.
1469 *
1470 * @returns {boolean}
1471 */
1472 isVisible() {
1473 return this._wt.wtTable.isVisible();
1474 }
1475 /**
1476 * Destroys internal WalkOnTable's instance. Detaches all of the bonded listeners.
1477 *
1478 * @private
1479 */
1480 destroy() {
1481 this._wt.destroy();
1482 this.eventManager.destroy();
1483 }
1484}
1485function _getAriaColcount() {
1486 return parseInt(this.hot.rootElement.getAttribute((0, _a11y.A11Y_COLCOUNT)()[0]), 10);
1487}
1488/**
1489 * Update the `aria-colcount` attribute by the provided value.
1490 *
1491 * @param {number} delta The number of columns to add or remove to the aria tag.
1492 */
1493function _updateAriaColcount(delta) {
1494 const colCount = _assertClassBrand(_TableView_brand, this, _getAriaColcount).call(this) + delta;
1495 (0, _element.setAttribute)(this.hot.rootElement, ...(0, _a11y.A11Y_COLCOUNT)(colCount));
1496}
1497var _default = exports.default = TableView;
\No newline at end of file