handsontable
Version:
Handsontable is a JavaScript Spreadsheet Component available for React, Angular and Vue.
326 lines (287 loc) • 12.6 kB
JavaScript
import "core-js/modules/es.array.index-of.js";
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); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
import { getScrollableElement, getTrimmingContainer } from "./../../../../helpers/dom/element.mjs";
import { defineGetter } from "./../../../../helpers/object.mjs";
import { arrayEach } from "./../../../../helpers/array.mjs";
import { warn } from "./../../../../helpers/console.mjs";
import EventManager from "./../../../../eventManager.mjs";
import { CLONE_TYPES, CLONE_TOP, CLONE_LEFT } from "./constants.mjs";
/**
* Creates an overlay over the original Walkontable instance. The overlay renders the clone of the original Walkontable
* and (optionally) implements behavior needed for native horizontal and vertical scrolling.
*
* @class Overlay
*/
export var Overlay = /*#__PURE__*/function () {
/**
* @param {Walkontable} wotInstance The Walkontable instance.
*/
function Overlay(wotInstance) {
_classCallCheck(this, Overlay);
defineGetter(this, 'wot', wotInstance, {
writable: false
});
var _this$wot$wtTable = this.wot.wtTable,
TABLE = _this$wot$wtTable.TABLE,
hider = _this$wot$wtTable.hider,
spreader = _this$wot$wtTable.spreader,
holder = _this$wot$wtTable.holder,
wtRootElement = _this$wot$wtTable.wtRootElement; // legacy support, deprecated in the future
this.instance = this.wot;
this.type = '';
this.mainTableScrollableElement = null;
this.TABLE = TABLE;
this.hider = hider;
this.spreader = spreader;
this.holder = holder;
this.wtRootElement = wtRootElement;
this.trimmingContainer = getTrimmingContainer(this.hider.parentNode.parentNode);
this.updateStateOfRendering();
}
/**
* Update internal state of object with an information about the need of full rendering of the overlay.
*
* @returns {boolean} Returns `true` if the state has changed since the last check.
*/
_createClass(Overlay, [{
key: "updateStateOfRendering",
value: function updateStateOfRendering() {
var previousState = this.needFullRender;
this.needFullRender = this.shouldBeRendered();
var changed = previousState !== this.needFullRender;
if (changed && !this.needFullRender) {
this.reset();
}
return changed;
}
/**
* Checks if overlay should be fully rendered.
*
* @returns {boolean}
*/
}, {
key: "shouldBeRendered",
value: function shouldBeRendered() {
return true;
}
/**
* Update the trimming container.
*/
}, {
key: "updateTrimmingContainer",
value: function updateTrimmingContainer() {
this.trimmingContainer = getTrimmingContainer(this.hider.parentNode.parentNode);
}
/**
* Update the main scrollable element.
*/
}, {
key: "updateMainScrollableElement",
value: function updateMainScrollableElement() {
var _this$wot = this.wot,
wtTable = _this$wot.wtTable,
rootWindow = _this$wot.rootWindow;
if (rootWindow.getComputedStyle(wtTable.wtRootElement.parentNode).getPropertyValue('overflow') === 'hidden') {
this.mainTableScrollableElement = this.wot.wtTable.holder;
} else {
this.mainTableScrollableElement = getScrollableElement(wtTable.TABLE);
}
}
/**
* Calculates coordinates of the provided element, relative to the root Handsontable element.
* NOTE: The element needs to be a child of the overlay in order for the method to work correctly.
*
* @param {HTMLElement} element The cell element to calculate the position for.
* @param {number} rowIndex Visual row index.
* @param {number} columnIndex Visual column index.
* @returns {{top: number, left: number}|undefined}
*/
}, {
key: "getRelativeCellPosition",
value: function getRelativeCellPosition(element, rowIndex, columnIndex) {
if (this.clone.wtTable.holder.contains(element) === false) {
warn("The provided element is not a child of the ".concat(this.type, " overlay"));
return;
}
var windowScroll = this.mainTableScrollableElement === this.wot.rootWindow;
var fixedColumn = columnIndex < this.wot.getSetting('fixedColumnsLeft');
var fixedRowTop = rowIndex < this.wot.getSetting('fixedRowsTop');
var fixedRowBottom = rowIndex >= this.wot.getSetting('totalRows') - this.wot.getSetting('fixedRowsBottom');
var spreaderOffset = {
left: this.clone.wtTable.spreader.offsetLeft,
top: this.clone.wtTable.spreader.offsetTop
};
var elementOffset = {
left: element.offsetLeft,
top: element.offsetTop
};
var offsetObject = null;
if (windowScroll) {
offsetObject = this.getRelativeCellPositionWithinWindow(fixedRowTop, fixedColumn, elementOffset, spreaderOffset);
} else {
offsetObject = this.getRelativeCellPositionWithinHolder(fixedRowTop, fixedRowBottom, fixedColumn, elementOffset, spreaderOffset);
}
return offsetObject;
}
/**
* Calculates coordinates of the provided element, relative to the root Handsontable element within a table with window
* as a scrollable element.
*
* @private
* @param {boolean} onFixedRowTop `true` if the coordinates point to a place within the top fixed rows.
* @param {boolean} onFixedColumn `true` if the coordinates point to a place within the fixed columns.
* @param {number} elementOffset Offset position of the cell element.
* @param {number} spreaderOffset Offset position of the spreader element.
* @returns {{top: number, left: number}}
*/
}, {
key: "getRelativeCellPositionWithinWindow",
value: function getRelativeCellPositionWithinWindow(onFixedRowTop, onFixedColumn, elementOffset, spreaderOffset) {
var absoluteRootElementPosition = this.wot.wtTable.wtRootElement.getBoundingClientRect();
var horizontalOffset = 0;
var verticalOffset = 0;
if (!onFixedColumn) {
horizontalOffset = spreaderOffset.left;
} else {
horizontalOffset = absoluteRootElementPosition.left <= 0 ? -1 * absoluteRootElementPosition.left : 0;
}
if (onFixedRowTop) {
var absoluteOverlayPosition = this.clone.wtTable.TABLE.getBoundingClientRect();
verticalOffset = absoluteOverlayPosition.top - absoluteRootElementPosition.top;
} else {
verticalOffset = spreaderOffset.top;
}
return {
left: elementOffset.left + horizontalOffset,
top: elementOffset.top + verticalOffset
};
}
/**
* Calculates coordinates of the provided element, relative to the root Handsontable element within a table with window
* as a scrollable element.
*
* @private
* @param {boolean} onFixedRowTop `true` if the coordinates point to a place within the top fixed rows.
* @param {boolean} onFixedRowBottom `true` if the coordinates point to a place within the bottom fixed rows.
* @param {boolean} onFixedColumn `true` if the coordinates point to a place within the fixed columns.
* @param {number} elementOffset Offset position of the cell element.
* @param {number} spreaderOffset Offset position of the spreader element.
* @returns {{top: number, left: number}}
*/
}, {
key: "getRelativeCellPositionWithinHolder",
value: function getRelativeCellPositionWithinHolder(onFixedRowTop, onFixedRowBottom, onFixedColumn, elementOffset, spreaderOffset) {
var tableScrollPosition = {
horizontal: this.clone.cloneSource.wtOverlays.leftOverlay.getScrollPosition(),
vertical: this.clone.cloneSource.wtOverlays.topOverlay.getScrollPosition()
};
var horizontalOffset = 0;
var verticalOffset = 0;
if (!onFixedColumn) {
horizontalOffset = tableScrollPosition.horizontal - spreaderOffset.left;
}
if (onFixedRowBottom) {
var absoluteRootElementPosition = this.wot.wtTable.wtRootElement.getBoundingClientRect();
var absoluteOverlayPosition = this.clone.wtTable.TABLE.getBoundingClientRect();
verticalOffset = absoluteOverlayPosition.top * -1 + absoluteRootElementPosition.top;
} else if (!onFixedRowTop) {
verticalOffset = tableScrollPosition.vertical - spreaderOffset.top;
}
return {
left: elementOffset.left - horizontalOffset,
top: elementOffset.top - verticalOffset
};
}
/**
* Make a clone of table for overlay.
*
* @param {string} direction Can be `Overlay.CLONE_TOP`, `Overlay.CLONE_LEFT`,
* `Overlay.CLONE_TOP_LEFT_CORNER`.
* @returns {Walkontable}
*/
}, {
key: "makeClone",
value: function makeClone(direction) {
if (CLONE_TYPES.indexOf(direction) === -1) {
throw new Error("Clone type \"".concat(direction, "\" is not supported."));
}
var _this$wot2 = this.wot,
wtTable = _this$wot2.wtTable,
rootDocument = _this$wot2.rootDocument,
rootWindow = _this$wot2.rootWindow;
var clone = rootDocument.createElement('DIV');
var clonedTable = rootDocument.createElement('TABLE');
var tableParent = wtTable.wtRootElement.parentNode;
clone.className = "ht_clone_".concat(direction, " handsontable");
clone.style.position = 'absolute';
clone.style.top = 0;
clone.style.left = 0;
clone.style.overflow = 'visible';
clonedTable.className = wtTable.TABLE.className;
clone.appendChild(clonedTable);
this.type = direction;
tableParent.appendChild(clone);
var preventOverflow = this.wot.getSetting('preventOverflow');
if (preventOverflow === true || preventOverflow === 'horizontal' && this.type === CLONE_TOP || preventOverflow === 'vertical' && this.type === CLONE_LEFT) {
this.mainTableScrollableElement = rootWindow;
} else if (rootWindow.getComputedStyle(tableParent).getPropertyValue('overflow') === 'hidden') {
this.mainTableScrollableElement = wtTable.holder;
} else {
this.mainTableScrollableElement = getScrollableElement(wtTable.TABLE);
} // Create a new instance of the Walkontable class
return new this.wot.constructor({
cloneSource: this.wot,
cloneOverlay: this,
table: clonedTable
});
}
/**
* Refresh/Redraw overlay.
*
* @param {boolean} [fastDraw=false] When `true`, try to refresh only the positions of borders without rerendering
* the data. It will only work if Table.draw() does not force
* rendering anyway.
*/
}, {
key: "refresh",
value: function refresh() {
var fastDraw = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
// When hot settings are changed we allow to refresh overlay once before blocking
var nextCycleRenderFlag = this.shouldBeRendered();
if (this.clone && (this.needFullRender || nextCycleRenderFlag)) {
this.clone.draw(fastDraw);
}
this.needFullRender = nextCycleRenderFlag;
}
/**
* Reset overlay styles to initial values.
*/
}, {
key: "reset",
value: function reset() {
if (!this.clone) {
return;
}
var holder = this.clone.wtTable.holder;
var hider = this.clone.wtTable.hider;
var holderStyle = holder.style;
var hidderStyle = hider.style;
var rootStyle = holder.parentNode.style;
arrayEach([holderStyle, hidderStyle, rootStyle], function (style) {
style.width = '';
style.height = '';
});
}
/**
* Destroy overlay instance.
*/
}, {
key: "destroy",
value: function destroy() {
new EventManager(this.clone).destroy();
}
}]);
return Overlay;
}();