2013年7月31日水曜日

jQuery UI Draggable でドラッグ中のスタイルを変える

ドラッグ中に半透明にしたりするには ui-draggable-dragging クラスを定義すればOKです。
.ui-draggable-dragging {
 opacity: 0.8;
}

2013年7月30日火曜日

jQuery UI でドロップ領域のホバークラスを変える

jQuery UI Droppable でドラッグオブジェクトがドロップ領域上にあるときのクラスを、
hoverClass で指定することができます。

droppable() でドロップ可能にする時、hoverClass オプションを渡すことで、
ドラッグ状態でマウスカースロが重なっている時のクラスを指定できます。
$('.drop').droppable({
    drop: function(event, ui) {
        alert(ui.draggable.html() + 'がドロップされました');
    },
    hoverClass: 'hover'
});

ドラッグしながらホバーした時のクラス変更サンプルを作成しました。

サンプルアプリ

ソースコード



2013年7月29日月曜日

jQuery UI droppable でドロップされた要素を取得する

jQuery UI Draggable でドラッグ可能にした DOM エレメントを、
jQuery UI Droppable で取得することができます。
draggable 要素の属性として name などを設定しておき、
droppable 要素の drop イベントで属性を読み込むことで、
何がドロップされたのかを判断することができます。
<div class="drop">ココへドロップ</div>
<div class="drag" name="HELLO"></div>
<div class="drag" name="WORLD"></div>
// ドラッグ可能にする
$('.drag').draggable();

// ドロップ可能にする
$('.drop').droppable({
    drop: function(event, ui) {
        var name = ui.draggable.attr('name');
        alert(name + 'がドロップされました');
    }
});

2013年7月28日日曜日

jQuery UI でドラッグ&ドロップ

jQuery UI を使えば DOM を簡単にドラッグ&ドロップさせることができます。
いくつかのパラメータによって細かい動作を設定できます。

3DS ウェブブラウザ用脱出ゲーム作成ツールのイベントエディタとして、
ドラッグ&ドロップによるブロックプログラミングを実装中です。
条件分岐なんかもできるようにする予定です。


HTML5 でも Draggable API を使ってドラッグ&ドロップを実装できるのですが、
ドロップ先にカチッとはまるような動きをさせたり、
スピードやアニメーションが設定できるため、
jQuery UI を使った方が個人的には使いやすいと思います。

jQuery UI は以下のサイトから落とせます。
デザインを変えたり、必要な機能だけをカスタマイズして落とすこともできます。
とりあえず使ってみるなら Stable ボタンを押せばOKです。
jQuery UI


zip を展開してみると大量のファイルが入っていることがわかります。
使用するのは

ui/minified/jquery-ui.min.js
themes/base/minified/jquery-ui.min.css
themes/base/minified/images

です。
これらを HTML で読み込んで使います。
jQuery UI を使うには jQuery が必要なので先に読み込んでください。
 css ファイルを置いたディレクトリ内に images ディレクトリを配置されるようにします。

あとは、jQuery オブジェクトの draggable() メソッドでドラッグ可能にできます。
droppable() も合わせて使うと、ドロップされた時のイベントを処理することができます。
$('#drag_element').draggable();


jQuery UI の公式サイトでソースコード付きのデモを見ることができます。
動作を変更できる様々なオプションが存在するので是非チェックしてみてください。
jQuery UI Draggable


2013年7月27日土曜日

jQueryで画面を暗くして操作できなくする

黒い半透明な <div> でコンテンツを覆ってクリックイベントを通さないようにできます。

ゲームのイベント中やメッセージ送りを待っている時など、
画面を暗くして操作できないようにしたい場合があります。

1つの手段として半透明な黒い <div> でコンテンツを覆い隠す方法があります。
一時的にコンテンツのクリックを不可能にするサンプルを作成しました。



サンプルアプリ
ソースコード

黒くて半透明な <div> をコンテンツの上に表示しています。
z-index でコンテンツよりも上に <div> を表示し、
jQuery から CSS の visibility の visible/hidden を切り替えています。

2013年7月26日金曜日

GAE + Go でホスト名を取得する

サーバのホスト名を以下のように取得出来ます。
c := appengine.NewContext(r)
hostname := appengine.DefaultVersionHostName(c)
c.Debugf("HOSTNAME: %s", hostname)

詳しくはこちらのドキュメントを参照してください
The appengine package - Google App Engine

2013年7月25日木曜日

Model の変化を Collection で処理する

Backbone.js の Collection は内包する Model の change イベントをキャッチできます。

Collection 内の Model を1つだけ選択できるようなプログラムを書く場合、
各 Model に selected 属性を追加して、その変化を Collection 側で取得して処理するのがよいです。
var collection = Backbone.Collection.extend({
    initialize: function() {
        this.on('change:selected', function(selectedModel) {
            console.log('collection 内の Model の selected が変更されました。');
            this.each(function(model) {
                model.set('selected', false, {silent: true});
            });
            selectedModel.set('selected', true, {silent: true});
        });
    }
});


以下に Collection 内の Model を1つだけ選択するサンプルを公開しました。
http://okanoworld.appspot.com/sample/backbonejs/select/index.html

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

2013年7月24日水曜日

Windows 用 GitHub クライアント

Windows 用の GitHub 公式クライアントが配布されています。
GitHub for Windows

GUI でコミットやリポジトリのクローンができます。




ちなみに Mac 用はこちらから落とせます。
GitHub for Mac



2013年7月23日火曜日

