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>