'use strict'; exports.__esModule = true; var _createClass = 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _element = require('./../../../helpers/dom/element'); var _object = require('./../../../helpers/object'); var _eventManager = require('./../../../eventManager'); var _eventManager2 = _interopRequireDefault(_eventManager); var _viewportColumns = require('./calculator/viewportColumns'); var _viewportColumns2 = _interopRequireDefault(_viewportColumns); var _viewportRows = require('./calculator/viewportRows'); var _viewportRows2 = _interopRequireDefault(_viewportRows); 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"); } } /** * @class Viewport */ var Viewport = 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 _eventManager2.default(this.wot); this.eventManager.addEventListener(window, 'resize', function () { _this.clientHeight = _this.getWorkspaceHeight(); }); } /** * @returns {number} */ _createClass(Viewport, [{ key: 'getWorkspaceHeight', value: function getWorkspaceHeight() { var trimmingContainer = this.instance.wtOverlays.topOverlay.trimmingContainer; var elemHeight = void 0; var height = 0; if (trimmingContainer === window) { height = document.documentElement.clientHeight; } else { 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 width = void 0; var totalColumns = this.wot.getSetting('totalColumns'); var trimmingContainer = this.instance.wtOverlays.leftOverlay.trimmingContainer; var overflow = void 0; var stretchSetting = this.wot.getSetting('stretchH'); var docOffsetWidth = document.documentElement.offsetWidth; var preventOverflow = this.wot.getSetting('preventOverflow'); if (preventOverflow) { return (0, _element.outerWidth)(this.instance.wtTable.wtRootElement); } if (this.wot.getSetting('freezeOverlays')) { width = Math.min(docOffsetWidth - this.getWorkspaceOffset().left, docOffsetWidth); } else { width = Math.min(this.getContainerFillWidth(), docOffsetWidth - this.getWorkspaceOffset().left, docOffsetWidth); } if (trimmingContainer === window && 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 document.documentElement.clientWidth; } if (trimmingContainer !== window) { overflow = (0, _element.getStyle)(this.instance.wtOverlays.leftOverlay.trimmingContainer, 'overflow'); if (overflow == 'scroll' || overflow == 'hidden' || overflow == 'auto') { // this is used in `scroll.html` // TODO test me return Math.max(width, trimmingContainer.clientWidth); } } 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 sum = 0; while (from < length) { sum += this.wot.wtTable.getColumnWidth(from); from++; } return sum; } /** * @returns {Number} */ }, { key: 'getContainerFillWidth', value: function getContainerFillWidth() { if (this.containerWidth) { return this.containerWidth; } var mainContainer = this.instance.wtTable.holder; var fillWidth = void 0; var dummyElement = void 0; dummyElement = document.createElement('div'); dummyElement.style.width = '100%'; dummyElement.style.height = '1px'; mainContainer.appendChild(dummyElement); 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() { return (0, _element.outerWidth)(this.wot.wtTable.TABLE) || (0, _element.outerWidth)(this.wot.wtTable.TBODY) || (0, _element.outerWidth)(this.wot.wtTable.THEAD); // IE8 reports 0 as offsetWidth; } /** * @returns {Number} */ }, { key: 'getColumnHeaderHeight', value: function getColumnHeaderHeight() { 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(); var columnHeaderHeight = void 0; if (containerHeight === Infinity) { return containerHeight; } columnHeaderHeight = this.getColumnHeaderHeight(); if (columnHeaderHeight > 0) { containerHeight -= columnHeaderHeight; } return containerHeight; } /** * @returns {Number} */ }, { key: 'getRowHeaderWidth', value: function getRowHeaderWidth() { var rowHeadersHeightSetting = this.instance.getSetting('rowHeaderWidth'); var rowHeaders = this.instance.getSetting('rowHeaders'); if (rowHeadersHeightSetting) { this.rowHeaderWidth = 0; for (var i = 0, len = rowHeaders.length; i < len; i++) { this.rowHeaderWidth += rowHeadersHeightSetting[i] || rowHeadersHeightSetting; } } 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(); var rowHeaderWidth = void 0; if (containerWidth === Infinity) { return containerWidth; } 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 _this2 = this; var visible = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var height = void 0; var pos = void 0; var fixedRowsTop = void 0; var scrollbarHeight = void 0; var fixedRowsBottom = void 0; var fixedRowsHeight = void 0; var totalRows = void 0; this.rowHeaderWidth = NaN; if (this.wot.wtSettings.settings.renderAllRows) { height = Infinity; } else { height = this.getViewportHeight(); } pos = this.wot.wtOverlays.topOverlay.getScrollPosition() - this.wot.wtOverlays.topOverlay.getTableParentOffset(); if (pos < 0) { pos = 0; } fixedRowsTop = this.wot.getSetting('fixedRowsTop'); fixedRowsBottom = this.wot.getSetting('fixedRowsBottom'); totalRows = this.wot.getSetting('totalRows'); if (fixedRowsTop) { fixedRowsHeight = this.wot.wtOverlays.topOverlay.sumCellSizes(0, fixedRowsTop); pos += fixedRowsHeight; height -= fixedRowsHeight; } if (fixedRowsBottom && this.wot.wtOverlays.bottomOverlay.clone) { fixedRowsHeight = this.wot.wtOverlays.bottomOverlay.sumCellSizes(totalRows - fixedRowsBottom, totalRows); height -= fixedRowsHeight; } if (this.wot.wtTable.holder.clientHeight === this.wot.wtTable.holder.offsetHeight) { scrollbarHeight = 0; } else { scrollbarHeight = (0, _element.getScrollbarWidth)(); } return new _viewportRows2.default(height, pos, this.wot.getSetting('totalRows'), function (sourceRow) { return _this2.wot.wtTable.getRowHeight(sourceRow); }, visible ? null : this.wot.wtSettings.settings.viewportRowCalculatorOverride, visible, 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 _this3 = this; var visible = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var width = this.getViewportWidth(); var pos = void 0; var fixedColumnsLeft = void 0; this.columnHeaderHeight = NaN; pos = this.wot.wtOverlays.leftOverlay.getScrollPosition() - this.wot.wtOverlays.leftOverlay.getTableParentOffset(); if (pos < 0) { pos = 0; } fixedColumnsLeft = this.wot.getSetting('fixedColumnsLeft'); if (fixedColumnsLeft) { var fixedColumnsWidth = this.wot.wtOverlays.leftOverlay.sumCellSizes(0, fixedColumnsLeft); pos += fixedColumnsWidth; width -= fixedColumnsWidth; } if (this.wot.wtTable.holder.clientWidth !== this.wot.wtTable.holder.offsetWidth) { width -= (0, _element.getScrollbarWidth)(); } return new _viewportColumns2.default(width, pos, this.wot.getSetting('totalColumns'), function (sourceCol) { return _this3.wot.wtTable.getColumnWidth(sourceCol); }, visible ? null : this.wot.wtSettings.settings.viewportColumnCalculatorOverride, visible, this.wot.getSetting('stretchH'), function (stretchedWidth, column) { return _this3.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; if (fastDraw) { var proposedRowsVisibleCalculator = this.createRowsCalculator(true); var proposedColumnsVisibleCalculator = this.createColumnsCalculator(true); if (!(this.areAllProposedVisibleRowsAlreadyRendered(proposedRowsVisibleCalculator) && this.areAllProposedVisibleColumnsAlreadyRendered(proposedColumnsVisibleCalculator))) { fastDraw = false; } } if (!fastDraw) { this.rowsRenderCalculator = this.createRowsCalculator(); this.columnsRenderCalculator = this.createColumnsCalculator(); } // delete temporarily to make sure that renderers always use rowsRenderCalculator, not rowsVisibleCalculator this.rowsVisibleCalculator = null; this.columnsVisibleCalculator = null; return fastDraw; } /** * Creates rowsVisibleCalculator and columnsVisibleCalculator (after draw, to determine what are * the actually visible rows and columns) */ }, { key: 'createVisibleCalculators', value: function createVisibleCalculators() { this.rowsVisibleCalculator = this.createRowsCalculator(true); this.columnsVisibleCalculator = this.createColumnsCalculator(true); } /** * 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) { if (proposedRowsVisibleCalculator.startRow < this.rowsRenderCalculator.startRow || proposedRowsVisibleCalculator.startRow === this.rowsRenderCalculator.startRow && proposedRowsVisibleCalculator.startRow > 0) { return false; } else if (proposedRowsVisibleCalculator.endRow > this.rowsRenderCalculator.endRow || proposedRowsVisibleCalculator.endRow === this.rowsRenderCalculator.endRow && proposedRowsVisibleCalculator.endRow < this.wot.getSetting('totalRows') - 1) { return false; } return true; } return false; } /** * 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) { if (proposedColumnsVisibleCalculator.startColumn < this.columnsRenderCalculator.startColumn || proposedColumnsVisibleCalculator.startColumn === this.columnsRenderCalculator.startColumn && proposedColumnsVisibleCalculator.startColumn > 0) { return false; } else if (proposedColumnsVisibleCalculator.endColumn > this.columnsRenderCalculator.endColumn || proposedColumnsVisibleCalculator.endColumn === this.columnsRenderCalculator.endColumn && proposedColumnsVisibleCalculator.endColumn < this.wot.getSetting('totalColumns') - 1) { return false; } return true; } return false; } /** * 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; }(); exports.default = Viewport;