GROWI, an open-source wiki, has a plug-in feature. You can use it to display your own data or customize the display.
In this article, I will explain the procedure for developing a GROWI plugin. I have previously created a plugin that automatically displays YouTube URLs in an embedded format, and this time, I will create a plugin that performs similar operations as a Remark plugin.
About the code
The code is goofmint/growi-plugin-remark-youtube: GROWI plugin for embed YouTube by Remark. The two files you should see are.
What is Remark?
Remark is a Markdown processor, which GROWI also uses as an engine to convert Markdown to HTML.
remarkjs/remark: markdown processor powered by plugins part of the @unifiedjs collective
Remark allows you to add your own notation within Markdown via plugins. Using this mechanism, you can also add plugins in GROWI.
Adding a plugin
This time, I will create a plugin that runs on the client side (browser). In this case, you will write the plugin's entry point in client-entry.tsx
.
You can add a Remark plugin by adding a function (see below) for remarkPlugins
.
import { plugin } from './src/youtube';
const activate = (): void => {
if (growiFacade == null || growiFacade.markdownRenderer == null) {
return;
}
const { optionsGenerators } = growiFacade.markdownRenderer;
optionsGenerators.customGenerateViewOptions = (...args) => {
const options = optionsGenerators.generateViewOptions(...args);
// Add plugin
options.remarkPlugins.push(plugin as any);
return options;
};
};
Contents of plugin
The plugin is written in src/youtube.ts
. This file is written to work as a Remark plugin.
import type { Plugin } from 'unified';
import { visit } from 'unist-util-visit';
// Add more properties
interface GrowiNode extends Node {
name: string;
type: string;
attributes: {[key: string]: string}
children: GrowiNode[];
value: string;
}
// Define plugin function
export const plugin: Plugin = function() {
return (tree) => {
visit(tree, (node) => {
const n = node as unknown as GrowiNode;
try {
if (n.type === 'leafGrowiPluginDirective' && n.name === 'youtube') {
// 1st arg is YouTube video ID
const id = Object.keys(n.attributes)[0];
// optional parameters
width and height
const { width, height } = n.attributes;
n.type = 'html';
// Create embed HTML of YouTube
n.value = `<div style="width: 100%; aspect-ratio: 16/9">
<iframe
width="${width || '560'}"
height="${height || '315'}"
src="https://www.youtube.com/embed/${id}"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin" allowfullscreen>
</iframe>
</div>
`;
}
}
catch (e) {
n.type = 'html';
n.value = `<div style="color: red;">Error: ${(e as Error).message}</div>`;
}
});
};
};
Description
The basic form of the plugin is as follows.
export const plugin: Plugin = function() {
return (tree) => {
visit(tree, (node) => {
// Write your code here
});
};
};
Inside node
is the AST (Abstract Syntax Tree) in Remark; the AST is the data structure resulting from parsing Markdown. All node information is sent to us, so I process only what I need.
You can then send the HTML you want to render for node.value
and it will be displayed on GROWI.
Usage
Here is how to use the plugin. This will display YouTube videos embedded.
$youtube(fGWaKXWrhdY,width=100%,height=100%)
The width
and height
are optional. If not specified, the default values are applied.
$youtube(fGWaKXWrhdY)
$youtube(fGWaKXWrhdY,width=100%)
$youtube(fGWaKXWrhdY,height=100%)
If there are any errors, they will be displayed in red text.
Difference from component-based plugins
Previously, I created a plugin called https://youtube.com/watch?v=fGWaKXWrhdY
that automatically embeds and displays URLs. This plugin works by simply pasting the URL into Markdown. In this case, it works by overriding React's a tag behavior.
In the component-based case, it can only be used for tags used in Markdown notation, such as h1-6 tags and code tags. In other words, it cannot be used with div tags, p tags, etc.
In order to be able to use it as a plugin even if it is written as a ground text in the editor, such as $youtube(fGWaKXWrhdY)
, you need to create a Remark plugin.
In addition, Remark plug-ins are convenient in that they can be passed options. By using options, the display can be more finely customized.
Summary
GROWI's plugin mechanism can be further extended (e.g., to run on the server side). Please develop plug-ins to customize GROWI to your liking.
GROWI, an OSS development wiki tool | comfortable information sharing for all
Top comments (0)