HTMLガイドブックはphpなのでFlaskでやってみた。この本は良書ですね、オススメです(最後のほうにNode.jsのサンプルも載ってるし)。
青い囲みの中にドラッグドロップするとアップロードされるが、ドラッグドロップAPIのためにスペースを用意するっていうのはなんかいまいちだなぁ。もうちょっと洗練されたドラッグドロップのインターフェースはないものかね。
ディレクトリ構成
$ tree
.
├── static
│ └── uploads
├── templates
│ └── index.html
└── uploader.py
サーバー側
from flask import Flask, request, url_for, render_template, make_response import os DEBUG = True SECRET_KEY = 'development key' UPLOAD_FOLDER = 'static/uploads' ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif']) app = Flask(__name__) app.config.from_object(__name__) def allowed_file(filename): return '.' in filename and \ filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS @app.route('/') def show_index(): return render_template('index.html') @app.route('/upload', methods=['POST']) def do_upload(): file = request.files['xhr2upload'] if file and allowed_file(file.filename): filename = file.filename file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) response = make_response(url_for('static', filename='uploads/'+filename, _external=True)) response.headers['Access-Control-Allow-Origin'] = '*' return response if __name__ == '__main__': app.run()
クライアント側(templates/index.html)
<!doctype html> <html> <head> <meta charset="utf-8"> <title>File Uploader</title> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.js"></script> <style> #dropbox { width: 500px; height: 200px; border: 1px solid blue; background: #eee; } #urllists { margin-top: 30px; width: 400px; height: 300px; overflow: auto; floar: left; boader: 1px solid blue; } #currentimage { margin-left: 420px; margin-top: 30px; } </style> </head> <body> <h1>File Uploader</h1> <div id=dropbox></div> <div id=urllists></div> <div id=currentimage></div> <script> var DnDUploader = function (base_id) { if(typeof(base_id) != "string" || base_id.length == 0 || document.getElementById(base_id) == null) return false; var __body = document.getElementsByTagName('body')[0]; var parent = document.getElementById(base_id); __body.addEventListener("drop", function(e){e.stopPropagation();e.preventDefault();}, false); __body.addEventListener("dragenter", function(e){e.stopPropagation();e.preventDefault();}, false); __body.addEventListener("dragover", function(e){e.stopPropagation();e.preventDefault();}, false); parent.addEventListener("drop", function(e){e.stopPropagation();e.preventDefault();_handleDrop(e);}, false); parent.addEventListener("dragenter", function(e){e.stopPropagation();e.preventDefault();}, false); parent.addEventListener("dragover", function(e){e.stopPropagation();e.preventDefault();}, false); var _handleDrop = function(e) { var x = e.layerX, y = e.layerY; var dt = e.dataTransfer, files = dt.files, count = files.length; var types = [ 'image/png', 'image/gif', 'image/jpeg' ]; for (var i=0; i < count; i++) { if (files[i].fileSize < 1048576) { var file = files[i]; var type = file.type; var filename = file.fileName; if($.inArray(file.type, types) == -1) { alert(file.type + 'はサポート外です。'); continue; } var reader = new FileReader(); reader.readAsDataURL(file); _upload(file); reader.onload = function(e) { var fileData = e.target.result; _drawImage(x, y, fileData); } } else { alert('ファイルが大きすぎます'); } } }; var _drawImage = function(x, y, file) { var imgElement = document.createElement('img'); imgElement.src = file; imgElement.style.position = 'absolute'; imgElement.style.display = 'none'; parent.appendChild(imgElement); setTimeout(function(e) { var o_w = imgElement.width; var o_h = imgElement.height; imgElement.width = o_w > 100 ? 100 : o_w; imgElement.height = parseInt( o_h * imgElement.width / o_w); var w = imgElement.width; var h = imgElement.height; imgElement.style.left = (x-w / 2)+'px'; imgElement.style.top = (y-h / 2)+'px'; imgElement.style.display = 'block'; },1); }; var _upload = function(file) { var fd = new FormData(); fd.append("xhr2upload", file); var xhr = new XMLHttpRequest() xhr.open("POST", "http://www.kzfmix.com:5000/upload"); xhr.send(fd); xhr.onload = function(e) { var url = e.target.responseText; $('#urllists').prepend('<p><a href="' + url + '">'+url+'</a></p>'); $('#currentimage').html('<img src="' +url+ '">'); } } } DnDUploader('dropbox'); </script> </body> </html>