"use strict"; exports.__esModule = true; exports.default = void 0; var _element = require("./../../../helpers/dom/element"); var _object = require("./../../../helpers/object"); var _eventManager = _interopRequireDefault(require("./../../../eventManager")); var _calculator = require("./calculator"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } /** * @class Viewport */ var Viewport = /*#__PURE__*/ function () { /** * @param wotInstance */ function Viewport(wotInstance) { var _this = this; _classCallCheck(this, Viewport); this.wot = wotInstance; // legacy support this.instance = this.wot; this.oversizedRows = []; this.oversizedColumnHeaders = []; this.hasOversizedColumnHeadersMarked = {}; this.clientHeight = 0; this.containerWidth = NaN; this.rowHeaderWidth = NaN; this.rowsVisibleCalculator = null; this.columnsVisibleCalculator = null; this.eventManager = new _eventManager.default(this.wot); this.eventManager.addEventListener(this.wot.rootWindow, 'resize', function () { _this.clientHeight = _this.getWorkspaceHeight(); }); } /** * @returns {number} */ _createClass(Viewport, [{ key: "getWorkspaceHeight", value: function getWorkspaceHeight() { var currentDocument = this.wot.rootDocument; var trimmingContainer = this.instance.wtOverlays.topOverlay.trimmingContainer; var height = 0; if (trimmingContainer === this.wot.rootWindow) { height = currentDocument.documentElement.clientHeight; } else { var elemHeight = (0, _element.outerHeight)(trimmingContainer); // returns height without DIV scrollbar height = elemHeight > 0 && trimmingContainer.clientHeight > 0 ? trimmingContainer.clientHeight : Infinity; } return height; } }, { key: "getWorkspaceWidth", value: function getWorkspaceWidth() { var wot = this.wot; var rootDocument = wot.rootDocument, rootWindow = wot.rootWindow; var trimmingContainer = this.instance.wtOverlays.leftOverlay.trimmingContainer; var docOffsetWidth = rootDocument.documentElement.offsetWidth; var totalColumns = wot.getSetting('totalColumns'); var preventOverflow = wot.getSetting('preventOverflow'); var width; var overflow; if (preventOverflow) { return (0, _element.outerWidth)(this.instance.wtTable.wtRootElement); } if (wot.getSetting('freezeOverlays')) { width = Math.min(docOffsetWidth - this.getWorkspaceOffset().left, docOffsetWidth); } else { width = Math.min(this.getContainerFillWidth(), docOffsetWidth - this.getWorkspaceOffset().left, docOffsetWidth); } if (trimmingContainer === rootWindow && totalColumns > 0 && this.sumColumnWidths(0, totalColumns - 1) > width) { // in case sum of column widths is higher than available stylesheet width, let's assume using the whole window // otherwise continue below, which will allow stretching // this is used in `scroll_window.html` // TODO test me return rootDocument.documentElement.clientWidth; } if (trimmingContainer !== rootWindow) { overflow = (0, _element.getStyle)(this.instance.wtOverlays.leftOverlay.trimmingContainer, 'overflow', rootWindow); if (overflow === 'scroll' || overflow === 'hidden' || overflow === 'auto') { // this is used in `scroll.html` // TODO test me return Math.max(width, trimmingContainer.clientWidth); } } var stretchSetting = wot.getSetting('stretchH'); if (stretchSetting === 'none' || !stretchSetting) { // if no stretching is used, return the maximum used workspace width return Math.max(width, (0, _element.outerWidth)(this.instance.wtTable.TABLE)); } // if stretching is used, return the actual container width, so the columns can fit inside it return width; } /** * Checks if viewport has vertical scroll * * @returns {Boolean} */ }, { key: "hasVerticalScroll", value: function hasVerticalScroll() { return this.getWorkspaceActualHeight() > this.getWorkspaceHeight(); } /** * Checks if viewport has horizontal scroll * * @returns {Boolean} */ }, { key: "hasHorizontalScroll", value: function hasHorizontalScroll() { return this.getWorkspaceActualWidth() > this.getWorkspaceWidth(); } /** * @param from * @param length * @returns {Number} */ }, { key: "sumColumnWidths", value: function sumColumnWidths(from, length) { var wtTable = this.wot.wtTable; var sum = 0; var column = from; while (column < length) { sum += wtTable.getColumnWidth(column); column += 1; } return sum; } /** * @returns {Number} */ }, { key: "getContainerFillWidth", value: function getContainerFillWidth() { if (this.containerWidth) { return this.containerWidth; } var mainContainer = this.instance.wtTable.holder; var dummyElement = this.wot.rootDocument.createElement('div'); dummyElement.style.width = '100%'; dummyElement.style.height = '1px'; mainContainer.appendChild(dummyElement); var fillWidth = dummyElement.offsetWidth; this.containerWidth = fillWidth; mainContainer.removeChild(dummyElement); return fillWidth; } /** * @returns {Number} */ }, { key: "getWorkspaceOffset", value: function getWorkspaceOffset() { return (0, _element.offset)(this.wot.wtTable.TABLE); } /** * @returns {Number} */ }, { key: "getWorkspaceActualHeight", value: function getWorkspaceActualHeight() { return (0, _element.outerHeight)(this.wot.wtTable.TABLE); } /** * @returns {Number} */ }, { key: "getWorkspaceActualWidth", value: function getWorkspaceActualWidth() { var wtTable = this.wot.wtTable; return (0, _element.outerWidth)(wtTable.TABLE) || (0, _element.outerWidth)(wtTable.TBODY) || (0, _element.outerWidth)(wtTable.THEAD); // IE8 reports 0 as offsetWidth; } /** * @returns {Number} */ }, { key: "getColumnHeaderHeight", value: function getColumnHeaderHeight() { var columnHeaders = this.instance.getSetting('columnHeaders'); if (!columnHeaders.length) { this.columnHeaderHeight = 0; } else if (isNaN(this.columnHeaderHeight)) { this.columnHeaderHeight = (0, _element.outerHeight)(this.wot.wtTable.THEAD); } return this.columnHeaderHeight; } /** * @returns {Number} */ }, { key: "getViewportHeight", value: function getViewportHeight() { var containerHeight = this.getWorkspaceHeight(); if (containerHeight === Infinity) { return containerHeight; } var columnHeaderHeight = this.getColumnHeaderHeight(); if (columnHeaderHeight > 0) { containerHeight -= columnHeaderHeight; } return containerHeight; } /** * @returns {Number} */ }, { key: "getRowHeaderWidth", value: function getRowHeaderWidth() { var rowHeadersWidthSetting = this.instance.getSetting('rowHeaderWidth'); var rowHeaders = this.instance.getSetting('rowHeaders'); if (rowHeadersWidthSetting) { this.rowHeaderWidth = 0; for (var i = 0, len = rowHeaders.length; i < len; i++) { this.rowHeaderWidth += rowHeadersWidthSetting[i] || rowHeadersWidthSetting; } } if (this.wot.cloneSource) { return this.wot.cloneSource.wtViewport.getRowHeaderWidth(); } if (isNaN(this.rowHeaderWidth)) { if (rowHeaders.length) { var TH = this.instance.wtTable.TABLE.querySelector('TH'); this.rowHeaderWidth = 0; for (var _i = 0, _len = rowHeaders.length; _i < _len; _i++) { if (TH) { this.rowHeaderWidth += (0, _element.outerWidth)(TH); TH = TH.nextSibling; } else { // yes this is a cheat but it worked like that before, just taking assumption from CSS instead of measuring. // TODO: proper fix this.rowHeaderWidth += 50; } } } else { this.rowHeaderWidth = 0; } } this.rowHeaderWidth = this.instance.getSetting('onModifyRowHeaderWidth', this.rowHeaderWidth) || this.rowHeaderWidth; return this.rowHeaderWidth; } /** * @returns {Number} */ }, { key: "getViewportWidth", value: function getViewportWidth() { var containerWidth = this.getWorkspaceWidth(); if (containerWidth === Infinity) { return containerWidth; } var rowHeaderWidth = this.getRowHeaderWidth(); if (rowHeaderWidth > 0) { return containerWidth - rowHeaderWidth; } return containerWidth; } /** * Creates: * - rowsRenderCalculator (before draw, to qualify rows for rendering) * - rowsVisibleCalculator (after draw, to measure which rows are actually visible) * * @returns {ViewportRowsCalculator} */ }, { key: "createRowsCalculator", value: function createRowsCalculator() { var calculationType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _calculator.RENDER_TYPE; var wot = this.wot; var wtSettings = wot.wtSettings, wtOverlays = wot.wtOverlays, wtTable = wot.wtTable, rootDocument = wot.rootDocument; var height; var scrollbarHeight; var fixedRowsHeight; this.rowHeaderWidth = NaN; if (wtSettings.settings.renderAllRows && calculationType === _calculator.RENDER_TYPE) { height = Infinity; } else { height = this.getViewportHeight(); } var pos = wtOverlays.topOverlay.getScrollPosition() - wtOverlays.topOverlay.getTableParentOffset(); if (pos < 0) { pos = 0; } var fixedRowsTop = wot.getSetting('fixedRowsTop'); var fixedRowsBottom = wot.getSetting('fixedRowsBottom'); var totalRows = wot.getSetting('totalRows'); if (fixedRowsTop) { fixedRowsHeight = wtOverlays.topOverlay.sumCellSizes(0, fixedRowsTop); pos += fixedRowsHeight; height -= fixedRowsHeight; } if (fixedRowsBottom && wtOverlays.bottomOverlay.clone) { fixedRowsHeight = wtOverlays.bottomOverlay.sumCellSizes(totalRows - fixedRowsBottom, totalRows); height -= fixedRowsHeight; } if (wtTable.holder.clientHeight === wtTable.holder.offsetHeight) { scrollbarHeight = 0; } else { scrollbarHeight = (0, _element.getScrollbarWidth)(rootDocument); } return new _calculator.ViewportRowsCalculator({ viewportSize: height, scrollOffset: pos, totalItems: wot.getSetting('totalRows'), itemSizeFn: function itemSizeFn(sourceRow) { return wtTable.getRowHeight(sourceRow); }, overrideFn: wtSettings.settings.viewportRowCalculatorOverride, calculationType: calculationType, scrollbarHeight: scrollbarHeight }); } /** * Creates: * - columnsRenderCalculator (before draw, to qualify columns for rendering) * - columnsVisibleCalculator (after draw, to measure which columns are actually visible) * * @returns {ViewportRowsCalculator} */ }, { key: "createColumnsCalculator", value: function createColumnsCalculator() { var calculationType = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _calculator.RENDER_TYPE; var wot = this.wot; var wtSettings = wot.wtSettings, wtOverlays = wot.wtOverlays, wtTable = wot.wtTable, rootDocument = wot.rootDocument; var width = this.getViewportWidth(); var pos = wtOverlays.leftOverlay.getScrollPosition() - wtOverlays.leftOverlay.getTableParentOffset(); this.columnHeaderHeight = NaN; if (pos < 0) { pos = 0; } var fixedColumnsLeft = wot.getSetting('fixedColumnsLeft'); if (fixedColumnsLeft) { var fixedColumnsWidth = wtOverlays.leftOverlay.sumCellSizes(0, fixedColumnsLeft); pos += fixedColumnsWidth; width -= fixedColumnsWidth; } if (wtTable.holder.clientWidth !== wtTable.holder.offsetWidth) { width -= (0, _element.getScrollbarWidth)(rootDocument); } return new _calculator.ViewportColumnsCalculator({ viewportSize: width, scrollOffset: pos, totalItems: wot.getSetting('totalColumns'), itemSizeFn: function itemSizeFn(sourceCol) { return wot.wtTable.getColumnWidth(sourceCol); }, overrideFn: wtSettings.settings.viewportColumnCalculatorOverride, calculationType: calculationType, stretchMode: wot.getSetting('stretchH'), stretchingItemWidthFn: function stretchingItemWidthFn(stretchedWidth, column) { return wot.getSetting('onBeforeStretchingColumnWidth', stretchedWidth, column); } }); } /** * Creates rowsRenderCalculator and columnsRenderCalculator (before draw, to determine what rows and * cols should be rendered) * * @param fastDraw {Boolean} If `true`, will try to avoid full redraw and only update the border positions. * If `false` or `undefined`, will perform a full redraw * @returns fastDraw {Boolean} The fastDraw value, possibly modified */ }, { key: "createRenderCalculators", value: function createRenderCalculators() { var fastDraw = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var runFastDraw = fastDraw; if (runFastDraw) { var proposedRowsVisibleCalculator = this.createRowsCalculator(_calculator.FULLY_VISIBLE_TYPE); var proposedColumnsVisibleCalculator = this.createColumnsCalculator(_calculator.FULLY_VISIBLE_TYPE); if (!(this.areAllProposedVisibleRowsAlreadyRendered(proposedRowsVisibleCalculator) && this.areAllProposedVisibleColumnsAlreadyRendered(proposedColumnsVisibleCalculator))) { runFastDraw = false; } } if (!runFastDraw) { this.rowsRenderCalculator = this.createRowsCalculator(_calculator.RENDER_TYPE); this.columnsRenderCalculator = this.createColumnsCalculator(_calculator.RENDER_TYPE); } // delete temporarily to make sure that renderers always use rowsRenderCalculator, not rowsVisibleCalculator this.rowsVisibleCalculator = null; this.columnsVisibleCalculator = null; return runFastDraw; } /** * Creates rowsVisibleCalculator and columnsVisibleCalculator (after draw, to determine what are * the actually fully visible rows and columns) */ }, { key: "createVisibleCalculators", value: function createVisibleCalculators() { this.rowsVisibleCalculator = this.createRowsCalculator(_calculator.FULLY_VISIBLE_TYPE); this.columnsVisibleCalculator = this.createColumnsCalculator(_calculator.FULLY_VISIBLE_TYPE); } /** * Returns information whether proposedRowsVisibleCalculator viewport * is contained inside rows rendered in previous draw (cached in rowsRenderCalculator) * * @param {Object} proposedRowsVisibleCalculator * @returns {Boolean} Returns `true` if all proposed visible rows are already rendered (meaning: redraw is not needed). * Returns `false` if at least one proposed visible row is not already rendered (meaning: redraw is needed) */ }, { key: "areAllProposedVisibleRowsAlreadyRendered", value: function areAllProposedVisibleRowsAlreadyRendered(proposedRowsVisibleCalculator) { if (!this.rowsVisibleCalculator) { return false; } var startRow = proposedRowsVisibleCalculator.startRow, endRow = proposedRowsVisibleCalculator.endRow; var _this$rowsRenderCalcu = this.rowsRenderCalculator, renderedStartRow = _this$rowsRenderCalcu.startRow, renderedEndRow = _this$rowsRenderCalcu.endRow; if (startRow < renderedStartRow || startRow === renderedStartRow && startRow > 0) { return false; } else if (endRow > renderedEndRow || endRow === renderedEndRow && endRow < this.wot.getSetting('totalRows') - 1) { return false; } return true; } /** * Returns information whether proposedColumnsVisibleCalculator viewport * is contained inside column rendered in previous draw (cached in columnsRenderCalculator) * * @param {Object} proposedColumnsVisibleCalculator * @returns {Boolean} Returns `true` if all proposed visible columns are already rendered (meaning: redraw is not needed). * Returns `false` if at least one proposed visible column is not already rendered (meaning: redraw is needed) */ }, { key: "areAllProposedVisibleColumnsAlreadyRendered", value: function areAllProposedVisibleColumnsAlreadyRendered(proposedColumnsVisibleCalculator) { if (!this.columnsVisibleCalculator) { return false; } var startColumn = proposedColumnsVisibleCalculator.startColumn, endColumn = proposedColumnsVisibleCalculator.endColumn; var _this$columnsRenderCa = this.columnsRenderCalculator, renderedStartColumn = _this$columnsRenderCa.startColumn, renderedEndColumn = _this$columnsRenderCa.endColumn; if (startColumn < renderedStartColumn || startColumn === renderedStartColumn && startColumn > 0) { return false; } else if (endColumn > renderedEndColumn || endColumn === renderedEndColumn && endColumn < this.wot.getSetting('totalColumns') - 1) { return false; } return true; } /** * Resets values in keys of the hasOversizedColumnHeadersMarked object after updateSettings. */ }, { key: "resetHasOversizedColumnHeadersMarked", value: function resetHasOversizedColumnHeadersMarked() { (0, _object.objectEach)(this.hasOversizedColumnHeadersMarked, function (value, key, object) { object[key] = void 0; }); } }]); return Viewport; }(); var _default = Viewport; exports.default = _default;