HTML5 ドラッグ&ドロップでファイルをアップロード

---
プログラム修正しました (2014/03/30)
ご報告ありがとうございました
---

HTML5 のドラッグ&ドロップ API  と jQuery.ajax() を使って、
ブラウザ上にドラッグ&ドロップしたファイルをサーバへアップロードする方法です。

ソースは GitHub へ上げました。
https://github.com/yokano/dnd_file_upload

以下の流れで実現出来ます。
  1. dropzone にファイルがドロップされる
  2. drop イベントが発生する
  3. イベントオブジェクトの dataTransfer からファイルを取得する
  4. FormData を作成してファイルを追加する
  5. Ajax でファイルを送信する
HTML
<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8">
  <title>ドラッグ&ドロップでファイルアップロード</title>
  <link rel="stylesheet" href="dnd.css">
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
  <script src="dnd.js"></script>
 </head>
 <body>
  <h1>画像ファイルのアップロード</h1>
  <div id="dropzone" dropzone>
   ここへ画像ファイルをドロップ
  </div>
 </body>
</html>

JavaScript
$(function() {
 $('#dropzone').on('drop', function(event) {
  var file = event.originalEvent.dataTransfer.files[0];
  var formData = new FormData();
  formData.append('file', file);
  
  $.ajax('./upload.php', {
   method: 'POST',
   contentType: false,
   processData: false,
   data:formData,
   error: function(xhr, error) {
    console.log('アップデートに失敗しました');
    console.log(error);
   },
   success: function(response) {
    console.log('アップロードに成功しました');
    console.log(response);
    
    
   }
  });

  return false;
    
 }).on('dragover', function(event) {
  return false;
 });
});
PHP
<?php

if(is_uploaded_file($_FILES['file']['tmp_name'])) {
 move_uploaded_file($_FILES['file']['tmp_name'], './' . $_FILES['file']['name']);
}

?>

サーバから見た場合、以下の <form> からファイルがアップロードされた時と、
全く同じデータがクライアントから渡されます。
formData.append('file', file) の 'file' が <input> タグの name 属性に対応します。
<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file"></file>
</form>

ドラッグ&ドロップについてはこちら
Drag and drop - W3C

FormData についてはこちら
The FormData Interface - W3C

jQuery.ajax() についてはこちら
jQuery.ajax() - jQuery

2013年7月22日月曜日

GAE + Go で Sign in with Facebook (2)

前回は Facebook にアプリを登録して Client ID と Client Secret を発行してもらいました。
GAE + Go で Sign in with Facebook

続いて実際にコードを書いていきます。
ちなみに今回は OAuth 2.0 の認証コード方式を使います。

まずログインボタンを設置します。
ボタンの画像はサードパーティから無料で提供されているものを使用しました。
リンク先を /login_facebook とします。
<a href="/login_facebook"><img src="/client/login/img/sign_in_with_facebook.png"></a>



/login_facebook に対応するハンドラを作成します。
http.HandleFunc から呼び出します。
// Facebook のログインボタンが押された時の処理
func (this *Controller) LoginFacebook(w http.ResponseWriter, r *http.Request) {
 c := appengine.NewContext(r)
 oauth := NewOAuth2(c, FACEBOOK_CLIENT_ID, FACEBOOK_CLIENT_SECRET)
 oauth.RequestAuthorizationCode(w, r, "https://www.facebook.com/dialog/oauth", url.QueryEscape("http://escape-3ds.appspot.com/callback_facebook"))
}

Facebook から発行された Client IDClient Secret を使って通信します。
最初に、アプリがユーザデータへアクセスする許可をユーザから得る必要があります。
Facebook ではユーザの許可を得る画面を OAuth Dialog と読んでいます。
OAuth Dialog の URL は http://www.facebook.com/dialog/oauth です。
ここに Client ID, Client Secret,  許可をもらった時のリダイレクト URL を GET で渡します。

詳しくはこちらをご覧ください
OAuth Dialog - Facebook Developers


上のコードでは自作のライブラリを使用しています。
中身はこんな感じになっています。
// OAuth 2.0
type OAuth2 struct {
 context appengine.Context
 clientId string
 clientSecret string
}

// OAuth2.0 インスタンスを返す
func NewOAuth2(c appengine.Context, clientId string, clientSecret string) *OAuth2 {
 oauth := new(OAuth2)
 oauth.context = c
 oauth.clientId = clientId
 
 oauth.clientSecret = clientSecret
 return oauth
}

// 認証コードをリクエストする
// 認証ページヘのリダイレクトを行いユーザに認証してもらう
// 認証が完了したらリダイレクトURIへ認証コードが返ってくる
func (this *OAuth2) RequestAuthorizationCode(w http.ResponseWriter, r *http.Request, targetUri string, redirectUri string) {
 targetUri = fmt.Sprintf("%s?client_id=%s&redirect_uri=%s&response_type=code", targetUri, this.clientId, redirectUri)
 http.Redirect(w, r, targetUri, 302)
}

