@revolist/revogrid
Version:
Virtual reactive data grid spreadsheet component - RevoGrid.
465 lines (418 loc) • 11.5 kB
JavaScript
import { generateFakeDataObjectAsync } from './data.js';
/**
* Map of prevented events
*/
globalThis.eventsPrevented = {};
/**
* Toggle row headers visibility
* @param {boolean} isShow - Show row headers if true, hide otherwise
*/
globalThis.showRowHeaders = function (isShow) {
const grid = document.querySelector('revo-grid');
grid.rowHeaders = isShow;
};
/**
* Toggle column grouping visibility
* @param {boolean} isShow - Show column grouping if true, hide otherwise
*/
globalThis.showColGrouping = function (isShow) {
globalThis.setData({
groupedHeader: isShow,
});
};
/**
* Set row size
* @param {number} s - Row size
*/
globalThis.setRowSize = function (s) {
const grid = document.querySelector('revo-grid');
grid.rowSize = s;
};
/**
* Apply several custom row sizes.
*/
globalThis.setCustomRowSizes = function () {
const grid = document.querySelector('revo-grid');
grid.rowDefinitions = [
{ type: 'rgRow', index: 1, size: 64 },
{ type: 'rgRow', index: 3, size: 96 },
{ type: 'rgRow', index: 6, size: 48 },
{ type: 'rgRow', index: 10, size: 120 },
];
};
/**
* Start editing cell
* @param {number} rgRow - Row index
* @param {string} prop - Column property
*/
globalThis.setEdit = function (rgRow, prop) {
const grid = document.querySelector('revo-grid');
grid.setCellEdit(rgRow, prop);
};
/**
* Scroll to column
* @param {number} [x=30] - Column index
*/
globalThis.scrollToCol = function (x = 30) {
const grid = document.querySelector('revo-grid');
grid.scrollToColumnProp(x);
};
/**
* Clear grouping
*/
globalThis.clearGrouping = function () {
const grid = document.querySelector('revo-grid');
grid.grouping = {};
};
/**
* Set row grouping
* @param {Array} props - Array of properties to group by
* @param {boolean} expandedAll - Expand all groups if true, collapse otherwise
*/
globalThis.setGrouping = function (props = [], expandedAll = false) {
const grid = document.querySelector('revo-grid');
grid.grouping = {
props,
expandedAll,
prevExpanded: { 'a': true, 'a,c': true },
groupLabelTemplate(createElement, { name, depth, expanded, providers }) {
if (providers.colType !== 'rgCol') return;
return createElement('span', null, `${expanded ? '-' : '+'} ${props[depth]}: ${name}`);
},
};
};
/**
* Set trimmed rows
* @param {Array} rows - Array of row indexes to trim
*/
globalThis.setTrimmed = function (rows = []) {
const grid = document.querySelector('revo-grid');
grid.trimmedRows = rows.reduce((r, v) => {
r[v] = true;
return r;
}, {});
};
/**
* Export grid
* @param {string} [filename='new file'] - File name
*/
globalThis.exportGrid = function (filename = 'new file') {
const grid = document.querySelector('revo-grid');
grid.getPlugins().then(plugins => {
plugins.forEach(p => {
if (p.exportFile) {
const exportPlugin = p;
exportPlugin.exportFile({ filename });
}
});
});
};
let defaultData = {
rows: 0,
cols: 0,
rowDrag: 0,
topPinned: [],
bottomPinned: [],
colPinEnd: [],
colPinStart: [],
};
let dataGenerationId = 0;
function formatNumber(value) {
return new Intl.NumberFormat('en').format(value);
}
function setLoader(text, visible = true) {
const $loader = document.querySelector('.loader');
if (!$loader) {
return;
}
$loader.textContent = text;
$loader.style.display = visible ? 'block' : 'none';
}
function cancelDataGeneration() {
dataGenerationId++;
setLoader('', false);
}
/**
* Set data
* @param {Object} [config={}] - Data configuration
*/
globalThis.setData = async function (config = {}) {
defaultData = { ...defaultData, ...config };
const generationId = ++dataGenerationId;
const totalCells = defaultData.rows * defaultData.cols;
setLoader(`Preparing ${formatNumber(defaultData.rows)} rows x ${formatNumber(defaultData.cols)} columns...`);
try {
// Let the loader paint before data generation starts.
await new Promise(resolve => setTimeout(resolve, 0));
const data = await generateFakeDataObjectAsync(defaultData, {
isCanceled: () => generationId !== dataGenerationId,
onProgress: ({ rows, totalRows }) => {
if (generationId !== dataGenerationId) {
return;
}
setLoader(
`Generated ${formatNumber(rows)} / ${formatNumber(totalRows)} rows (${formatNumber(totalCells)} cells)...`,
);
},
});
if (generationId !== dataGenerationId || !data) {
return;
}
const grid = document.querySelector('revo-grid');
if (!grid) {
return;
}
grid.columns = data.headers;
grid.source = data.rows;
grid.pinnedTopSource = data.pinnedTopRows;
grid.pinnedBottomSource = data.pinnedBottomRows;
setLoader('', false);
} catch (error) {
if (generationId === dataGenerationId) {
setLoader(`Data generation failed: ${error?.message || error}`);
throw error;
}
}
};
globalThis.setRtl = function (checked) {
const grid = document.querySelector('revo-grid');
grid.rtl = checked;
globalThis.document.dir = checked ? 'rtl' : 'ltr';
};
/**
* Set pinned rows/columns
* @param {string} type - Type of pinned rows/columns
* @param {boolean} checked - True if rows/columns are pinned, false otherwise
*/
globalThis.setPinned = function (type, checked) {
const val = [];
if (checked) {
switch (type) {
case 'colPinStart':
val.push(0);
break;
case 'colPinEnd':
val.push(1);
break;
case 'topPinned':
val.push(0);
break;
case 'bottomPinned':
val.push(1);
break;
}
}
globalThis.setData({
[type]: val,
});
};
/**
* Prevent event debug
* @param {string} name - Event name
* @param {boolean} checked - True if event should be prevented, false otherwise
*/
globalThis.preventEvent = function (name, checked) {
globalThis.eventsPrevented[name] = checked;
};
let keys = 2;
let attrs = {};
/**
* Toggle visibility of grid
* @param {boolean} checked - True if grid is visible, false otherwise
*/
globalThis.toggleVisibility = function (checked) {
if (!checked) {
const grid = document.querySelector('revo-grid');
attrs = {};
// Get all attributes from the source element
const attributes = grid.attributes;
// Loop through the attributes and set them on the target element
for (let i = 0; i < attributes.length; i++) {
const attribute = attributes[i];
attrs[attribute.name] = attribute.value;
}
grid.remove();
} else {
const holder = document.querySelector('.grid-holder');
const grid = document.createElement('revo-grid', { is: 'revo-grid' });
// Recover attributes
Object.keys(attrs).forEach(key => {
grid.setAttribute(key, attrs[key]);
});
grid.setAttribute('key', keys++);
holder.appendChild(grid);
globalThis.setData();
}
};
let timerUpdateInterval;
/**
* Toggle timer update
* @param {boolean} checked - True if timer should be updated, false otherwise
* @param {number} [inteval=3] - Update interval in seconds
*/
globalThis.timerUpdate = function (checked, inteval = 3) {
clearInterval(timerUpdateInterval);
if (checked) {
timerUpdateInterval = setInterval(() => {
const grid = document.querySelector('revo-grid');
grid.source = [...grid.source];
}, inteval * 1000);
}
};
/**
* Set theme
* @param {string} theme - Theme name
*/
globalThis.theme = function (theme) {
const grid = document.querySelector('revo-grid');
if (theme?.includes('dark')) {
document.documentElement.setAttribute('data-bs-theme', 'dark');
} else {
document.documentElement.removeAttribute('data-bs-theme');
}
grid.theme = theme || 'default';
};
globalThis.onload = onLoad;
globalThis.clearFilter = () => {
const grid = document.querySelector('revo-grid');
grid.filter = {};
};
globalThis.sortColumn = (columnProp= 0, additive = false) => {
const grid = document.querySelector('revo-grid');
grid.updateColumnSorting({
prop: columnProp,
}, 'asc', additive);
};
globalThis.clearSorting = () => {
const grid = document.querySelector('revo-grid');
grid.clearSorting();
};
globalThis.setFilter = () => {
const grid = document.querySelector('revo-grid');
const filterFunc = (cellValue, extraValue) => {
if (!cellValue) {
return false;
}
if (typeof cellValue !== 'string') {
cellValue = JSON.stringify(cellValue);
}
return cellValue === extraValue;
};
// if you want extra input field for @extraValue
filterFunc.extra = 'input';
const filterConfig = {
// include: ['newEqual'],
customFilters: {
newEqual: {
columnFilterType: 'myFilterType', // column filter type id
name: 'myEqual',
func: filterFunc,
},
},
disableDynamicFiltering: true,
multiFilterItems: {
0: [
{
type: "contains",
value: '9:0',
},
],
},
};
grid.filter = filterConfig;
};
/**
* Deep groups should align with a1/a2/a3/b1/b2/b3.
* https://github.com/revolist/revogrid/issues/828
*/
globalThis.setColumnGroupOffsetBugDemo = () => {
cancelDataGeneration();
const grid = document.querySelector('revo-grid');
grid.columns = [
{ prop: 'q1', name: 'Q1', size: 90 },
{ prop: 'q2', name: 'Q2', size: 90 },
{
name: 'Root',
children: [
{
name: 'A',
children: [
{
name: 'A1',
children: [
{ prop: 'a1', name: 'A1-1', size: 90 },
{ prop: 'a2', name: 'A1-2', size: 90 },
],
},
{
name: 'A2',
children: [{ prop: 'a3', name: 'A2-1', size: 90 }],
},
],
},
{
name: 'B',
children: [
{
name: 'B1',
children: [{ prop: 'b1', name: 'B1-1', size: 90 }],
},
{
name: 'B2',
children: [
{ prop: 'b2', name: 'B2-1', size: 90 },
{ prop: 'b3', name: 'B2-2', size: 90 },
],
},
],
},
],
},
];
grid.source = [
{ q1: 'left-1', q2: 'left-2', a1: 'a1', a2: 'a2', a3: 'a3', b1: 'b1', b2: 'b2', b3: 'b3' },
{ q1: 'left-3', q2: 'left-4', a1: 'a4', a2: 'a5', a3: 'a6', b1: 'b4', b2: 'b5', b3: 'b6' },
];
grid.pinnedTopSource = [];
grid.pinnedBottomSource = [];
grid.rowHeaders = true;
};
/**
* On load function
*/
function onLoad() {
const grid = document.querySelector('revo-grid');
grid.readonly = false;
grid.range = true;
grid.resize = true;
grid.filter = true;
grid.exporting = true;
grid.rowHeaders = true;
// grid.rowDefinitions = [{
// size: 200,
// type: 'rgRow',
// index: 2,
// }];
// grid.stretch = true;
/*
grid.autoSizeColumn = {
mode: 'autoSizeAll',
};*/
// default
setData({ rows: 100, cols: 100 });
// events testing
// 'beforerange', 'setRange', 'beforefocuslost', 'beforecellfocus', 'afterfocus', 'beforeedit', 'aftercolumnresize'
const events = ['aftercolumnresize'];
events.forEach(e => {
grid.addEventListener(e, $e => {
if (globalThis.eventsPrevented[e]) {
$e.preventDefault();
}
console.log(
`%c${e}`,
'background: #50d260; color: #fff; border-radius: 3px; padding: 2px 5px;',
$e,
);
});
});
}