2013年8月31日土曜日

Survival in Colosseum 1.04 を公開


Hammerwatch のカスタムマップ Survival in Colosseum 1.04 を公開しました。

ゲームバランスが調整され、マルチの野良パーティでもクリアできるレベルになりました。以前のバージョンでは難易度が非常に高く、よっぽどではない限りクリアできないレベルでした。

野良のマルチで隠しステージを含めて最後までクリアできています。
Hammerwatch を持っている方はぜひ友達と一緒に遊んでみてください。

ちなみに、持っていないマップは「Missing」と表示されますが、
部屋の中に入ると自動的にダウンロードが始まりますので、
とりあえず入ってみるのがオススメです。

Survival in Colosseum についての情報はこちらのフォーラムをご覧ください。
http://hammerwatch.com/forum/index.php?topic=1634.0

2013年8月30日金曜日

Gimp で背景を透明にする

png ファイルの背景を Gimp で透過してみます。
OS は Windows 7 です。

Gimp でファイルを開きます
レイヤー > 透明部分 > アルファチャンネルの追加 をクリックします。
すでに追加されていて選択でき場合はそのまま次へ進みます。




Z キーでズームツールを出して拡大します。Ctrl + Z で縮小できます。



U キーでファジー選択ツールにします。ツール > 選択ツール > ファジー選択 でもOK.
消したい場所を領域をクリックして選択します。
Shift を押しながらだと複数選択できます。



Delete キーで削除します。



Shift + Ctrl + E で png 画像としてエクスポートすれば完成です。


2013年8月29日木曜日

BitTorrent で CentOS をダウンロード

Mac の BitTorrent を使って CentOS のディスクイメージを落として DVD に焼く方法

落とすもの: CentOS 6
環境:Mac OS X 10.8.4

1. BitTorrent をダウンロード・インストール
http://www.bittorrent.com/intl/ja/



2. CentOS のミラーサーバを開く
Donwloads > Mirrors > Mirror List > Asian > Japan のどれかの HTTP 
の順番にクリック


3. torrent ファイルを落とす 
ミラーサーバの
6/ > isos/ > i386 か x86_64 (CPU に合わせて) > CentOS-6.4-i386-bin-DVD1to2.torrent 
からダウンロード

4. torrent ファイルを開く(デフォルトで BitTorrent が起動する)
そのままOK 

5. ダウンロードが始まるので終わるまで待つ 


6. Donwload フォルダの中にイメージファイルが落とされる

7. iMac に空の DVD を入れる 

8. ダイアログが出てくるのでディスクユーティリティで開く を選択


9. ディスクを作成 > 落としたiso ファイル を選択


10. 書き込み終わったら DVD が自動で出てきます

11. 同じように 2 も焼きます

12. あとはインストールしたいパソコンに入れて DVD から起動すればOKです。

2013年8月28日水曜日

Google のキーワード検索回数を調べる

Google AdWords のキーワードプランナーを使うと無料でキーワード検索回数を調べることができます。

まず Google AdWords にログインします。
Google AdWords

「ツールと分析」メニューから「キーワードプランナー」を選択します。
「キーワードと広告グループの候補を検索する」を開いて、
検索したいキーワードを入力します。



「候補を取得」ボタンを押すとキーワードに関するデータが表示されます。
「月間検索ボリューム」が1ヶ月間に検索された回数の平均値(1年間から計算)です。



マーケティングの道具として使えそうですね。

2013年8月27日火曜日

Survival in Colosseum を公開

HammerWatch のカスタムマップ「Survival in Colosseum」を公開しました。



こちらからダウンロード
http://okanoworld.appspot.com/sample/hammerwatch/survival_colosseum.hwm

更新情報については公式のフォーラムに掲載します。
http://hammerwatch.com/forum/index.php?topic=1634.0

ダウンロードしたファイルを HammerWatch の levelsディレクトリに配置すると、
ゲーム開始時のレベルとして選択できるようになります。

Windows の場合は、
C:\ProgramFiles\Steam\SteamApps\common\Hammerwatch\levels

Mac の場合は、
~/Library/Application Support /Steam/SteamApps/common/Hammerwatch/levels

に入れてください。

最初の方は簡単ですが、進んでいくに連れてどんどん難しくなっていきます。
Hammerwatch ユーザの方はぜひ遊んでみてください!

2013年8月26日月曜日

もうすぐ公開予定の HammerWatch カスタムマップ

HammerWatch のカスタムマップ「Survival in Colosseum」がほぼ完成しました。
残りは難易度調整のみという段階です。



こちらはベータ版に入っていたミニゲームの Survival モードと同じく、
キャラクタを強化しつつ、大量の敵から生き残っていくマップです。

全部で 20 ステージほど準備しており、ベータ版には無かったボス戦があります。
しかも、どのボスもキャンペーンモードとは一味違ったシチュエーションが楽しめます。



難易度はキャンペーンと比べると高いですが、
1回1回のプレイ時間は短いので、気軽にさくさく楽しめると思います。
マルチで遊ぶとより楽しめそうです。

ちなみに、エディタについてわからないことがあったら、Steam のフォーラムにて質問すればゲーム開発者本人を含むユーザから教えてもらえるので、エディタを使っている方は活用するとよいと思います。

Editor, help and questions 
http://steamcommunity.com/workshop/filedetails/discussion/122788084/846954921964016285/

2013年8月25日日曜日

jQuery の CDN の場所

jQuery は公式から CDN が提供されています。
<script> タグの src に URL をコピペするだけですぐに jQuery が使えます。

jQuery の公式ページを開いて、下の方にある QUICK ACCESS の URL が使用できます。


2013年8月24日土曜日

お勧めゲーム「HammerWatch」

つい最近 Steam で発売したばかりのインディーズゲーム「HammerWatch」が面白いです。オンライン4人までで上から見た視点のダンジョンを探検するアクションRPGです。難易度がかなりシビアで、4人でやってもなかなか最上階にはたどり着けません。

面白いのはエディタとして開発ツールが同梱されていることです。ユーザが独自に自作のストーリーやマップなどを追加して再配布することで、長い間楽しむことができます。スプライトや音声ファイルなども自分で自由に追加することが可能で、ものすごく凝ったシナリオを作ることが可能です。

私も自作のマップを作りながら、あれよあれよという間に夜が明けてしまい、すでに眼球と手首の痛みがやばい状態です。しかし、マップ作りが面白くてなかなかやめられません。

グラフィックや音楽などの素材は最初からゲームに入っているものがたくさんあります。また、スクリプトもドラッグアンドドロップで簡単に作ることができるので、意外と簡単にそれっぽい動きを作ることができます。

スクリプトを線で繋げて動作を決める

ボス部屋らしくアイテムをばら撒こうとするとこうなる



そして外国人のユーザと一緒に冒険できるものロマンがあって楽しいですね。日本人のパラディンとフランス人のウィザードが声を掛け合ってトラップを回避してたりして、いろいろあるけどここは平和だなぁと感じました。

HammerWatch 公式サイトはこちら。
http://www.hammerwatch.com/

そのうち、エディタの使い方を記事にして説明するかもしれません。

2013年8月23日金曜日

jQuery 基本のセレクタ・フィルタまとめ

jQuery 1.10 のリファレンスで BASIC とされているセレクタとフィルタのまとめです。


セレクタ

セレクタを使うとドキュメント上の DOM 要素を取得できます。

$('*')
すべての要素を選択

$('.class_name')
クラスで選択

$('element_name')
要素名で選択

$('#id')
id で選択

$('selector, selector, selector...')
複数の条件を指定


フィルタ

セレクタで引っかかった要素に対して更にフィルタを掛けて絞り込むことができます。
$('#id:filter') のように、セレクタの後ろに : で区切ってフィルタを付けます。

:animated
アニメーション中の要素だけ

:eq(index)
index 番目の要素だけ
index をマイナスにすると後ろから数える

:even
偶数番目の要素だけ

:first
最初の要素だけ

:focus
現在フォーカスされている要素だけ

:gt(index)
index番目より後ろの要素だけ
index をマイナスにすると後ろから数える

