UNPKG

handsontable

Version:

Handsontable is a JavaScript Data Grid available for React, Angular and Vue.

350 lines (332 loc) • 12.2 kB
"use strict"; exports.__esModule = true; require("core-js/modules/es.error.cause.js"); var _element = require("../../../../helpers/dom/element"); var _bottom = _interopRequireDefault(require("./../table/bottom")); var _base = require("./_base"); var _constants = require("./constants"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _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; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _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); } /** * @class BottomOverlay */ class BottomOverlay extends _base.Overlay { /** * @param {Walkontable} wotInstance The Walkontable instance. @TODO refactoring: check if can be deleted. * @param {FacadeGetter} facadeGetter Function which return proper facade. * @param {Settings} wtSettings The Walkontable settings. * @param {DomBindings} domBindings Dom elements bound to the current instance. */ constructor(wotInstance, facadeGetter, wtSettings, domBindings) { super(wotInstance, facadeGetter, _constants.CLONE_BOTTOM, wtSettings, domBindings); /** * Cached value which holds the previous value of the `fixedRowsBottom` option. * It is used as a comparison value that can be used to detect changes in that value. * * @type {number} */ _defineProperty(this, "cachedFixedRowsBottom", -1); this.cachedFixedRowsBottom = this.wtSettings.getSetting('fixedRowsBottom'); } /** * Factory method to create a subclass of `Table` that is relevant to this overlay. * * @see Table#constructor * @param {...*} args Parameters that will be forwarded to the `Table` constructor. * @returns {BottomOverlayTable} */ createTable() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return new _bottom.default(...args); } /** * Checks if overlay should be fully rendered. * * @returns {boolean} */ shouldBeRendered() { return this.wtSettings.getSetting('shouldRenderBottomOverlay'); } /** * Updates the top overlay position. * * @returns {boolean} */ resetFixedPosition() { if (!this.needFullRender || !this.shouldBeRendered() || !this.wot.wtTable.holder.parentNode) { // removed from DOM return false; } const { rootWindow } = this.domBindings; const overlayRoot = this.clone.wtTable.holder.parentNode; overlayRoot.style.top = ''; let overlayPosition = 0; const preventOverflow = this.wtSettings.getSetting('preventOverflow'); if (this.trimmingContainer === rootWindow && (!preventOverflow || preventOverflow !== 'vertical')) { overlayPosition = this.getOverlayOffset(); overlayRoot.style.bottom = `${overlayPosition}px`; } else { overlayPosition = this.getScrollPosition(); this.repositionOverlay(); } const positionChanged = this.adjustHeaderBordersPosition(overlayPosition); this.adjustElementsSize(); return positionChanged; } /** * Updates the bottom overlay position. */ repositionOverlay() { const { wtTable, wtViewport } = this.wot; const { rootDocument } = this.domBindings; const cloneRoot = this.clone.wtTable.holder.parentNode; let bottomOffset = 0; if (!wtViewport.hasVerticalScroll()) { bottomOffset += wtViewport.getWorkspaceHeight() - wtTable.getTotalHeight(); } if (wtViewport.hasVerticalScroll() && wtViewport.hasHorizontalScroll()) { bottomOffset += (0, _element.getScrollbarWidth)(rootDocument); } cloneRoot.style.bottom = `${bottomOffset}px`; } /** * Sets the main overlay's vertical scroll position. * * @param {number} pos The scroll position. * @returns {boolean} */ setScrollPosition(pos) { const { rootWindow } = this.domBindings; const scrollableElement = this.mainTableScrollableElement; let result = false; if (scrollableElement === rootWindow && pos !== rootWindow.scrollY) { const oldScrollX = rootWindow.scrollY; rootWindow.scrollTo((0, _element.getWindowScrollLeft)(rootWindow), top); result = oldScrollX !== rootWindow.scrollY; } else if (pos !== scrollableElement.scrollTop) { const oldScrollLeft = scrollableElement.scrollTop; scrollableElement.scrollTop = pos; result = oldScrollLeft !== scrollableElement.scrollTop; } return result; } /** * Triggers onScroll hook callback. */ onScroll() { this.wtSettings.getSetting('onScrollHorizontally'); } /** * Calculates total sum cells height. * * @param {number} from Row index which calculates started from. * @param {number} to Row index where calculation is finished. * @returns {number} Height sum. */ sumCellSizes(from, to) { const { wtTable, wtSettings } = this.wot; const defaultRowHeight = wtSettings.getSetting('stylesHandler').getDefaultRowHeight(); let row = from; let sum = 0; while (row < to) { const height = wtTable.getRowHeight(row); sum += height === undefined ? defaultRowHeight : height; row += 1; } return sum; } /** * Adjust overlay root element, children and master table element sizes (width, height). */ adjustElementsSize() { this.updateTrimmingContainer(); if (this.needFullRender) { this.adjustRootElementSize(); this.adjustRootChildrenSize(); } } /** * Adjust overlay root element size (width and height). */ adjustRootElementSize() { const { wtTable, wtViewport } = this.wot; const { rootDocument, rootWindow } = this.domBindings; const overlayRoot = this.clone.wtTable.holder.parentNode; const overlayRootStyle = overlayRoot.style; const preventOverflow = this.wtSettings.getSetting('preventOverflow'); if (this.trimmingContainer !== rootWindow || preventOverflow === 'horizontal') { let width = wtViewport.getWorkspaceWidth(); if (wtViewport.hasVerticalScroll()) { width -= (0, _element.getScrollbarWidth)(rootDocument); } width = Math.min(width, wtTable.wtRootElement.scrollWidth); overlayRootStyle.width = `${width}px`; } else { overlayRootStyle.width = ''; } this.clone.wtTable.holder.style.width = overlayRootStyle.width; let tableHeight = (0, _element.outerHeight)(this.clone.wtTable.TABLE); if (!wtTable.hasDefinedSize()) { tableHeight = 0; } overlayRootStyle.height = `${tableHeight}px`; } /** * Adjust overlay root childs size. */ adjustRootChildrenSize() { const { holder } = this.clone.wtTable; this.clone.wtTable.hider.style.width = this.hider.style.width; holder.style.width = holder.parentNode.style.width; holder.style.height = holder.parentNode.style.height; } /** * Adjust the overlay dimensions and position. */ applyToDOM() { const total = this.wtSettings.getSetting('totalRows'); if (typeof this.wot.wtViewport.rowsRenderCalculator.startPosition === 'number') { this.spreader.style.top = `${this.wot.wtViewport.rowsRenderCalculator.startPosition}px`; } else if (total === 0) { // can happen if there are 0 rows this.spreader.style.top = '0'; } else { throw new Error('Incorrect value of the rowsRenderCalculator'); } this.spreader.style.bottom = ''; if (this.needFullRender) { this.syncOverlayOffset(); } } /** * Synchronize calculated left position to an element. */ syncOverlayOffset() { const styleProperty = this.isRtl() ? 'right' : 'left'; const { spreader } = this.clone.wtTable; if (typeof this.wot.wtViewport.columnsRenderCalculator.startPosition === 'number') { spreader.style[styleProperty] = `${this.wot.wtViewport.columnsRenderCalculator.startPosition}px`; } else { spreader.style[styleProperty] = ''; } } /** * Scrolls vertically to a row. * * @param {number} sourceRow Row index which you want to scroll to. * @param {boolean} [bottomEdge=false] If `true`, scrolls according to the bottom edge (top edge is by default). */ scrollTo(sourceRow, bottomEdge) { let newY = this.getTableParentOffset(); const sourceInstance = this.wot.cloneSource ? this.wot.cloneSource : this.wot; const mainHolder = sourceInstance.wtTable.holder; let scrollbarCompensation = 0; if (bottomEdge && mainHolder.offsetHeight !== mainHolder.clientHeight) { scrollbarCompensation = (0, _element.getScrollbarWidth)(this.domBindings.rootDocument); } if (bottomEdge) { newY += this.sumCellSizes(0, sourceRow + 1); newY -= this.wot.wtViewport.getViewportHeight(); // Fix 1 pixel offset when cell is selected newY += 1; } else { newY += this.sumCellSizes(this.wtSettings.getSetting('fixedRowsBottom'), sourceRow); } newY += scrollbarCompensation; this.setScrollPosition(newY); } /** * Gets table parent top position. * * @returns {number} */ getTableParentOffset() { if (this.mainTableScrollableElement === this.domBindings.rootWindow) { return this.wot.wtTable.holderOffset.top; } return 0; } /** * Gets the main overlay's vertical scroll position. * * @returns {number} Main table's vertical scroll position. */ getScrollPosition() { return (0, _element.getScrollTop)(this.mainTableScrollableElement, this.domBindings.rootWindow); } /** * Gets the main overlay's vertical overlay offset. * * @returns {number} Main table's vertical overlay offset. */ getOverlayOffset() { const { rootWindow } = this.domBindings; const preventOverflow = this.wtSettings.getSetting('preventOverflow'); let overlayOffset = 0; if (this.trimmingContainer === rootWindow && (!preventOverflow || preventOverflow !== 'vertical')) { const rootHeight = this.wot.wtTable.getTotalHeight(); const overlayRootHeight = this.clone.wtTable.getTotalHeight(); const maxOffset = rootHeight - overlayRootHeight; const docClientHeight = this.domBindings.rootDocument.documentElement.clientHeight; overlayOffset = Math.max(this.getTableParentOffset() - this.getScrollPosition() - docClientHeight + rootHeight, 0); if (overlayOffset > maxOffset) { overlayOffset = 0; } } return overlayOffset; } /** * Adds css classes to hide the header border's header (cell-selection border hiding issue). * * @param {number} position Header Y position if trimming container is window or scroll top if not. * @returns {boolean} */ adjustHeaderBordersPosition(position) { const fixedRowsBottom = this.wtSettings.getSetting('fixedRowsBottom'); const areFixedRowsBottomChanged = this.cachedFixedRowsBottom !== fixedRowsBottom; const columnHeaders = this.wtSettings.getSetting('columnHeaders'); let positionChanged = false; if ((areFixedRowsBottomChanged || fixedRowsBottom === 0) && columnHeaders.length > 0) { const masterParent = this.wot.wtTable.holder.parentNode; const previousState = (0, _element.hasClass)(masterParent, 'innerBorderBottom'); this.cachedFixedRowsBottom = this.wtSettings.getSetting('fixedRowsBottom'); if (position || this.wtSettings.getSetting('totalRows') === 0) { (0, _element.addClass)(masterParent, 'innerBorderBottom'); positionChanged = !previousState; } else { (0, _element.removeClass)(masterParent, 'innerBorderBottom'); positionChanged = previousState; } } return positionChanged; } } exports.BottomOverlay = BottomOverlay;