handsontable
Version:
Handsontable is a JavaScript Data Grid available for React, Angular and Vue.
358 lines (340 loc) • 12.9 kB
JavaScript
"use strict";
exports.__esModule = true;
require("core-js/modules/es.error.cause.js");
var _element = require("../../../../helpers/dom/element");
var _inlineStart = _interopRequireDefault(require("../table/inlineStart"));
var _base = require("./_base");
var _selection = require("../selection");
var _constants = require("./constants");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
* @class InlineStartOverlay
*/
class InlineStartOverlay 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_INLINE_START, wtSettings, domBindings);
}
/**
* 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 {InlineStartOverlayTable}
*/
createTable() {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return new _inlineStart.default(...args);
}
/**
* Checks if overlay should be fully rendered.
*
* @returns {boolean}
*/
shouldBeRendered() {
return this.wtSettings.getSetting('shouldRenderInlineStartOverlay');
}
/**
* Updates the left overlay position.
*
* @returns {boolean}
*/
resetFixedPosition() {
const {
wtTable
} = this.wot;
if (!this.needFullRender || !this.shouldBeRendered() || !wtTable.holder.parentNode) {
// removed from DOM
return false;
}
const {
rootWindow
} = this.domBindings;
const overlayRoot = this.clone.wtTable.holder.parentNode;
const preventOverflow = this.wtSettings.getSetting('preventOverflow');
let overlayPosition = 0;
if (this.trimmingContainer === rootWindow && (!preventOverflow || preventOverflow !== 'horizontal')) {
overlayPosition = this.getOverlayOffset() * (this.isRtl() ? -1 : 1);
(0, _element.setOverlayPosition)(overlayRoot, `${overlayPosition}px`, '0px');
} else {
overlayPosition = this.getScrollPosition();
(0, _element.resetCssTransform)(overlayRoot);
}
const positionChanged = this.adjustHeaderBordersPosition(overlayPosition);
this.adjustElementsSize();
return positionChanged;
}
/**
* Sets the main overlay's horizontal scroll position.
*
* @param {number} pos The scroll position.
* @returns {boolean}
*/
setScrollPosition(pos) {
const {
rootWindow
} = this.domBindings;
let result = false;
if (this.isRtl()) {
pos = -pos;
}
const scrollableElement = this.mainTableScrollableElement;
if (scrollableElement === rootWindow && pos !== rootWindow.scrollX) {
const oldScrollX = rootWindow.scrollX;
rootWindow.scrollTo(pos, (0, _element.getWindowScrollTop)(rootWindow));
result = oldScrollX !== rootWindow.scrollX;
} else if (pos !== scrollableElement.scrollLeft) {
const oldScrollLeft = scrollableElement.scrollLeft;
scrollableElement.scrollLeft = pos;
result = oldScrollLeft !== scrollableElement.scrollLeft;
}
return result;
}
/**
* Triggers onScroll hook callback.
*/
onScroll() {
this.wtSettings.getSetting('onScrollVertically');
}
/**
* Calculates total sum cells width.
*
* @param {number} from Column index which calculates started from.
* @param {number} to Column index where calculation is finished.
* @returns {number} Width sum.
*/
sumCellSizes(from, to) {
const defaultColumnWidth = this.wtSettings.getSetting('defaultColumnWidth');
let column = from;
let sum = 0;
while (column < to) {
sum += this.wot.wtTable.getColumnWidth(column) || defaultColumnWidth;
column += 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 === 'vertical') {
let height = wtViewport.getWorkspaceHeight();
if (wtViewport.hasHorizontalScroll()) {
height -= (0, _element.getScrollbarWidth)(rootDocument);
}
height = Math.min(height, wtTable.wtRootElement.scrollHeight);
overlayRootStyle.height = `${height}px`;
} else {
overlayRootStyle.height = '';
}
this.clone.wtTable.holder.style.height = overlayRootStyle.height;
const tableWidth = (0, _element.outerWidth)(this.clone.wtTable.TABLE);
overlayRootStyle.width = `${tableWidth}px`;
}
/**
* Adjust overlay root childs size.
*/
adjustRootChildrenSize() {
const {
holder
} = this.clone.wtTable;
const cornerStyle = (0, _selection.getCornerStyle)(this.wot);
const selectionCornerOffset = this.wot.selectionManager.getFocusSelection() ? parseInt(cornerStyle.width, 10) / 2 : 0;
this.clone.wtTable.hider.style.height = this.hider.style.height;
holder.style.height = holder.parentNode.style.height;
// Add selection corner protruding part to the holder total width to make sure that
// borders' corner won't be cut after horizontal scroll (#6937).
holder.style.width = `${parseInt(holder.parentNode.style.width, 10) + selectionCornerOffset}px`;
}
/**
* Adjust the overlay dimensions and position.
*/
applyToDOM() {
const total = this.wtSettings.getSetting('totalColumns');
const styleProperty = this.isRtl() ? 'right' : 'left';
if (typeof this.wot.wtViewport.columnsRenderCalculator.startPosition === 'number') {
this.spreader.style[styleProperty] = `${this.wot.wtViewport.columnsRenderCalculator.startPosition}px`;
} else if (total === 0) {
this.spreader.style[styleProperty] = '0';
} else {
throw new Error('Incorrect value of the columnsRenderCalculator');
}
if (this.isRtl()) {
this.spreader.style.left = '';
} else {
this.spreader.style.right = '';
}
if (this.needFullRender) {
this.syncOverlayOffset();
}
}
/**
* Synchronize calculated top position to an element.
*/
syncOverlayOffset() {
if (typeof this.wot.wtViewport.rowsRenderCalculator.startPosition === 'number') {
this.clone.wtTable.spreader.style.top = `${this.wot.wtViewport.rowsRenderCalculator.startPosition}px`;
} else {
this.clone.wtTable.spreader.style.top = '';
}
}
/**
* Scrolls horizontally to a column at the left edge of the viewport.
*
* @param {number} sourceCol Column index which you want to scroll to.
* @param {boolean} [beyondRendered] If `true`, scrolls according to the right
* edge (left edge is by default).
* @returns {boolean}
*/
scrollTo(sourceCol, beyondRendered) {
const {
wtSettings
} = this;
const rowHeaders = wtSettings.getSetting('rowHeaders');
const fixedColumnsStart = wtSettings.getSetting('fixedColumnsStart');
const sourceInstance = this.wot.cloneSource ? this.wot.cloneSource : this.wot;
const mainHolder = sourceInstance.wtTable.holder;
const rowHeaderBorderCompensation = fixedColumnsStart === 0 && rowHeaders.length > 0 && !(0, _element.hasClass)(mainHolder.parentNode, 'innerBorderInlineStart') ? 1 : 0;
let newX = this.getTableParentOffset();
let scrollbarCompensation = 0;
if (beyondRendered) {
const columnWidth = this.wot.wtTable.getColumnWidth(sourceCol);
const viewportWidth = this.wot.wtViewport.getViewportWidth();
if (columnWidth > viewportWidth) {
beyondRendered = false;
}
}
if (beyondRendered && mainHolder.offsetWidth !== mainHolder.clientWidth) {
scrollbarCompensation = (0, _element.getScrollbarWidth)(this.domBindings.rootDocument);
}
if (beyondRendered) {
newX += this.sumCellSizes(0, sourceCol + 1);
newX -= this.wot.wtViewport.getViewportWidth();
// Compensate for the right header border if scrolled from the absolute left.
newX += rowHeaderBorderCompensation;
} else {
newX += this.sumCellSizes(this.wtSettings.getSetting('fixedColumnsStart'), sourceCol);
}
newX += scrollbarCompensation;
// If the table is scrolled all the way left when starting the scroll and going to be scrolled to the far right,
// we need to compensate for the potential header border width.
if ((0, _element.getMaximumScrollLeft)(this.mainTableScrollableElement) === newX - rowHeaderBorderCompensation && rowHeaderBorderCompensation > 0) {
this.wot.wtOverlays.expandHiderHorizontallyBy(rowHeaderBorderCompensation);
}
return this.setScrollPosition(newX);
}
/**
* Gets table parent left position.
*
* @returns {number}
*/
getTableParentOffset() {
const preventOverflow = this.wtSettings.getSetting('preventOverflow');
let offset = 0;
if (!preventOverflow && this.trimmingContainer === this.domBindings.rootWindow) {
offset = this.wot.wtTable.holderOffset.left;
}
return offset;
}
/**
* Gets the main overlay's horizontal scroll position.
*
* @returns {number} Main table's horizontal scroll position.
*/
getScrollPosition() {
return Math.abs((0, _element.getScrollLeft)(this.mainTableScrollableElement, this.domBindings.rootWindow));
}
/**
* Gets the main overlay's horizontal overlay offset.
*
* @returns {number} Main table's horizontal overlay offset.
*/
getOverlayOffset() {
const {
rootWindow
} = this.domBindings;
const preventOverflow = this.wtSettings.getSetting('preventOverflow');
let overlayOffset = 0;
if (this.trimmingContainer === rootWindow && (!preventOverflow || preventOverflow !== 'horizontal')) {
if (this.isRtl()) {
overlayOffset = Math.abs(Math.min(this.getTableParentOffset() - this.getScrollPosition(), 0));
} else {
overlayOffset = Math.max(this.getScrollPosition() - this.getTableParentOffset(), 0);
}
const rootWidth = this.wot.wtTable.getTotalWidth();
const overlayRootWidth = this.clone.wtTable.getTotalWidth();
const maxOffset = rootWidth - overlayRootWidth;
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 X position if trimming container is window or scroll top if not.
* @returns {boolean}
*/
adjustHeaderBordersPosition(position) {
const {
wtSettings
} = this;
const masterParent = this.wot.wtTable.holder.parentNode;
const rowHeaders = wtSettings.getSetting('rowHeaders');
const fixedColumnsStart = wtSettings.getSetting('fixedColumnsStart');
const totalRows = wtSettings.getSetting('totalRows');
const preventVerticalOverflow = wtSettings.getSetting('preventOverflow') === 'vertical';
if (totalRows) {
(0, _element.removeClass)(masterParent, 'emptyRows');
} else {
(0, _element.addClass)(masterParent, 'emptyRows');
}
let positionChanged = false;
if (!preventVerticalOverflow) {
if (fixedColumnsStart && !rowHeaders.length) {
// "innerBorderLeft" is for backward compatibility
(0, _element.addClass)(masterParent, 'innerBorderLeft innerBorderInlineStart');
} else if (!fixedColumnsStart && rowHeaders.length) {
const previousState = (0, _element.hasClass)(masterParent, 'innerBorderInlineStart');
if (position) {
(0, _element.addClass)(masterParent, 'innerBorderLeft innerBorderInlineStart');
positionChanged = !previousState;
} else {
(0, _element.removeClass)(masterParent, 'innerBorderLeft innerBorderInlineStart');
positionChanged = previousState;
}
}
}
return positionChanged;
}
}
exports.InlineStartOverlay = InlineStartOverlay;