オープンソースのWikiであるGROWIにはプラグイン機能が用意されています。自社のデータを表示したり、表示をカスタマイズするのに利用できます。
今回は、GROWIプラグインとして作ったTable Gridプラグインを紹介します。これは、Markdown記法で記述したテーブルにGrid.jsを適用して、ソート・検索・ページネーション機能を追加するものです。
プラグインを追加する
利用する際には、GROWIの管理画面の プラグイン
にて追加してください。URLは https://github.com/goofmint/growi-plugin-table-grid
です。
使い方
利用する際には、編集画面でいつも通りMarkdown記法にてテーブルを記述します。
| Header1 | Header2 | Header3 |
| ------- | ------- | ------- |
| 1 | 2 | 3 |
| 4 | 5 | 6 |
| 7 | 8 | 9 |
そうすると、プレビュー画面にはGrid.jsを使った高機能なテーブルが表示されます。
注意点
空の行があると、うまく描画できないようです。また、データの編集に対してリアルタイムに反映できない問題があります。反映したい場合には、一旦空白行を入れて(エラーにして)から、再度正しいデータを入力すると反映されます。
コードについて
今回はtableタグに対してプラグイン機構を追加しています。HTML構造に対して適用するので、Rehypeのプラグインとして実装しています。
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); // プラグインを追加
return options;
};
// For preview
optionsGenerators.customGeneratePreviewOptions = (...args) => {
const preview = optionsGenerators.generatePreviewOptions(...args);
preview.rehypePlugins.push(plugin as any); // プラグインを追加
return preview;
};
};
export const plugin: Plugin = function() {
return (tree) => {
visit(tree, (node) => {
const n = node as unknown as GrowiNode;
try {
// tableタグ以外は無視
if (n.type !== 'element' || n.tagName !== 'table') {
return;
}
// この中で実装
}
catch (e) {
n.type = 'html';
n.value = `<div style="color: red;">Error: ${(e as Error).message}</div>`;
}
});
};
};
変換処理について
tableタグの中身から、thead/tbodyを取得します。そして、それぞれをGrid.jsの形に合わせて変換します。
const [thead, tbody] = n.children;
const columns = thead.children[0].children.map(c => c.children[0].value);
// ["Header1", "Header2", "Header3"] となる
const data = tbody.children.map(row => row.children
.map(cell => cell.children[0].value));
// [["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"]] となる
そして、それをGrid.jsに対して適用します。オプションはなるべく多くしています。スタイルは、GROWIのテーマに合わせています。
const grid = new Grid({
columns, // ヘッダー
data, // データ
pagination: true, // ページネーション
search: true, // 検索
sort: true, // ソート
resizable: true, // カラムサイズ変更
// スタイル
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)',
},
},
});
この時点ではまだHTMLにDOMが追加されていないので、追加を確認でき次第Grid.jsでレンダリングしています。
// 識別用のクラス
const className = `table-grid-${Math.random().toString(36).slice(2)}`;
n.properties.className = `${n.properties.className} ${className}`;
// DOMが追加されるまで待つ
const id = setInterval(() => {
const el = document.querySelector(`.${className}`);
if (el) {
clearInterval(id);
el.innerHTML = ''; // 元々表示されているHTMLを削除
grid.render(el); // Grid.jsでレンダリング
}
}, 1000);
スタイルについて
GROWIではテーマを選択できるので、選択したテーマによって色が異なります。また、テーマによってダークモード・ライトモードもあります。そのため、スタイルはCSS変数を使ってテーマに合わせています。
特にカラムのソートアイコン(画像)はダークモードだと背景色と同じ色になってしまうので、CSSフィルターを使って反転させています。
@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;
}
まとめ
GROWIプラグインを使うと、表示を自由に拡張できます。足りない機能があれば、どんどん追加できます。ぜひ、自分のWikiをカスタマイズしましょう。