GROWI is an open-source Wiki platform that offers a plugin system, enabling users to display and customize their data effectively.
In this article, we introduce the Table Grid plugin developed for GROWI. This plugin applies Grid.js to tables written in Markdown, adding functionalities such as sorting, searching, and pagination.
Adding the Plugin
To use this plugin, navigate to the Plugins
section in GROWI's administration panel and add the following URL: https://github.com/goofmint/growi-plugin-table-grid
.
Usage
In the editor, write a table using standard Markdown syntax:
| Header1 | Header2 | Header3 |
| ------- | ------- | ------- |
| 1 | 2 | 3 |
| 4 | 5 | 6 |
| 7 | 8 | 9 |
Upon previewing, the table will be enhanced with Grid.js, providing advanced features.
Important Notes
- Empty Rows: The plugin may not render tables correctly if empty rows are present.
- Real-time Updates: Changes to data might not reflect immediately. To update, insert a blank line (causing an error) and then re-enter the correct data.
About the Code
The plugin integrates with the table
tag using GROWI's plugin system and is implemented as a Rehype plugin.
const activate = (): void => {
if (growiFacade == null || growiFacade.markdownRenderer == null) {
return;
}
const { optionsGenerators } = growiFacade.markdownRenderer;
// For page view
optionsGenerators.customGenerateViewOptions = (...args) => {
const options = optionsGenerators.generateViewOptions(...args);
options.rehypePlugins.push(plugin as any); // Add plugin
return options;
};
// For preview
optionsGenerators.customGeneratePreviewOptions = (...args) => {
const preview = optionsGenerators.generatePreviewOptions(...args);
preview.rehypePlugins.push(plugin as any); // Add plugin
return preview;
};
};
The plugin processes the table
tag, extracting thead
and tbody
to transform them into a format compatible with Grid.js.
export const plugin: Plugin = function() {
return (tree) => {
visit(tree, (node) => {
const n = node as unknown as GrowiNode;
try {
// Ignore non-table tags
if (n.type !== 'element' || n.tagName !== 'table') {
return;
}
// Implementation here
}
catch (e) {
n.type = 'html';
n.value = `<div style="color: red;">Error: ${(e as Error).message}</div>`;
}
});
};
};
The transformation involves mapping the table headers and data to Grid.js's structure:
const [thead, tbody] = n.children;
const columns = thead.children[0].children.map(c => c.children[0].value);
// Results in ["Header1", "Header2", "Header3"]
const data = tbody.children.map(row => row.children
.map(cell => cell.children[0].value));
// Results in [["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"]]
These are then applied to Grid.js with various options, styled to match GROWI's theme:
const grid = new Grid({
columns, // Headers
data, // Data
pagination: true, // Pagination
search: true, // Search
sort: true, // Sorting
resizable: true, // Column resizing
// Styling
style: {
table: {
border: '2px solid var(--bs-secondary-bg)',
},
th: {
color: 'var(--bs-body-color)',
backgroundColor: 'var(--bs-body-bg)',
},
td: {
color: 'var(--bs-body-color)',
backgroundColor: 'var(--bs-body-bg)',
},
footer: {
backgroundColor: 'var(--bs-secondary-bg)',
},
},
});
Since the DOM isn't updated immediately, the plugin waits for the DOM to be ready before rendering with Grid.js:
// Unique class for identification
const className = `table-grid-${Math.random().toString(36).slice(2)}`;
n.properties.className = `${n.properties.className} ${className}`;
// Wait for DOM to be ready
const id = setInterval(() => {
const el = document.querySelector(`.${className}`);
if (el) {
clearInterval(id);
el.innerHTML = ''; // Clear existing HTML
grid.render(el); // Render with Grid.js
}
}, 1000);
Styling Considerations
GROWI supports multiple themes, including dark and light modes. To ensure compatibility, the plugin utilizes CSS variables. For instance, sort icons may blend with the background in dark mode; applying a CSS filter inverts their color:
@media (prefers-color-scheme: dark) {
.gridjs-sort {
filter: invert(100%);
}
}
.gridjs-input {
color: var(--bs-body-color) !important;
background-color: var(--bs-body-bg) !important;
}
.gridjs-pages button {
color: var(--bs-body-color) !important;
background-color: var(--bs-body-bg) !important;
}
Conclusion
GROWI's plugin system allows for extensive customization of its display features. If you find any functionalities lacking, consider developing and adding your
Top comments (0)