Google Apps Scriptを使った独自メニューの作り方

[Google Apps Script](https://developers.google.com/apps-script/)（以降はGASと記述する）を使うと[Google スプレッドシート](https://www.google.com/intl/ja_jp/sheets/about/)・[Google ドキュメント](https://www.google.com/intl/ja_jp/docs/about/)・[Google フォーム](https://www.google.com/intl/ja_jp/forms/about/)に独自のメニューを追加する事ができます。
また、メニューから自身で定義したGASの処理を動かせます。
本記事では独自メニューの作り方を解説します。


# メニューの作り方
以下の手順でおこないます。

1. Uiクラスを取得する
2. Uiクラスからメニューを作成する
3. メニューにアイテムを追加する
4. メニューをUiクラスに追加する


## コードの記述
まずはスプレッドシートでのやり方を解説します。

スクリプトエディタを開いて以下のコードを記述します。
ファイルが開かれたら自動でメニューが追加されるようになります。

```javascript
/**
 * ファイルを開いたときのイベントハンドラ
 */
function onOpen() {
  var ui = SpreadsheetApp.getUi();           // Uiクラスを取得する
  var menu = ui.createMenu('追加したメニュー');  // Uiクラスからメニューを作成する
  menu.addItem('アイテム1', 'onClickItem1');   // メニューにアイテムを追加する
  menu.addToUi();                            // メニューをUiクラスに追加する
}

function onClickItem1() {
  Browser.msgBox('アイテム1がクリックされました。');
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35595/5b80e02f-7bea-9cd0-2043-d90f92396b18.png)


# 区切り線を追加する
メニューが多くなってくると見づらくなってきます。
そういう場合は区切り線を追加します。

```javascript
  var ui = SpreadsheetApp.getUi();
  var menu = ui.createMenu('追加したメニュー');
  menu.addItem('アイテム1', 'onClickItem1');
  menu.addItem('アイテム2', 'onClickItem2');
  menu.addSeparator();                       // 区切り線を追加する
  menu.addItem('アイテム3', 'onClickItem3');
  menu.addToUi();
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35595/b261e310-0f5d-73e4-58ae-3287b0acdee7.png)


# サブメニューを作る（階層構造にする）
更にメニューが増えてくると区切り線だけでも厳しくなってきます。
そのような場合はサブメニューを追加します。

```javascript
  var ui = SpreadsheetApp.getUi();
  var menu = ui.createMenu('追加したメニュー');
  menu.addItem('アイテム1', 'onClickItem1');
  menu.addItem('アイテム2', 'onClickItem2');
  menu.addSeparator();
  menu.addSubMenu(                           // サブメニューをメニューに追加する
      ui.createMenu("サブメニュー")             // Uiクラスからメニューを作成する
      .addItem("サブアイテム1", "onClickSubItem1") // メニューにアイテムを追加する    
  );
  menu.addToUi();
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35595/6f451338-3dbe-4ebd-65fc-88332fe40fe6.png)


# ソースをきれいにする
最後にソースをきれいにしておきましょう。

[Ui#createMenu()](https://developers.google.com/apps-script/reference/base/ui#createmenucaption)は[Menuクラス](https://developers.google.com/apps-script/reference/base/menu)を返します。
また、以下のMenuクラスのメソッドは自身のMenuクラスを返します。

- addItem(caption, functionName)
- addSeparator()
- addSubMenu(menu)

ということはつなげて書くことができます。
`menu`変数も消せるので一石二鳥ですね。

```javascript
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('追加したメニュー')
    .addItem('アイテム1', 'onClickItem1')
    .addItem('アイテム2', 'onClickItem2')
    .addSeparator()
    .addSubMenu(
      ui.createMenu("サブメニュー")
        .addItem("サブアイテム1", "onClickSubItem1")
    )
    .addToUi();
```

# ドキュメントとフォームの場合
スプレッドシートの場合は、SpreadsheetAppを使いましたが、ドキュメントとフォームはそこを変えるだけです。

| 種類         | メニューの追加 | サブメニューの追加 | クラス         |
|--------------|:--------------:|:------------------:|----------------|
| スプレッドシート|○|○|SpreadsheetApp|
| ドキュメント|○|○|DocumentApp|
| フォーム（古いバージョン）|○|○|FormApp|
| フォーム（新しいバージョン）|○|△|FormApp|

## フォーム（新しいバージョン）の注意点
フォームの新しいバージョンだとサブメニューのアイテムが普通のメニュー扱いになります。
※ヘルプ押しても反応がないですし、マウスのフォーカスも効いてないのでここはGoogleの対応漏れだと思われます。

### 新しいバージョン
![image.png](https://qiita-image-store.s3.amazonaws.com/0/35595/58fb53bb-53b7-8aee-1d9b-00538a5e5abc.png)

### 古いバージョン
![image.png](https://qiita-image-store.s3.amazonaws.com/0/35595/529f7975-8e6d-9fdc-3390-0032ef4a331f.png)


# その他

## 階層は結構深くまでいける
7階層ぐらい試しましたが問題なく表示されます。
そんなに作ることはないでしょうが。

## onOpen以外でもメニューの追加は可能
OnOpenに書くのが基本ですが、後からGASで追加することも可能です。

## メニューは削除できない
一度作ったメニューをGASから削除できません。
もちろんプログラムを修正してファイルを開き直せば更新されます。


## 古いやり方？
ググると[Spreadsheet#addMenu()](
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet#addMenu(String,Object))を使った古いやり方？も出てきますが、サブメニューが追加できませんしスプレッドシート限定の書き方のようです。
現状は使う必要はないでしょう。（あったら教えてください）


# あとがき
GASを使った仕事が増えていきそうな空気を感じるので、自身も勉強しつつ初心者向けの記事を色々書いていければと思います。