Confluenceに自動化スクリプトを埋め込んだ

諸事情により急遽Confluenceのカレンダーの運用が始まったのですが、
入力内容に定形のものが多く、手入力が手間だったので、
JavaScriptを埋め込んで入力を一部自動化したメモです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244191/8c088841-823d-2ae0-3efd-3af58aa31023.png)

# 前提
Attlasian Confluence 7.19.17 (サーバ版です。クラウド版ではデータが取得できないため動作しないとのこと)
カレンダーは"Team Calendar"コンテンツ
長期的に使い続けるかは不明だが、当面の間は週に数回の入力が発生する見込み。
who欄とwhat欄が必須入力。
登録済みのイベント表示で自分が特別扱いされないので見分けにくい。

# 自動化した内容
1. who欄は入力モーダル表示時にデフォルトで自分を入れる。
2. what欄はevent type選択時にevent type名をそのまま入れる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244191/47fba542-5d79-5092-53e5-dd92a59046f0.png)

3. ついでにイベント読み込み時、招待者に自分の名前があれば太字で表示する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244191/3e15869a-588e-4c5f-247d-a6701baf11ba.png)


# 実装
"HTML"コンテンツをInsertして、以下のようなScriptタグを埋め込みました。
```
<script>
// metaから自分のアカウント情報を取得
const key = document.getElementsByName('ajs-remote-user-key')[0].content;
const displayName = document.getElementsByName('ajs-user-display-name')[0].content;
const name = document.getElementsByName('ajs-remote-user')[0].content;
const icon = document.getElementsByName('ajs-current-user-avatar-uri-reference')[0].content;

// 自分の予定だけ太字にする
const bold = () => {
  // 1秒毎にイベント読み込みチェック
  const intervalId = setInterval(() => {
    // カレンダーのイベントオブジェクトの一覧取得
    const fcEvents = document.getElementsByClassName('fc-event-title');
    // 件数が1件以上なら多分読み込み終わったと判断
    if (fcEvents.length > 0) {
      clearInterval(intervalId);
      fcEvents.forEach((fcEvent) => {
        if (fcEvent.innerText.indexOf(displayName) === 0) {
          fcEvent.style.fontWeight = 'bold';
        }
      });
    }
  }, 1000);
};

// イベントの登録/編集時の入力アシストする
const autoRegister = () => {
  // カレンダーの入力モーダル展開時をきれいに取れなかったのでmouseup毎にチェック
  document.onmouseup = (e) => {
    const dialogElement = document.getElementById('edit-event-dialog');
    // 入力ダイアログがない、またはそれにbind属性付与済みの場合は何もせず終了
    if (!dialogElement || dialogElement.getAttribute('bind')) {
      return;
    }
    // イベント登録は一度でいいので、目印に属性を付与しておく
    dialogElement.setAttribute('bind', 'true');

    // who欄自動入力
    const invitees = document.getElementsByClassName('invitees')[0];
    // 1人も登録されていない場合のみ自動入力
    if (invitees.children.length === 0) {
      // 可視化
      invitees.classList.remove('hidden');
      // 見た目はある程度揃える
      // データ用配列にきちんと追加してないので削除が効かないため削除ボタンは非表示
      invitees.innerHTML = `<li class="invitee" title="${displayName}(${name})"><div class="invitee-left" threedots="${displayName}(${name}"><img src="${icon}"><span class="invitee-name-display">${displayName}<span class="user-name">(${name})</span></span></div></li>`;
      // datasetでは埋め込めなかったので止むなくjqueryのdata関数使用
      $('.invitees').find('.invitee').eq(0).data('entity', {id: key, displayName: displayName});
    }

    // what欄自動入力
    const eventType = document.getElementById('event-type');
    eventType.onchange = () => {
      const eventTypeLabel = eventType.options[eventType.selectedIndex].text;
      const whatElement = document.getElementById('what-text');
      whatElement.value = eventTypeLabel;
    }
  }
}

// 実行
bold();
autoRegister();
</script>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244191/ca597339-b494-3ae7-86eb-367920d5adfd.png)


# サボった点
・入力フォームの生成/破棄のイベントを捉えるのが面倒で、マウスのクリックにイベントリスナを付けています。
・イベントの招待者への登録処理が最低限のため、自動登録されたものについては削除ボタンが動きません。
（一度登録した後ならば、再度編集画面を開いての削除は可能です）
・招待者のdataの持ち方で回避方法がわからずjqueryを使ってしまいました。
・consoleに本件とは関係のないDeprecatedが大量にでていましたが、そっと見なかったことにしました。
・テストコードがありません。
・バージョン管理もしていません(WebStormのlocal histroy任せ)。

# 感想
普段はChrome extensionなどで対応することが多く、wikiへの埋め込みは初めてでしたが
短時間で簡単に実装できた割に喜んでもらえたので実装して良かったです。
使い捨てとはいえレガシーなやり方で汚いコードを記事として書いた恥ずかしさは成長の糧にしたいと思います:flushed: