sus-happy
1/15/2015 - 12:53 AM

Local File Drag to Browser

Local File Drag to Browser

( function( global, U ) {
    "use strict";

    // 必要条件に満たしていなければ終了
    if (
        ! Element.prototype.addEventListener ||
        ! document.querySelector
    ) {
        return;
    }

    function DROP_FILES( events ) {
        this._construct( events );
    }

    // interface ----------------------------------------------
    DROP_FILES['prototype']['_construct'] = DROP_FILES_construct;
    // 個別イベント指定
    DROP_FILES['prototype']['setEvent']   = DROP_FILES_setEvent;
    // CSS指定
    DROP_FILES['prototype']['setCss']     = DROP_FILES_setCss;
    // 汎用関数
    DROP_FILES['prototype']['mix']        = DROP_FILES_mix;
    DROP_FILES['prototype']['fill']       = DROP_FILES_fill;
    DROP_FILES['prototype']['getType']    = DROP_FILES_getType;
    DROP_FILES['prototype']['isFunction'] = DROP_FILES_isFunction;

    // construct ----------------------------------------------
    function DROP_FILES_construct( events ) {
        var that = this;

        // コールバック関数群
        this._callbacks = {
            over:  null,
            leave: null,
            drop:  null
        };
        // 引数をオーバライド
        if( events ) this.fill( this._callbacks, events );

        // #drop_maskのDOMが存在していれば追加しない
        var drop_mask = document.querySelector( '#drop_mask' );
        if( drop_mask !== null ) {
            this.$mask = drop_mask;
        } else {
            // ドロップエリア
            drop_mask = document.createElement( 'div' );
            drop_mask.id = 'drop_mask';

            // CSSを定義する
            this.mix( drop_mask.style, {
                position:   'fixed',
                height:     '100%',
                width:      '100%',
                top:        '0',
                left:       '0',
                background: 'rgba(255,240,0,.5)',
                display:    'none',
                zIndex:     '1'
            } );
            this.$mask = drop_mask;

            // bodyの最後に追加
            document.body.style.height = '100%';
            document.getElementsByTagName('html')[0].style.height = '100%';
            document.body.appendChild( drop_mask );
        }

        // ドラッグ処理
        // ファイルを運んできているか判定するだけ
        document.body.addEventListener( 'dragover', function( e ) {
            // 通常イベントは発火させない
            e.stopPropagation();
            e.preventDefault();
            // ドロップマスクを表示
            that.$mask.style.display = 'block';

            // over 関数が設定してある?
            if( that.isFunction( that._callbacks.over ) ) {
                that._callbacks.over( e );
            }
        }, false );

        // ドラッグアウトはマスク要素に
        this.$mask.addEventListener( 'dragleave', function( e ) {
            // 通常イベントは発火させない
            e.stopPropagation();
            e.preventDefault();
            // ドロップマスクを隠す
            that.$mask.style.display = 'none';

            // leave 関数が設定してある?
            if( that.isFunction( that._callbacks.leave ) ) {
                that._callbacks.leave( e );
            }
        }, false );

        // ドロップ処理
        this.$mask.addEventListener( 'drop', function( e ) {
            // 通常イベントは発火させない
            e.stopPropagation();
            e.preventDefault();
            // ドロップマスクを隠す
            that.$mask.style.display = 'none';

            // drop 関数が設定してある?
            if( that.isFunction( that._callbacks.drop ) ) {
                that._callbacks.drop( e );
            }
        }, false );
    }

    // implements ----------------------------------------------

    // 関数の個別指定
    function DROP_FILES_setEvent( tgt, func ) {
        if( this._callbacks[ tgt ] !== U ) {
            this._callbacks[ tgt ] = func;
        }
    }

    // マスクのCSSを書き換え
    function DROP_FILES_setCss() {
        var key = arguments[0];
        // 第一引数がobjectなら複数指定
        if( this.getType( key ) === 'object' ) {
            var i;
            for( i in key ) {
                if( key.hasOwnProperty( i ) ) {
                    this.setCss( i, key[ i ] );
                }
            }
        } else {
            // CSSのキーのハイフンを取ってキャメルケースに
            var tmp = key.split( '-' );
            for( var j=1, k=tmp.length; j<k; j++ ) {
                tmp[j] = tmp[j].charAt(0).toUpperCase() + tmp[j].slice(1);
            }
            key = tmp.join( '' );
            this.$mask.style[ key ] = arguments[1];
        }
    }

    // 元オブジェクトにプロパティが無くても合成
    function DROP_FILES_mix( a, b ) {
        var i;
        for( i in b ) {
            if( b.hasOwnProperty( i ) ) {
                a[i] = b[i];
            }
        }
        return a;
    }

    // 元オブジェクトにプロパティが無かったら合成しない
    function DROP_FILES_fill( a, b ) {
        var i;
        for( i in b ) {
            if( b.hasOwnProperty( i ) ) {
                i in a || ( a[i] = b[i] );
            }
        }
        return a;
    }

    // 変数型を取得
    // 変数型対応値
    var class2type = {
        '[object Boolean]'  : 'boolean',
        '[object Number]'   : 'number',
        '[object String]'   : 'string',
        '[object Function]' : 'function',
        '[object Array]'    : 'array',
        '[object Date]'     : 'date',
        '[object RegExp]'   : 'regExp',
        '[object Object]'   : 'object',
        '[object Error]'    : 'error',
    };
    function DROP_FILES_getType( obj ) {
        if ( obj == null ) {
            return obj + "";
        }
        return typeof obj === "object" || typeof obj === "function" ?
            class2type[ toString.call(obj) ] || "object" :
            typeof obj;
    };

    // 変数が関数かどうか
    function DROP_FILES_isFunction( fn ) {
        return this.getType( fn ) === 'function';
    }


    // Exports ----------------------------------------------
    if ("process" in global) {
        module["exports"] = DROP_FILES;
    }
    global["DROP_FILES"] = DROP_FILES;

} )( (this || 0).self || global );