連絡先管理アプリケーション

Spine.jsで連絡先管理アプリケーションを作ってみる。

HTML

<script src="https://raw.github.com/maccman/book-assets/master/ch11/spine.contacts/lib/spine.js"></script>
<script src="https://raw.github.com/maccman/book-assets/master/ch11/spine.contacts/lib/spine.list.js"></script>
<script src="https://raw.github.com/maccman/book-assets/master/ch11/spine.contacts/lib/spine.model.local.js"></script>
<script src="https://raw.github.com/maccman/book-assets/master/ch11/spine.contacts/lib/jquery.tmpl.js"></script>
<script type="text/x-jquery-tmpl" id="contactsTemplate">
    <li class="item">
        {{if fullName()}}
            <div>${fullName()}</div>
        {{else}}
            <div>名前なし</div>
        {{/if}}
    </li>
</script>

<script type="text/x-jquery-tmpl" id="contactTemplate">
    <dl>
        <dt>名前</dt>
        <dd>${first_name} ${last_name}</dd>
        <dt>メールアドレス</dt>
        {{if email}}
            <dd>${email}</dd>
        {{else}}
            <dd>なし</dd>
        {{/if}}
    </dl>
</script>

<script type="text/x-jquery-tmpl" id="editContactTemplate">
    <dl>
        <dt>ファーストネーム</dt>
        <dd><input type="text" name="first_name" value="${first_name}" autofocus></dd>
        <dt>ラストネーム</dt>
        <dd><input type="text" name="last_name" value="${last_name}"></dd>
        <dt>メールアドレス</dt>
        <dd><input type="text" name="email" value="${email}"></dd>
    </dl>
</script>

<div id="sidebar">
    <ul class="items"></ul>
    <footer>
        <button>新規連絡先</button>
    </footer>
</div>
<div id="contacts">
    <div class="show">
        <ul class="options">
            <li class="optEdit">連絡先の編集</li>
        </ul>
        <div class="content"></div>
    </div>
    <div class="edit">
        <ul class="options">
            <li class="optSave default">連絡先の保存</li>
            <li class="optDestroy">連絡先の削除</li>
        </ul>
        <div class="content"></div>
    </div>
</div>

CSS

body{
    line-height:2;
}
#sidebar{
    width:20%;
    float:left;
}
#sidebar .current{
    background:#000;
    color:#fff;
}
#contacts{
    width:75%;
    float:right;
}
#contacts dt{
    background:#efefef;
}
#contacts .options{
    margin-bottom:1em;
    overflow:hidden;
}
#contacts .options li{
    width:10em;
    margin-right:1em;
    float:left;
    background:#000;
    color:#fff;
    text-align:center;
}

JavaScript

(function($, window, document, undefined){

    // ユーティリティ用のメソッドを定義
    $.extend($.fn, {

        // 要素に紐付けられたモデルデータを返す
        item: function(){

            // 紐付けられたモデルデータを取得
            var item = $(this).tmplItem().data;

            // モデルデータを返す(reloadで再取得してから)
            // http://spinejs.com/api/models内のreloadAPI参照
            return ($.isFunction(item.reload) ? item.reload() : null);

        },

        // 渡されたモデルデータを持つ要素を返す
        forItem: function(item){

            return this.filter(function(){

                // 紐付けられたもモデルデータを代入
                var compare = $(this).tmplItem().data;

                // モデルデータがあり、モデルデータと一致すればその要素を返す
                // http://spinejs.com/api/models内のeqlAPI参照
                if (item.eql && item.eql(compare) || item === compare) return true;

            });

        },

        // 指定された要素内の配列を返す
        serializeForm: function(){

            // 返り値用にオブジェクトを生成
            var result = {};

            // 指定された要素をシリアライズし、配列を返す
            $.each($(this).find('input, textarea').serializeArray(), function(i, item){
                result[item.name] = item.value;
            });

            // JSONオブジェクトを返す(e.x.{ email: '...', first_name: '...', last_name: '...' })
            return result;

        }

    });

    // Contactモデル
    // Spineの最新版だと設定方法は変更されているので注意
    var Contact = Spine.Model.setup('Contact', ['first_name', 'last_name', 'email']);

    // ローカルストレージを利用するのでLocalを継承(要local.js)
    Contact.extend(Spine.Model.Local);

    // テンプレート内で使用するためにインスタンスメソッドを追加
    Contact.include({
        fullName: function(){
            // ファーストネーム、ラストネームが設定されていない場合はfalseを返す
            if (!this.first_name && !this.last_name) return;
            return (this.first_name + ' ' + this.last_name);
        }
    });

    // Sidebarコントローラー
    var Sidebar = Spine.Controller.create({

        // インスタンス変数を追加
        elements: {
            '.items': 'items'
        },

        // buttonをclickするとcreateメソッドを叩く
        events: {
    ...