今回はリダイレクト先として http://escape-3ds.appspot.com/callback_facebook を設定しました。
自分のアプリに合わせてコールバック先の URL を設定してください。
コールバックされた後の処理を書きます。
こちらも http.HandleFunc() で呼び出されるようにしましょう。
// Facebook でユーザがアクセスを許可した時に呼び出されるコールバック関数
func (this *Controller) CallbackFacebook(w http.ResponseWriter, r*http.Request) {
 c := appengine.NewContext(r)
 userInfo := this.RequestFacebookToken(w, r)
 
 model := NewModel(c)
 view := NewView(c, w)
 
 key := ""
 if model.ExistOAuthUser("Facebook", userInfo["oauth_id"]) {
  // 既存ユーザ
  params := make(map[string]string, 2)
  params["OAuthId"] = userInfo["oauth_id"]
  params["Type"] = "Facebook"
  key = model.GetUserKey(params)
 } else {
  // 新規ユーザ
  params := make(map[string]string, 4)
  params["user_type"] = "Facebook"
  params["user_name"] = userInfo["name"]
  params["user_oauth_id"] = userInfo["oauth_id"]
  params["user_pass"] = ""
  user := model.NewUser(params)
  key = model.AddUser(user)
 }
 
 if this.GetSession(c, r) == "" {
  this.StartSession(w, r, key)
 }
 view.Gamelist(key)
}

ユーザからの許可が得られたら、アクセストークンを Facebook に要求します。
上のコードでは RequestFacebookToken() で要求しています。
このとき、ユーザIDとユーザ名が含まれたレスポンスが Facebook から返されます。
データベース上にユーザID が存在するかどうかを調べて、新規ユーザかどうかを判断しています。
アクセストークンの取得先 URL は https://graph.facebook.com/oauth/access_token です。

アクセストークンについてはこちら
Access Tokens - Facebook Developer

RequestFacebookToken() の中身はこんな感じ。
// Facebook へアクセストークンを要求する。
// この関数は Facebook から認証コードをリダイレクトで渡された時に呼ばれる。
// ユーザ情報を格納した map を返す。
func (this *Controller) RequestFacebookToken(w http.ResponseWriter, r *http.Request) map[string]string {
 c := appengine.NewContext(r)
 code := r.FormValue("code")
 oauth := NewOAuth2(c, FACEBOOK_CLIENT_ID, FACEBOOK_CLIENT_SECRET)
 token := oauth.RequestAccessToken(w, r, "https://graph.facebook.com/oauth/access_token", url.QueryEscape("http://escape-3ds.appspot.com/callback_facebook"), code)
 response := oauth.RequestAPI(w, "https://graph.facebook.com/me", token)
 
 // JSON を解析
 type UserInfo struct {
  Id string `json:"id"`
  Name string `json:"name"`
 }
 userInfo := new(UserInfo)
 err := json.Unmarshal(response, userInfo)
 Check(c, err)
 
 result := make(map[string]string, 2)
 result["oauth_id"] = userInfo.Id
 result["name"] = userInfo.Name
 
 return result
}

RequestAccessToken() でアクセストークンとユーザ情報を取得して、
レスポンスのユーザデータのパースしています。

RequestAccessToken() の中身はこんな感じ。
// アクセストークンをリクエストする
// 引き換えとして認証コードを渡すこと
func (this *OAuth2) RequestAccessToken(w http.ResponseWriter, r *http.Request, targetUri string, redirectUri string, code string) string {
 targetUri = fmt.Sprintf("%s?client_id=%s&redirect_uri=%s&client_secret=%s&code=%s", targetUri, this.clientId, redirectUri, this.clientSecret, code)
 
 params := make(map[string]string, 4)
 params["client_id"] = this.clientId
 params["redirect_uri"] = redirectUri
 params["client_secret"] = this.clientSecret
 params["code"] = code
 response := Request(this.context, "GET", targetUri, params, "")
 
 body := make([]byte, 1024)
 _, err := response.Body.Read(body)
 Check(this.context, err)
 
 // response: oauth_token=******&expires=******
 responseParams := strings.Split(string(body), "&")
 tokenParam := strings.Split(responseParams[0], "=")
 return tokenParam[1]
}

すべてのコードは GitHub においてあります。
https://github.com/yokano/escape3ds

OAuth 2.0 に関するコントローラは
server/controller/controller.go
server/controller/oauth.go

ライブラリは
server/lib/oauth2.go

にあります。

2013年7月20日土曜日

名刺印刷時に余白が入ってしまい台紙からずれる

印刷時に自動的に余白が入り、ミシン目が入った名刺の台紙からはみ出してしまう場合の対処法です。
プリンタのプロパティで「フチなし全面印刷」にチェックを入れると余白が消えてデザイン通りに印刷できます。

台紙は Elecom 「なっとく名刺」を使用しました。
名刺作成用のソフトも提供されているのですが、
今回は台紙のサイズに合わせて inkscape で A4 のデザインを作成しました。

しかし印刷時に、余白の設定を 0mm にしているのにもかかわらず、
自動的に余白が挿入されて、台紙のミシン目から少しずれてしまう状態になりました。
ちなみに、プリンタは Canon MP540、ソフトは Windows7 の Adobe Acrobat です。

印刷時のプロパティで、ページ設定から「フチなし全面印刷」にチェックを入れると、
余白が挿入されずデザイン通りに印刷することができました。

印刷画面からプロパティを選択
フチなし全面印刷にチェックを入れる

GAE + Go で Sign in with Facebook(1)

以前 GAE + GO で Twitter ログインの記事を書きましたが、今回は Facebook d
    GAE + Go で Sign in with Twitter - y.okano blog

Facebook ログイン関係の公式ドキュメントはこちら
    Facebook Login - facebook developers

Twitter は OAuth 1.0 を採用していますが、Facebook では OAuth 2.0 になります。
    OAuth Core 1.0 Revision A - oauth.net
    OAuth 2.0 - rfc6749
    
