summaryrefslogtreecommitdiff
path: root/js/dojo/dojox/form/uploader
diff options
context:
space:
mode:
authorTristan Zur <tzur@web.web.ccwn.org>2014-03-27 22:27:47 +0100
committerTristan Zur <tzur@web.web.ccwn.org>2014-03-27 22:27:47 +0100
commitb62676ca5d3d6f6ba3f019ea3f99722e165a98d8 (patch)
tree86722cb80f07d4569f90088eeaea2fc2f6e2ef94 /js/dojo/dojox/form/uploader
Initial commit of intern.ccwn.org contentsHEADmaster
Diffstat (limited to 'js/dojo/dojox/form/uploader')
-rw-r--r--js/dojo/dojox/form/uploader/Base.js126
-rw-r--r--js/dojo/dojox/form/uploader/FileList.js202
-rw-r--r--js/dojo/dojox/form/uploader/plugins/Flash.js307
-rw-r--r--js/dojo/dojox/form/uploader/plugins/HTML5.js241
-rw-r--r--js/dojo/dojox/form/uploader/plugins/IFrame.js79
5 files changed, 955 insertions, 0 deletions
diff --git a/js/dojo/dojox/form/uploader/Base.js b/js/dojo/dojox/form/uploader/Base.js
new file mode 100644
index 0000000..4587c76
--- /dev/null
+++ b/js/dojo/dojox/form/uploader/Base.js
@@ -0,0 +1,126 @@
+//>>built
+define("dojox/form/uploader/Base", [
+ "dojo/dom-form",
+ "dojo/dom-style",
+ "dojo/dom-construct",
+ "dojo/dom-attr",
+ "dojo/has",
+ "dojo/_base/declare",
+ "dojo/_base/event",
+ "dijit/_Widget",
+ "dijit/_TemplatedMixin",
+ "dijit/_WidgetsInTemplateMixin"
+],function(domForm, domStyle, domConstruct, domAttr, has, declare, event, Widget, TemplatedMixin, WidgetsInTemplateMixin){
+
+has.add('FormData', function(){return !!window.FormData;});
+has.add("xhr-sendAsBinary", function(){var xhr=window.XMLHttpRequest && new window.XMLHttpRequest(); return xhr && !!xhr.sendAsBinary;});
+has.add("file-multiple", function(){return !!({'true':1,'false':1}[domAttr.get(document.createElement('input',{type:"file"}), 'multiple')]);});
+
+ /*=====
+ Widget = dijit._Widget;
+ TemplatedMixin = dijit._TemplatedMixin;
+ WidgetsInTemplateMixin = dijit._WidgetsInTemplateMixin;
+ =====*/
+return declare("dojox.form.uploader.Base", [Widget, TemplatedMixin, WidgetsInTemplateMixin], {
+ //
+ // Version: 1.6
+ //
+ // summary:
+ // The Base class used for dojox.form.Uploader and dojox.form.uploader.FileList.
+ //
+ // description:
+ // Should not be used as a standalone. To be mixed in with other classes.
+ //
+
+ getForm: function(){
+ // summary:
+ // Finds the parent form of the Uploader, if it exists.
+ //
+ if(!this.form){
+ var n = this.domNode;
+ while(n && n.tagName && n !== document.body){
+ if(n.tagName.toLowerCase() == "form"){
+ this.form = n;
+ break;
+ }
+ n = n.parentNode;
+ }
+ }
+ return this.form // Node;
+ },
+
+ getUrl: function(){
+ // summary:
+ // Finds the URL to upload to, whether it be the action in the parent form, this.url or
+ // this.uploadUrl
+ //
+ if(this.uploadUrl) this.url = this.uploadUrl;
+ if(this.url) return this.url;
+ if(this.getForm()) this.url = this.form.action;
+ return this.url; // String
+ },
+
+
+ connectForm: function(){
+ // summary:
+ // Internal. Connects to form if there is one.
+ //
+ this.url = this.getUrl();
+ if(!this._fcon && !!this.getForm()){
+ this._fcon = true;
+ this.connect(this.form, "onsubmit", function(evt){
+ event.stop(evt);
+ this.submit(this.form);
+ });
+ }
+ },
+
+ supports: function(what){
+ // summary:
+ // Does feature testing for uploader capabilities. (No browser sniffing - yay)
+ //
+ switch(what){
+ case "multiple":
+ if(this.force == "flash" || this.force == "iframe") return false;
+ return has("file-multiple");
+ case "FormData":
+ return has(what);
+ case "sendAsBinary":
+ return has("xhr-sendAsBinary");
+ }
+ return false; // Boolean
+ },
+ getMimeType: function(){
+ // summary:
+ // Returns the mime type that should be used in an HTML5 upload form. Return result
+ // may change as the current use is very generic.
+ //
+ return "application/octet-stream"; //image/gif
+ },
+ getFileType: function(/* String */name){
+ // summary:
+ // Gets the extension of a file
+ return name.substring(name.lastIndexOf(".")+1).toUpperCase(); // String
+ },
+ convertBytes: function(bytes){
+ // summary:
+ // Converts bytes. Returns an object with all conversions. The "value" property is
+ // considered the most likely desired result.
+ //
+ var kb = Math.round(bytes/1024*100000)/100000;
+ var mb = Math.round(bytes/1048576*100000)/100000;
+ var gb = Math.round(bytes/1073741824*100000)/100000;
+ var value = bytes;
+ if(kb>1) value = kb.toFixed(1)+" kb";
+ if(mb>1) value = mb.toFixed(1)+" mb";
+ if(gb>1) value = gb.toFixed(1)+" gb";
+ return {
+ kb:kb,
+ mb:mb,
+ gb:gb,
+ bytes:bytes,
+ value: value
+ }; // Object
+ }
+});
+});
diff --git a/js/dojo/dojox/form/uploader/FileList.js b/js/dojo/dojox/form/uploader/FileList.js
new file mode 100644
index 0000000..ed17c33
--- /dev/null
+++ b/js/dojo/dojox/form/uploader/FileList.js
@@ -0,0 +1,202 @@
+//>>built
+define("dojox/form/uploader/FileList", [
+ "dojo/_base/fx",
+ "dojo/dom-style",
+ "dojo/dom-class",
+ "dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dijit/_base/manager",
+ "dojox/form/uploader/Base"
+],function(fx, domStyle, domClass, declare, lang, array, manager, formUploaderBase){
+
+ /*=====
+ formUploaderBase = dojox.form.uploader.Base;
+ =====*/
+return declare("dojox.form.uploader.FileList", [formUploaderBase], {
+ //
+ // Version: 1.6
+ //
+ // summary:
+ // A simple widget that provides a list of the files currently selected by
+ // dojox.form.Uploader
+ //
+ // description:
+ // There is a required CSS file: resources/UploaderFileList.css.
+ // This is a very simple widget, and not beautifully styled. It is here mainly for test
+ // cases, but could very easily be used, extended, modified, or copied.
+ //
+ // uploaderId: String
+ // The id of the dojox.form.Uploader to connect to.
+ uploaderId:"",
+ // uploader: dojox.form.Uploader
+ // The dojox.form.Uploader to connect to. Use either this property of unploaderId. This
+ // property is populated if uploaderId is used.
+ //
+ uploader:null,
+ // headerIndex: String
+ // The label for the index column.
+ //
+ headerIndex:"#",
+ // headerType: String
+ // The label for the file type column.
+ //
+ headerType:"Type",
+ // headerFilename: String
+ // The label for the file name column.
+ //
+ headerFilename:"File Name",
+ // headerFilesize: String
+ // The label for the file size column.
+ //
+ headerFilesize:"Size",
+
+ _upCheckCnt:0,
+ rowAmt:0,
+
+ templateString: '<div class="dojoxUploaderFileList">' +
+ '<div dojoAttachPoint="progressNode" class="dojoxUploaderFileListProgress"><div dojoAttachPoint="percentBarNode" class="dojoxUploaderFileListProgressBar"></div><div dojoAttachPoint="percentTextNode" class="dojoxUploaderFileListPercentText">0%</div></div>' +
+ '<table class="dojoxUploaderFileListTable">'+
+ '<thead><tr class="dojoxUploaderFileListHeader"><th class="dojoxUploaderIndex">${headerIndex}</th><th class="dojoxUploaderIcon">${headerType}</th><th class="dojoxUploaderFileName">${headerFilename}</th><th class="dojoxUploaderFileSize" dojoAttachPoint="sizeHeader">${headerFilesize}</th></tr></thead>'+
+ '<tbody class="dojoxUploaderFileListContent" dojoAttachPoint="listNode">'+
+ '</tbody>'+
+ '</table>'+
+ '<div>'
+ ,
+
+ postCreate: function(){
+ this.setUploader();
+ this.hideProgress();
+ },
+
+ reset: function(){
+ // summary:
+ // Clears all rows of items. Happens automatically if Uploader is reset, but you
+ // could call this directly.
+ //
+ for(var i=0;i<this.rowAmt;i++){
+ this.listNode.deleteRow(0);
+ }
+ this.rowAmt = 0;
+ },
+
+ setUploader: function(){
+ // summary:
+ // Connects to the Uploader based on the uploader or the uploaderId properties.
+ //
+ if(!this.uploaderId && !this.uploader){
+ console.warn("uploaderId not passed to UploaderFileList");
+ }else if(this.uploaderId && !this.uploader){
+ this.uploader = manager.byId(this.uploaderId);
+ }else if(this._upCheckCnt>4){
+ console.warn("uploader not found for ID ", this.uploaderId);
+ return;
+ }
+ if(this.uploader){
+ this.connect(this.uploader, "onChange", "_onUploaderChange");
+ this.connect(this.uploader, "reset", "reset");
+ this.connect(this.uploader, "onBegin", function(){
+ this.showProgress(true);
+ });
+ this.connect(this.uploader, "onProgress", "_progress");
+ this.connect(this.uploader, "onComplete", function(){
+ setTimeout(lang.hitch(this, function(){
+ this.hideProgress(true);
+ }), 1250);
+ });
+ if(!(this._fileSizeAvail = {'html5':1,'flash':1}[this.uploader.uploadType])){
+ //if uploadType is neither html5 nor flash, file size is not available
+ //hide the size header
+ this.sizeHeader.style.display="none";
+ }
+ }else{
+ this._upCheckCnt++;
+ setTimeout(lang.hitch(this, "setUploader"), 250);
+ }
+ },
+
+ hideProgress: function(/* Boolean */animate){
+ var o = animate ? {
+ ani:true,
+ endDisp:"none",
+ beg:15,
+ end:0
+ } : {
+ endDisp:"none",
+ ani:false
+ };
+ this._hideShowProgress(o);
+ },
+
+ showProgress: function(/* Boolean */animate){
+ var o = animate ? {
+ ani:true,
+ endDisp:"block",
+ beg:0,
+ end:15
+ } : {
+ endDisp:"block",
+ ani:false
+ };
+ this._hideShowProgress(o);
+ },
+
+ _progress: function(/* Object */ customEvent){
+ this.percentTextNode.innerHTML = customEvent.percent;
+ domStyle.set(this.percentBarNode, "width", customEvent.percent);
+ },
+
+ _hideShowProgress: function(o){
+ var node = this.progressNode;
+ var onEnd = function(){
+ domStyle.set(node, "display", o.endDisp);
+ }
+ if(o.ani){
+ domStyle.set(node, "display", "block");
+ fx.animateProperty({
+ node: node,
+ properties:{
+ height:{
+ start:o.beg,
+ end:o.end,
+ units:"px"
+ }
+ },
+ onEnd:onEnd
+ }).play();
+ }else{
+ onEnd();
+ }
+ },
+
+ _onUploaderChange: function(fileArray){
+ this.reset();
+ array.forEach(fileArray, function(f, i){
+ this._addRow(i+1, this.getFileType(f.name), f.name, f.size);
+ }, this)
+ },
+
+ _addRow: function(index, type, name, size){
+
+ var c, r = this.listNode.insertRow(-1);
+ c = r.insertCell(-1);
+ domClass.add(c, "dojoxUploaderIndex");
+ c.innerHTML = index;
+
+ c = r.insertCell(-1);
+ domClass.add(c, "dojoxUploaderIcon");
+ c.innerHTML = type;
+
+ c = r.insertCell(-1);
+ domClass.add(c, "dojoxUploaderFileName");
+ c.innerHTML = name;
+ if(this._fileSizeAvail){
+ c = r.insertCell(-1);
+ domClass.add(c, "dojoxUploaderSize");
+ c.innerHTML = this.convertBytes(size).value;
+ }
+
+ this.rowAmt++;
+ }
+});
+});
diff --git a/js/dojo/dojox/form/uploader/plugins/Flash.js b/js/dojo/dojox/form/uploader/plugins/Flash.js
new file mode 100644
index 0000000..473410b
--- /dev/null
+++ b/js/dojo/dojox/form/uploader/plugins/Flash.js
@@ -0,0 +1,307 @@
+//>>built
+define("dojox/form/uploader/plugins/Flash", [
+ "dojo/dom-form",
+ "dojo/dom-style",
+ "dojo/dom-construct",
+ "dojo/dom-attr",
+ "dojo/_base/declare",
+ "dojo/_base/config",
+ "dojo/_base/connect",
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dojox/form/uploader/plugins/HTML5",
+ "dojox/embed/Flash"
+],function(domForm, domStyle, domConstruct, domAttr, declare, config, connect, lang, array, formUploaderPluginsHTML5, embedFlash){
+
+
+var pluginsFlash = declare("dojox.form.uploader.plugins.Flash", [], {
+ //
+ // Version: 1.6
+ //
+ // summary:
+ // A plugin for dojox.form.Uploader that utilizes a Flash SWF for handling to upload in IE.
+ // All other browsers will use the HTML5 plugin, unless force="flash" is used, then Flash
+ // will be used in all browsers. force="flash" is provided because Flash has some features
+ // that HTML5 does not yet have. But it is still not recommended because of the many problems
+ // that Firefox and Webkit have with the Flash plugin.
+ //
+ // description:
+ // Inherits all properties from dojox.form.Uploader and formUploaderPluginsHTML5.
+ // All properties and methods listed here are specific to the Flash plugin only.
+ //
+ // swfPath:String
+ // Path to SWF. Can be overwritten or provided in djConfig.
+ swfPath:config.uploaderPath || require.toUrl("dojox/form/resources/uploader.swf"),
+ //
+ // skipServerCheck: Boolean
+ // If true, will not verify that the server was sent the correct format.
+ // This can be safely set to true. The purpose of the server side check
+ // is mainly to show the dev if they've implemented the different returns
+ // correctly.
+ skipServerCheck:true,
+ //
+ // serverTimeout:Number (milliseconds)
+ // The amount of time given to the uploaded file
+ // to wait for a server response. After this amount
+ // of time, the onComplete is fired but with a 'server timeout'
+ // error in the returned item.
+ serverTimeout: 2000,
+ //
+ // isDebug: Boolean
+ // If true, outputs traces from the SWF to console. What exactly gets passed
+ // is very relative, and depends upon what traces have been left in the DEFT SWF.
+ isDebug:false,
+ //
+ // devMode: Boolean.
+ // Re-implemented. devMode increases the logging, adding style tracing from the SWF.
+ devMode:false,
+ //
+ // deferredUploading: Number (1 - X)
+ // (Flash only) throttles the upload to a certain amount of files at a time.
+ // By default, Flash uploads file one at a time to the server, but in parallel.
+ // Firefox will try to queue all files at once, leading to problems. Set this
+ // to the amount to upload in parallel at a time.
+ // Generally, 1 should work fine, but you can experiment with queuing more than
+ // one at a time.
+ // This is of course ignored if selectMultipleFiles equals false.
+ deferredUploading:0,
+ //
+ // force: String
+ // Use "flash" to always use Flash (and hopefully force the user to download the plugin
+ // if they don't have it).
+ force:"",
+
+ postMixInProperties: function(){
+ if(!this.supports("multiple")){
+ // Flash will only be used in IE6-8 unless force="flash"
+ this.uploadType = "flash";
+ this._files = [];
+ this._fileMap = {};
+ this._createInput = this._createFlashUploader;
+ this.getFileList = this.getFlashFileList;
+ this.reset = this.flashReset;
+ this.upload = this.uploadFlash;
+ this.fieldname = "flashUploadFiles"; ///////////////////// this.name
+ }
+ this.inherited(arguments);
+ },
+
+ /*************************
+ * Public Events *
+ *************************/
+
+ onReady: function(/* dojox.form.FileUploader */ uploader){
+ // summary:
+ // Stub - Fired when embedFlash has created the
+ // Flash object, but it has not necessarilly finished
+ // downloading, and is ready to be communicated with.
+ },
+
+ onLoad: function(/* dojox.form.FileUploader */ uploader){
+ // summary:
+ // Stub - SWF has been downloaded 100%.
+ },
+
+ onFileChange: function(fileArray){
+ // summary:
+ // Stub - Flash-specific event. Fires on each selection of files
+ // and only provides the files selected on that event - not all files
+ // selected, as with HTML5
+ },
+
+ onFileProgress: function(fileArray){
+ // summary:
+ // Stub - Flash-specific event. Fires on progress of upload
+ // and only provides a file-specific event
+ },
+
+
+ /*************************
+ * Public Methods *
+ *************************/
+
+ getFlashFileList: function(){
+ // summary:
+ // Returns list of currently selected files
+ return this._files; // Array
+ },
+
+ flashReset: function(){
+ this.flashMovie.reset();
+ this._files = [];
+ },
+
+ /*************************
+ * Private Methods *
+ *************************/
+
+ uploadFlash: function(/*Object ? */formData){
+ // summary:
+ // Uploads selected files. Alias "upload()" should be used instead.
+ // tags:
+ // private
+ this.onBegin(this.getFileList());
+ this.flashMovie.doUpload(formData);
+ },
+
+ _change: function(fileArray){
+ this._files = this._files.concat(fileArray);
+ array.forEach(fileArray, function(f){
+ f.bytesLoaded = 0;
+ f.bytesTotal = f.size;
+ this._fileMap[f.name+"_"+f.size] = f;
+ }, this);
+ this.onChange(this._files);
+ this.onFileChange(fileArray);
+ },
+ _complete: function(fileArray){
+ var o = this._getCustomEvent();
+ o.type = "load";
+ this.onComplete(fileArray);
+ },
+ _progress: function(f){
+ this._fileMap[f.name+"_"+f.bytesTotal].bytesLoaded = f.bytesLoaded;
+ var o = this._getCustomEvent();
+ this.onFileProgress(f);
+ this.onProgress(o);
+ },
+ _error: function(err){
+ this.onError(err);
+ },
+ _onFlashBlur: function(fileArray){
+ //console.log("UploaderFlash._onFlashBlur");
+ },
+
+ _getCustomEvent: function(){
+ var o = {
+ bytesLoaded:0,
+ bytesTotal:0,
+ type:"progress",
+ timeStamp:new Date().getTime()
+ };
+
+
+ for(var nm in this._fileMap){
+ o.bytesTotal += this._fileMap[nm].bytesTotal;
+ o.bytesLoaded += this._fileMap[nm].bytesLoaded;
+ }
+ o.decimal = o.bytesLoaded / o.bytesTotal;
+ o.percent = Math.ceil((o.bytesLoaded / o.bytesTotal)*100)+"%";
+ return o; // Object
+ },
+
+ _connectFlash: function(){
+ // summary:
+ // Subscribing to published topics coming from the
+ // Flash uploader.
+ // description:
+ // Sacrificing some readbilty for compactness. this.id
+ // will be on the beginning of the topic, so more than
+ // one uploader can be on a page and can have unique calls.
+ //
+
+ this._subs = [];
+ this._cons = [];
+
+ var doSub = lang.hitch(this, function(s, funcStr){
+ this._subs.push(connect.subscribe(this.id + s, this, funcStr));
+ });
+
+ doSub("/filesSelected", "_change");
+ doSub("/filesUploaded", "_complete");
+ doSub("/filesProgress", "_progress");
+ doSub("/filesError", "_error");
+ doSub("/filesCanceled", "onCancel");
+ doSub("/stageBlur", "_onFlashBlur");
+
+ this.connect(this.domNode, "focus", function(){
+ // TODO: some kind of indicator that the Flash button
+ // is in focus
+ this.flashMovie.focus();
+ this.flashMovie.doFocus();
+ });
+ if(this.tabIndex>=0){
+ domAttr.set(this.domNode, "tabIndex", this.tabIndex);
+ }
+ },
+ _createFlashUploader: function(){
+ // summary:
+ // Internal. Creates Flash Uploader
+ //
+ var url = this.getUrl();
+ if(url){
+ if(url.toLowerCase().indexOf("http")<0 && url.indexOf("/")!=0){
+ // Appears to be a relative path. Attempt to
+ // convert it to absolute, so it will better
+ //target the SWF.
+ //
+ var loc = window.location.href.split("/");
+ loc.pop();
+ loc = loc.join("/")+"/";
+ url = loc+url;
+ }
+ }else{
+ console.warn("Warning: no uploadUrl provided.");
+ }
+
+ this.inputNode = domConstruct.create("div", {className:"dojoxFlashNode"}, this.domNode, "first");
+ domStyle.set(this.inputNode, {
+ position:"absolute",
+ top:"-2px",
+ width:this.btnSize.w+"px",
+ height:this.btnSize.h+"px",
+ opacity:0
+ });
+
+ var w = this.btnSize.w;
+ var h = this.btnSize.h;
+
+ var args = {
+ expressInstall:true,
+ path: (this.swfPath.uri || this.swfPath) + "?cb_" + (new Date().getTime()),
+ width: w,
+ height: h,
+ allowScriptAccess:"always",
+ allowNetworking:"all",
+ vars: {
+ uploadDataFieldName: this.flashFieldName || this.name+"Flash",
+ uploadUrl: url,
+ uploadOnSelect: this.uploadOnSelect,
+ deferredUploading:this.deferredUploading || 0,
+ selectMultipleFiles: this.multiple,
+ id: this.id,
+ isDebug: this.isDebug,
+ noReturnCheck: this.skipServerCheck,
+ serverTimeout:this.serverTimeout
+ },
+ params: {
+ scale:"noscale",
+ wmode:"transparent",
+ wmode:"opaque",
+ allowScriptAccess:"always",
+ allowNetworking:"all"
+ }
+
+ };
+
+ this.flashObject = new embedFlash(args, this.inputNode);
+ this.flashObject.onError = lang.hitch(function(msg){
+ console.error("Flash Error: " + msg);
+ });
+ this.flashObject.onReady = lang.hitch(this, function(){
+ this.onReady(this);
+ });
+ this.flashObject.onLoad = lang.hitch(this, function(mov){
+ this.flashMovie = mov;
+ this.flashReady = true;
+
+ this.onLoad(this);
+ });
+ this._connectFlash();
+ }
+});
+dojox.form.addUploaderPlugin(pluginsFlash);
+
+
+return pluginsFlash;
+});
diff --git a/js/dojo/dojox/form/uploader/plugins/HTML5.js b/js/dojo/dojox/form/uploader/plugins/HTML5.js
new file mode 100644
index 0000000..cf16ccc
--- /dev/null
+++ b/js/dojo/dojox/form/uploader/plugins/HTML5.js
@@ -0,0 +1,241 @@
+//>>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;
+});
diff --git a/js/dojo/dojox/form/uploader/plugins/IFrame.js b/js/dojo/dojox/form/uploader/plugins/IFrame.js
new file mode 100644
index 0000000..93f5e7e
--- /dev/null
+++ b/js/dojo/dojox/form/uploader/plugins/IFrame.js
@@ -0,0 +1,79 @@
+//>>built
+define("dojox/form/uploader/plugins/IFrame", [
+ "dojo/dom-construct",
+ "dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojo/_base/array",
+ "dojo/io/iframe",
+ "dojox/form/uploader/plugins/HTML5"
+],function(domConstruct, declare, lang, array, ioIframe, formUploaderPluginsHTML5){
+
+
+var pluginsIFrame = declare("dojox.form.uploader.plugins.IFrame", [], {
+ //
+ // Version: 1.6
+ //
+ // summary:
+ // A plugin for dojox.form.Uploader that adds Ajax upload capabilities.
+ //
+ // description:
+ // Only supported by IE, due to the specifc iFrame hack used. The
+ // formUploaderPluginsHTML5 plugin should be used along with this to add HTML5
+ // capabilities to browsers that support them. Progress events are not supported.
+ // Inherits all properties from dojox.form.Uploader and formUploaderPluginsHTML5.
+ //
+
+ force:"",
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ if(!this.supports("multiple") || this.force =="iframe"){
+ this.uploadType = "iframe";
+ this.upload = this.uploadIFrame;
+ }
+ },
+
+ uploadIFrame: function(data){
+ // summary:
+ // Internal. You could use this, but you should use upload() or submit();
+ // which can also handle the post data.
+ //
+ var form, destroyAfter = false;
+ if(!this.getForm()){
+ //enctype can't be changed once a form element is created
+ form = domConstruct.place('<form enctype="multipart/form-data" method="post"></form>', this.domNode);
+ array.forEach(this._inputs, function(n, i){
+ if(n.value) form.appendChild(n);
+ }, this);
+ destroyAfter = true;
+ }else{
+ form = this.form;
+ }
+
+ var url = this.getUrl();
+
+ var dfd = ioIframe.send({
+ url: url,
+ form: form,
+ handleAs: "json",
+ content: data,
+ error: lang.hitch(this, function(err){
+ if(destroyAfter){ domConstruct.destroy(form); }
+ this.onError(err);
+ }),
+ load: lang.hitch(this, function(data, ioArgs, widgetRef){
+ if(destroyAfter){ domConstruct.destroy(form); }
+ if(data["ERROR"] || data["error"]){
+ this.onError(data);
+ }else{
+ this.onComplete(data);
+ }
+ })
+ });
+ }
+});
+
+dojox.form.addUploaderPlugin(pluginsIFrame);
+
+return pluginsIFrame;
+});