0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Gmailの「スヌーズ期間…」メニューのアイテムをユーザスクリプトからクリックする

Posted at

要約

Gmailの「スヌーズ期間…」メニューのアイテムをユーザースクリプトで自動クリックする時、element.click()では反応せず、mousedownイベントとmouseupイベントを連続で発火させたら反応しました。

// 動かない例
targetItem.click();
// 動く例
targetItem.dispatchEvent(
  new MouseEvent("mousedown", {
    bubbles: true,
    cancelable: true
  })
);
targetItem.dispatchEvent(
  new MouseEvent("mouseup", {
    bubbles: true,
    cancelable: true
  })
);

今回は「スヌーズ期間…」メニューしか調査していませんが、それ以外のポップアップメニューでも同じかもしれないのでメモとして残しておきます。また、今回はTampermonkeyでユーザースクリプトを記述していますが、拡張機能でもおそらく同じことだと思います。

※正直「何故こうなのか」は分かっておらず偶然上手く動いているだけかもしれません。将来的に動かなくなる可能性は十分にありますので参考にする際は自己責任でお願いします。

検証環境

OS: Windows 11 Home 23H2
ブラウザ: Chrome 132.0.6834.84(Official Build) (64 ビット) 日本語環境
Tampermonkey: 5.3.3
Gmail: 2025-0116時点版

事の発端

Gmailで「スヌーズ」を選択すると「スヌーズ期間…」メニューがポップアップ表示されます。

image.png

image.png

私はプリセットの時間を使わず毎回「日付と時間を選択」をクリックしていたため面倒臭くなり、これをスキップしたくなりました。つまり、「スヌーズ期間…」メニューが出現したら自動で即座に「日付と時間を選択」をクリック(したことに)させたかったのです。

「スヌーズ期間…」メニューのDOM構造

調べてみると「スヌーズ期間…」メニューの正体は次のようなDOM構造で、body配下にappendされることが分かりました(かなり簡略化しています。本当はもっと色々な属性があり、divタグの構造も深いです)。

<div role="menu" aria-label="スヌーズ メニュー">
  <div>スヌーズ期間…</div>
  <div role="menuitem">今日中 木 18:00</div>
  <div role="menuitem">明日 金 8:00</div>
  <div role="separator"></div>
  <div role="menuitem">日付と時間を選択</div>
</div>

DOMの変化を監視してariaLabel === "スヌーズ メニュー"のエレメントが現れたらその配下にある目的のmenuitemをクリックすればやりたいことが実現できる気がしました。

click版ユーザスクリプト(失敗)

早速、次のようなユーザスクリプトを書いてTampermonkeyで動かしてみました。

// ==UserScript==
// @name         SkipGmailSnoozeMenu
// @description  Gmailの「スヌーズ期間…」メニューをスキップする(注意:これは動きません)
// @match        https://mail.google.com/*
// ==/UserScript==
(function () {
  "use strict";
  // body配下の変更を監視する。
  new MutationObserver(observeSnoozeMenu).observe(document.body, {
    childList: true
  });

  // 「スヌーズ期間…」メニューが出現したら即座に「日付と時間を選択」を選択する。
  function observeSnoozeMenu(mutations) {
    for (const mutation of mutations) {
      for (const node of mutation.addedNodes) {
        // 「スヌーズ期間…」メニューにだけ反応する
        const isSnoozeMenu =
          node instanceof Element && node.ariaLabel === "スヌーズ メニュー";
        if (!isSnoozeMenu) {
          continue;
        }

        // 「日付と時間を選択」アイテムのDOMを取得
        const targetItem = Array.from(
          node.querySelectorAll("[role=menuitem]")
        ).find((e) => e.textContent === "日付と時間を選択");
        if (!targetItem) {
          throw new Error("GmailのDOM構造が変わった可能性があります");
        }

        // 「日付と時間を選択」アイテムをクリックする(★注意:動かない)
        targetItem.click();
      }
    }
  }
})();

結果、動きませんでした。深追いはしませんが、どうやらGmailは単純にclickイベントハンドリングしているだけはないようです。

mousedown,mouseupイベント版ユーザスクリプト(成功)

試行錯誤の結果、menuitemのDOMに対してmousedownイベントとmouseupイベントを連続で発火させるとクリックしたことになる事が判明しました。先程のコードのtargetItem.click()の部分を次のように書き換えたら狙い通り動くようになりました。

// 「日付と時間を選択」アイテムをクリックする
// `targetItem.click()`では動かないため`mousedown`イベントと`mouseup`イベントを連続で発火させる。
targetItem.dispatchEvent(
  new MouseEvent("mousedown", {
    bubbles: true,
    cancelable: true
  })
);
targetItem.dispatchEvent(
  new MouseEvent("mouseup", {
    bubbles: true,
    cancelable: true
  })
);
成功版コードの全量
// ==UserScript==
// @name         SkipGmailSnoozeMenu
// @description  Gmailの「スヌーズ期間…」メニューをスキップする
// @match        https://mail.google.com/*
// ==/UserScript==
(function () {
  "use strict";
  // body配下の変更を監視する。
  new MutationObserver(observeSnoozeMenu).observe(document.body, {
    childList: true
  });

  // 「スヌーズ期間…」メニューが出現したら即座に「日付と時間を選択」を選択する。
  function observeSnoozeMenu(mutations) {
    for (const mutation of mutations) {
      for (const node of mutation.addedNodes) {
        // 「スヌーズ期間…」メニューにだけ反応する
        const isSnoozeMenu =
          node instanceof Element && node.ariaLabel === "スヌーズ メニュー";
        if (!isSnoozeMenu) {
          continue;
        }

        // 「日付と時間を選択」アイテムのDOMを取得
        const targetItem = Array.from(
          node.querySelectorAll("[role=menuitem]")
        ).find((e) => e.textContent === "日付と時間を選択");
        if (!targetItem) {
          throw new Error("GmailのDOM構造が変わった可能性があります");
        }

        // 「日付と時間を選択」アイテムをクリックする
        // `targetItem.click()`では動かないため`mousedown`イベントと`mouseup`イベントを連続で発火させる。
        targetItem.dispatchEvent(
          new MouseEvent("mousedown", {
            bubbles: true,
            cancelable: true
          })
        );
        targetItem.dispatchEvent(
          new MouseEvent("mouseup", {
            bubbles: true,
            cancelable: true
          })
        );
      }
    }
  }
})();

このユーザスクリプトは2025-0116現在のGmailの実装に強く依存しており、Gmailの実装変更に極めて弱いことに注意してください。特にariaLabelやtextContentは変更されやすい属性であり、長期的に見ると動かなくなる可能性が高いです。必要に応じてDOM構造の確認やスクリプトの更新を行ってください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?