Facebook からは JavaScript でログインが可能な SDK が提供されています。
今回はサーバサイドでログインを実装するので、JavaScript SDK は使用しません。

JavaScript SDK を使ったログイン方法についてはこちら
    The Login Flow for Web - facebook developers
    
JavaScript SDK を使わないログイン方法についてはこちら
    The Login Flow for Web (without JavaScript SDK)
    

アプリの登録

まず、Facebook に自作のアプリを登録します。
Facebook のアプリ管理ページを開きます。
    アプリ - facebook developers
    
右上の「+新しいアプリを作成」ボタンを押すと以下の様なダイアログが出ます。


Display Name,  App Category を入力します。
App Namespace は入力しなくて OK です。
Web Hosting は GAE を使うためチェックは外した状態にします。

アプリを登録したら、自動的にアプリの基本設定が表示されます。
ここに表示される App IDApp Secret をログインに使用します。


App Domains に GAE のアプリのドメイン名を入力します。
appname.appspot.com という感じです。

更に画面下の「アプリを Facebook に結合する方法を選択」部分を変更します。
「Facebook でログインするウェブサイト」のサイト URL を入力します。
http://appname.appspot.com/ という感じです。

ここまで変更できたら「変更を保存」ボタンを押して保存します。
これで Facebook でログインするためのアプリ登録が完了です。

今日はここまで。

2013年7月19日金曜日

GAE 開発サーバへ別のデバイスからアクセスする

サーバ起動時に IP アドレスを指定すれば他のデバイスからもアクセスできます
$ dev_appserver.py -a 192.168.1.5 myapp

-a オプションで渡した IP アドレスがローカル開発サーバのホストになります。
上の例の場合では、同じネットワーク内から 192.168.1.5:8080 でアクセスできます。
3DS や スマホ用のアプリを作っている時には実機で確認するのに便利です。
ちなみに localhost:8080 ではアクセスできなくなるので要注意です。


3DS上でデバッグ

開発用ローカルサーバについての詳細は公式サイトをご覧ください

    The Go Development Server - Google App Engine
    https://developers.google.com/appengine/docs/go/tools/devserver

2013年7月18日木曜日

Backbone.Collection の並び順を指定する

Backbone.Collection 内の model は comparator を指定することで任意の並び順に変更できます。

Backbone.Collection は Backbone.Model を複数入れておくことができるものです。
var People = Backbone.Model.extend({
});

var Peoples = Backbone.Collection.extend({
    model: People
});

var okano = new People({'name': 'okano'});
var tanaka = new People({'name': 'tanaka'});
var abe = new People({'name': 'abe'});

var peoples = new Peoples();
peoples.add([okano, tanaka, abe]);

console.log(peoples.toJSON()); // [ { name: "okano" }, { name: "tanaka" }, {name: "abe"} ]


Collection 内で comparator メソッドを定義することで並び替え方法を指定出来ます。
comparator メソッドは Collection 内の各 Model を引数として繰り返し呼び出されます。
comparator が返した値(文字列 or 数値)の大小(前後)によって並び順が決まります。
以下の例では、名前の昇順に並び替えています。
var People = Backbone.Model.extend({
});

var Peoples = Backbone.Collection.extend({
    model: People,
    comparator: function(people) {
        return people.get('name');  // 名前で並び替える
    }
});

var okano = new People({'name': 'okano'});
var tanaka = new People({'name': 'tanaka'});
var abe = new People({'name': 'abe'});

var peoples = new Peoples();
peoples.add([okano, tanaka, abe]);

console.log(peoples.toJSON()); // [ { name: "abe" }, { name: "okano" }, {name: 'tanaka'} ]


2013年7月17日水曜日

Backbone.js の Model 操作は必ず get() , set() を使う

Backbone.js で Model のプロパティを操作するときには必ず get(), set() を使います。

ドット演算子で操作しようとすると意図した変化はおきないので要注意です。
this.model.set('filling', filling);  // プロパティが更新される
this.mode.filling = filling;         // プロパティは更新されない

var filling = this.model.get('filling');  // プロパティが取得できる
var filling = this.model.filling;         // プロパティが取得できない

モデルのプロパティを変更するサンプルプログラムを作りました。

アプリURL
http://okanoworld.appspot.com/sample/backbonejs/get_set/index.html

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


2013年7月16日火曜日

Backbone.js リストのサンプル

Backbone.js の Collection をリスト表示するサンプルです。

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

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


基本的に View が listenTo() で Collection を監視します。
Collection の add や remove イベントが発生したら、render() で画面を再描画しています。


listenTo() - Backbone.js
http://backbonejs.org/#Events-listenTo

Collection - Backbone.js
http://backbonejs.org/#Collection

2013年7月15日月曜日

Backbone.js でイベントを通知せずに Model を操作する

Backbone.js では Model と View がイベントを通してやり取りします。

例えば View が listenTo() を使って Model の変更を監視し、
変更があったら画面へ反映させるといったことができます。

しかし、画面へ反映させず Model だけをこっそり変更したい場合があるかもしれません。
その場合は Model 変更時に silent オプションを追加することで実現出来ます。
silent に設定された操作は、他のオブジェクトへイベントを発行しません。
addBookSilentButtonHasClicked: function() {
    var title = window.prompt('タイトルを入力してください');
    if(title == '') {
        return;
    }
    this.model.add({title: title}, {silent: true});
}


以下に実際に動くサンプルプログラムを置きました。
http://okanoworld.appspot.com/sample/backbonejs/silent_event/index.html


