Chrome拡張機能を使ってファイルパスを他人に共有するときの変換の手間を省く【Windows向け】

![名称未設定-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/4e9a4695-2bc2-07af-3c6c-d3a15f2fcc2a.png)
# 概要

ファイル管理アプリの[Dropbox](https://www.dropbox.com/)や[Box](https://www.box.com/ja-jp)は便利ですが、デスクトップアプリ版を使っていると、同じアプリを使っている人にパス位置を共有する時にファイルパスに自身のユーザー名が入り、そのまま貼っても相手とは異なってしまうため、「このファイル見て！」と共有する際に一手間挟む必要があります。

```plaintext:例（Boxの場合：Windows）
C:\Users\PC1234\Box\
```

上記の場合、`PC1234`がユーザー名の想定です。
これはユニークですがWinodwsの場合、`%username%`という環境変数を使うことでエクスプローラーで開いた時にそれを入力した人のユーザー名に自動で置き換えることが可能です。

つまり、
```
C:\Users\%username%\Box\
```

を共有することで自分も相手も使えるファイルパスとなります。

とは言え、毎回変換をするのは面倒なので`Chromeの拡張機能`を使って自動変換を行います。

# 全体のファイル構成

Chromeの拡張機能のフォルダ構成は以下のような形です（iconはオプション）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/eabbc21e-0621-c62d-1135-1758f17f40bf.png)


内容としては、
- マニフェストファイル：拡張機能の説明や読み込む.jsやアイコンファイルを指定するもの。
- JavaScriptファイル：実際の処理が書かれたファイル。名称は自由。
- アイコン：拡張機能のアイコン画像（必須ではない。いらすとやを拝借）。

となっています。

# マニフェストファイル

構成情報を記述するJSON形式のファイルです。
拡張機能の名前や説明、アイコン、バージョンなどの情報を書くもので必須です。
どのURLに対して有効にするか、使用するJavaScriptファイルなども指定します。

```json:manifest.json（記述例）
{
  "manifest_version": 3,
  "name": "拡張機能名",
  "description": "拡張機能についての説明",
  "version": "1.0",
  "icons": {
    "128": "icon.png"
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["replace_text.js"]
    }
  ]
}
```

# JavaScriptファイル

2通りの方法があり両方を解説いたしますが、基本的にはどちらも正規表現を使って大文字小文字の区別なく、`C:\Users\"*"\Box\`という文字列を検索し、`"*"`を`%username%`に置き換えます。
※`"*"`は任意の文字列の任意の文字数。つまりワイルドカード扱い。

## A.ページ全体を変換する方法
html要素に含まれるテキストを全て変換する方法です。
この方法を用いると、全てを変換出来る反面、`ページ崩れなどが多く発生する`ため、
マニフェストファイルにURLを限定して利用する方が良いかと思います。

```javascript:replace_text.js
// ドキュメント全体のHTMLコンテンツを取得し、置換
document.body.innerHTML = document.body.innerHTML.replace(
    // 該当パターン
    /C:\\Users\\.+\\Box\\/gi,
    // 置換結果
    "C:\\Users\\%username%\\Box\\"
);
```

コード内では`innerHTML`としていますが、取得範囲を分けられます。
- `innerHTML`：要素の開始タグと終了タグの間にあるHTMLコンテンツを取得。ただし、自身の閉じタグ内のHTMLコンテンツは含まれない。
- `outerHTML`：要素の開始タグと終了タグを含む、要素自体とそのHTMLコンテンツを取得。要素自体も含まれ、置き換えることができます。
- `innerText`：要素の開始タグと終了タグの間にあるテキストコンテンツを取得。ただし、CSSによって非表示にされたテキストは含まれない。
- `textContent`：要素の開始タグと終了タグの間にあるすべてのテキストコンテンツを取得。CSSによって非表示にされたテキストも含まれる。

また、該当パターンの正規表現つけている`/g`と/`i`について、
`/g`はグローバル検索をするためのフラグで正規表現と一致するすべての文字列を置換します。
`/i`は大文字と小文字の区別をなく該当するようにしています。


## B.コピー（CTRL+C） or カット(CTRL+X)したものを自動変換する方法
Chrome上でテキストコピーしたものに対して変換をかけるという方法です。
html全体に変換をかけないため、ページ崩れを抑えつつ、目的を達成できます。
```javascript:replace_text.js
// 置換するための関数を定義
const replaceText = (text) => {
    // 該当パターン
    const regex = /C:\\Users\\.+(\\Box\\)/gi;
    // regexを指定内容に置換する
    const replacedText = text.replace(regex, 'C:\\Users\\%username%$1');
    return replacedText;
}

// コピーもしくはカットイベントを処理する関数を定義
const copyOrCut = (event) => {
    // クリップボードオブジェクトを取得
    const clipboard = event.clipboardData;
    // 選択されたテキストを取得
    const text = window.getSelection().toString();
    // 正規表現パターンに一致する部分を置換
    const replacedText = replaceText(text);
    event.preventDefault();
    // クリップボードに置換後のテキストをセット
    clipboard.setData('text/plain', replacedText);
}

// 動作イベントの監視
document.addEventListener('copy', copyOrCut);
document.addEventListener('cut', copyOrCut);
```

### 注意点
Windowsで動作するコードです。
コード内で`"\"`（バックスラッシュ）が2連続で入力されているのは、`"\"`がエスケープ文字であり、２連続でないと単一の`"\"`とならないため。

また、どうやら上記の方法の片方、もしくは両方が効かないページが存在するようです。
正確な理由はわからないのですがJavascriptでの操作を禁ずる処理が入っているような気がします。

# Chrome拡張の導入方法

Google Chromeを開き、右上のパズルアイコンを開き[拡張機能の管理]をクリックします。
その後、右のデベロッパーモードをオンにし、[パッケージ化されていない拡張機能を読み込む]をクリックし、読み込みたい拡張機能のフォルダを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/e38a8dc9-c6a1-c2bb-6135-d57f00beee4d.png)

無事に追加されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/67564327-78a0-5c8d-93ea-08ae54b4f307.png)

通常のサイトに戻り、右上のパズルアイコンをクリックし、該当の拡張機能をピン留めします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/56007f6d-5f7b-670d-6dfd-b545eb3cbc55.png)

これで導入完了です！

### テスト

Googleの検索窓にてBの方法で実際に試してみます。

当てはまるテキストをコピー（CTRL+C）します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/d82da4ce-8229-1eff-ec69-27d89e283e38.png)

ペースト（CTRL+V）します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211946/fa7a9685-8a5b-f34f-a7bd-9ca9f83a3a9c.png)

無事に反映できました！
これで誰もが使えるファイルパスになりましたね:relaxed:

# あとがき

今回はWinodws用に作成しましたが、Macでは一部コードが微妙に異なるようです。
これを応用することでWindowsとMacのファイルパスが微妙に異なる問題も対処可能と思います。

一方で　各jsファイルを使うとサイトの挙動が安定しなくなることがあり…
もう少し調べてより快適に使えるようにしていきます:bow_tone1: