Chromeプラグインの作成：ページからテキストコンテンツを抽出する

## はじめに

この記事では、JavaScriptを使用して特定のDOMノードおよびその子孫からテキストコンテンツを抽出するChromeプラグインを作成する方法を説明します。これはシリーズ記事の第2部で、前回の記事で説明した関数を使用してプラグインを作成します。
第1部の記事をご覧になりたい方は、こちらをチェックしてください → [JavaScriptでページからテキストコンテンツを抽出する関数の実装方法](https://qiita.com/figueiredoluiz/items/21032255101b0cc68e0e)。


## 背景

前回の記事では、JavaScriptを使用してDOMノードからテキストコンテンツを抽出する関数の実装方法を説明しました。今回は、その関数をChromeプラグインに組み込み、ウェブページ上の任意のノードから簡単にテキストを抽出できるようにします。

## 目的

このプラグインの目的は、ユーザーがウェブページ上の任意の要素を簡単に選択し、そのテキストコンテンツを抽出してクリップボードにコピーできるようにすることです。以下のMermaidダイアグラムは、拡張機能の動作の流れを視覚化したものです。

```mermaid
graph TD;
  A[ユーザーが拡張機能のアイコンをクリックまたはCtrl+Shift+Yを押す] --> B[ハイライトモードを切り替える]
  B --> C[ユーザーが要素にマウスをホバー]
  C --> D[ユーザーがハイライトされた要素をクリック]
  D --> E[テキストコンテンツを抽出とクリップボードにコピー]
```

## プロジェクト設定

プロジェクトを設定するには、GitHubリポジトリをクローンするか、以下の手順に従ってファイルを作成します。

ディレクトリ構造は以下の通りです：

```
clean-content-copier/
│
├── .gitignore
├── README.md
├── LICENSE
└── src/
    ├── background.js
    ├── content.js
    ├── manifest.json
    └── icon/
        ├── icon16.png
        ├── icon48.png
        └── icon128.png

```

## マニフェストファイルの作成

`manifest.json`ファイルは、Chromeプラグインの設定ファイルです。以下のコードを使用してください：

```json
{
    "manifest_version": 3,
    "name": "Clean Content Copier",
    "description": "Easily highlight and copy cleaned text content from web pages.",
    "version": "1.0",
    "permissions": ["activeTab", "scripting"],
    "background": {
      "service_worker": "background.js"
    },
    "icons": {
        "16": "icons/icon16.png",
        "48": "icons/icon48.png",
        "128": "icons/icon128.png"
    },
    "action": {
      "default_icon": {
        "16": "icons/icon16.png",
        "48": "icons/icon48.png",
        "128": "icons/icon128.png"
      }
    },
    "commands": {
      "toggle-highlight-mode": {
        "suggested_key": {
          "default": "Ctrl+Shift+Y"
        },
        "description": "Toggle highlight mode"
      }
    }
}

```

## マニフェストの各オプションの説明

- `manifest_version`: Chrome拡張機能のマニフェストファイルのバージョン。現在はバージョン3が最新です。
- `name`: 拡張機能の名前。
- `version`: 拡張機能のバージョン。
- `description`: 拡張機能の説明。
- `permissions`: 拡張機能が必要とする権限。`activeTab`は現在アクティブなタブへのアクセスを許可し、`scripting`はスクリプトの実行を許可します。詳細は[こちら](https://developer.chrome.com/docs/extensions/develop/concepts/declare-permissions?hl=ja)をご覧ください。
- `background`: バックグラウンドスクリプトの設定。`service_worker`はバックグラウンドで動作するJavaScriptファイルです。
- `icons`: 拡張機能のアイコンのサイズ別の設定。
- `action`: ツールバーのアイコンをクリックしたときに表示されるポップアップとアイコンの設定。
- `commands`: キーボードショートカットを設定し、説明を追加します。

## Content.jsの作成

`content.js`ファイルには、前回の記事で説明したテキスト抽出関数を含めます：

```jsx
(function () {
  // Initialize it as inactive
  window.__HighlightMode = false;

  // Toggle highlight mode
  window.toggleHighlightMode = function () {
    if (window.__HighlightMode) {
      window.__HighlightMode = false;
      document.body.removeEventListener("mouseover", highlightElement);
      document.body.removeEventListener("click", copyElementContent, true);
      clearHighlights();
    } else {
      window.__HighlightMode = true;
      document.body.addEventListener("mouseover", highlightElement);
      document.body.addEventListener("click", copyElementContent, true);
    }
  };

  // Highlight element on mouseover
  function highlightElement(event) {
    clearHighlights();
    event.target.style.outline = "2px solid pink";
  }

  // Clear all highlights
  function clearHighlights() {
    document.querySelectorAll("*").forEach((el) => {
      el.style.outline = "";
    });
  }

  // Copy element content on click
  function copyElementContent(event) {
    event.preventDefault();
    event.stopPropagation();
    let element = event.target;
    let textContent = getTextContent(element);
    navigator.clipboard.writeText(textContent).then(() => {
      alert("Content copied to clipboard!");
    });
    window.toggleHighlightMode();
  }

  // Get text content
  function getTextContent(element) {
    let textContent = "";
    if (element) {
      let children = element.childNodes;
      children.forEach(function (child) {
        if (child.nodeType === Node.TEXT_NODE) {
          let trimmedText = child.textContent.trim();
          if (trimmedText) {
            textContent += trimmedText + "\\n";
          }
        } else if (child.nodeType === Node.ELEMENT_NODE) {
          textContent += getTextContent(child);
        }
      });
    }
    return textContent;
  }

  // Initial script execution
  if (!window.__HighlightMode) {
    window.toggleHighlightMode();
  }
})();
```

このスクリプトは、指定されたノードからテキストを抽出し、マウスオーバーでハイライトし、クリックでテキストをクリップボードにコピーします。

## Background.jsの作成

`background.js`ファイル：

```jsx
chrome.action.onClicked.addListener((tab) => {
  chrome.scripting.executeScript({
    target: { tabId: tab.id },
    files: ["content.js"],
  });
});

chrome.commands.onCommand.addListener((command) => {
  if (command === "toggle-highlight-mode") {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
      chrome.scripting.executeScript({
        target: { tabId: tabs[0].id },
        files: ["content.js"],
      });
    });
  }
});
```

このスクリプトは、拡張機能のアイコンがクリックされたときに`content.js`スクリプトを実行し、キーボードショートカットでも同じ機能を提供します。

## プラグインのテスト方法

Chromeブラウザでプラグインをテストする手順は以下の通りです：

1. `chrome://extensions/`にアクセスします。
2. 右上の「デベロッパーモード」をオンにします。
3. 「パッケージ化されていない拡張機能を読み込む」をクリックし、プロジェクトのディレクトリを選択します。
4. プラグインがChromeに追加されます。

次に、任意のウェブページでプラグインを使用してテキストを抽出し、正しく動作することを確認します。

## 結論

この記事では、JavaScriptを使用してDOMノードからテキストコンテンツを抽出するChromeプラグインを作成する方法を説明しました。このプラグインは、指定したノードから簡単にテキストを抽出し、クリップボードにコピーすることができます。また、このプロジェクトは、読者が自分のプラグインを作成する際の参考としても利用できます。さらに学びたい方は、以下の参考文献やGitHubリポジトリを参照してください。

## 参考文献

- [Chrome Extensions Documentation](https://developer.chrome.com/docs/extensions/)
- [GitHubリポジトリ: clean-content-copier-for-chrome](https://github.com/figueiredoluiz/clean-content-copier-for-chrome)