ソースコードは GitHub で公開しています。
https://github.com/yokano/sample/tree/master/backbonejs/silent_event



リストにモデルの内容が表示されています。
左側の追加ボタンを押すと通常通りモデルが追加されます。
サイレントボタンを押すと、 slient にモデルが追加されます。
silent の場合は View は Model の変更を通知されないので画面の再描画が行われません。


2013年7月14日日曜日

GAE + Go で管理者専用機能を作る

GAE + Go でデバッグツールや、データの削除ツールなどをアプリ内に同梱する場合、
該当する URL パターンを管理者専用にできます。

app.yaml を開き、管理者専用にしたい URL に login: admin を指定します。
application: appname
version: 0
runtime: go
api_version: go1

handlers:
# 管理者専用の API を設定 #
- url: /debug
  login: admin
  script: _go_app

- url: /.*
  script: _go_app

login: admin に設定した URL へアクセスしようとすると、
以下のようにログインページヘ遷移され、アプリ管理者のログインを求められます。
(写真は認証方式を Google アカウントにしている場合です)



ちなみにローカル開発環境では以下の様なフォームが出力されます。
"Sign in as Administrator" にチェックを入れると認証が通ります。


デバッグ用のページは管理者専用に設定しましょう。


詳しくは公式のドキュメントをご覧ください。

    Requiring Login or Administrator Status - Google App Engine    https://developers.google.com/appengine/docs/go/config/appconfig#Requiring_Login_or_Administrator_Status

2013年7月13日土曜日

godoc で Go のドキュメントを生成する

Java には JavaDoc, JavaScript には JSDoc がありますが、
Go には公式のドキュメント生成ツールとして godoc があります。

    Godoc: documenting Go code
    http://golang.org/doc/articles/godoc_documenting_go_code.html 

GAE の SDK for Go を入れていればそのまま使えます。
$ godoc -html ./model > model.html
出力された HTML は下の写真です。


しかし、このままではスタイルや JavaScript が参照されていません。
デフォルトの HTML テンプレート内で CSS や JS を参照していないためです。

テンプレートはSDK 内の goroot/lib/godoc/godoc.html が使われます。
CSS と JS は以下にあります。

    goroot/doc/style.css
    goroot/doc/godoc.js 

テンプレートのHTMLからこれらのファイルを参照すると、
公式サイトと同じデザインになります。
あとは、必要に応じてスタイルを編集すれば OK です。

私の場合は、 <frameset> を使ってこんな感じのテンプレートを作りました。


godoc はファイルの先頭部分や、関数名の直前に書かれたコメントを拾ってくれます。
/* */ ではなく // を使うのが一般的なようです。

ついでに、godoc を生成するシェルスクリプトを書いておき、
コミット前に実行すると常に最新のドキュメントがプログラムに同梱できて便利です。

godoc.sh
#!/bin/sh
godoc -html ./server > ./document/server/server.html
godoc -html ./server/config > ./document/server/config.html
godoc -html ./server/controller > ./document/server/controller.html
godoc -html ./server/model > ./document/server/model.html
godoc -html ./server/view > ./document/server/view.html
godoc -html ./server/lib > ./document/server/lib.html
実行
$ sh godoc.sh



ちなみに、godoc とは別に GitHub のリポジトリの URL を貼り付けると、
自動的にドキュメントを生成してくれる Web サービスなどもあるようです。
自分でテンプレートを作るのが面倒なときはこっちのほうがいいかも。

   GoDoc
   http://godoc.org


2013年7月12日金曜日

input タグだけを FormData として送信したいとき

以前の記事で、<form> 内の <input type="file"> を Ajax で送信する方法を書きました。

    jQuery.ajax() でファイルを送る
    http://yokano-jp.blogspot.jp/2013/07/jqueryajax.html

FormData のコンストラクタには <form> を渡す必要があります。
基本的には <form> で <input> を囲んでおくべきですが、
<form> で囲まれていない <input> をどうしても送りたい場合には、
JavaScript の内部で <form> を作成して送る方法もあります。

HTML
<input id="file" type="file">

JavaScript
var form = $('<form></form>').append($('#file'));
var formdata = new FormData(form.get(0));
$.ajax('/upload', {
    method: 'POST',
    contentType: false,
    processData: false,
    data: formdata,
    dataType: 'json',
    error: function() {
        console.log('error');
    },
    success: function(data) {
        console.log('blobkey', data.blobkey);
    }
});

2013年7月11日木曜日

Backbone.js の sync() ではデータに id を付けるのはサーバの役割?

モデルに自動的に振られる cid をデータベース上の id として使おうとしていたら、
sync() の create でデータの id を指定できなかったという話です。


Backbone.sync() 

Backbone.js では sync() 関数を使ってブラウザ上のデータと
サーバ上のデータベースを ajax によって同期させることができます。

モデルの中で urlRoot を指定しておけば、
それを基準にした URL へリクエストが投げられます。

例えばブラウザ上で作成しているゲームをサーバへ同期させるために、
以下のように指定したとします。
/**
 * ゲームモデル
 */
var Game = Backbone.Model.extend({
    urlRoot: '/sync/game',
    defaults: {
        name: '',
        description: '',
        thumbnail: '',
        firstScene: null,
        sceneList: null
    },
    initialize: function() {
        this.set('sceneList', new SceneList());
    }
});

