//>>built
define("dojox/form/uploader/plugins/HTML5", [
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/_base/array",
"dojo"
],function(declare, lang, array, dojo){
var pluginsHTML5 = declare("dojox.form.uploader.plugins.HTML5", [], {
//
// Version: 1.6
//
// summary:
// A plugin for dojox.form.Uploader that adds HTML5 multiple-file upload capabilities and
// progress events.
//
// description:
// Add this plugin to have HTML5 capabilities in the Uploader. Note that it does not add
// these capabilities to browsers that don't support them. For IE or older browsers, add
// additional plugins: IFrame or Flash.
//
errMsg:"Error uploading files. Try checking permissions",
// Overwrites "form" and could possibly be overwritten again by iframe or flash plugin.
uploadType:"html5",
postCreate: function(){
this.connectForm();
this.inherited(arguments);
if(this.uploadOnSelect){
this.connect(this, "onChange", function(data){
this.upload(data[0]);
});
}
},
_drop: function(e){
dojo.stopEvent(e);
var dt = e.dataTransfer;
this._files = dt.files;
this.onChange(this.getFileList());
},
/*************************
* Public Methods *
*************************/
upload: function(/*Object ? */formData){
// summary:
// See: dojox.form.Uploader.upload
//
this.onBegin(this.getFileList());
if(this.supports("FormData")){
this.uploadWithFormData(formData);
}else if(this.supports("sendAsBinary")){
this.sendAsBinary(formData);
}
},
addDropTarget: function(node, /*Boolean?*/onlyConnectDrop){
// summary:
// Add a dom node which will act as the drop target area so user
// can drop files to this node.
// description:
// If onlyConnectDrop is true, dragenter/dragover/dragleave events
// won't be connected to dojo.stopEvent, and they need to be
// canceled by user code to allow DnD files to happen.
// This API is only available in HTML5 plugin (only HTML5 allows
// DnD files).
if(!onlyConnectDrop){
this.connect(node, 'dragenter', dojo.stopEvent);
this.connect(node, 'dragover', dojo.stopEvent);
this.connect(node, 'dragleave', dojo.stopEvent);
}
this.connect(node, 'drop', '_drop');
},
sendAsBinary: function(/* Object */data){
// summary:
// Used primarily in FF < 4.0. Sends files and form object as binary data, written to
// still enable use of $_FILES in PHP (or equivalent).
// tags:
// private
//
if(!this.getUrl()){
console.error("No upload url found.", this); return;
}
// The date/number doesn't matter but amount of dashes do. The actual boundary
// will have two more dashes than this one which is used in the header.
var boundary = "---------------------------" + (new Date).getTime();
var xhr = this.createXhr();
xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
// finally send the request as binary data
// still accessed as $_FILES
var msg = this._buildRequestBody(data, boundary);
if(!msg){
this.onError(this.errMsg);
}else{
console.log("msg:", msg)
console.log("xhr:", xhr)
xhr.sendAsBinary(msg);
}
},
uploadWithFormData: function(/* Object */data){
// summary
// Used with WebKit and Firefox 4+
// Upload files using the much friendlier FormData browser object.
// tags:
// private
//
if(!this.getUrl()){
console.error("No upload url found.", this); return;
}
var fd = new FormData();
array.forEach(this._files, function(f, i){
fd.append(this.name+"s[]", f);
}, this);
if(data){
for(var nm in data){
fd.append(nm, data[nm]);
}
}
var xhr = this.createXhr();
xhr.send(fd);
},
_xhrProgress: function(evt){
if(evt.lengthComputable){
var o = {
bytesLoaded:evt.loaded,
bytesTotal:evt.total,
type:evt.type,
timeStamp:evt.timeStamp
};
if(evt.type == "load"){
// 100%
o.percent = "100%",
o.decimal = 1;
}else{
o.decimal = evt.loaded / evt.total;
o.percent = Math.ceil((evt.loaded / evt.total)*100)+"%";
}
this.onProgress(o);
}
},
createXhr: function(){
var xhr = new XMLHttpRequest();
var timer;
xhr.upload.addEventListener("progress", lang.hitch(this, "_xhrProgress"), false);
xhr.addEventListener("load", lang.hitch(this, "_xhrProgress"), false);
xhr.addEventListener("error", lang.hitch(this, function(evt){
this.onError(evt);
clearInterval(timer);
}), false);
xhr.addEventListener("abort", lang.hitch(this, function(evt){
this.onAbort(evt);
clearInterval(timer);
}), false);
xhr.onreadystatechange = lang.hitch(this, function(){
if(xhr.readyState === 4){
// console.info("COMPLETE")
clearInterval(timer);
this.onComplete(JSON.parse(xhr.responseText.replace(/^\{\}&&/,'')));
}
});
xhr.open("POST", this.getUrl());
timer = setInterval(lang.hitch(this, function(){
try{
if(typeof(xhr.statusText)){} // accessing this error throws an error. Awesomeness.
}catch(e){
//this.onError("Error uploading file."); // not always an error.
clearInterval(timer);
}
}),250);
return xhr;
},
_buildRequestBody : function(data, boundary){
var EOL = "\r\n";
var part = "";
boundary = "--" + boundary;
var filesInError = [], files = this._files;
array.forEach(files, function(f, i){
var fieldName = this.name+"s[]";//+i;
var fileName = f.fileName;
var binary;
try{
binary = f.getAsBinary() + EOL;
part += boundary + EOL;
part += 'Content-Disposition: form-data; ';
part += 'name="' + fieldName + '"; ';
part += 'filename="'+ fileName + '"' + EOL;
part += "Content-Type: " + this.getMimeType() + EOL + EOL;
part += binary;
}catch(e){
filesInError.push({index:i, name:fileName});
}
}, this);
if(filesInError.length){
if(filesInError.length >= files.length){
// all files were bad. Nothing to upload.
this.onError({
message:this.errMsg,
filesInError:filesInError
});
part = false;
}
}
if(!part) return false;
if(data){
for(var nm in data){
part += boundary + EOL;
part += 'Content-Disposition: form-data; ';
part += 'name="' + nm + '"' + EOL + EOL;
part += data[nm] + EOL;
}
}
part += boundary + "--" + EOL;
return part;
}
});
dojox.form.addUploaderPlugin(pluginsHTML5);
return pluginsHTML5;
});