オープンソースのWikiであるGROWIにはプラグイン機能が用意されています。自社のデータを表示したり、表示をカスタマイズするのに利用できます。
今回は、GROWIプラグインとして作ったPDFビューワーを紹介します。Remarkプラグインとして作れば、手軽に拡張できます。
コードについて
コードはgoofmint/growi-plugin-pdf-viewer: Viewing PDF File inside of GROWI
にあります。見るべきファイルとしては、以下の2つになります。
プラグインを追加する
利用する際には、GROWIの管理画面の プラグイン
にて追加してください。URLは https://github.com/goofmint/growi-plugin-pdf-viewer
です。
使い方
プラグインは $pdfviewer
という記法を使います。エディタにて、PDFファイルをアップロードし、 $pdfviewer(ファイル名)
と記述すると、PDFビューワーが表示されます。
たとえば以下のような記述です。
$pdfviewer(/attachment/669c803453e575a188286be3)
ただし、そのままだと埋め込みサイズがうまくいかないので、 width
と height
のオプションで調整してください。
$pdfviewer(/attachment/669c803453e575a188286be3,width=75%,height=850px)
実装について
プラグインの登録部分 client-entry.tsx
のコードです。
import { plugin } from './src/pdfviewer';
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;
};
};
PDFビューワー部分
今回はPDF Viewerとして、PDF.jsをベースにした ts-pdf
を利用しています。Webワーカーが必要なので、CloudfareのCDNから取得しています。また、PDFを表示するdivタグが必要なので一旦それをレンダリングし、その後(500ms後)にPDFを表示します。
何度かこのプラグインコード部分が呼ばれることがあったので、描画したdivタグの中にShadow DOMが存在しないかを確認しています。あればPDFビューワーを初期化しません。
divタグのidは、ファイルパスをsha256でハッシュ化しています。これにより、1ページの中で複数のPDFビューワーを表示しても問題ありません。
import sha256 from 'crypto-js/sha256';
import { TsPdfViewer, TsPdfViewerOptions } from 'ts-pdf';
import type { Plugin } from 'unified';
import { visit } from 'unist-util-visit';
interface GrowiNode extends Node {
name: string;
type: string;
attributes: {[key: string]: string}
children: GrowiNode[];
value: string;
}
export const plugin: Plugin = function() {
return (tree) => {
visit(tree, (node) => {
const n = node as unknown as GrowiNode;
try {
if (n.type === 'leafGrowiPluginDirective' && n.name === 'pdfviewer') {
const filePath = Object.keys(n.attributes)[0];
const { width, height } = n.attributes;
// ファイル名からユニークなIDを生成
const key = sha256(filePath);
const containerSelector = `#pdf-${key}`;
const options: TsPdfViewerOptions = {
containerSelector,
workerSource: 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.min.js',
};
n.type = 'html';
// PDFビューワーを表示するdivタグをレンダリング
n.value = `<div id="pdf-${key}" style="width: ${width}; height: ${height};"></div>`;
// HTML描画を待って、500ms後にPDFビューワーを初期化
setTimeout(() => {
if (!document.querySelector(containerSelector)?.shadowRoot) {
const viewer = new TsPdfViewer(options);
viewer.openPdfAsync(filePath);
}
}, 500);
}
}
catch (e) {
n.type = 'html';
n.value = `<div style="color: red;">Error: ${(e as Error).message}</div>`;
}
});
};
};
注意点
PDF.jsには表示サイズを調整してくれる機能があるのですが、ts-pdfにはないため、表示サイズを手動調整する必要があります。また、CMapファイルを指定するオプションが見当たらず、現状では日本語PDFの表示には対応していません(指定方法があれば教えてください!)。
まとめ
GROWIのRemarkプラグインを使うと、Markdown記法を自由に拡張できます。足りない機能があれば、どんどん追加できます。ぜひ、自分のWikiをカスタマイズしましょう。