jsライブラリを作成する

# はじめに

[長押しボタンを作ってみた](https://qiita.com/ta__ho/items/b0338a97e53856f220c0)ので、それをjsライブラリ化します。

# 今回やりたいこと

babel7とwebpackでの環境構築は完了したので、実際にライブラリを作成します。
[jsライブラリを作成するためにbabel7+webpack4で環境構築](https://qiita.com/ta__ho/items/8b11192795208dc3f2bd)

# 実装

### フォルダ構成

基本的なフォルダ構成は以下の通りです。

```
├── README.md
├── babel.config.js
├── dist
│   └── main.js
├── example
│   ├── conic-gradient.js
│   ├── index.html
│   ├── main.js
│   ├── other.html
│   └── sample.html
├── package-lock.json
├── package.json
├── src
│   ├── index.js
│   ├── svg.json
│   └── utils.js
├── test
│   └── utils.spec.js
└── webpack.config.js

```

```
dist: build後のscript用
example: 今まで検証等で使用したソースコード用
src: ライブラリのソースコード用
test: テストコード用
```

それぞれのディレクトリの用途は記載の通りで、基本的に`src`の下にソースコードを置いて行きます。

### 外部IFの設計

このライブラリを利用する際に、どのような記述をするか決めます。
具体的には、外出しする変数を決めます。

例えばボタン等のUIライブライを使用する場合、色を指定できたりすると思いますが、それと同じような感じです。

今回は以下のような感じでIF設計をしました。

```sample.html
<script src="../dist/main.js"></script> // ライブラリの読み込み
<div id="boring-decision"></div> // 長押しボタンをappendするDOM
<script>
    var boringDecision = new BoringDecision({
        limit : 2000,  // 長押しする秒数
        startColor : "black",  // 進捗表示時のバーの色
        endColor : "green",  // 長押し後のバーの色
        size: 100,  // ボタンのサイズ
        callback: window.select  // 長押し完了後に呼ばれるcallback関数
    });
    boringDecision.init();
</script>
```

これを元に内部の処理を作って行きます。

### constractorの作成

先ほどのIFを読み込むことができるようにメインのクラスを作って行きます。

```index.js
export default class BoringDecision {
  constructor(settings) {
    this.limit = settings.limit || 2000;
    this.startColor = settings.startColor || "black";
    this.endColor = settings.endColor || "white";
    this.size = settings.size || 100;
    this.targetDom = document.getElementById("boring-decision");
    this.callback = settings.callback;
  }
}
```

まずは、`constractor`でIFで指定した値を取得します。
ここでは、仮に変数が設定されていない場合も動くようにデフォルト値を設定するようにします。

`this.limit = settings.limit || 2000;`

### utils.jsの作成

次に、ブラウザ判定処理を作成します。
このライブラリでは、ブラウザ毎に挙動が異なるため、ブラウザ判定を行う必要があります。

`index.js`に処理を記載してもいいのですが、1つのクラスが大きくなってしまうため、分けます。
クラス名は、`Utils`として、ファイル名は、`utils.js`としました。

```utils.js
export default class Utils {

  static get ua() {
    return window.navigator.userAgent.toLowerCase(); 
  }

  static isChrome = () => { 
    if (this.ua.indexOf('chrome') > 0) {
      return true;
    }
    return false;
  }

  static isSafari = () => {
    if (this.ua.indexOf('chrome') < 0 && this.ua.indexOf('safari') > 0) {
      return true;
    }
    return false;
  }
 
  static isFirefox = () => {
    if (this.ua.indexOf('firefox') > 0) {
      return true;
    }
    return false;
  }

  static isIe = () => {
    if (this.ua.indexOf('trident') > 0) {
      return true;
    }
    return false;
  }

  static isEdge = () => {
    if (this.ua.indexOf('edge') > 0) {
      return true;
    }
    return false;
  }

  static hasConicGradient = () => {
    if (this.isSafari() || this.isFirefox() || this.isIe() || this.isEdge()) {
      return false;
    } 
    return true;
  }
}
```

こんな感じで、ブラウザ判定処理とライブラリ内で使用している`conic-gradient`が使えるブラウザかどうかを判定しています。
このクラス内で、ユーザーエージェントを取得する処理を以下のように書いています。

```utils.js
  static get ua() {
    return window.navigator.userAgent.toLowerCase(); 
  }
```

`static get`をつけることで、呼び出す時に同じクラス内であれば、`this.ua`でユーザーエージェントを取得することができます。
また、ブラウザ判定処理にも`staic`をつけています。

これによって、他クラスから呼ばれる時に、`Utils`をインスタンス化しなくても呼ぶことができます。
`Utils`は、呼び出し元から渡される変数を持っておらず、インスタンス化の必要がないので、全ての処理を静的メソッドで呼び出せるようにしました。

### svg.jsonの読み込み

次に、`conic-gradient`が使えないブラウザ用に準備した`svg.js`をjson化して読み込ませます。

今回の実装でここが一番ハマった部分なんですが、jsonファイルを読み込む時に、parserのエラーがでました。
理由としては、RFCで規定しているjsonの規約に沿っていなかったからです。

[RFC 8259](https://tools.ietf.org/html/rfc8259)

ブラウザでこのjsonを読み込ませるとエラーが出なかったのですが、node.jsのparserで読み込ませると規約を前提に処理が実行されるためエラーがでます。

例えば、`'`ではダメで、`\"`にする必要があるとかです。

これらのエラーをなんとか取り除き読み込めるようにします。

### メイン処理の実装

以前作成したソースコードを転写して、整形して完成です。

# 最後に
今回の記事で書いたプログラミングの様子をYoutube上にアップロードしておりますので、是非ご覧ください。
[【実況】長押しボタンライブラリ作成①](https://www.youtube.com/watch?v=Xy6uwV_JOJY&t=722s)
[【実況】長押しボタンライブラリ作成②](https://www.youtube.com/watch?v=OuFRTbxBNH8)
[えんじにぁ〜TV](https://www.youtube.com/channel/UCYCbtkuInmgpK0Hv3W2orEg)

この次はテストを書きます。