そして sync() 関数を使ってサーバ上へデータを送ります。
この時、引数に create/read/update/delete のいずれかをセット出来ます。(いわゆるCRUD)
ここで指定した操作に合わせて、HTTP リクエストのメソッドが変わります。

    create   -> POST
    update -> PUT
    read     -> GET
    delete   -> DELETE

このとき、以下のようにリクエスト URL が決定します。

    create    -> /sync/game/
    update   -> /sync/game/id
    read       -> /sync/game[/id]
    delete     -> /sync/game/id

update や delete ではモデルの id が自動的に URL へ付加されます。
サーバ側でこの id に対応するデータを削除すればOKです。

詳しくは公式ドキュメントを参照してください。

    Sync - Backbone.js
    http://backbonejs.org/#Sync

create に id がない

create ではまだデータベース上に存在しないデータを追加するので、
id はサーバ側で付けるということになっているようです。

ブラウザ上で新しいモデルを作成した時に、
自動的に付加される cid をデータベース上の idとして使おうと思っていたのですが、
create では id を指定できないのでサーバ側で付けるように変更する必要がありそうです。

クライアント id は複数のクライアント間で被ってしまう可能性があるから、
サーバ側で id を付けるようになっているんだと思います。

2013年7月10日水曜日

HTML の親ページのスタイルは小フレームへは適用されない

実は知らなかったのでメモ。よく考えたら当然ですね。
フレームで参照している先のページのスタイルが変わってしまったら困りますから。

index.html
<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8">
  <title>html test</title>
  <style>
   frame h1 {
    color: red;
   }
  </style>
 </head>
 <frameset>
  <frame src="frame.html"></frame>
 </frameset>
</html>

frame.html
<h1>This is frame</h1>
<p>frame</p>



godoc のテンプレートを作成している時に発見しました。


2013年7月9日火曜日

GAE + Go で他ディレクトリの go ファイルを読み込む

GAE + Go では import 文で他のディレクトリ内の go ファイルを読み込むことができます。

import 文でアプリケーションルートディレクトリから、
読み込みたい go ファイルが置いてあるディレクトリまでを指定することで、
対象ディレクトリ内のすべての go ファイルを読み込むことができます。

例えば以下の様な分割をしていたとします。




view 内の go ファイルから model 内の go ファイルを参照するとします。
以下のように import 文を書きます。

view/hoge.go
package gae

// approot 直下の model ディレクトリ内のすべての go ファイルを読み込む
import "model"  

func showModel() {
    data := model.GetData()
    fmt.Fprintf("Data is %s", data.ToString())
}

package をインポートしたときと同様に、
関数や変数を使うときには読み込んだディレクトリ名を先頭に付けます。
data := model.GetData()

先頭にディレクトリ名を付けたくない場合は、以下のように読みこめばOKです。
package gae

import . "model"

func showModel() {
    data := GetData()
    fmt.Fprintf("Data is %s", ToString())
}

また、パッケージと同様で、
関数名や変数名は大文字で始まるものだけが外部から参照できます。
小文字で始まる関数を別のファイルから使うことはできないので注意が必要です。

2013年7月8日月曜日

jQuery.ajax() でファイルを送る

HTML の <input type="file"> で選択したファイルを  jQuery.ajax() で送る方法です。

通常は <input type="submit"> ボタンを押した時にファイルが送信されますが、
JavaScript で後から送信したい場合があります。

HTML が以下のようになっていたとします。
<h2>ファイルアップロード</h2>
<form id="ajaxform">
    <input id="file" name="file" type="file"></input>
    <input id="submit" type="submit"></input>
</form>

jQuery で以下のように書きます。
// ファイルのアップロード
$('#submit').click(function() {
  
    // FormData の作成
    var form = $('#ajaxform').get(0);
    var formData = new FormData(form);
  
    // FormData を送信
    $.ajax('/upload', {
        method: 'POST',
        contentType: false,
        processData: false,
        data: formData,
        dataType: 'json',
        error: function() {
            console.log('error');
        },
        success: function() {
            console.log('success');
        }
    });
 
    // false を返してデフォルトの動作をキャンセル
    return false;
});

dataType はサーバの出力に合わせて変更して下さい。

ポイントは contentType と processData が false になるところです。
contentType = 'multipart/form-data' にはなりません。
詳しくは jQuery のドキュメントをご覧ください。


参考

jQuery.ajax()
    http://api.jquery.com/jQuery.ajax/

The FormData Interface - W3C
    http://www.w3.org/TR/2010/WD-XMLHttpRequest2-20100907/#the-formdata-interface

jQueryでAjaxでファイルアップロード - やわらかたまご - molaovo -

2013年7月7日日曜日

光くしゃみ反射と金縛り

昨日は金縛りにあってあまり眠れませんでした。
高校時代からよく発生しています。

疲れているのに眠れないという状態の時によく発生します。
ギーンという強い耳鳴りがして、脳が痺れていくような感覚があります。
そのあと体が徐々に動かなくなっていきます。
この時、体を起こそうと力を入れると、この状態が治ります。
そのまま横になっていると、しばらくすると再び耳鳴りが始まるといった具合です。
この状態で放置すると耳鳴りがどんどん強くなっていきます。
金縛りが起きたら、一旦明るい部屋へ行って落ち着くとその後眠りやすくなります。

ネットで調べると耳鳴りから始まるタイプは結構あるみたいですね。
まったく発生しない人もいるようです。

ちなみに、小さい頃から太陽など眩しいものを見るとくしゃみが出るのですが、
これは光くしゃみ反射というもので、遺伝によってくしゃみがでるかどうか決まるみたいです。
Wikipedia によると日本人の約25%が光くしゃみ反射を持つらしいです。

