handsontable
Version:
Handsontable is a JavaScript Spreadsheet Component available for React, Angular and Vue.
576 lines (492 loc) • 17.5 kB
JavaScript
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _iterableToArrayLimit(arr, i) { var _i = arr && (typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]); if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
import "core-js/modules/web.dom-collections.for-each.js";
import "core-js/modules/es.string.trim.js";
import "core-js/modules/es.symbol.js";
import "core-js/modules/es.symbol.description.js";
import "core-js/modules/es.object.to-string.js";
import "core-js/modules/es.symbol.iterator.js";
import "core-js/modules/es.array.iterator.js";
import "core-js/modules/es.string.iterator.js";
import "core-js/modules/web.dom-collections.iterator.js";
import "core-js/modules/es.array.slice.js";
import "core-js/modules/es.function.name.js";
import "core-js/modules/es.array.from.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); return Constructor; }
import { addClass, outerHeight, outerWidth } from "./../helpers/dom/element.mjs";
import { arrayEach } from "./../helpers/array.mjs";
/**
* @class GhostTable
* @util
*/
var GhostTable = /*#__PURE__*/function () {
function GhostTable(hotInstance) {
_classCallCheck(this, GhostTable);
/**
* Handsontable instance.
*
* @type {Core}
*/
this.hot = hotInstance;
/**
* Container element where every table will be injected.
*
* @type {HTMLElement|null}
*/
this.container = null;
/**
* Flag which determine is table was injected to DOM.
*
* @type {boolean}
*/
this.injected = false;
/**
* Added rows collection.
*
* @type {Array}
*/
this.rows = [];
/**
* Added columns collection.
*
* @type {Array}
*/
this.columns = [];
/**
* Samples prepared for calculations.
*
* @type {Map}
* @default {null}
*/
this.samples = null;
/**
* Ghost table settings.
*
* @type {object}
* @default {Object}
*/
this.settings = {
useHeaders: true
};
}
/**
* Add row.
*
* @param {number} row Row index.
* @param {Map} samples Samples Map object.
*/
_createClass(GhostTable, [{
key: "addRow",
value: function addRow(row, samples) {
if (this.columns.length) {
throw new Error('Doesn\'t support multi-dimensional table');
}
if (!this.rows.length) {
this.container = this.createContainer(this.hot.rootElement.className);
}
var rowObject = {
row: row
};
this.rows.push(rowObject);
this.samples = samples;
this.table = this.createTable(this.hot.table.className);
this.table.colGroup.appendChild(this.createColGroupsCol());
this.table.tr.appendChild(this.createRow(row));
this.container.container.appendChild(this.table.fragment);
rowObject.table = this.table.table;
}
/**
* Add a row consisting of the column headers.
*
* @param {Map} samples A map with sampled table values.
*/
}, {
key: "addColumnHeadersRow",
value: function addColumnHeadersRow(samples) {
var colHeader = this.hot.getColHeader(0);
if (colHeader !== null && colHeader !== void 0) {
var rowObject = {
row: -1
};
this.rows.push(rowObject);
this.container = this.createContainer(this.hot.rootElement.className);
this.samples = samples;
this.table = this.createTable(this.hot.table.className);
this.table.colGroup.appendChild(this.createColGroupsCol());
this.appendColumnHeadersRow();
this.container.container.appendChild(this.table.fragment);
rowObject.table = this.table.table;
}
}
/**
* Add column.
*
* @param {number} column Column index.
* @param {Map} samples A map with sampled table values.
*/
}, {
key: "addColumn",
value: function addColumn(column, samples) {
if (this.rows.length) {
throw new Error('Doesn\'t support multi-dimensional table');
}
if (!this.columns.length) {
this.container = this.createContainer(this.hot.rootElement.className);
}
var columnObject = {
col: column
};
this.columns.push(columnObject);
this.samples = samples;
this.table = this.createTable(this.hot.table.className);
if (this.getSetting('useHeaders') && this.hot.getColHeader(column) !== null) {
// Please keep in mind that the renderable column index equal to the visual columns index for the GhostTable.
// We render all columns.
this.hot.view.appendColHeader(column, this.table.th);
}
this.table.tBody.appendChild(this.createCol(column));
this.container.container.appendChild(this.table.fragment);
columnObject.table = this.table.table;
}
/**
* Get calculated heights.
*
* @param {Function} callback Callback which will be fired for each calculated row.
*/
}, {
key: "getHeights",
value: function getHeights(callback) {
if (!this.injected) {
this.injectTable();
}
arrayEach(this.rows, function (row) {
// -1 <- reduce border-top from table
callback(row.row, outerHeight(row.table) - 1);
});
}
/**
* Get calculated widths.
*
* @param {Function} callback Callback which will be fired for each calculated column.
*/
}, {
key: "getWidths",
value: function getWidths(callback) {
if (!this.injected) {
this.injectTable();
}
arrayEach(this.columns, function (column) {
callback(column.col, outerWidth(column.table));
});
}
/**
* Set the Ghost Table settings to the provided object.
*
* @param {object} settings New Ghost Table Settings.
*/
}, {
key: "setSettings",
value: function setSettings(settings) {
this.settings = settings;
}
/**
* Set a single setting of the Ghost Table.
*
* @param {string} name Setting name.
* @param {*} value Setting value.
*/
}, {
key: "setSetting",
value: function setSetting(name, value) {
if (!this.settings) {
this.settings = {};
}
this.settings[name] = value;
}
/**
* Get the Ghost Table settings.
*
* @returns {object|null}
*/
}, {
key: "getSettings",
value: function getSettings() {
return this.settings;
}
/**
* Get a single Ghost Table setting.
*
* @param {string} name The setting name to get.
* @returns {boolean|null}
*/
}, {
key: "getSetting",
value: function getSetting(name) {
if (this.settings) {
return this.settings[name];
}
return null;
}
/**
* Create colgroup col elements.
*
* @returns {DocumentFragment}
*/
}, {
key: "createColGroupsCol",
value: function createColGroupsCol() {
var _this = this;
var fragment = this.hot.rootDocument.createDocumentFragment();
if (this.hot.hasRowHeaders()) {
fragment.appendChild(this.createColElement(-1));
}
this.samples.forEach(function (sample) {
arrayEach(sample.strings, function (string) {
fragment.appendChild(_this.createColElement(string.col));
});
});
return fragment;
}
/**
* Create table row element.
*
* @param {number} row Row index.
* @returns {DocumentFragment} Returns created table row elements.
*/
}, {
key: "createRow",
value: function createRow(row) {
var _this2 = this;
var rootDocument = this.hot.rootDocument;
var fragment = rootDocument.createDocumentFragment();
var th = rootDocument.createElement('th');
if (this.hot.hasRowHeaders()) {
this.hot.view.appendRowHeader(row, th);
fragment.appendChild(th);
}
this.samples.forEach(function (sample) {
arrayEach(sample.strings, function (string) {
var column = string.col;
var cellProperties = _this2.hot.getCellMeta(row, column);
cellProperties.col = column;
cellProperties.row = row;
var renderer = _this2.hot.getCellRenderer(cellProperties);
var td = rootDocument.createElement('td'); // Indicate that this element is created and supported by GhostTable. It can be useful to
// exclude rendering performance costly logic or exclude logic which doesn't work within a hidden table.
td.setAttribute('ghost-table', 1);
renderer(_this2.hot, td, row, column, _this2.hot.colToProp(column), string.value, cellProperties);
fragment.appendChild(td);
});
});
return fragment;
}
/**
* Creates DOM elements for headers and appends them to the THEAD element of the table.
*/
}, {
key: "appendColumnHeadersRow",
value: function appendColumnHeadersRow() {
var _this3 = this;
var rootDocument = this.hot.rootDocument;
var domFragment = rootDocument.createDocumentFragment();
var columnHeaders = [];
if (this.hot.hasRowHeaders()) {
var th = rootDocument.createElement('th');
columnHeaders.push([-1, th]);
domFragment.appendChild(th);
}
this.samples.forEach(function (sample) {
arrayEach(sample.strings, function (string) {
var column = string.col;
var th = rootDocument.createElement('th');
columnHeaders.push([column, th]);
domFragment.appendChild(th);
});
}); // Appending DOM elements for headers
this.table.tHead.appendChild(domFragment);
arrayEach(columnHeaders, function (columnHeader) {
var _columnHeader = _slicedToArray(columnHeader, 2),
column = _columnHeader[0],
th = _columnHeader[1]; // Using source method for filling a header with value.
_this3.hot.view.appendColHeader(column, th);
});
}
/**
* Create table column elements.
*
* @param {number} column Column index.
* @returns {DocumentFragment} Returns created column table column elements.
*/
}, {
key: "createCol",
value: function createCol(column) {
var _this4 = this;
var rootDocument = this.hot.rootDocument;
var fragment = rootDocument.createDocumentFragment();
this.samples.forEach(function (sample) {
arrayEach(sample.strings, function (string) {
var row = string.row;
var cellProperties = _this4.hot.getCellMeta(row, column);
cellProperties.col = column;
cellProperties.row = row;
var renderer = _this4.hot.getCellRenderer(cellProperties);
var td = rootDocument.createElement('td');
var tr = rootDocument.createElement('tr'); // Indicate that this element is created and supported by GhostTable. It can be useful to
// exclude rendering performance costly logic or exclude logic which doesn't work within a hidden table.
td.setAttribute('ghost-table', 1);
renderer(_this4.hot, td, row, column, _this4.hot.colToProp(column), string.value, cellProperties);
tr.appendChild(td);
fragment.appendChild(tr);
});
});
return fragment;
}
/**
* Remove table from document and reset internal state.
*/
}, {
key: "clean",
value: function clean() {
this.rows.length = 0;
this.rows[-1] = void 0;
this.columns.length = 0;
if (this.samples) {
this.samples.clear();
}
this.samples = null;
this.removeTable();
}
/**
* Inject generated table into document.
*
* @param {HTMLElement} [parent=null] The element to which the ghost table is injected.
*/
}, {
key: "injectTable",
value: function injectTable() {
var parent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
if (!this.injected) {
(parent || this.hot.rootElement).appendChild(this.container.fragment);
this.injected = true;
}
}
/**
* Remove table from document.
*/
}, {
key: "removeTable",
value: function removeTable() {
if (this.injected && this.container.container.parentNode) {
this.container.container.parentNode.removeChild(this.container.container);
this.container = null;
this.injected = false;
}
}
/**
* Create col element.
*
* @param {number} column Column index.
* @returns {HTMLElement}
*/
}, {
key: "createColElement",
value: function createColElement(column) {
var col = this.hot.rootDocument.createElement('col');
col.style.width = "".concat(this.hot.view.wt.wtTable.getStretchedColumnWidth(column), "px");
return col;
}
/**
* Create table element.
*
* @param {string} className The CSS classes to add.
* @returns {object}
*/
}, {
key: "createTable",
value: function createTable() {
var className = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var rootDocument = this.hot.rootDocument;
var fragment = rootDocument.createDocumentFragment();
var table = rootDocument.createElement('table');
var tHead = rootDocument.createElement('thead');
var tBody = rootDocument.createElement('tbody');
var colGroup = rootDocument.createElement('colgroup');
var tr = rootDocument.createElement('tr');
var th = rootDocument.createElement('th');
if (this.isVertical()) {
table.appendChild(colGroup);
}
if (this.isHorizontal()) {
tr.appendChild(th);
tHead.appendChild(tr);
table.style.tableLayout = 'auto';
table.style.width = 'auto';
}
table.appendChild(tHead);
if (this.isVertical()) {
tBody.appendChild(tr);
}
table.appendChild(tBody);
addClass(table, className);
fragment.appendChild(table);
return {
fragment: fragment,
table: table,
tHead: tHead,
tBody: tBody,
colGroup: colGroup,
tr: tr,
th: th
};
}
/**
* Create container for tables.
*
* @param {string} className The CSS classes to add.
* @returns {object}
*/
}, {
key: "createContainer",
value: function createContainer() {
var className = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var rootDocument = this.hot.rootDocument;
var fragment = rootDocument.createDocumentFragment();
var container = rootDocument.createElement('div');
var containerClassName = "htGhostTable htAutoSize ".concat(className.trim());
addClass(container, containerClassName);
fragment.appendChild(container);
return {
fragment: fragment,
container: container
};
}
/**
* Checks if table is raised vertically (checking rows).
*
* @returns {boolean}
*/
}, {
key: "isVertical",
value: function isVertical() {
return !!(this.rows.length && !this.columns.length);
}
/**
* Checks if table is raised horizontally (checking columns).
*
* @returns {boolean}
*/
}, {
key: "isHorizontal",
value: function isHorizontal() {
return !!(this.columns.length && !this.rows.length);
}
}]);
return GhostTable;
}();
export default GhostTable;