プリザンターにHedgedocを埋め込んでリアルタイム同時編集する

タスク管理のためにプリザンターを使用していて、議事録として複数人で同時編集するためにHedgedocを使用しています。

Hedgedocは単純なマークダウンのページを作成できるだけのものなので、管理はプリザンターで行って同時編集の機能だけ使う方法を検討しました。
Hedgedocの内容をプリザンターに埋め込んで使えるようにしてみます。

# 環境
- [Pleasanter](https://www.pleasanter.org/ja/manual/about) 1.4.15.0
- [Hedgedoc](https://hedgedoc.org/) 1.10.3
- 同じローカルにサーバー立てているとします
- `http://192.168.11.1/pleasanter/`
- `http://192.168.11.1/hedgedoc/`

# プリザンターのスクリプト
## 編集画面
- Hedgedocのパス用に`説明A`を追加
- HTMLタブからBody Script Bottomに追加
- `<script src="/pleasanter/scripts/extensions/AddHedgedoc/main.js"></script>`
- ベースurlを変えているので`/pleasanter/`を入れています
- 出力先は　新規作成と編集

## スクリプト
- 先ほどのパスにスクリプトをかく
- ページを開いたときに、議事録ボタンを追加します`CreateAddButton`
- 説明Aに入力されていたら、その内容を埋め込んで表示します`AddViewHedgedoc`
- 説明Aに入力されていない状態で議事録ボタンを押すと、HedgedocのAPIで新たなページを作り、そのURLを説明Aに入れて更新します`GetNewHedgedoc`

```main.js
function CreateAddButton() {
    const mainCommands = document.getElementById('MainCommands');
    // ボタンを作成
    const button = document.createElement('button');
    button.textContent = '議事録';
    button.setAttribute('id', 'buttonAddHedgedoc');
    button.addEventListener('click', () => GetNewHedgedoc());
    // MainCommands の子要素として追加
    mainCommands.appendChild(button);
};

function GetNewHedgedoc() {
    const mainCommands = document.getElementById('Issues_DescriptionA.viewer');
    if ($p.getControl("DescriptionA").val() != "") return;
    const url = "http://192.168.11.1/hedgedoc/new";
    const options = {
        method: "GET",
        headers: {
            "Content-Type": "application/json",
        }
    };

    fetch(url, options)
        .then(response => response)
        .then(data => {
            $p.set($p.getControl("DescriptionA"), data.url);
            const createCommand = document.getElementById('CreateCommand');
            const updateCommand = document.getElementById('UpdateCommand');
            if (createCommand) {
                createCommand.click();
            } else if (updateCommand) {
                updateCommand.click();
            } else {
                alert("更新できませんでした。");
            }
        })
        .catch(error => console.error("Error:", error));
}

function AddViewHedgedoc() {

    if ($p.getControl("DescriptionA").val() == "") return;
    // iframe要素を作成
    const iframe = document.createElement("iframe");
    iframe.src = $p.getControl("DescriptionA").val();
    iframe.style.width = "100vw";
    iframe.height = "800";
    // MainContainerの要素を取得し、子要素として追加
    const container = document.getElementById("Application");
    if (container) {
        container.appendChild(iframe);
    } else {
        console.error("Applicationの要素が見つかりませんでした。");
    }
}

// 読み込んだ時
document.addEventListener("DOMContentLoaded", function () { CreateAddButton(); AddViewHedgedoc(); });
// 更新した時
$p.events.after_set_Update = function () { CreateAddButton(); AddViewHedgedoc(); }
```

# 完成
- 説明AのURLページが埋め込まれます！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2383487/573453cd-9375-488e-8dd0-887065c8f32c.png)

- リアルタイム編集ができました！
![レコーディング-2025-05-13-140316.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2383487/37058826-e903-4873-a6be-b04cc63ef043.gif)

# Hedgedocの設定
- HedgedocのNginxの設定について、ドキュメントが更新されていないようで上手くいきませんでした
- こちらのIssuesを参考にできました
- [Issues#1024のコメント](https://github.com/hedgedoc/hedgedoc/issues/1024#issuecomment-796770679)

# 参考
- [プリザンター](https://pleasanter.org/ja/manual/about) 
- [Hedgedoc](https://pleasanter.org/ja/manual/about)
- https://qiita.com/silane1001/items/b459fac6affacb285985
- https://qiita.com/inajob/items/d04ef69eb43c4fba81d8