光くしゃみ反射 - Wikipedia
http://ja.wikipedia.org/wiki/%E5%85%89%E3%81%8F%E3%81%97%E3%82%83%E3%81%BF%E5%8F%8D%E5%B0%84

2年くらいまえに「眩しいとくしゃみ出ますよね」という話をしたら、
「出る出る」という人と、「全く出ない」という人がいてちょっとショックを受けたのを思い出しました。

眩しくてくしゃみが出る人、よく金縛りになる人とは仲良くなれそうな気がする今日このごろです。

2013年7月6日土曜日

Backbone.js に乗り換えた

しばらく AngularJS を使っていたのですが、ふと Backbone.js を入れてみたらかなり使いやすかったです。
3DS 用の脱出ゲーム作成ツールのエディタ部分を Backbone.js で書いてみました。

    escape3ds/client/editor
    https://github.com/yokano/escape3ds/tree/master/client/editor

AngularJS のドキュメントと比べると、ドキュメントの量が少なくてシンプルです。
読む方からするとすごい楽でした。(これ大事だと思う)

    Backbonejs
    http://backbonejs.org/



3DS 向け脱出ゲーム作成サービスのログイン・ユーザ管理部分と、
画面作成をするシーンエディタはほぼできました。





残りは

  • アイテムエディタ
  • イベントエディタ(シーン内に領域や画像をタッチした時の処理)
  • テストプレイ機能
  • ランタイム(ゲームの処理)
  • 3DS 用に書き出し

くらいです。
最終的な書き出しは、データベース内のゲーム情報を json ファイルとして書きだして、
ランタイムがそれを読み込んで処理する感じにしようと思っています。

もぐらたたきを作ったときは処理の途中で「スクリプトを停止しました」と表示され、
スクリプトの動作が停止してしまうことが多々ありました。
3ds の Web ブラウザが json の読み込み時点でスクリプトを停止しないか心配ですが、
そうなるようだったら、 JSON を出力せずに、JavaScript のコードを直接書きだそうかと考え中です。

今月中には公開して、Android のゲーム開発に移りたいです。

2013年7月5日金曜日

Go + GAE で HTML テンプレート内に変数を展開

HTML テンプレート内に以下のような {{}} 構文を書くと変数を展開することができます。
昨日のコードをそのまま編集します。

html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello Template!</title>
  </head>
  <body>
    <h1>Hello Template!</h1>
    <div>
      私の名前は {{.Name}} です。
    </div>
  </body>
</html>

go
package helloworld

import (
    "net/http"
    "html/template"
)

func init() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    t, err := template.ParseFiles("app/template.html")
    if err == nil {
            contents := make(map[string]string, 1)
            contents["Name"] = "y.okano"
            t.Execute(w, contents)
        }
    })
}
構造体やマップを作って template.Execute() に渡すと該当する変数を探して展開してくれます。

2013年7月4日木曜日

Go + GAE で HTML ファイルを表示

Go + GAE で HTML ファイルを表示する方法です。

環境構築は昨日の記事をご覧ください。
http://yokano-jp.blogspot.jp/2013/07/google-app-engine-go.html


HTML ファイルを作成

画面に表示される HTML ファイルを作成します。
今回は ApplicationRoot/app/template.html として作成しました。
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello Template!</title>
  </head>
  <body>
    <h1>Hello Template!</h1>
    <div>
      HTML ファイルを出力するテストです
    </div>
  </body>
</html>


HTML ファイルを表示

Go のスクリプトを以下のように編集します
package helloworld

import (
    "net/http"
    "html/template"
)

func init() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        t, err := template.ParseFiles("app/template.html")
        if err == nil {
            t.Execute(w, nil)
        }
    })
}

これで localhost:8080 へアクセスすると HTML ファイルが表示されます。


2013年7月3日水曜日

Google App Engine + Go の開発環境構築

Google App Engine では無料でウェブアプリをホスティングすることができます。
また、データベースやユーザ管理など便利な機能が色々と付いています。

サーバサイドとして使える言語は Java, Python, Go, PHP です。
今回は Go を使った場合の開発環境の整え方です。


Python のインストール

まず、Python をインストールします。
GAE の SDK に Python スクリプトが含まれているため必要となります。
Mac OS X の場合はデフォルトでインストールされているので不用です。
Windows を使っている場合は以下からダウンロード、インストールしてください。

    Python.org


SDK のインストール

GAE の開発キットをインストールします。
公式サイトの Downloads をクリックして SDK のダウンロードをしてください。

    Google App Engine - Google Developers


PHP, Python, Java, Go 用の4種類があるので Go を落とします。
また、OS 毎に SDK が異なるので自分の OS に合わせてダウンロードして下さい。

zip を展開すると google_appengine というフォルダが出来ます。
フォルダを好きな場所に置き、パスを通しておいてください。
Mac なら Application ディレクトリに入れておけば OK です。

ターミナルを開いて以下のコマンドが実行できるか確認します。
何かしら表示されれば OK です。
$ dev_appserver.py


Hello World!

GAE の開発用ローカルサーバを立てて Go から Hello World! します。
好きな場所に GAE フォルダを作成し、その中に helloworld フォルダを作成します。
helloworld フォルダの中身が Web アプリになります。
GAE フォルダは Web アプリをまとめておくために作っています。

