drag & dropをRspecでテストする(結果：ダメだった)

# 注意
結果：やりたいことはできなかった。
結果としての回避策：URLによって、Dataをhtmlタグのdata attributeなどにセットして、そこからJSを動かすようにして、テストを書くことで回避した。

以下で書いたものは、自分が調べたもので、紆余曲折があるので、暇な人だけが見るべき！


#やりたいこと

http://dev.classmethod.jp/references/html5-drag-drop-api-review-dom/ を参考にして、ドラッグ・アンド・ドロップを実装

(DOM = Document Object Model：<p>などの要素にアクセスする仕組み（参照：http://piyo-js.com/05/dom.html ）)


```js
$('.draggable-span').on 'dragstart', (e) ->
  e.originalEvent.dataTransfer.setData 'val', this.val()

$('.droppable-span').on 'drop', (e) ->
  e.preventDefault()
  e.stopPropagation()
  # ドラッグされたものの名前などを書いたりする処理。
```
このコードをCapybaraでテストしたい！

#参考
D&Dのテスト書いてるのは、
http://ria10.hatenablog.com/entry/20131230/1388372110
これが一番近そう

- capybara-webkit
- drag_to 
- jquery-sortable（https://github.com/johnny/jquery-sortable/blob/master/source/js/jquery-sortable.js）

参考にして、　`drag_to`を使って以下のように書いてみた。

```rb
draggable = page.find('#draggable')
target = page.find('#goal')
draggable.drag_to target
screenshot_and_open_image
```

#問題
うまく移動されていない。
Capybaraでdrag_to がうまくいかない。

#理由: 呼ばれるイベントの違い

細かく、drag_toで何がされてるかを見てみると、以下のmouseイベントがとれていた。（今回は、driverにpoltergeistを利用。実は、capybara-webkitだと下のmouseeventすら取れ無かった。）

draggableの方で、
1. mouseover
2. mouseenter
3. mousemove
4. mousedown
5. mouseleave
6. mouseout
Dropされる方で、
7. mouseover
8. mouseenter
9. mousemove
10. mouseup

しかし、重要な、'dragstart', 'drop'などのドラッグイベントはとれない！マウスイベントのみ。

おそらくjquery-sortableは、mouseeventで、実装されているよう。

まとめると、

**ドラッグイベント**と**マウスイベント**は別物である！（以下に簡単にドラッグ・アンド・ドロップに関連しそうなイベントをまとめておく。）

主なドラッグイベント
1. drag
2. dragend
3. dragenter
4. dragexit
5. dragleave
6. dragover
7. dragstart
8. drop

主なマウスイベント(drag_toで取れていたイベントを載せた)
1. mouseover
2. mouseenter
3. mousemove
4. mousedown
5. mouseleave
6. mouseout
7. mouseup


##解決策: Triggerでdragstart を発火させる(未解決)

### やってみる
[jQueryで画像やリンクのクリック状態（マウスイベント）やキーボード入力状態を強制的に作り出す](http://logic.moo.jp/data/archives/853.html)を参考に`dragstart`というDragEventを発火させてみる。

###ちなみにDragEventとは

DOM event

### 問題：`e.originalEvent.dataTransfer`で使っているoriginalEventがない。

実際にドラッグした場合：

```js
j…y.Event {originalEvent: DragEvent, type: "dragstart", timeStamp: 8800.24, jQuery1113048166412157867233: true, which: 1…}
```

`$('#some_id').trigger('dragstart')`で発火した場合：

```js
…y.Event {type: "dragstart", timeStamp: 1472621534967, jQuery1113048166412157867233: true, isTrigger: 3, namespace: ""…}
```

実際には、`originalEvent: DragEvent`があるのに対して、triggerには、ない!


### そもそもoriginalEventとは、
http://d.hatena.ne.jp/da-yoshi/20100924/1285307128

>
jQueryのbindを使うとdataTransferプロパティがイベントから取得出来ない現象が起こりました。原因は、わかってしまえば単純で、jQueryのイベントハンドラに渡されるeventオブジェクトはjQueryがブラウザ互換性の為に作成した独自オブジェクトだからでした。HTML5等で新たに追加されたプロパティにアクセスするには、大元のeventオブジェクトを取得する必要があります。

と書かれている。


### イベントをもう少し細かく作ってやってみる！
ただ`trigger`するとダメそうなので、

[jQueryのtrigger()みたいに、イベントを作ったり発火させたりしてみよう。](http://ginpen.com/2015/12/23/create-and-dsipatch-event/)
これを参考に、
```js
  event = new DragEvent('dragstart', {bubbles: true})
  el = document.querySelector('#col_0')
  el.dispatchEvent(event)
```

と書いてみると、originalEventに関してはできた。だが、originalEventがdatatransferを持っていない。Defaultでは、nullになるため。。（ここでうまく初期化する方法がわからん。）

- `DragEvent`は、[ここ](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent/DragEvent) に書いてあるようにDragEventオブジェクトを総合的に作るコンストラクタである。
- DragEvent interfaceは、DOM eventである。
- `MouseEvent`と`Event`を継承している
- `DragEvent.dataTransfer`(read only): drag & drop の間にデータが送られる（Although this interface has a constructor, it is not possible to create a useful DataTransfer object from script, since DataTransfer objects have a processing and security model that is coordinated by the browser during drag-and-drops.）
- `Document.querySelector()`は、Selectorに合うDocumentのなかの最初のElementを返す。

上の例で`$('#col_0')`では動かない。これでは帰ってくるのが、`[<span...></span>]`こんなかんじである。
逆に、Document.querySelector()の方は、html tagそのままが取れている。`<span class="draggable-span"...></span>`


#しょうがない解決策

coffeeのクラスをGlobalにして、rspecから、`execute_script()`で無理矢理トリガーする。。。

ただ、テストのために、不必要にGlobalにするのが嫌だ。


# ドラッグ・アンド・ドロップの詳細

## draggableにするには、
draggable属性与えて、dragstartのEventListenerをあたえる。（ドラッグされたデータを保存する。）

## event handlerは
ドラッグされたテクスト選択ではなく、 DataTransfer object にデータを保存し、許可された効果をセットする(copy, move, link, など)

## dropされる側は、
- dropzoneの属性を与えて、drop イベントリスナーをつける
- dropzoneの値は、データ・タイプを指定する。 ('string:text/plain', 'file:image/png'など)

## dragされたOriginalのものを消したい場合は、

`dragend` eventを使う

## DataTransfer interface

- このObjectは、ドラッグデータをとるときに使われる。
- ドラッグドロップのがFireされている間のみ有効



# 結論

dragEventは、無理ｗｗ

調べ漏れや、もっといい方法があるかもしれないので、何かあればコメントいただければ嬉しいです。


# 他の参考資料

1. [Native HTML5 Drag and Drop](http://www.html5rocks.com/en/tutorials/dnd/basics/)
2. [HTML 5 drag and drop API](http://mereskin.github.io/dnd/)
3. https://github.com/thoughtbot/capybara-webkit/issues/804