:header
<h1> や <h2> などのヘッダだけ

:lang(language)
lang 属性が language の要素だけ

:last
最後の要素だけ

:less(index)
index 番目より前にある要素だけ
index をマイナスにすると後ろから数える

:not
セレクタに引っかからなかった要素だけ

:odd
奇数番目の要素だけ

:root
ドキュメントのルート要素だけ

:target
URI のフラグメント id に一致する要素だけ
例えば、URI が http://example.com/#foo だったら $('p:target') は <p id="target"></p> を選択する。

2013年8月22日木曜日

accept 属性でアップロードするファイルフォーマットを指定

HTML5 では <input> タグの type 属性が "file" の場合に、アップロードできるファイルのフォーマットを指定する属性があります。

accept 属性を追加して以下の値をセットします。

  • image/*, video/*, audio/*
  • MIMEタイプ
  • ファイル拡張子

image/*, video/*, audio/* はそれぞれ画像ファイル、動画ファイル、音声ファイルだけを受け入れる値です。MIME タイプは image/png などのように更に具体的な値を設定可能です。ファイル拡張子は ".doc" や ".txt" などの用にファイルの拡張子によって受け入れるかどうかを判断するオプションです。

Mac の Safari, Firefox, Chrome で試してみたのですが、ファイルの拡張子による指定は今のところ、Chrome でしか動いていませんでした。実際には image/*, video/*, audio/* か MIME タイプを使うことになりそうです。

accept が指定されている場合には、アップロードするファイルの選択画面で、フォーマットが合わないファイルは選択不可能になります。もちろん気休め程度なので、サーバ側でのチェックは必須ですが。

指定されたフォーマットだけが選択可能になる


以下にサンプルを作成しました。いくつかのブラウザでお試しください。

ソースコードはこちら(GitHub)

accept 属性の仕様はこちら(W3C)

2013年8月21日水曜日

Google App Engine の無料で使える範囲

Google App Engine は無料で使える Web アプリをホスティングできるサービスです。
Java, Python, Go, PHP 向けの様々な API が提供されています。

GAE では各機能ごとに無料で使える範囲が決まっています。
使用できる上限については以下のページにまとめられています。

Quotas - Google App Engine


いくつか見てみると、無料で使える範囲は以下にようになっています。


ブロッブストア
5GBまで

チャネル
API使用回数 1日657,000回まで、かつ、1分3,000回まで
作成数 1日100チャネルまで、かつ、1分6チャネルまで
接続時間 1日200時間まで、かつ、1分12時間まで
送信データ量 割り当てられた帯域上限に依存、かつ、1分22MBまで

コードとデータ容量(アプリのファイルサイズ)
1GBまで

データストア
保存データ 1GB まで
インデックス数 200個まで
書き込み処理 1日50,000回まで
読み込み処理 1日50,000回まで
細かい処理(Count()とか) 1日50,000回まで

デプロイ
アプリのアップロード 1日10,000回まで
ファイル数 1バージョン10,000ファイルまで
ファイルサイズ 1ファイル32MBまで
全バージョンの全ファイルサイズ 合計1GBまで

ログ
ログデータ(検索) 100MBまで
ログデータ 1GBまで
※ Logs data retrieva ってなんだろう・・・

メール
API使用回数 1日100回、かつ、1分32回
送信 1日100回、かつ、1分8回
管理者メール 1日5,000回、かつ、1分24回
メッセージサイズ 1日60MB、かつ、1分340KB
添付ファイル 1日2,000個、かつ、1分8個
添付ファイルサイズ 1日100MB、かつ、1分10MB

リクエスト
送信帯域 1日1GB、かつ、1分56MB
受信帯域 1日1GB; 14,400GB、かつ、1分56MB


以下省略。
詳しくは上のサイトをご覧ください。

2013年8月20日火曜日

Backbone.js でメソッドのオーバーライド

Backbone.js ではクラスベースオブジェクト指向のようにメソッドのオーバーライドが可能です。親のクラスから継承したメソッドを上書きしたり、拡張したりすることができます。

継承先のクラスで以下のように書くと、継承元のメソッドを呼び出すことができます。
SuperClass.prototype.MethodName.call(this);

SupeClassMethodName はそれぞれ変更してください。
Backbone.js のクラスのメソッドは prototype 内に定義されています。
これをサブクラスから呼び出すことで親のメソッドを実行できます。
このとき call() を使って、this をサブクラス自身に設定して呼び出しています。

以下に親 View のメソッドをオーバーライドするサンプルを作成しました。
もちろん Model でも同じことが可能です。

サンプルアプリ
http://okanoworld.appspot.com/sample/backbonejs/override/index.html

ソースコード
https://github.com/yokano/sample/tree/master/backbonejs/override

サンプルでは灰色と緑の View が表示されます。
緑の View は灰色の View を継承しています。
灰色の View はクリックすると BLOCK と表示します。
緑色の View はクリックされると親ビューのクリック処理を呼び出してから、
独自の処理として GREEN と表示しています。

2013年8月19日月曜日

Go の Slice は参照型

Go 言語の Slice は代入すると参照が渡されます。
そのため、引数として渡した関数内での変更が、もとの Slice に影響します。
func addSlice(s []string) {
    s[1] = "WORLD"
}

func main() {
    s := make([]string, 2)
    s[0] = "HELLO"
    addSlice(s)
    log.Printf("SLICE: %v", s)  // [HELLO WORLD]
}

2013年8月18日日曜日

Go で構造体の要素に複数のタグを付ける

昨日の記事の通り、Go では構造体のプロパティにタグを付けることによってパッケージに動作を指示することができます。

複数のタグを1つの要素につける場合は、スペースで区切って指定することができます。
例えば、datastore には保存したくないけれど JSON の変換には含めて欲しい場合、
以下のように書くことができます。
type People struct {
    Name string `json:"name" datastore:"-"` // JSON には含めて datastore には含めない
}


2013年8月17日土曜日

Go で構造体を JSON に変換するときのタグ付け

Go の構造体の各要素にはタグを付けることができます。
タグを付けることでパッケージに要素の扱い方を支持することができます。
type People struct {
    Id int `json:"-"`          // id は変換後の json に含めない
    Name string `json:"name"`  // Name は name として json 化
}
people := new(People)
people.Id = 1
people.Name = 'tanaka'
bytes, err := json.Marshal(people)  // bytes = {"name":"tanaka"}

例えば、 json パッケージを使って構造体を JSON に変換するときに使います。
タグに json: "-" を指定することで、変換時にこの要素を無視することを指示できます。
また、json: "名前" とすることで変換後の要素の名前を指定することもできます。
他にも Google App Engine の datastore パッケージなどで同じ書き方ができます。
詳しくはそれぞれのパッケージドキュメントを参照してください。

Package - Go
http://golang.org/pkg/

2013年8月16日金曜日

モデルのプロパティを複数同時にセットする

Backbone.js でモデルのプロパティを複数同時にセットすることができます。
// 1つずつセット
var book1 = new Book();
book1.set('name', 'すぐ滑れるスキー');
book1.set('autor', 'スキー大好きおじさん');

// まとめてセット
var book2 = new Book();
book2.set({
    name: '野球練習法',
    author: '野球大好きおじさん'
});

まとめてセットした場合、change イベントは1回だけ実行されます。

2013年8月15日木曜日

GAE + Go で指定した時刻に処理を実行する

Google App Engine では、taskqueue パッケージを使って指定した時刻に処理を実行することができます。「メールアドレスの仮登録後、24時間経っても本登録がされなかったらデータベースから削除する」みたいなときに便利です。
Task Queue Go API Overview - Google App Engine

パッケージのインポート
import "appengine/taskqueue"


タスクの作成

タスクは taskqueue.Task 型で表され、taskqueue.NewPOSTTask() 関数で作成できます。
タスクは、指定した URL に HTTP POST を送ることで実行されます。
ユーザからのアクセスと同様に handleFunc() 関数で処理を割り振ります。
url.Values 型で POST で引き渡すデータを指定できます。
また、 time.Duration 型で現在時刻からどれくらい後に実行するのかを指定できます。
ETA を使って実行時刻を直接指定することもできます。
実行時刻の指定がない場合、即時実行されます。
// POST で渡すデータ
values := url.Values{}
values.Set("interim_key", key)

// 24時間後に実行
delay, err := time.ParseDuration("24h")
Check(c, err)

// タスクの作成("/cancel" に POST で送信)
task := taskqueue.NewPOSTTask("/cancel", values)
task.Delay = delay


キューにタスクを追加

GAE ではアプリごとに複数のタスクキューを持つことができます。それぞれのタスクキューで、タスクを実行するタイミングや、キューの容量などを設定できます。
今回は最初から準備されている default という名前のキューにタスクを入れます。
default キューは実行できるタスクが無いか 5 秒毎にチェック・実行されます。
オリジナルのキューを作成する場合は queue.yaml を作って設定してください。
Go Task Queue Configuration - Google App Engine
タスクは taskqueue.Add 関数でキューに追加できます。
// task を default キューに追加する
taskqueue.Add(c, task, "default")

これで24時間後に実行されるタスクを作成できました。


URL を管理者専用にする 

このままではユーザが /cancel にアクセスできてしまうので管理者専用にします。
GAE + Go で管理者専用機能を作る - y.okano blog
を参考に app.yaml で login: admin を指定しておきます。


開発サーバでタスクを手動実行する

ローカルの開発サーバでは、デバッグ用に手動でタスクを実行するツールも付いています。これを使わなくても自動実行はできますが、手動で実行したい場合は利用します。

http://localhost:8080/_ah/admin/queues

にアクセスすることでキューの状態や、タスクの実行が可能です。


2013年8月14日水曜日

モデルの特定のプロパティの変化だけを監視する

Backbone.js ではイベントの名前空間を使って特定のプロパティだけを対象にイベントの監視ができます。listenTo() で "イベント名:プロパティ名" という : で区切った形で特定のプロパティのイベントだけを監視することができます。
// モデルの name プロパティが変わった時だけ nameHasChanged を実行する
view.listenTo(view.model, 'change:name', view.nameHasChanged);

: の後ろのプロパティ名は Backbone.js によって自動的に付加されます。
もちろん 'change' だけ書いた場合でも実行されます。

2013年8月13日火曜日

Android エミュレータとキーボードの対応表

Android Developer Tool に同梱されているエミュレータは、キーボード入力にも対応しています。Android Developers のエミュレータのページでキーボードとエミュレータの対応表が公開されています。

Android Emulator - Android Developers
http://developer.android.com/tools/help/emulator.html

2013年8月12日月曜日

Galaxy S II (ISW11SC) の USB ドライバインストール方法

au の Galaxy S II (ISW11SC) の USB ドライバをインストールする方法です。Samsung の Kies というソフトウェアをインストールする必要があります。

Windows7 が入ったノート PC に Galaxy S II を繋いでもドライバを自動でインストールしてくれませんでした。



au のドライバのページから "〈GALAXY SII WiMAX ISW11SC 専用〉USBドライバ" をクリックします。



KIES のページに飛ぶので「Windows用」を落とします。



KIES とはファイルの管理やデバイスのソフトウェアアップデートができるソフトのようです。iPhone でいうところの iTunes のようなものだと思います。

ダウンロードした KiesSetup.exe を実行します。KiesSetup.exe をスマホがつながった状態で起動すると外してくださいと言われます。外しましょう。



利用規約を読んで次へ進むとインストールが始まります。



オプションは不要なのでチェックを外してスキップします。



デバイスを繋ぐよう言われるのでつないでみます。



デバイスドライバのインストールが始まります。今度は Windows が自動的にドライバを見つけてくれます。



しばらく待てばドライバのインストールが完了します。


2013年8月11日日曜日

datastore に保存できるプロパティの容量

GAE + Go ではデータストアに保存できるプロパティの大きさがデータ型によって異なります。string では 500Byte までですが、[]byte では 1MByte まで保存可能です。

ESCAPE 3DS のイベントエディタでデータが保存できなくなる問題が発生していました。調べてみると、サーバに以下のエラーログが出力されていました。
ERROR: API error 1 (datastore_v3: BAD_REQUEST): ApplicationError: 1 Property Code is too long. Maximum length is 500.

500Byte を超えるとデータが保存できないようです。
リファレンスを見てみると、[]byte であれば 1MByte まで保存できると書いてあります。
The datastore package - Google App Engine
- []byte (up to 1 megabyte in length)

データストアに保存するときに []byte に変換することで制限を 1MByte にできました。
クライアントに出力する際に、その都度 string へ変換する必要があるので注意が必要です。

2013年8月10日土曜日

jQuery で特定の DOM の表示が完了したタイミングを取る

特定の DOM の表示が完了したかどうかは ready() で取得することができます。
var target = $('<div id="target"></div>');
$('body').append(target);
target.ready(function() {
    console.log('target の準備が完了');
});

一般的に、ドキュメントがロードされた時には以下のように書いていると思います。
$(function() {
    // ドキュメントロード後の処理
});

これと同じで、スクリプトの実行中に新しく作られた DOM についても、
表示が完了してから操作すべき場合があります。
例えば、DOM の高さを測ったりする場合です。
var target = $('<div id="target"></div>');
$('body').append(target);
console.log(target.height());  // まだ表示されてない場合は 0 になる
target.ready(function() {
    console.log(target.height());  // 表示後の実際の高さ
});

2013年8月9日金曜日

Collection の initialize() で要素を追加する

Backbone.js の Collection を初期化するときには、第1引数にモデルのリストを渡すことになっています。
constructor / initialize - Backbone.js

このとき渡したリストが Collection 内のモデルリストの初期値になります。
重要なのは initialize() 内でモデルを追加しても、引数として渡された値が優先されて、
結果的にモデルリストが変化しないことです。
var Model = Backbone.Model.extend({
    defaults: {
        name: ''
    }
});

var Collection = Backbone.Collection.extend({
    model: Model,
    initialize: function() {
        this.add({name: 'taro'});
    }
});

var collection = new Collection([]);
console.log(collection.toJSON());  // []

上の例では Collection 内の initialize() 内で {name: 'taro'} を追加しようとしていますが、
実際には引数として最初に渡された [] が優先されます。

initialize() 内で Collection のモデルを操作したい場合には、
引数として null を渡せば OK です。
var Model = Backbone.Model.extend({
 defaults: {
  name: ''
 }
});

var Collection = Backbone.Collection.extend({
 model: Model,
 initialize: function() {
  this.add({name: 'taro'});
 }
});

var collection = new Collection(null);
console.log(collection.toJSON());  // [{name: 'taro'}]


2013年8月8日木曜日

View の初期化時に渡したオプションを後から参照する

Backbone.View で初期化時に渡したオプションは this.options で後から参照できます。
var View = Backbone.View.extend({
    tagName: 'div',
    render: function() {
        console.log(this.options.data);  // hello
        return this;
    }
});

var view = new View({
    data: 'hello'
});

$('body').append(view.render().el);


2013年8月7日水曜日

jQuery UI Draggable で margin を設定するとずれる

jQuery UI の Draggable API で、センタリングした draggable 要素が実際に表示されている座標とは違う場所にドロップ判定が発生してしまいます。
cursorAt オプションを使用することでセンタリングしたまま正しい判定が可能です。

実際にこの挙動が起きるサンプルプログラムを作成しました。
http://okanoworld.appspot.com/sample/jqueryui/dnd_position/index.html

ソースコードはこちら
https://github.com/yokano/sample/tree/master/jqueryui/dnd_position



droppable 要素 1 つと、draggable 要素 2 つがあります。
すべて margin を auto にしてセンタリングしています。

緑の draggable 要素を droppable 要素にドラッグしても反応がありません。
実際には droppable 要素の右側へ移動させることで反応します。
これはドラッグ中に表示される helper が margin を計算しないため、
実際に使われる drop 判定座標がずれてしまっているためです。

青の draggable 要素はセンタリングされているにも関わらず正しく判定されますね。
こちらは cursorAt を使って正しい判定ができるようにしています。

公式の trac に登録されたチケットをみてみると、
ドラッグ時に表示される helper は margin を考慮してくれないと書かれています。
#9325 Draggable: helpers do not account for margin on draggable element - jQuery UI

対処法として cursorAt が使えると書いてあります。
cursorAt は draggable 要素をドラッグした時に本来表示される位置からずらして表示するためのオプションです。

例えば
$('#drag').draggable({
    cursorAt: {
        left: 30,
        top: 25
    }
});
とすると、ドラッグ中に draggable 要素の helper が本来表示される位置から左に30px、上に25pxずれて表示されます。

青の draggable について JavaScript でこんな感じに書きます。
$('#revise').on('mousedown', function() {
    // ずれている距離を計算
    var difference = $(this).offset().left + $(this).width() / 2;

    // 同じ距離だけ右にずらして位置を合わせる
    $(this).draggable('option', 'cursorAt', {right: difference});

    // ドラッグ中のセンタリングを解除する
    $(this).draggable('option', 'start', function() {
        $(this).removeClass('center');
    });
    $(this).draggable('option', 'stop', function() {
        $(this).addClass('center');
    });
});

まず offset() と width() を使ってずれている距離を計算します。(difference)
実際の判定座標が左にずれているので、cursorAt で右に戻します。
この状態でドラッグするとドロップ判定箇所は正しい場所になるのですが、
見た目上、ドラッグ中の要素が右へずれてしまうので、センタリングを解除します。
センタリングを解除すると要素が左端に移動するので、
右にずらした距離とプラマイゼロになってうまいこと元の場所に表示されます。
これで、見た目上は何も変わっていないのに、ドロップ判定だけを右へずらすことができます。

2013年8月6日火曜日

HTML5 ドラッグ&ドロップ API の drop イベントが発動しない

drop イベントは dargover イベントと dragenter イベントをキャンセルしなければ発動しない仕様になっています。
$('#dropzone').on('drop', function() {
 $(this).html('ドロップされました');
}).on('dragover dragenter', function() {
 // イベントをキャンセル
 return false;
});

サンプルアプリ
http://okanoworld.appspot.com/sample/html5/dnd_dom/index.html

ソースコード
https://github.com/yokano/sample/tree/master/html5/dnd_dom


2013年8月5日月曜日

CSS で画像をカーソルにするときの注意

CSS の cursor で画像を設定した場合、他の値も設定しなければなりません。
cursor: url("cursor_img.png"), "pointer";

画像が存在しなかった場合、後ろに繋げた値が適用されます。

CSS cursor プロパティについてはこちらを参照
CSS/Properties/cursor - W3C

2013年8月4日日曜日

JavaScript の変数と JSON の変換

JavaScript の Web アプリケーションが外部とのデータをやり取りするときには、
JSON 形式がよく使われます。

JavaScript の変数を JSON 化、または JSON を JavaScript に変数化する場合、
以下のメソッドが使えます。
// JavaScript から JSON
var json = JSON.stringify(js_variable);

// JSON から JavaScript
var js_variable = JSON.parse(json);


以下に変換のサンプルアプリを作成しました。
http://okanoworld.appspot.com/sample/js/json/index.html

ソースコードはこちら
https://github.com/yokano/sample/tree/master/js/json


2013年8月3日土曜日

Backbone.js で View を継承する

Backbone.js では View を作るときに Backbone.View を継承しています。
作成した View オブジェクトを更に継承することができます。




サンプルアプリ
http://okanoworld.appspot.com/sample/backbonejs/extend_view/index.html

ソースコード
https://github.com/yokano/sample/tree/master/backbonejs/extend_view


JavaScript
var DrinkView = Backbone.View.extend({
 tagName: 'div',
 className: 'drink',
 render: function() {
  this.$el.append('<div class="filling"></div>');
  return this;
 },
 empty: function() {
  this.$el.find('.filling').remove();
 }
});

var CoffieView = DrinkView.extend({
 className: 'drink coffie'
});

var OrangeJuiceView = DrinkView.extend({
 className: 'drink orange_juice'
});


var drinkView = new DrinkView();
var coffieView = new CoffieView();
var orangeJuiceView = new OrangeJuiceView();

$('body').append(drinkView.render().el);
$('body').append(coffieView.render().el);
$('body').append(orangeJuiceView.render().el);

共通する動作をする複数の View は、まとめておくと綺麗にかけます。

2013年8月2日金曜日

HTML5 ドラッグAPI 仕様書翻訳後半

翻訳は途中で力尽きました・・・
もう1回ゆっくり読み直さないと詳細は理解できなさそう。

とりあえず大事なのは
- ユーザがドラッグを始めたらブラウザが drag data store にデータを追加する
- drag data store は直接触れない
- drag data store にアクセスするために使うのが dataTransfer インタフェース
- dataTransfer インタフェースは DOM に発行されるドラッグイベントに付加される
- ファイルシステムや他のアプリケーションからドラッグするため、OSに依存して動作が変わる部分がある。(他のキーとの組み合わせが意味する操作とか)

といったところでしょうか。


以下翻訳メモ後半。

原文はこちら
http://www.w3.org/TR/2012/CR-html5-20121217/editing.html#dnd

------



7.7.4 DragEvent インタフェース

ドラッグ&ドロップ処理モデルはいくつかのイベントを呼び出す。それらはすべて DragEvent インタフェースを使う。

[Constructor(DomString type, optional DragEventInit eventInitDict)]
interface DragEvent : MouseEvent {
    readonly attribute DataTransfer? dataTransfer;
};

dictionary DragEventInit : EventInit {
    // Attributes from UIEvent:
    Window? view = null;
    long detail = 0;
    // Attributes for MouseEvent:
    long screenX = 0;
    long screenY = 0;
    long clientX = 0;
    long clientY = 0;
    boolean ctrlKey = false;
    boolean shiftKey = false;
    boolean altKey = false;
    boolean metaKey = false;
    unsigned short button = 0;
    unsigned short buttons = 0;
    EventTarget? relatedTarget = null;
    // Attributes for DragEvent:
    DataTransfer? dataTransfer;
};

 以下は非標準
----
event.dataTransfer:DataTransferオブジェクトを返す
----

DragEvent の dataTransfer は初期化された値を返さなければならない。オブジェクトが作られた時、この属性は null に初期化されなければならない。これはイベントにコンテキストを知らせるためにある。

ユーザエージェントが e という名前のドラッグアンドドロップイベントをエレメント上で実行することを要求した時、以下の手順で drag data store を使用しなければならない。

1. e が dragstart だったら drag data store mode を read/write モードにする
   e が drop だったら drag data store mode を red-only モードにする
2. dataTransfer に新しく作られた drag data store と関連づいた DataTransfer を代入する。
3. effectAllowed に drag data store の drag data store allowed effects state を代入する
4. e が dragstart, drag, dragleave のいずれかだったら dropEffect に "none" を代入する。e が drop または dragend だったらcurrent drag operation と同じ値を代入する。その他は effectAllowed に基づいた値と drag-and-drop ソースによって、以下の表から与えられる値になる。

effectAllowed    | dropEffect
"none"           | "none"
"copy"           | "copy"
"copyLink"       | "copy" または "link"
"copyMove"       | "copy" または "move"
"all"            | "copy" または "link" または "move"
"link"           | "link"
"linkMove"       | "link" または "move"
"move"           | "move"
"uninitialized"  | "move" または "copy" または "link"
 textfield 選択中|
"uninitialized"  | "copy" か "link" か "move"
 ドラッグ中      |
"uninitialized"  | "link" か "copy" か "move"
 a要素を選択中   | "link" か "copy" か "move"
それ以外のケース | "copy" か "link" か "move"

上の表以外で、ユーザエージェントのプラットフォームの慣習的なものがあれば、ユーザエージェントはそちらの操作をするかもしれない。

例えば、Windows の慣習では "alt" キーを押しながらドラッグしている間は、移動やコピーよりも、データをリンクさせることを意味する。従って、Windows では "alt" キーが押されている間は "copy" や "move" ではなく "link" となる。

5. 信頼された DragEvent を作成して e として初期化する。バブリングするか、キャンセル可能でない限り、 e は dragleave か dragend であり、detail 属性を 0 で初期化する。mouse と key 属性はユーザインタラクションを行う入力デバイスの状態によって初期化する。relatedTarget 属性は null で初期化する。dataTransfer 属性は DataTransfer 変数によって初期化する。DataTransfer オブジェクトは上で作成されている。
6. target 要素の DragEvent を通知する
7. drag data store allowed effects state に dataTransfer の effectAllowed 属性をセットする。(e が dragstart の場合だけ変更できる)
8. drag data store mode を最初のステップで変更していたら protected モードの戻す。
9. dataTransfer と drag data store の関係を切る


7.7.5 ドラッグ&ドロップ処理モデル

ユーザがドラッグを開始した時、ユーザエージェントは下記のステップを処理しなければならない。以下のステップを実行するときには、ドラッグ開始地点が他のドキュメントやアプリケーションであり、どこでドラッグを開始されたのかを知ることができない場合であっても、実行しなくてはならない。

1. 以下の手順で何がドラッグされたのかを突き止める
    選択によってドラッグが開始されたのであれば、選択から開始された。
    そうではなく、Document からドラッグが開始されたのであれば、それはdraggable 属性が設定されているノードから先祖へと向かって参照していった先の、最初の要素である。draggable に設定された要素がなければ何もドラッグされていないため、以下のステップを中止してドラッグ&ドロップ操作は行わない。
 それ以外はユーザエージェントの外側からのドラッグである。何がドラッグされたのかはドラッグが開始されたドキュメントやアプリケーションによって定義される。

 ノート:href属性を持っているimg要素とa要素はデフォルトでdraggable属性にtureを設定している。

2. drag data store を作成する。すべてのドラッグ&ドロップイベントはこのセクションのステップの後に続いて発行され、drag data store を使わなければならない。

3. 以下の手順でどの DOM ノードがソースノードなのかを確証する。
    ドラッグされたのが選択範囲なら、ユーザがドラッグを開始した Text ノードがソースノードである。ユーザがユーザエージェントに具体的なノードを通知していない場合は、ドラッグされた選択領域を含んでいる Text ノードがソースノードである。
    それ以外で、DOM要素がドラッグされていたら、ソースノードはその要素である。
    それ以外なら、ソースノードは他のドキュメントやアプリケーションの一部である。この仕様が、イベントがソースノードから発行されることを要求するとき、ユーザエージェントはプラットフォームの慣習やシチュエーションに合わせて適切なソースノードを決めなければならない。
 ノート:ドラッグ&ドロップ中はソースノードから複数のイベントが発行される。

4. 以下の手順でドラッグされたノード一覧を確定する
    選択領域がドラッグされた場合は、ドラッグされたノード一覧は、選択領域の中に部分的に、または完全に含まれているノードの木構造である。(選択領域のすべての先祖を返す)
    それ以外ならドラッグされたノード一覧はソースノードだけを含む。

5. 選択領域がドラッグされたのなら、drag data store item list に以下のプロパティをもつ要素を追加する。
    The drag data item type string: "text/plain"
    The drag data item kind: Unicode 文字列
    The actual data: 選択した文字列

    それ以外で、ファイルがドラッグされた場合は、drag data store item list に各ファイルの情報を元にしたプロパティを持つ要素を追加する。
    The drag data item type string: ファイルの MIME type か "application/octet-stream"
    The drag data item kind: File
    The actual data: ファイルの中身と名前
    ノート: 現在ではファイルはブラウザの外からしかドラッグできない

    ドラッグがアプリケーションの外で始まった場合、ドラッグされたデータに相応しい(プラットフォームの慣習にあった)データを drag data store item list に追加しなければならない。プラットフォームが MIME types を使っていなかったとしても、ユーザエージェントは最も適切な MIME type を割り当てるよう試みなければならない。そして、すべてのケースで、drag data item type は ASCII コードの小文字でなければならない。

6. ドラッグアンドドロップ初期化ステップは他の使用で定義される。

7. 以下のサブステップを実行する

    1. urls に絶対URL のカラリストを入れる
    2. ドラッグされたノード一覧の各ノードに対して
        ノードが href 属性付きの a 要素なら、href をリゾルブした URL を urls に追加する
        ノードが src 属性付きの img 要素なら、src をリゾルブした URL をノードに追加する
    3. urls が空のままなら、以下のステップは中止する
    4. url にurls を改行で区切って連結した文字列を代入する。
    5. drag data store item list に以下の手順にそってアイテムを追加する
        type: text/uri-list
        kind: Unicode文字列
        data: url文字列

8. ユーザエージェントに合わせて適切な drag datastore store default feedback を更新する。

9. dragstart という名前でソースノードのドラッグ&ドロップイベントを実行する
    イベントがキャンセルされたら、ドラッグ&ドロップイベントは発生せず、以下のステップを中止する。
    メモ:イベントリスナ無しのイベントは、ほとんどの定義で、永遠にキャンセルされず、作者が意図して防がない限りユーザのためにドラッグ&イベントは利用可能である。

10. 以下で説明しているようにして、プラットフォームの慣習に合わせてドラッグアンドロップを始める
    ドラッグ&ドロップフィードバックは以下の利用可能なソースによって生成されなければならない。
    1. drag data store bitmap。このケースでは、drag data store hot spot coordinate がカーソルの位置を表すために使われなくてはならない。この値は CSS のleft と top として表現される。
    2. drag data store default feedback

ユーザエージェントがドラッグ&ドロップ処理を開始する瞬間から操作が終了するまで、デバイスのインプットイベント(マウスやキーボードイベント)は制限しなくてはならない。

ドラッグ操作中、immediate user selection と呼ばれるドロップターゲットがユーザによってエレメントへ直接指定される。(エレメントはユーザによってだけ選択されることができる。他のノードはドロップターゲットとして利用可能であってはならない)。しかしながら immediate user selection は current target element である必要はない。これはドラッグ&ドロップ操作の中の一部である現在選択中のエレメントのことである。

immediate user selection はユーザが選択した別の要素として変更される(ポインティングデバイスで選択肢たり、他の方法を使う)。current target element は immediate user selection が変化した時に変化する。下記で説明する通り、ドキュメント内のイベントリスナの結果に基づく。

current target element も immediate user selection も null をとることができる。これはターゲットエレメントが選択されていないことを意味する。これらは別のドキュメントのエレメントをとることもできるし、他の(Webではない)プログラムのものでもよい。(例えばワードプロセッサから選択してきたテキストでも良い)。current target element は null で初期化される。

さらに、 current drag operation もあり、"none", "copy", "link", "move" を値として持つことができる。初期状態では "none" を持つ。これは下記の手順によってユーザエージェントが更新できる。

ユーザエージェントはドラッグ操作が始まったらすぐに初期化して、 350ms(±200ms) 毎にその後はドラッグ操作中以下のステップをタスクキューに追加し続けなければならない。

1. ユーザエージェントがまだ以前の処理を指定たら、次の処理が来た時、これらの処理を中断する。(フレームを飛ばす)
2. drag という名前のイベントをソースノードに対して実行する。このイベントがキャンセルされたら、 current drag operation を "none" にしなければならない。(ドラッグ操作は行われない)
3. drag イベントがキャンセルされておらず、ユーザのドラッグ&ドロップ操作が終わっていなければ、ドラッグ&ドロップ操作の状態を以下のステップでチェックする。
    1. もしユーザが最後の処理よりも後で immediate user selection を変更し、それが current target element と同じではなかったら、current target element を以下の手順でアップデートする。
        * 新しい immediate user selection が null だったら、current target element も null にする。
        * 新しい immediate user selection が DOM ドキュメントかアプリケーションだったら、 current target element に immediate user selection を代入する
        * それ以外だったら dragenter イベントを immediate user selection に対して発行する。
          イベントがキャンセルされたら、current target element を immediate user selection にする。
          それ以外なら、以下のリストから適切な処理を実行する。
          - immediate user selection がテキストフィールド(例えばテキストエリやinput要素)または、editing host , editable 要素で、なおかつ drag data store item list が type = "text/plain" で kind が Unicode 文字列の要素を持っていたら、current target element を immediate user selection にセットする。
          - immediate user selection が drop zone 属性を持っていて、 drag data store とマッチするなら、current target element を immediate user selection にセットする。
          - immediate user selection が drop zone の先祖の要素であり、drag data store にマッチするなら、new target に直近の先祖エレメントを代入する。
            もし、immediate user selection が new target だったら、current target element を変化させない。
            それ以外なら、dragenter という名前のドラッグイベントを new target に対して発行する。current target element を new target にする。
          - immediate user selection が body 要素だったら、current target element はそのままにする。
          - それ以外なら、もし1つ以上のDocument オブジェクトが存在したら、dragenter イベントを body 要素に対して発行する。current target を body 要素にする。イベントがキャンセルされたかどうかは気にしない。
    2. もし上のステップで current target element が変更されていて、なおかつ target element が null または DOM ドキュメントの一部なら gragleave イベントを直前の target element に対して発行する。
    3. current target element が DOM なら、 dragover イベントを current target element に発行する。
       dragover イベントがキャンセルされていなかったら、以下のリストから適切なものを実行する。
            * current target element がテキストフィールド、editing host または editable 要素であり、drag data store item list の中に type が "text/plain"、kind がUnicode のアイテムがあったら、current drag operation を "copy" か "move" のどちらか適切な方にセットする。
            * current target element が drop zone 属性を持つエレメントであり、 drag data store にマッチして、具体的な操作を持っていたら、 current drag operation を current target element の drop zone 属性にする。
            * current target element が drop zone 属性を持っていて、drag data store にマッチして、具体的な操作を持っていなければ、 current drag operation に "copy" をセットする。
            * それ以外なら、current drag operation を"none" にする。

        それ以外(dragover イベントがキャンセルされた)なら、DragEvent オブジェクトの dataTransferオブジェクトの effectAllow と dropEffect属性に基づく値を current drag operation にセットする。イベント終了後に下の表のように鳴る。

                                 effectAllowed                         | dropEffect | Drag operation
"uninitialized", "copy", "copyLink", "copyMove", "all"  | "copy"      | "copy"
"uninitialized", "link", "copyLInk" , "linkMove", "all"     | "link"        | "link"
"uninitialized", "move", "copyMove", "linkMove", "all" |  "move"    | "move"
それ以外                                                                                  | "none"

    4. それ以外なら、current target element が DOM 要素ではない場合、プラットフォームの具体的なメカニズムをドラッグオペレーションの判断のために使う。(none, copy, link, move)そして、current drag operation にそれをセットする。

    5. ドラッグフィードバック(例えばマウスカーソル)を current drag operation に合わせて以下のように更新する。
Drag operation | Feedback
"copy"             | ドロップしたらデータがコピーされる
"link"               | ドロップしたらデータがリンクされる
"move"            | ドロップしたらデータが移動される
"none"             | 操作はなく、ドロップするとドラッグアンドドロップがキャンセルされる

4. それ以外で、ユーザがドラッグ&ドロップ操作を終了した(例えばマウスボタンを離した)、または drag イベントがキャンセルされたら、これが最後の処理に鳴る。以下の手順で処理をして、ドラッグ&ドロップ操作を終了する。
    1. current drag operation が "none" だった、または、ユーザがドラッグ&ドロップ操作をキャンセルした(例えば escape キーを押した)、または、current target element がnull だったら、ドラッグ操作は失敗する。以下のサブステップを実行する。
        1. dropped を false にする。
        2. current target element が DOM 要素だったら、dragleave イベントをその要素に発行する。そうではなく、current target element が null だったら、ドラッグをキャンセルするためにプラットフォームの慣習を使用する。
      それ以外だったら、ドラッグ操作は成功する。以下のサブステップを実行する。
       1. dropped を true にする
       2. current target element が DOM 要素だったら、drop イベントを current target element に発行する。それ以外なら、dropを指定するためにプラットフォームの慣習を使用する。
       3. イベントがキャンセルされたら、current drag operation に DragEvent オブジェクトの dataTransfer オブジェクト dropEffect 属性に基づく値をイベントが終了した後にセットする。
          それ以外なら、イベントはキャンセルされない。以下のようにしてデフォルトの動作を実行する。
          - もし current target element がテキストフィールド、 editing host 、 editable 要素のいずれかであり、かつ、typeが"text/plain"、kind が Unicode 文字列のアイテムが drag data store item list 内に存在していたら、実際のデータを drag data store item list の中に挿入する。その時、type を "text/plain"、kindをUnicode文字列、以下略。
         - それ以外、current drag operation を "none" にする。
    2. dragend イベントをソースノードに対して発行する
    3. デフォルトの dragend イベントの動作として以下のリストの中から適切なものを実行する 

2013年8月1日木曜日

HTML5 ドラッグ&ドロップ仕様書翻訳メモ

W3Cの HTML5 Drag And Drop API の仕様書を解読中です。
まだ途中ですがメモ。

原文はこちら
http://www.w3.org/TR/2012/CR-html5-20121217/editing.html#dnd


以下翻訳。


7.7 ドラッグ&ドロップ


このセクションではイベント駆動のドラッグ&ドラッグ機構について定義する。

この仕様は具体的にドラッグアンドロップを動かす具体的な仕組みについては述べない。

ポインティングデバイスによる視覚的な伝達手段では、ドラッグ操作はデフォルトの mousedown イベント、それに続くいくつかの mousemove イベント、そしてマウスが離されることでドロップをトリガーできる。

ポインティングデバイス以外の入力方式を使うとき、ユーザは自分の意図する目的のために、何をドラッグしたいのか、どこにドロップしたいのかを明確に示さなければならないだろう。

どのような方法でも、ドラッグ&ドロップ操作には開始座標が必要(マウスがどこでクリックされたのか、ドラッグのために選択された要素の開始セクションなど)、もしかしたらいくつかの中間ステップを持つかもしれない(エレメントがドラッグ中にマウスを動かされた場合、ユーザがドロップ可能な座標にエレメントを持ってきた時など)、そして必ず終了座標も持つ(上記のエレメントからマウスボタンが離された、エレメントの選択が確定した)、またはキャンセルされる場合もある。終了座標は最後に選択されたドロップ可能要素の座標でなければならない(もし操作がキャンセルされなかったら、中間ステップで使用したエレメントでなければならない)。


7.7.1 導入

このセクションは標準的ではない。

ドラッグ可能要素を作るのは簡単:要素に draggable 属性を与える、そしてドラッグされているデータを保存する dragstart イベントリスナをセットする。

イベントハンドラは一般的に、テキストドラッグがテキスト選択ではないことをチェックする必要がある。そして DataTransfer オブジェクトにデータを保存する必要があり、許可されたエフェクトを追加する(コピー、移動、リンク、またはそれらの組み合わせ)。


<p>好きなフルーツはなんですか?</p>
<ol ondragstart="dragStartHandler(event)">
  <li draggable="true" data-value="fruit-apple">りんご</li>
  <li draggable="true" data-value="fruit-orange">みかん</li>
  <li draggable="true" data-value="fruit-pear">なし</li>
</ol>
<script>
  var internalDNDType = 'text/x-example'; // あなたのサイトに合わせて書き換える
  function dragStartHandler(event) {
    if (event.target instanceof HTMLLIElement) {
      // 移動させるデータとして要素の data-value="" 属性を使う
      event.dataTransfer.setData(internalDNDType, event.target.dataset.value);
      event.dataTransfer.effectAllowed = 'move'; // move を許可する
    } else {
      event.preventDefault(); // LI要素以外はドラッグさせない
    }
  }
</script>

ドロップを受け入れるためには、ドロップ対象は dropzone 属性を持ち、drop イベントを監視する。

dropzone 属性の値は受け入れるデータの種類("string:text/plain"であらゆるテキストを受け入れる、または"file:image/png"でPNG画像ファイルを受け入れるなど)、フィードバックの種類(move だとデータが移動される)を指定する。

 メモ:dropzone属性を使う代わりに、dragenterイベント(ドロップをアクセプトするかどうかを判断する)とdragoverイベント(ユーザに何をフィードバックするのか)を使える。

drop イベントは現在のドロップを受け入れる。このイベントはキャンセルされることが必要、dropEffect はsource が使うことができる。(またはリセットされる)


<p>一番好きな果物をドロップしてね</p>
<ol dropzone="move string:text/x-example" ondrop="dropHandler(event)">
  <!-- "text/x-example"を自分のサイトに合わせて変えるのを忘れないように -->
  <script>
    var internalDNDType = 'text/x-example'; // 自分のサイトに合わせて書き換える
    function dropHandler(event) {
      var li = document.createElement('li');
      var data = event.dataTransfer.getData(internalDNDType);
      if (data == 'fruit-apple') {
        li.textContent = 'りんご';
      } else if (data == 'fruit-orange') {
        li.textContent = 'みかん';
      } else {
        li.textContent = '知らない果物';
      }
      event.target.appendChild(li);
    }
  </script>
</ol>

ドラッグされた元々の要素を画面から削除するために、 dragend イベントを使う。

元々のマークアップをアップデートしてイベント処理をしている。

<p>好きな果物は?</p>
<ol ondragstart="dragStarthandler(event)" ondragend="dragEndHandler(event)">
  ..上のコード...
</ol>
<script>
  function dragStarthandler(event) {
    // …上のコード...
  }
  function dragEndHandler(event) {
    // …上のコード…
    event.target.parentNode.removeChild(event.target);
  }
</script>


7.7.2 ドラッグデータの保存

ドラッグ&ドロップ操作の基礎にあるデータは、drag data storeとして知られていて、以下の情報から成り立っている。

◯drag data item listはドラッグされたデータのリストで、それぞれ以下の情報から成り立っている。
   - drag data item kind:データの種類
     - Plain Unicode string:テキスト
     - File:ファイル名とバイナリデータ
   - drag data item type string:一般的には MIME type でデータタイプかフォーマットを与える。MIME  type が与えられない場合は過去の名残などの理由がある。API は MIME types を使うことを強要しない。他の値でも動く。すべてのケースにおいて、すべての値は API によって ASCII コードの変換される。

 メモ:dropzone属性にスペースを含む文字列は使えない、MIME types か空白を含まない文字列を使うことが推奨される。

 item type は Unicode 文字列であることが条件。

 実際のデータ:drag data item kind 毎に、バイナリデータとファイルネーム(Unicode)を持つ。

 drag data store item list はリストにアイテムが追加されたらソートされる。

◯ドラッグ次のUIフィードバックに以下の情報が使われる
   - ユーザエージェントは デフォルトフィードバックとして、drag data store default feed back を持つ。
   - オプションで、drag data store bitmap と drag data store hot spot coordinate としてビットマップ画像と座標の組を持てる

◯drag data store mode は以下のいずれかをとる。
 - Read/write mode:dragstart イベント用。新しいデータは drag data store に追加できる。
 - Read-only mode:drop  イベント用。ドラッグデータとして表現されるアイテムリストを読める。新しいデータの追加はできない。
 - Protected mode:その他のイベント用。ドラッグデータとして表現される drag data store のフォーマットと種類を数えることができるが、読み込んだり追加したりすることはできない。

◯drag data store allowed effects state という文字列。


drag data store が作られた時、上記のデータは以下のように初期化されなければならない。drag data store item list は空、drag data store default feedback は存在しない、drag data store bitmap と drag data store hot spot coordinate を持たない、drag data store mode は protected mode、drag data store allowed effects state は "uninitialized"になる。


7.7.3 DataTransfer インタフェース

DataTransfer オブジェクトはドラッグ&ドロップ操作の根底に隠れている drag data sotre を表に出すために使われる。

interface DataTransfer {
                 attribute DOMString dropEffect;
                 attribute DOMString effectAllowed;
    readonly attribute DataTransferItemList items;
    void setDragImage(Element image, long x, long y);
};

以下は非標準。実装についての要求。

---
dataTransfer.dropEffect
    現在選択されている操作の種類を返す。もし effectAllowed で許可されていない種類だった場合は操作は失敗する。選択している操作を変更するために、この値を設定できる。可能な値は "none", "copy", "link", "move"のいずれか。

dataTransfer.effectAllowed
 許可する操作の種類を返す。許可する操作を変更するためにセットすることができる(dragstartイベントの間だけ)。設定できる値は "none", "copy", "copyLink", "copyMove", "link", "linkMove", "move", "all", "uninitialized"のいずれか。

dataTransfer.items
 ドラッグデータと一緒に DaraTransferItemList を返す。

dataTransfer.setDragImage(element, x, y)
 ドラッグフィードバックをアップデートして、以前のフィードバックと置き換えるために使う。

dataTransfer.types
 dragstart イベントでセットしたフォーマットのリストを返す。また、もしいくつかのファイルがドラッグされていたら、types の1つは "Files" になる。

data = dataTransfer.getData(format)
 具体的なデータを返す。データなかったら空文字列を返す。

dataTransfer.setData(format, data)
 具体的なデータを追加する

dataTransfer.clearData([format])
 format で設定されているデータを削除する。引数がない場合はすべてのデータを削除する。

dataTransfer.files
 ドラッグされている FileList があれば返す。
---

DataTransfer オブジェクトはドラッグ&ドロップイベントの間使われる。そしてドラッグ&ドロップイベントが発生している間は有効である。

DataTransfer オブジェクトは drag data store と関連している。

dropEffect 属性はユーザがドラッグ&ドロップ操作をしている間のフィードバックを制御する。DataTransferオブジェクトが作成された時、dropEffect 属性として文字列の値がセットされる。取得するとき、必ず現在の値を返さなければならない。セットするとき、新しい値が "none", "copy", "link", "move"のいずれかだったら、 dropEffect属性は新しい値に変更されなければならない。その他の値は無視されなければならない。

effectAllowed 属性は dragenter イベントと dragoverイベントの間、 dropEffect属性を初期化するためにドラッグ&ドロップ処理モデルによって使われる。DragTransferオブジェクトが作成された時、effectAllowed属性は文字列で初期化される。取得するとき、必ず現在の値を返す。セットするとき、もじ drag data sotre の mode が read/write であり、 "none", "copy", "copyLink", "copyMove", "link", "linkMove", "move", "all", "uninitialized" だったら新しい値に書き換える。その他だったら変更しない。

items 属性は DataTransfer オブジェクトに関連付いた DataTransferItemList オブジェクトを返さなければならない。どんな時でも同じデータを返さなければならない。

setDragImage(element, x, y) メソッドは必ず以下のステップで実行されること。

1. もし DataTransfer オブジェクトが drag data store と今後関連づかないなら、以下のステップはやらなず、何も起きない。
2. もし drag data store の mode が read/write mode だったら、以下のステップをやらず、何も起きない。
3. もし element 引数が img 要素だったら、 drag data store bitmap に要素の画像をセットする。そうじゃなければ drag data store bitmap に、与えられた要素から画像を生成してセットする。(具体的なsより方法についてはここでは述べない)
4.  drag data store hot spot coordinate に、与えられた x, y をセットする。

type 属性は live read only 配列を以下のステップで返さなければならない。同じオブジェクトはいつでも必ず同じ値を返す。

1. 空の配列 L から始める
2. DataTransfer オブ絵jクトが今後 drag data store と関連づかないなら、配列は空とする。以下のステップをやらずに、空の配列 L を返す。
3. drag data store item list の各要素の kind (Unicode文字列)について、 L に追加する。
4. drag data store item list の中に kind が File のアイテムがあったら、L に "Files" を追加する。
5. これらのステップによって生成された文字列が L に入る。

getData(format) メソッドは以下のステップで実行されなければならない

1. DataTransfer オブジェクトが今後 drag data store と関連づかないなら、空文字を返して以下のステップはやらない。
2. drag data store の mode が protected だったら、空文字を返して何もしない。
3. fomart に最初の引数を小文字に変換したものを代入
4. convert-to-URL に false を代入
5. format が "text" だったら、"text/plain" に変更
6. format が "url" だったら、"text/uri-list" に変更して convert-to-URL を true にする
7. drag data store item list に kind が Unicode 文字列かつ type string が format と同じアイテムがなければ、空文字を返して以下のステップを中止する。
8. result に drag data store item list 内の kind が Unicode 文字列で type string が format と同じアイテムを代入する。
9. convert-to-URL が true だったら、text/uri-list にあった形式にパースして、result にセットする。
10. result を返す

setData(format, data) は以下のステップで実行されなければならない

1. DataTransfer オブジェクトが drag data store に関連づかないなら何もしない。
2. drag data store の model が read/write mode でなければ、何もしない。
3. format に最初の引数の format を小文字に変換して代入する
4. formart が text だったら text/plain に変更する。format が url だったら text/uri-list に変更する。
5. drag data store item list から、 kind が Unicode でtype string が format のアイテムを削除する。
6. drag data store item list に kind が Unicode で type string が format、data が第2引数に渡された文字列をセットする。

clearData() は以下のステップで実行されなければならない

1. DataTransfer オブジェクトが drag data store と以後関連づかないなら、何もしない。
2. drag data store の mode が read/write じゃなかったら、何もしない。
3. メソッドが引数なしで呼ばれたら、drag store item list 内で kind が Unicode の要素を削除して、以後のステップをやらない。
4. format に第一引数を小文字にした文字列を代入する
5. format が text だったら text/plain にする。 url だったら text/uri-list にする。
6. kind が Unicode で、type が format と同じアイテムを drag data store item list から削除する。

メモ:clearData() メソッドはドラッグにファイルが挿入されているかどうかに影響されない。clearData() が呼ばれて types 属性リストが空だったとしても影響されない。

files 属性は File オブジェクトを含む live FireList 配列を以下のステップによって表現して返す。同じオブジェクトはいつでも同じ値を返す。

1. 空の配列 L から始める
2. DataTransfer オブジェクトが drag data store と以後関連づかないなら、FileList を空にして以下のステップをやらない。空のリスト L を返す。
3. drag data store の mode が protected mode だったら、以下のステップをやらずに空のリスト L を返す。
4. drag data store item list の kind が File のアイテムに対して、L にアイテムのデータ(ファイルとファイル名)を追加する。
5. 以上のステップで見つかったのもを L とする。

 メモ:このバージョンの API はドラッグ中の types を表には出さない。


7.7.3.1 DataTransferItemList インタフェース

各 DataTransfer オブジェクトは DataTransferItemList に関連づいている。

interface DataTransferItemList {
    readonly attribute unsigned long length;
    getter DataTransferItem (unsigned long index);
    deleter void (unsigned long index);
    void clear();

    DataTransferItem? add(DOMString data, DOMString type);
    DataTransferItem? add(File data);
}

以下は非標準。実装について。
----
items.length
    drag data store の要素数を返す

items[index]
    指定された位置にある DataTransferItem オブジェクトを返す

delete items[index]
    指定された位置のアイテムを削除する

items.clear()
    drag data store のすべてのアイテムを削除

items.add(data)
items.add(data, type)
 引数として受け取ったデータを drag data store に追加する。もし data がプレーンテキストだったら type も与えられているべきである。

DataTransferItemList の DataTransfer オブジェクトは drag data store に関連づいている、DataTransferItemList オブジェクトの mode は drag data store mode と同じ。DataTransferItemList オブジェクトのDataTransfer オブジェクトがdrag data store と関連づいていないバア愛、DataTransferItemList オブジェクトの mode は disabled になる。このセクションで参照されるdrag data store は DataTransferItemList オブジェクトの DataTransfer オブジェクトと関連づいている。

length 属性は disabled のとき必ず 0 を返さなければならない。それ以外は drag data store item list の長さを返す。

DataTransferItemList が disabled モードではないとき、 0 から n - 1 までの間の値をとる。n は drag data store item list の長さ。

DataTransferItemList オブジェクトのインデックス i を決めるために、ユーザエージェントは drag data store の i 番目として表現される DataTransferItem オブジェクトを返さなければならない。DataTransferItemList オブジェクトから取得してきた要素は、同じものならどんなときでも必ず同じ値を返さなければならない。DataTransferItem オブジェクトは DataTransferItemList オブジェクトのように、初期化時に同じDataTransferオブジェクトから関連付けられる。

i としてインデックスされた DataTransferItemList のプロパティを削除するために、ユーザエージェントは以下のステップで実行しなければならない。

1. DataTransferItemList が read/write モードではなかったら、InvalidStateError 例外をスローして以下のステップを中止する。
2. drag data store の i番目のデータを削除する

DataTransferItemList が read/write モードだったら clear() メソッドは drag data store のすべての要素を削除しなければならない。それ以外は何もしてはいけない。

add() メソッドは以下の手順に従わなければならない。

1. DataTransferItemList が read/write モードではなかったら、nullを返して以下のステップを中止する。
2. 以下のリストから適切なステップにジャンプする
    → 第一引数が文字列
        drag data store item list 内に kind が Unicode で type がメソッドの第二引数と同じ物があれば、NotSupportedError 例外をスローして以下のステップを中断する。
        それ以外なら、drag data store item list に kind が Unicode で type がメソッドの第二引数であり、データがメソッドの第一引数の文字列であるアイテムを追加する。
    → 第一引数が File
        kind が FIle で type が File のファイルタイプでデータが引数として渡された File であるアイテムを drag data store item list に追加する。
3. 新しく追加されたアイテムの index プロパティとその値(新しく作られた DataTransferItem)を返す。


7.7.3.2 DataTransferItem インタフェース

各 DataTransferItem は DataTransfer に関連している。

interface DataTransferItem {
    readonly attribute DOMString kind;
    readonly attribute DOMString type;
    void getAsString(FunctionStringCallback? _callback);
    File? getAsFile();
};

[Callback, NoInterfaceObject]
interface FunctionStringCallback {
    void handleEvent(DOMString data);
}

以下は非標準
---
item.kind
    drag data item kind を返す。"string" か "file"。
item.type
    drag data item type を返す。
item.getAsString(callback)
    drag data item kind の文字列を引数として callback を呼び出す
file = item.getAsFile()
    アイテムの kind が File だったら File を返す
---

DataTansferItem と DataTransfer は drag data store と drag data store item list に関連づいていて、DataTransferItem を内部に持っている。DataTransferItem の mode はdrag data store mode と同じものである。DataTransferItem の DataTransfer が drag data store と関連づいていない、または DataTransfer が関連した drag data store item list から削除されていた場合、DataTransferItem の mode は disabled になる。このセクションで言う drag data store はDataTransferItem の DataTransfer オブジェクトに関連した drag data store である。

DataTransferItem が disable モードなら kind は空文字を返さなくてはならない。それ以外なら以下の表に合わせた値を撮らなくてはならない。

          Kind              | String
Plain Unicode string | "string"
File                         | "file"

DataTransferItem が disable なら type は空文字を返さなくてはならない。それ以外なら DataTransferItem の drag data item type string を返さなくてはならない。

getAsString(callback) は以下の手順で動かなくてはならない。

1. callback が null なら以下の手順を中止する
2. DataTransferItem が read/write モードまたは read-only mode ではなかったら以下の手順を中止して、callback は呼ばない。
3. drag data item kind が Unicode 文字列じゃなかったら以下の手順を中止して callback は呼ばない。
4. それ以外なら、callback をタスクキューに追加する。DataTransferItem として表現される実際のデータを渡して callback を呼び出す。

getAsFile() は以下のように動作しなければならない

1. DataTransferItem が read/write または read-only ではなかったら null を返して以下のステップを中止
2. drag data item kind は File ではなかったら、 null を返して以下のステップを中止
3. DataTransferItem として表現される File を返す