HTML5 File API デスクトップからブラウザにファイルをドロップしてアップロード

デスクトップからブラウザにファイルをドロップできるようにしたい。

参考
Reading files in JavaScript using the File APIs
Drag and DropとFile APIを試す
はまちーのにっき。

File APIと、FormDataというのを使った。ちょっとごちゃごちゃしてるけど、dorpクラスにdorpされたファイルを、順番にupload関数に渡してアップロードしている。cakePHPで受け取ってFileBinderで保存しましたが、FormData使ってファイルを渡すと、$this->request->params[‘form’]に入っていた。dropされたらウインドウの下のに、ボックスが現れて、アップロード中のファイル名が表示されて、アップロード成功したら青くなって、失敗したら赤くなって、完了したらフェードアウトしてる様。$.Deferred()は、終わるまで次の処理を待たせたりできるやつらしいので、使ってみた。全てをしっかり理解していないので、効率的じゃなさそうだけど、とりあえずこれで出来た。

$(function(){
    jQuery.event.props.push('dataTransfer');

    $(document).on('drop', '.drop', function(evt){
        evt.stopPropagation();
        evt.preventDefault();

        var files = evt.dataTransfer.files;
        var url = $(this).attr('name');

        $.when(
            $.each(files, function(idx, file) {
                upload(url, idx, file);
            })
        ).done(function(){
            $('#popup').delay(2000).fadeOut('slow');
        });
    });

    $(document).on("dragenter", '.drop', false);
    $(document).on('dragover', '.drop', function(evt){
        $(this).css({'color':'#0000ff', 'width':'200px'});
        return false;
    });
    $(document).on('dragleave', '.drop', function(evt){
        $(this).css({'color' : '#000000', 'width':'130px'});
        return false;
    });
});

function upload(url, idx, file){
    var dfd = $.Deferred();
    fd = new FormData();
    fd.append('file',file);
    $.ajax({
        url: url,
        type: "POST",
        data: fd,
        processData: false,
        contentType: false,
        beforeSend:function(){
            if($('#popup').length == 0){
                $('#container').append('<div id="popup" display="none"></div>');
            }else{
                if(! $('#popup span').is(':visible')){
                    $('#popup').empty().fadeIn('first');
                }
            }
            $('#popup').append('<span class="file_' + idx  + '">' + file.name + '<br></span>');
        },
        success:function(){
            $('.file_' + idx).css({'color':'#00ccff'});
        },
        error:function(){
            $('.file_' + idx).css({'color':'#ff3333'});
        },
        complete:function(){
            $('.file_' + idx).fadeOut('slow');
            setTimeout(function(){
                dfd.resolve();
            }, 2000);
        }
    });
    return dfd.promise();
}

jQuery AjaxとSpinnerの使い方

$(function(){
    //追加と検索の表示切替
    $('.add_btn').click(function(){
        $('#add').toggleClass('none');
        $('#result').toggleClass('none');
    });
    //追加の登録ボタンを押したとき→登録処理
    $('.put_btn').click(function(){
        put_customer();
        return false;
    });
});

//お客様データの追加
function put_customer() {
    //data取得・作成
    var name = $('input[name="data[Customer][n]"]').val();
    var kana = $('input[name="data[Customer][k]"]').val();
    var mail = $('input[name="data[Customer][m]"]').val();
    var call1 = $('input[name="data[Customer][c1]"]').val();
    var call2 = $('input[name="data[Customer][c2]"]').val();
    var address = $('input[name="data[Customer][a]"]').val();
    var data = {'Customer':{'name':name,'name_kana':kana,'mail':mail,'call1':call1,'call2':call2,'address':address}};
    data = JSON.stringify(data);
    //spinnerのオプション設定
    var opts = {
        position: 'center',
        hide: true
    };
    //ajax
    $.ajax({
        type: "POST",
        url: location.pathname + '/add.json',
        data: data,
        beforeSend:function(){
            $('.put_btn').spinner(opts);
        },
        success: function(msg){
            $('.error').empty();
            $('.success').empty();
            //バリデーションエラー
            if(msg['error']){
                for(var e in msg['error']){
                    $('.error').append(msg['error'][e][0] + '<br>');
                }
                $('.error').append('<br>');
            //登録エラー
            }else if(!msg['msg']){
                $('.error').append('登録できませんでした。恐れ入りますが再度お試しください。<br><br>');
            //登録成功
            }else{
                $('.success').append('登録しました。<br><br>');
                //フォームのクリア
                $('#add input').val('');
                
            }
        },
        error:function(){
            $('.error').append('登録できませんでした。恐れ入りますが再度お試しください。<br><br>');
        },
        complete:function(){
            $('.put_btn').spinner('remove');
        }
    });
}

どうももうSpinnerプラグインは削除されてるっぽい??再掲。

/*
    Spinner provides a simple approach for adding and removing a preloader
    for your web applications. Usage is as simple as calling $('elem').spinner() and
    subsequently $('elem').spinner.remove(). You may create your own preloader
    at http://www.ajaxload.info. Please note that if you use a custom preloader,
    you must pass in the new height and width as options.
    
    Copyright (C) 2010 Corey Ballou
    Website: http://www.jqueryin.com
    Documentation: http://www.jqueryin.com/projects/spinner-jquery-preloader-plugin/

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
(function($) {
    $.fn.spinner = function(options) {
        var opts = $.extend({}, $.fn.spinner.defaults, options);

        return this.each(function() {
            var l=0, t=0, w=0, h=0, shim=0, $s;
            var $this = $(this);
            
            // removal handling
            if (options == 'remove' || options == 'close') {
                var $s = $this.data('spinner');
                var o = $this.data('opts');
                if (typeof $s != 'undefined') {
                    $s.remove();
                    $this.removeData('spinner').removeData('opts');
                    if (o.hide) $this.css('visibility', 'visible');
                    o.onFinish.call(this);
                    return;
                }
            }
            
            // retrieve element positioning
            var pos = $this.offset();
            w = $this.outerWidth();
            h = $this.outerHeight();
            
            // calculate vertical centering
            if (h > opts.height) shim = Math.round((h - opts.height)/ 2);
            else if (h < opts.height) shim = 0 - Math.round((opts.height - h) / 2);
            t = pos.top + shim + 'px';
            
            // calculate horizontal positioning
            if (opts.position == 'right') {
                l = pos.left + w + 10 + 'px';
            } else if (opts.position == 'left') {
                l = pos.left - opts.width - 10 + 'px';
            } else {
                l = pos.left + Math.round(.5 * w) - Math.round(.5 * opts.width) + 'px';
            }
            
            // call start callback
            opts.onStart.call(this);
            
            // hide element?
            if (opts.hide) $this.css('visibility', 'hidden');
            
            // create the spinner and attach
            $s = $('<img src="' + opts.img + '" style="position: absolute; left: ' + l +'; top: ' + t + '; width: ' + opts.width + 'px; height: ' + opts.height + 'px; z-index: ' + opts.zIndex + ';" />').appendTo('body');
            
            // removal handling
            $this.data('spinner', $s).data('opts', opts);
        });
    };
    
    // default spinner options
    $.fn.spinner.defaults = {
        position    : 'right'       // left, right, center
        , img       : 'img/spinner.gif' // path to spinner img
        , height    : 16            // height of spinner img
        , width     : 16            // width of spinner img
        , zIndex    : 1001          // z-index of spinner
        , hide      : false         // whether to hide the elem
        , onStart   : function(){ } // start callback
        , onFinish  : function(){ } // end callback
    };
})(jQuery);