Files
railwaysystem/RuoYi-Vue/ruoyi-ui/node_modules1/handsontable/utils/ghostTable.js
T
2026-09-10 15:40:10 +08:00

475 lines
13 KiB
JavaScript

"use strict";
exports.__esModule = true;
require("core-js/modules/es.error.cause.js");
require("core-js/modules/es.array.push.js");
var _element = require("./../helpers/dom/element");
var _array = require("./../helpers/array");
/**
* @class GhostTable
*/
class GhostTable {
constructor(hotInstance) {
/**
* 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.
*/
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);
}
const rowObject = {
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.
*/
addColumnHeadersRow(samples) {
const colHeader = this.hot.getColHeader(0);
if (colHeader !== null && colHeader !== void 0) {
const 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.
*/
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);
}
const 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.
*/
getHeights(callback) {
if (!this.injected) {
this.injectTable();
}
(0, _array.arrayEach)(this.rows, row => {
// -1 <- reduce border-top from table
callback(row.row, (0, _element.outerHeight)(row.table) - 1);
});
}
/**
* Get calculated widths.
*
* @param {Function} callback Callback which will be fired for each calculated column.
*/
getWidths(callback) {
if (!this.injected) {
this.injectTable();
}
(0, _array.arrayEach)(this.columns, column => {
// The GhostTable class is responsible for calculating the columns' width based on the
// contents rendered in the cells. In some cases, when the column's width calculated by
// the browser is a decimal point with a fractional component. For example, 35.32px.
// The usage of the `.offsetWidth` (or our helper `outerWidth`) is incorrect.
// The `outerWidth` in the mentioned example (35.32px) would return 35 pixels that
// would cause the text to not fit in the cell, thus increasing the row height.
// That's why the `getBoundingClientRect` method is used. The method returns the number
// that is rounded up to make sure that there will be a space for the cell's content.
const {
width
} = column.table.getBoundingClientRect();
callback(column.col, Math.ceil(width));
});
}
/**
* Set the Ghost Table settings to the provided object.
*
* @param {object} settings New Ghost Table Settings.
*/
setSettings(settings) {
this.settings = settings;
}
/**
* Set a single setting of the Ghost Table.
*
* @param {string} name Setting name.
* @param {*} value Setting value.
*/
setSetting(name, value) {
if (!this.settings) {
this.settings = {};
}
this.settings[name] = value;
}
/**
* Get the Ghost Table settings.
*
* @returns {object|null}
*/
getSettings() {
return this.settings;
}
/**
* Get a single Ghost Table setting.
*
* @param {string} name The setting name to get.
* @returns {boolean|null}
*/
getSetting(name) {
if (this.settings) {
return this.settings[name];
}
return null;
}
/**
* Create colgroup col elements.
*
* @returns {DocumentFragment}
*/
createColGroupsCol() {
const fragment = this.hot.rootDocument.createDocumentFragment();
if (this.hot.hasRowHeaders()) {
fragment.appendChild(this.createColElement(-1));
}
this.samples.forEach(sample => {
(0, _array.arrayEach)(sample.strings, 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.
*/
createRow(row) {
const {
rootDocument
} = this.hot;
const fragment = rootDocument.createDocumentFragment();
const th = rootDocument.createElement('th');
if (this.hot.hasRowHeaders()) {
this.hot.view.appendRowHeader(row, th);
fragment.appendChild(th);
}
this.samples.forEach(sample => {
(0, _array.arrayEach)(sample.strings, string => {
const column = string.col;
const cellProperties = this.hot.getCellMeta(row, column);
cellProperties.col = column;
cellProperties.row = row;
const renderer = this.hot.getCellRenderer(cellProperties);
const 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(this.hot, td, row, column, this.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.
*/
appendColumnHeadersRow() {
const {
rootDocument
} = this.hot;
const domFragment = rootDocument.createDocumentFragment();
const columnHeaders = [];
if (this.hot.hasRowHeaders()) {
const th = rootDocument.createElement('th');
columnHeaders.push([-1, th]);
domFragment.appendChild(th);
}
this.samples.forEach(sample => {
(0, _array.arrayEach)(sample.strings, string => {
const column = string.col;
const th = rootDocument.createElement('th');
columnHeaders.push([column, th]);
domFragment.appendChild(th);
});
});
// Appending DOM elements for headers
this.table.tHead.appendChild(domFragment);
(0, _array.arrayEach)(columnHeaders, columnHeader => {
const [column, th] = columnHeader;
// Using source method for filling a header with value.
this.hot.view.appendColHeader(column, th);
});
}
/**
* Create table column elements.
*
* @param {number} column Column index.
* @returns {DocumentFragment} Returns created column table column elements.
*/
createCol(column) {
const {
rootDocument
} = this.hot;
const fragment = rootDocument.createDocumentFragment();
this.samples.forEach(sample => {
(0, _array.arrayEach)(sample.strings, string => {
const row = string.row;
const cellProperties = this.hot.getCellMeta(row, column);
cellProperties.col = column;
cellProperties.row = row;
const renderer = this.hot.getCellRenderer(cellProperties);
const td = rootDocument.createElement('td');
const 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(this.hot, td, row, column, this.hot.colToProp(column), string.value, cellProperties);
tr.appendChild(td);
fragment.appendChild(tr);
});
});
return fragment;
}
/**
* Remove table from document and reset internal state.
*/
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.
*/
injectTable() {
let 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.
*/
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}
*/
createColElement(column) {
const col = this.hot.rootDocument.createElement('col');
col.style.width = `${this.hot.view._wt.wtTable.getStretchedColumnWidth(column)}px`;
return col;
}
/**
* Create table element.
*
* @param {string} className The CSS classes to add.
* @returns {object}
*/
createTable() {
let className = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
const {
rootDocument
} = this.hot;
const fragment = rootDocument.createDocumentFragment();
const table = rootDocument.createElement('table');
const tHead = rootDocument.createElement('thead');
const tBody = rootDocument.createElement('tbody');
const colGroup = rootDocument.createElement('colgroup');
const tr = rootDocument.createElement('tr');
const 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);
(0, _element.addClass)(table, className);
fragment.appendChild(table);
return {
fragment,
table,
tHead,
tBody,
colGroup,
tr,
th
};
}
/**
* Create container for tables.
*
* @param {string} className The CSS classes to add.
* @returns {object}
*/
createContainer() {
let className = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
const {
rootDocument
} = this.hot;
const fragment = rootDocument.createDocumentFragment();
const container = rootDocument.createElement('div');
const containerClassName = `htGhostTable htAutoSize ${className.trim()}`;
(0, _element.addClass)(container, containerClassName);
fragment.appendChild(container);
return {
fragment,
container
};
}
/**
* Checks if table is raised vertically (checking rows).
*
* @returns {boolean}
*/
isVertical() {
return !!(this.rows.length && !this.columns.length);
}
/**
* Checks if table is raised horizontally (checking columns).
*
* @returns {boolean}
*/
isHorizontal() {
return !!(this.columns.length && !this.rows.length);
}
}
var _default = GhostTable;
exports.default = _default;