helloworld フォルダ内に app.yaml という名前のファイルを作成します。
これは Web アプリの設定ファイルです。
app.yaml 内に以下をコピペします。
application: helloworld
version: 1
runtime: go
api_version: go1

handlers:
- url: /.*
  script: _go_app

helloworld フォルダ内に app フォルダを作成します。
app フォルダの中に helloworld.go を作成します。
go スクリプトはサブディレクトリ内に置かなければならないので、appフォルダを作成しました。
helloworld.go に以下をコピペします。
package helloworld

import (
 "net/http"
 "fmt"
)

func init() {
 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hello World!")
 })
}

ターミナルを開きます。
GAE/ フォルダまで移動して、以下を実行します。
$ dev_appserver.py helloworld

エラーがなければ開発サーバが起動します。
ターミナルにはサーバのログが表示され続けます。
⌘ + C でサーバを終了出来ます。

サーバが起動している状態で Web ブラウザで

http://localhost:8080/

にアクセスすると Hello World! と表示されます。



これで開発環境の構築は完了です。

2013年7月2日火曜日

Jcrop で画像を範囲選択できるようにする

Jcrop とは Web ページ内の画像が範囲選択できるようになるライブラリです。


Jcrop
http://deepliquid.com/content/Jcrop.html



ダウンロード

上の公式サイトからスクリプトをダウンロードします。
Download Jcrop v0.9.12 → Jcrop-0.9.12 (zip format) をクリックします。

 zip ファイルを展開します。


index.html を Web ブラウザで開くとデモを見れます。



スクリプトの設置とロード

以下のファイルを自分のアプリ内に設置します。

css/Jcrop.gif
css/jquery.Jcrop.min.css
js/jquery.min.js
js/jquery.Jcrop.min.js

アプリの HTML でこれらのファイルを読み込みます。
sample.js はアプリ本体の js です。
Jcrop で範囲選択させる <img> を追加しておきます。
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="css/jquery.Jcrop.min.css"></link>
    <script src="js/jquery.min.js"></script>
    <script src="js/jquery.Jcrop.min.js"></script>
    <script src="js/sample.js"></script>
  </head>
  <body>
    <h1>Jcrop サンプル</h1>
    <img id="target" src="living1.png">
  </body>
</html>


範囲選択できるようにする

sample.js 内で、画像を選択可能にします。
$(function() {
   $('#target').Jcrop();
});

これで画像をドラッグアンドドロップで範囲選択できるようになります。



範囲選択のイベントを取得する

Jcrop では以下のイベントが使用出来ます。
  • onChange : ドラッグされている間、発生し続ける
  • onSelect : ドロップされた時に発生する
  • onRelease: 別の場所をクリックして選択状態が解除された時に発生する
画像を選択可能にするときに、
コールバック関数を渡すことでこれらのイベントを処理出来ます。
$(function() {
    var hasSelected = function() {
        console.log('選択されました')
    };
 
    var hasChanged = function() {
        console.log('変更されました');
    };
 
    var hasReleased = function() {
        console.log('リリースされました');
    };
 
    $('#target').Jcrop({
        onSelect: hasSelected,
        onChange: hasChanged,
        onRelease: hasReleased
    });
});



選択範囲の大きさや座標を取得する

Jcrop から発行されるイベントには選択範囲に関する情報が付加されます。
コールバック関数の引数として受けることができます。
$(function() {
    var hasSelected = function(data) {
        // 選択領域の左上の頂点の座標
        var x1 = data.x;
        var y1 = data.y;
  
        // 選択領域の右下の頂点の座標
        var x2 = data.x2;
        var y2 = data.y2;
  
        // 選択領域の幅と高さ
        var w = data.w;
        var h = data.h;
  
        console.log('選択領域は(' + x1 + ',' + y1 + ')から(' + x2 + ',' + y2 + ')までの幅' + w + 'px,高さ' + h + 'pxです')
    };
 
    var hasChanged = function() {
    };
 
    var hasReleased = function() {
    };
 
    $('#target').Jcrop({
        onSelect: hasSelected,
        onChange: hasChanged,
        onRelease: hasReleased
    });
});


その他の詳しい使い方は公式サイトのマニュアルをご覧ください。


Jcrop
http://deepliquid.com/content/Jcrop.html

2013年7月1日月曜日

Go の template パッケージと AngularJS の共存

AngularJS では HTML 内に {{}} で囲まれた部分を Angular 文として処理します。
一方、Go の template パッケージも {{}} で囲まれた部分を Go のコードとして処理します。
この2つが衝突してエラーが起きます。

GAE + Go では予め作っておいた HTML テンプレートに変数を展開するのが基本です。
このとき、HTML 内の変数が入る部分に {{.変数名}} という形式で表現します。

一方、AngularJS でも同様に HTML 内に Model の変数を当てはめて出力します。
書式も同じで HTML に {{変数名}} という形式で表現します。

AngularJS の変数を出力するために {{変数名}} を HTML テンプレートに埋め込むと、
Go が「これは Go の変数名だ」と勘違いして変数を探しに行きます。
Go 内で定義されていない変数を参照しようとするため nil pointer エラーが発生します。
runtime error: invalid memory address or nil pointer dereference

衝突を回避するために AngularJS で {{}} を別の記号に変更できます。
app.config(function($interpolateProvider) {
 $interpolateProvider.startSymbol('{[{');
 $interpolateProvider.endSymbol('}]}');
});

これで {{変数名}} が Go の変数を、 {[{変数名}]} が JS の変数を指すようになります。