es6でよく使うユーティリティ

#`es6`(`javascript`、`js`)でよく使うユーティリティについて
主観的にはなるが、`es6`で頻繁に利用する機能の実装を備忘録としてまとめていく。

##日付の扱い
`2017-09-11 13:51:01`や`2017/09/11 13:51:01`のどちらでデータを扱うか不明なとき、また、日付データを使って`9月11日`といった表記が必要になることがある。
こういったケースでは与えらた日付データを正規表現で分解して配列として扱えるようにする。


```js
const divideDateTime = dt => {
  const m = dt.match(/(\d{4})*[-\/]*(\d{1,2})[-\/]*(\d{1,2}) *((\d{1,2}):(\d{1,2})(:(\d{1,2}))*)*/)
  return [
    m[1] ? parseInt(m[1], 10) : 0,
    m[2] ? parseInt(m[2], 10) : 0,
    m[3] ? parseInt(m[3], 10) : 0,
    m[5] ? parseInt(m[5], 10) : 0,
    m[6] ? parseInt(m[6], 10) : 0,
    m[8] ? parseInt(m[8], 10) : 0,
  ]
}
```

なお、日付データを配列に変換し、曜日を取得したい場合は、下記のように1行で実現できる。
配列`c`は上記の`divideDateTime`の戻り値。

```js
'日月火水木金土'[new Date(c[0], c[1], c[2]).getDay()]
```

##URLパラメータ（クエリ文字列）を取得する
`http://test.tk/index?a=1&b=2`のようなURLのパラメータを取得したいときは、下記配列を返す関数を利用する。

```js
export const queries = obj => {
  let params = []
  Object.keys(obj).map((key) => {
    params.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]))
  })
  return params.join('&').replace(/%20/g,'+')
}
```

##連想配列（ハッシュ）オブジェクトから値だけ配列に変換する
連想配列`{ one:1, two:2, three:3 }`とを配列`[1, 2, 3]`に変換したいときは以下を利用。

```js
export const convert = obj => {
  let ret = []
  if (obj && Object.keys(obj).length > 0) {
    ret = Object.keys(obj).map((key) => {
      return obj[key]
    })
  }
  return ret
}
```

##`email`の`localpart`を抽出する
`email`の`localpart`（@よりも前の部分）を抽出したいときは以下。

```js
export const local_part = email => {
  const m = email.match(/(^[_a-z0-9-]+(\.[_a-z0-9-]+)*)@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/)
  return  m && m.length > 1 ? m[1] : ""
}
```

##フォーマットされた日付データを文字列で取得
下記は現在の日付を`2017-10-10 10:10:10`といった形式で取得するときの関数。
`月`については`+1`をするのをたいてい忘れてしまう。

```js
const formattedDate = () => {
  const dt = new Date()
  const y = dt.getFullYear()
  const m = dt.getMonth() + 1
  const d = dt.getDate()
  const h = dt.getHours()
  const i = dt.getMinutes()
  const s = dt.getSeconds()
  return `${y}-${m}-${d} ${h}:${i}:${s}`
}
```

##ドラッグ&ドロップでファイルを保存
ドラッグとドロップとでイベントを発生させる領域が異なる場合、ドロップするエリアにドラッグイベントが発生すると、2つの領域でドラッグイベントが相互に発生し、結果的にUI上ではちらつきが発生する。
以下のように実装し、回避する。
ユーティリティとはいえないがこれも備忘録として記載。[こちら](https://qiita.com/sounisi5011/items/dc4878d3e8b38101cf0b)が参考になった。
なお、`app.bundle.js`のビルド方法については[こちら](https://qiita.com/hiroykam/items/135c51310087182b03cb)を参照。

```html:sample.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>Dnd</title>
    <style type="text/css">
      .red { background: #ff0000; }
    </style>
  </head>
  <body>
    <div class="js-dnd-block" style="background: #8f8f8f; text-align: center; height: 300px; width: 400px;">
      <div style="color: #ffffff">DnD</div>
      <div class="js-drop-block" style="padding: 100px;">
        <input type="file" name="line_image" class="js-file" multiple />
      </div>
    </div>
    <footer>
      <script type="text/javascript" src="app.bundle.js"></script>
    </footer>
  </body>
</html>
```

```js:app.js
"use strict";

import Dnd from "./dnd"

class App {
  static exec() {
    const obj = new App()
    obj.init()
  }

  init() {
    const parent = document.querySelector(".js-dnd-block")
    const drop = parent.querySelector(".js-drop-block")
    if (parent && drop) {
      const h = new Dnd(parent, drop)
    }
  }
}

App.exec()
```

```js:dnd.js
"use strict"

export default class Dnd {
  constructor(parent, drop) {
    this.parent = parent
    this.drop = drop
    this.entering = false
    this.observe_()
  }

  observe_() {
    const changeColor = f => {
      if (f) this.drop.className = "js-drop-block red"
      else   this.drop.className = "js-drop-block"
    }
    this.parent.addEventListener("dragenter", e => {
      this.entering = true
    }, false)

    this.parent.addEventListener("dragover", e => {
      this.entering = false
      const finput = document.querySelector(".js-file")
      finput.value = ""
      changeColor(true)
    }, false)

    this.parent.addEventListener("dragleave", e => {
      if (this.entering) {
        this.entering = false
      } else {
        changeColor(false)
      }
    }, false)

    document.addEventListener('dragover', e => {
      e.preventDefault()
    }, false)
    document.addEventListener('drop', e => {
      e.preventDefault()
      changeColor(false)
    }, false)

    this.drop.addEventListener("drop", e => {
      e.preventDefault()
      changeColor(false)
      const files = e.dataTransfer.files
      const finput = document.querySelector(".js-file")
      finput.files = files
    }, false)
  }
}
```