「AIR DATEPICKER」の使い方 ~ライブラリを直接いじってしまえ 編~

※[基礎編はこちら](https://qiita.com/kapy/items/8fa1db21f5d1d4dbf59b)

どうも。kapyです。
先述の基礎編は、前座です。
気持ちとしてはこちらが書きたい内容でした。
「AIR DATEPICKER」はJQuery環境下なので、昔からあるページなどで自前のプラグイン化していると、うまく動きませんました。
そんなときは諦めて、ライブラリを直接編集しましょう。

###動作確認した環境
Google Chrome 88.0.4324.150 / firefox 81.0.2 / IE 11 / safari 14.0.3 /
###AIR DATEPICKERについて
[公式ドキュメント](http://t1m0n.name/air-datepicker/docs/)
[ダウンロード](https://github.com/t1m0n/air-datepicker/tree/master/dist/js)


##何が原因で動かなかったか
軽く、今回なぜライブラリの直接編集に至ったのか、書いておきます。
直接の原因は、よくある$マークのコンフリクトです。
noConflictやJQuery直打ちなど、ググって試しては見たものの、一向に動作する気配がなく、
さらには、animate関数など他の便利な関数達も使えない不便な状況でした。
かと言って、消すと、また別のファイルでが起こってしまい、編集可能な範囲での解決は困難だと、判断しました。
（外部案件だと、よくある。。？）

##そうか。ライブラリに直接書けばいい

###まずは、規約を確認
今回のライブラリは、[MITライセンス](https://licenses.opensource.jp/MIT/MIT.html)です。商用ライブラリだと、改変不可の場合もあるようなので、一応注意しておきましょう。

###最低限の保守性
さて、ライブラリの編集に踏み切るとしても、軽量化は、そのままにしておきたい。。。
運用面も考慮し、以下の3点に注意をおきました。

1. 一旦、min.jsを整形プラグインで整形しなおして、あとで、改行などをとる
2. 後から見た人もわかるよう、ファイル名の変更
3. 出来る限り、自前の変数と関数は、他のファイルで参照しておく


####① 一旦、min.jsを整形ライブラリで整形しなおして、あとで、改行などをとる
筆者は整形にvscodeのbeautifyという拡張機能を使っています。
まあ、インデントわけが見れればいいので、chrome開発者ツールなどでも、可能です。
[Chromeデベロッパーツールで圧縮(minified)されたJavaScriptを読みやすく表示する](https://qiita.com/comocc/items/461a5019a2da7031d429)

軽量化し直すときは、こちらを使いました。
[compress.com](https://www.compresss.com/jp/compress-json.html)

####② 後から見た人もわかるよう、ファイル名の変更
一応、編集してしまっているので、名前を変えて、保存しておきます。
誰かがコピーしようとしても、これは弄くり回してるよ、ということで、今回は「datepicker.min.local.js」とします。

####③ 出来る限り、自前の変数と関数は、他のファイルで参照しておく
最終的に、編集後のライブラリは軽量化しなおして、元に戻しておきたいので、運用上修正が発生しうるところは、別ファイルで管理することにします。
今回は「datepicker.options.js」という名前で管理します。

###実際に書いてみる
今回、手を入れたのは以下です。それぞれ解説します。


- minDate/maxDateを外部変数により制御
- onSelectイベント時に値を取得、外部関数で処理
- onHideイベント時に、データ処理用の関数を忍ばせる
- 閉じるボタンを無理やり追加
- クリック時にスマホだと画面にカレンダーが収まらないので、スクロール関数を付与

###minDate/maxDateを外部変数により制御
今回、日付の選択できる期間を、絞りたかったので、予め用意した変数を差し込みます。

```javascript:datepicker.options.js
var minDateInput = new Date(2020,10,1)//2020/11/1から
var maxDateInput = new Date(2021,2,31//2021/3/31まで
```

次に変数をライブラリの初期設定のところにぶち込みます。
ちなみに、clearButtonやautoCloseなど、boolean型で設定されるプロパティは、全てこの「l」の中に初期設定されているので、そこを編集すれば、動きます。

```javascript:datepicker.min.local.js
! function(){
  // 略
  l = {
    // 略
    minDate:minDateInput,
    maxDate:maxDateInput,
  }
  //略
}
```


###onSelectイベント時に値を取得、外部関数で処理
jsで値をリアルタイムに処理したいので、値を取得する関数を、ぶち込みます。
もし、rangeをtrueにしてるときなどは、変数を二つ用意するか、配列にして取得してください。


```javascript:datepicker.options.js
var getSelectedDate;

var _getDateValue = function _getDateValue(v){
  getSelectedDate = v;
  return getSelectedDate;

}

```

引数「t」がどうやら、選択された日付のようです。

```javascript:datepicker.min.local.js
selectDate: function (t) {
  _getDateValue(t);
  //略
}
```

###onHide,onShowイベント時にも、データ処理用の関数を忍ばせる
もし、表示,非表示の時に処理を追加したいときは、こちらをお使いください。
ただ、重すぎる処理を走らせると、ラグが生じてなんともUIよろしくない感じになりますので注意。

```javascript:datepicker.min.local.js
hide: function () {
  //適当な関数
}
```

###閉じるボタンを無理やり追加
AIR DATEPICKERは、クリアボタンは設定できますが、閉じるボタンは筆者が探した感じ、ありません。
閉じるイベントはあるのですが、「ボタンもDatePickerのなかに入れたい」という人は、
素直にぶち込みましょう。
「i」のところに、buttonsというdivがあり、その中に別の変数で、clearbuttonが挿入されているようなので、中に予め一つ追加しておきます。クラス名やidは適宜つけてください。

```javascript:datepicker.min.local.js
function () {
  var //略,
      i = '
         <div class="datepicker--buttons">
           <button type="button" id="js-dp-close" class="js-dp-close datepicker--button">閉じる</button>
         </div>';
  //略
}
```

ただ、掲題の通り、js制御不可な状態なので、css周りをいじって、むりくり消す仕様を作ります。
まず、ライブラリのHideイベントの記載されている箇所から、cssを直接いじってるプロパティを削除します。

```javascript:datepicker.min.local.js
hide: function () {
  //略
  this.$datepicker.removeClass("active").css({
    //left: "-100000px" <- 削除
  }),
  //略
```

ここで、「active」というクラス名の着脱が行われていることがわかるので、cssで上書きしていきます。
「pointer-events」と「visibility」で、ポインター（クリック・タッチ）とフォーカス両方、打ち消しておくと、アクセシビリティてきに、良いかと思います。

```css:style.css

.datepicker{
  /* 略 */
  left:-100000px;
  pointer-events: none;
  visibility: none;
  opacity: 0;  
}
.datepicker.active{
  /* 略 */
  pointer-events: fill;
  visibility: visible;
  opacity: 1;
}

```

###クリック時にスマホだと画面にカレンダーが収まらないので、スクロール関数を付与
スマートフォンとかだと、inputをタッチすると、画面の外にDatePickerが起動してしまうことがあるので、位置までスクロールするようにします。
スクロールはcssだけで実装できますが、polyfillだけ、注意してください。筆者はこれを使っています。
[smoothscroll.js](https://github.com/iamdustan/smoothscroll)

```javascript:datepicker.min.local.js
setPosition: function (t) {
  //略
  window.scrollTo({top:e-80,left:0,behavior:'smooth'});
  //e はDatePicker上部のY座標。-80しているのは、マージンです。
}
```


##終わりに
以上、今回の対応まとめでした。ライブラリは、予期しない挙動をする時があるので、時間がある時orどうしてもやらなきゃいけないときなど、見てみるといいです。勉強し始めの時だと、作者にもよりますが、かなり勉強にもなりました。

コメントいただければ、適宜改訂します。
こういうのを実装したい、などもできるだけ一緒に考えるので、連絡ください。
もし、参考になったよ、というかたがおられましたら、twitterのDMでも、LGTMでも反応いただけると、次回記事のモチベーションになります。

最後までお付き合いいただき、ありがとうございました。