DEV Community

Atsushi
Atsushi

Posted on

Introduction to the GROWI calendar display plug-in

The open source wiki, GROWI has a plugin facility. It can be used to display your own data or to customise the display.

In this article, we introduce a calendar display plugin that we created as a GROWI plugin; it was a popular plugin on Pukiwiki, so we tried to imitate it.

calendar.jpg

Add the plugin.

To use it, please add it at Plugin in the GROWI administration page, the URL is https://github.com/goofmint/growi-plugin-calendar.

Admin

Usage.

To use, write $calendar in the page. The calendar will be displayed where you write.

$calendar
Enter fullscreen mode Exit fullscreen mode

Click on a date to create a new page with that date. This can be used for daily reports, diaries, etc.

new-page.jpg

Options.

Available options include.

Change the year and month to be displayed.

You can change the year and month displayed by specifying the month as the first argument and the year as the second argument.

$calendar(12,2021)
Enter fullscreen mode Exit fullscreen mode

Changing the display language

The default is English, but you can change the display language with the lang option. Japanese is ja.

$calendar(lang=fr)
Enter fullscreen mode Exit fullscreen mode

French

Changing the criteria for generating a page name when clicking on a date

By default, clicking on a date generates a page name YYYYY/MM/DD. In other words, it is a hierarchical structure. You can change this.

$calendar(separator=-)
Enter fullscreen mode Exit fullscreen mode

The above will generate pages like 2024-10-02. If you do not like the hierarchical structure, use this.

Combinations of settings

The above options can be combined.

$calendar(12,2021,lang=fr,separator=-)
$calendar(12,2021,separator=-)
Enter fullscreen mode Exit fullscreen mode

About the code

The code is goofmint/growi-plugin-calendar: GROWI plugin shows calendar
The code can be found at The two files to look at are.

About client-entry.tsx

The client-entry.tsx is the registration part of the plugin. The calendar plugin is registered as a Remark plugin.

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;
  };
};
Enter fullscreen mode Exit fullscreen mode

About src/calendar.ts

The calendar display uses Vanilla Calendar - Lightweight calendar on pure JavaScript. available in JavaScript.

import VanillaCalendar from vanilla-calendar-pro;.
import vanilla-calendar-pro/build/vanilla-calendar.min.css;
Enter fullscreen mode Exit fullscreen mode

In the case of the Remark plugin, the entire drawing process is sent to the visit function, so only the part of this that displays the calendar is extracted.

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') {
                    // process in here
                }
            } catch (e) {
                n.type = 'html';
        n.value = `<div style="color: red;">Error: ${(e as Error).message}</div>`;
      }
        });
    });
};
Enter fullscreen mode Exit fullscreen mode

Getting options.

Option data can be retrieved via node.attributes.

const [month, year] = Object.keys(n.attributes);
const lang = n.attributes.lang || 'en';
const separator = n.attributes.separator || '/';
Enter fullscreen mode Exit fullscreen mode

Then, once done, only the calendar tags are output.

n.type = 'html';
n.value = '<div id="calendar"></div>';
Enter fullscreen mode Exit fullscreen mode

After the HTML is rendered and we see that #calendar is there, we start the drawing process.

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);
Enter fullscreen mode Exit fullscreen mode

Processing when a date is clicked

When the date is clicked, the page information is retrieved and the page name is correctly retrieved.

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}/`;
};
Enter fullscreen mode Exit fullscreen mode

Summary.

The GROWI plugin gives you the freedom to extend your display. If there are missing functions, you can add more and more. By all means, customise your own wiki.

GROWI, the OSS development wiki tool | comfortable information sharing for all

Top comments (0)