オープンソースのWikiであるGROWIにはプラグイン機能が用意されています。自社のデータを表示したり、表示をカスタマイズするのに利用できます。
今回は、GROWIプラグインとして作ったカレンダー表示プラグインを紹介します。Pukiwikiでも人気のあったプラグインなので、真似してみました。
プラグインを追加する
利用する際には、GROWIの管理画面の プラグイン
にて追加してください。URLは https://github.com/goofmint/growi-plugin-calendar
です。
使い方
利用する際には、ページの中で $calendar
と書きます。記述した場所にカレンダーが表示されます。
$calendar
日付をクリックすると、その日付で新しいページが作成できます。日報や日記などに利用できます。
オプション
利用できるオプションは以下があります。
表示する年月を変更する
1つ目の引数に月、2つ目の引数に年を指定することで、表示する年月を変更できます。
$calendar(12,2021)
表示言語を変更する
デフォルトは英語ですが、表示言語を lang
オプションで変更できます。日本語は ja
です。
$calendar(lang=fr)
日付をクリックした際のページ名生成基準を変える
デフォルトでは日付をクリックすると YYYY/MM/DD
というページ名が生成されます。つまり階層構造になります。これを変更することができます。
$calendar(separator=-)
上記の指定だと、 2024-10-02
のようなページが生成されます。階層構造が嫌な場合は、こちらを利用してください。
設定の組み合わせ
上記オプションは組み合わせて利用できます。
$calendar(12,2021,lang=fr,separator=-)
$calendar(12,2021,separator=-)
コードについて
コードはgoofmint/growi-plugin-calendar: GROWI plugin shows calendar
にあります。見るべきファイルとしては、以下の2つになります。
client-entry.tsxについて
client-entry.tsxはプラグインの登録部分です。カレンダープラグインをRemarkプラグインとして登録しています。
const activate = (): void => {
if (growiFacade == null || growiFacade.markdownRenderer == null) {
return;
}
const { optionsGenerators } = growiFacade.markdownRenderer;
optionsGenerators.customGenerateViewOptions = (...args) => {
const options = optionsGenerators.generateViewOptions(...args);
options.remarkPlugins.push(plugin as any); // プラグイン登録
return options;
};
};
src/calendar.tsについて
カレンダー表示は Vanilla Calendar - Lightweight calendar on pure JavaScript を利用しています。HTMLで表示する必要があるので、JavaScriptで利用できるものを採用しています。
import VanillaCalendar from 'vanilla-calendar-pro';
import 'vanilla-calendar-pro/build/vanilla-calendar.min.css';
Remarkプラグインの場合、描画処理がすべて visit 関数に送られてきますので、この中からカレンダー表示を行う部分だけを抜き出しています。
export const plugin: Plugin = function() {
return (tree) => {
visit(tree, (node) => {
const n = node as unknown as GrowiNode;
try {
if (n.type === 'leafGrowiPluginDirective' && n.name === 'calendar') {
// この中で処理
}
} catch (e) {
n.type = 'html';
n.value = `<div style="color: red;">Error: ${(e as Error).message}</div>`;
}
});
});
};
オプションの取得
オプションデータは node.attributes
で取得できます。
const [month, year] = Object.keys(n.attributes);
const lang = n.attributes.lang || 'en';
const separator = n.attributes.separator || '/';
そして、一旦カレンダーのタグだけ出力して終了します。
n.type = 'html';
n.value = '<div id="calendar"></div>';
HTMLのレンダリングが行われて、 #calendar
があるのを確認してから描画処理に入ります。
const id = setInterval(() => {
if (document.querySelector('#calendar') != null) {
// カレンダーオブジェクト作成
const cal = new VanillaCalendar('#calendar', {
settings: {
lang, // 表示言語
// 表示年月
selected: {
month: isNaN(month as unknown as number) ? new Date().getMonth() : parseInt(month) - 1,
year: isNaN(year as unknown as number) ? new Date().getFullYear() : parseInt(year),
},
},
actions: {
// 日付クリック時の処理
async clickDay(event, self) {
const page = self.selectedDates[0].replaceAll(/-/g, separator);
const path = await getPagePath();
location.href = `${path}${page}`;
},
},
});
// 表示
cal.init();
// 終了
clearInterval(id);
}
}, 100);
日付をクリックした際の処理
日付をクリックした際に、ページ情報を取得してページ名を正しく取得しています。
const getPagePath = async() => {
if (location.pathname === '/') return '/';
const pageId = location.pathname.replace(/\//, '');
const res = await fetch(`/_api/v3/page?pageId=${pageId}`);
const json = await res.json();
const { path } = json.page;
return `${path}/`;
};
まとめ
GROWIプラグインを使うと、表示を自由に拡張できます。足りない機能があれば、どんどん追加できます。ぜひ、自分のWikiをカスタマイズしましょう。