Azure用語に対応するAWS用語を表示するユーザースクリプト

# はじめに
AWSは知っているがAzureはよく知らない、という状態でAzureの勉強をするとき、「この機能はAWSで言うところのこれ」という情報があると、すんなり頭に入ってきたりします。
[公式の比較表](https://docs.microsoft.com/ja-jp/azure/architecture/aws-professional/services)を見れば対応はわかるのですが、いちいち見に行くのは面倒なので、ユーザースクリプトにしてみました。

# 作ったもの
## できること
以下のように、ページ内のAzure用語にカーソルを合わせると、対応するAWS用語がポップアップされるようになります。用語は[比較表](https://docs.microsoft.com/ja-jp/azure/architecture/aws-professional/services)や、[こちらの記事](https://qiita.com/hayao_k/items/906ac1fba9e239e08ae8)から拾いました。
![screenshot_after2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114715/243f395a-bc4d-d897-aab5-e50fa424a35c.jpeg)

Qiitaと、[ここ](https://docs.microsoft.com/ja-jp/azure/guides/developer/azure-developer-guide)のような、MSのドキュメントサイト配下のページで動作します。

## インストール
[Tampermonkey](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo?hl=ja)などの、ユーザースクリプト実行用アドオンを入れた上で、[Greasy Fork](https://greasyfork.org/ja/scripts/399618-map-terms-azure-to-aws)からインストールします。インストール後に、以下にカーソルを合わせてポップアップが出てきたら成功です。

|テスト|
|:--|
|Azure Marketplace|

## 仕組み
わざわざ説明するほどのものでもないのですが、一応、以下のような仕組みにしています。
※ソース全体は[こちら](https://github.com/uemuram/map_terms_azure_to_aws)

・用語の対応はあらかじめ定義しておきます。

```javascript
  const termMappings = [
    { 'azure': 'Azure Marketplace', 'aws': 'AWS Marketplace' },
    { 'azure': 'Azure Machine Learning', 'aws': 'SageMaker' },
      // …
   ];
```

・[こちら](http://raining.bear-life.com/css/css%E3%81%A7%E7%B0%A1%E5%8D%98%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB%E3%83%81%E3%83%83%E3%83%97%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95)を参考に、ポップアップ用のスタイル定義も作っておきます。

```javascript
  let style = document.createElement("style");
  document.head.appendChild(style);
  let sheet = style.sheet;
  sheet.insertRule("div.tooltip {display:inline; border-bottom:solid 1px #87CEFA}", 0);
  sheet.insertRule("div.tooltip span {display:none; padding:5px; margin:10px 0 0 0px;}", 1);
  sheet.insertRule("div.tooltip:hover span {display:inline;  position:absolute; border:1px solid #CCC; border-radius:5px; background:#F7F7F7; color:#666; font-size:12px; line-height:1.6em;}", 2);
```

・あとはbody全体を走査し、テキストノード(nodeType=3)であれば、対応表と突き合わせてヒットした部分をポップアップ用のhtmlに置換しています。

```javascript
  // ヒットした部分を加工する
  let replaceTermString = function (str) {
    for (let i = 0; i < termMappings.length; i++) {
      let index = str.indexOf(termMappings[i].azure);
      if (index >= 0) {
        let beforeStr = str.substring(0, index);
        let afterStr = str.substring(index + termMappings[i].azure.length);
        return replaceTermString(beforeStr)
          + '<div class="tooltip">' + termMappings[i].azure + "<span>" + termMappings[i].aws + '</span></div>'
          + replaceTermString(afterStr);
      }
    }
    return str;
  }

  // 子要素を走査し、テキストノード(nodeType=3)であれば、書き換えを行う
  let replaceTerm = function (r) {
    let children = r.childNodes;
    let l = children.length;
    for (let i = 0; i < l; i++) {
      let child = (children[i]);
      if (child.nodeType == 3 && !/^[ \n\t]+$/.test(child.nodeValue) && child.nodeValue.length > 0) {
        let newStr = replaceTermString(child.nodeValue);
        // 書き換えが発生した場合はDOMを変更
        if(newStr !== child.nodeValue){
          let newSpan = document.createElement("span");
          newSpan.innerHTML = newStr;
          r.insertBefore(newSpan, child);
          child.remove();
        }
      } else {
        replaceTerm(child);
      }
    }
  }

replaceTerm(window.document.body);
```

ユーザスクリプトを使って、ページ内の特定文字列を任意のhtmlに書き換えたい場合に応用できる書き方かと思います。

# おわりに
Azure学習の一助になれば幸いです。