HTML5.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. define("dojox/form/uploader/plugins/HTML5", [
  2. "dojo/_base/declare",
  3. "dojo/_base/lang",
  4. "dojo/_base/array",
  5. "dojo"
  6. ],function(declare, lang, array, dojo){
  7. var pluginsHTML5 = declare("dojox.form.uploader.plugins.HTML5", [], {
  8. //
  9. // Version: 1.6
  10. //
  11. // summary:
  12. // A plugin for dojox.form.Uploader that adds HTML5 multiple-file upload capabilities and
  13. // progress events.
  14. //
  15. // description:
  16. // Add this plugin to have HTML5 capabilities in the Uploader. Note that it does not add
  17. // these capabilities to browsers that don't support them. For IE or older browsers, add
  18. // additional plugins: IFrame or Flash.
  19. //
  20. errMsg:"Error uploading files. Try checking permissions",
  21. // Overwrites "form" and could possibly be overwritten again by iframe or flash plugin.
  22. uploadType:"html5",
  23. postCreate: function(){
  24. this.connectForm();
  25. this.inherited(arguments);
  26. if(this.uploadOnSelect){
  27. this.connect(this, "onChange", function(data){
  28. this.upload(data[0]);
  29. });
  30. }
  31. },
  32. _drop: function(e){
  33. dojo.stopEvent(e);
  34. var dt = e.dataTransfer;
  35. this._files = dt.files;
  36. this.onChange(this.getFileList());
  37. },
  38. /*************************
  39. * Public Methods *
  40. *************************/
  41. upload: function(/*Object ? */formData){
  42. // summary:
  43. // See: dojox.form.Uploader.upload
  44. //
  45. this.onBegin(this.getFileList());
  46. if(this.supports("FormData")){
  47. this.uploadWithFormData(formData);
  48. }else if(this.supports("sendAsBinary")){
  49. this.sendAsBinary(formData);
  50. }
  51. },
  52. addDropTarget: function(node, /*Boolean?*/onlyConnectDrop){
  53. // summary:
  54. // Add a dom node which will act as the drop target area so user
  55. // can drop files to this node.
  56. // description:
  57. // If onlyConnectDrop is true, dragenter/dragover/dragleave events
  58. // won't be connected to dojo.stopEvent, and they need to be
  59. // canceled by user code to allow DnD files to happen.
  60. // This API is only available in HTML5 plugin (only HTML5 allows
  61. // DnD files).
  62. if(!onlyConnectDrop){
  63. this.connect(node, 'dragenter', dojo.stopEvent);
  64. this.connect(node, 'dragover', dojo.stopEvent);
  65. this.connect(node, 'dragleave', dojo.stopEvent);
  66. }
  67. this.connect(node, 'drop', '_drop');
  68. },
  69. sendAsBinary: function(/* Object */data){
  70. // summary:
  71. // Used primarily in FF < 4.0. Sends files and form object as binary data, written to
  72. // still enable use of $_FILES in PHP (or equivalent).
  73. // tags:
  74. // private
  75. //
  76. if(!this.getUrl()){
  77. console.error("No upload url found.", this); return;
  78. }
  79. // The date/number doesn't matter but amount of dashes do. The actual boundary
  80. // will have two more dashes than this one which is used in the header.
  81. var boundary = "---------------------------" + (new Date).getTime();
  82. var xhr = this.createXhr();
  83. xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
  84. // finally send the request as binary data
  85. // still accessed as $_FILES
  86. var msg = this._buildRequestBody(data, boundary);
  87. if(!msg){
  88. this.onError(this.errMsg);
  89. }else{
  90. console.log("msg:", msg)
  91. console.log("xhr:", xhr)
  92. xhr.sendAsBinary(msg);
  93. }
  94. },
  95. uploadWithFormData: function(/* Object */data){
  96. // summary
  97. // Used with WebKit and Firefox 4+
  98. // Upload files using the much friendlier FormData browser object.
  99. // tags:
  100. // private
  101. //
  102. if(!this.getUrl()){
  103. console.error("No upload url found.", this); return;
  104. }
  105. var fd = new FormData();
  106. array.forEach(this._files, function(f, i){
  107. fd.append(this.name+"s[]", f);
  108. }, this);
  109. if(data){
  110. for(var nm in data){
  111. fd.append(nm, data[nm]);
  112. }
  113. }
  114. var xhr = this.createXhr();
  115. xhr.send(fd);
  116. },
  117. _xhrProgress: function(evt){
  118. if(evt.lengthComputable){
  119. var o = {
  120. bytesLoaded:evt.loaded,
  121. bytesTotal:evt.total,
  122. type:evt.type,
  123. timeStamp:evt.timeStamp
  124. };
  125. if(evt.type == "load"){
  126. // 100%
  127. o.percent = "100%",
  128. o.decimal = 1;
  129. }else{
  130. o.decimal = evt.loaded / evt.total;
  131. o.percent = Math.ceil((evt.loaded / evt.total)*100)+"%";
  132. }
  133. this.onProgress(o);
  134. }
  135. },
  136. createXhr: function(){
  137. var xhr = new XMLHttpRequest();
  138. var timer;
  139. xhr.upload.addEventListener("progress", lang.hitch(this, "_xhrProgress"), false);
  140. xhr.addEventListener("load", lang.hitch(this, "_xhrProgress"), false);
  141. xhr.addEventListener("error", lang.hitch(this, function(evt){
  142. this.onError(evt);
  143. clearInterval(timer);
  144. }), false);
  145. xhr.addEventListener("abort", lang.hitch(this, function(evt){
  146. this.onAbort(evt);
  147. clearInterval(timer);
  148. }), false);
  149. xhr.onreadystatechange = lang.hitch(this, function(){
  150. if(xhr.readyState === 4){
  151. // console.info("COMPLETE")
  152. clearInterval(timer);
  153. this.onComplete(JSON.parse(xhr.responseText.replace(/^\{\}&&/,'')));
  154. }
  155. });
  156. xhr.open("POST", this.getUrl());
  157. timer = setInterval(lang.hitch(this, function(){
  158. try{
  159. if(typeof(xhr.statusText)){} // accessing this error throws an error. Awesomeness.
  160. }catch(e){
  161. //this.onError("Error uploading file."); // not always an error.
  162. clearInterval(timer);
  163. }
  164. }),250);
  165. return xhr;
  166. },
  167. _buildRequestBody : function(data, boundary){
  168. var EOL = "\r\n";
  169. var part = "";
  170. boundary = "--" + boundary;
  171. var filesInError = [], files = this._files;
  172. array.forEach(files, function(f, i){
  173. var fieldName = this.name+"s[]";//+i;
  174. var fileName = f.fileName;
  175. var binary;
  176. try{
  177. binary = f.getAsBinary() + EOL;
  178. part += boundary + EOL;
  179. part += 'Content-Disposition: form-data; ';
  180. part += 'name="' + fieldName + '"; ';
  181. part += 'filename="'+ fileName + '"' + EOL;
  182. part += "Content-Type: " + this.getMimeType() + EOL + EOL;
  183. part += binary;
  184. }catch(e){
  185. filesInError.push({index:i, name:fileName});
  186. }
  187. }, this);
  188. if(filesInError.length){
  189. if(filesInError.length >= files.length){
  190. // all files were bad. Nothing to upload.
  191. this.onError({
  192. message:this.errMsg,
  193. filesInError:filesInError
  194. });
  195. part = false;
  196. }
  197. }
  198. if(!part) return false;
  199. if(data){
  200. for(var nm in data){
  201. part += boundary + EOL;
  202. part += 'Content-Disposition: form-data; ';
  203. part += 'name="' + nm + '"' + EOL + EOL;
  204. part += data[nm] + EOL;
  205. }
  206. }
  207. part += boundary + "--" + EOL;
  208. return part;
  209. }
  210. });
  211. dojox.form.addUploaderPlugin(pluginsHTML5);
  212. return pluginsHTML5;
  213. });