jquery.fileupload-fp.js 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * jQuery File Upload File Processing Plugin 1.2
  3. * https://github.com/blueimp/jQuery-File-Upload
  4. *
  5. * Copyright 2012, Sebastian Tschan
  6. * https://blueimp.net
  7. *
  8. * Licensed under the MIT license:
  9. * http://www.opensource.org/licenses/MIT
  10. */
  11. /*jslint nomen: true, unparam: true, regexp: true */
  12. /*global define, window, document */
  13. (function (factory) {
  14. 'use strict';
  15. if (typeof define === 'function' && define.amd) {
  16. // Register as an anonymous AMD module:
  17. define([
  18. 'jquery',
  19. 'load-image',
  20. 'canvas-to-blob',
  21. './jquery.fileupload'
  22. ], factory);
  23. } else {
  24. // Browser globals:
  25. factory(
  26. window.jQuery,
  27. window.loadImage
  28. );
  29. }
  30. }(function ($, loadImage) {
  31. 'use strict';
  32. // The File Upload FP version extends the fileupload widget
  33. // with file processing functionality:
  34. $.widget('blueimp.fileupload', $.blueimp.fileupload, {
  35. options: {
  36. // The list of file processing actions:
  37. process: [
  38. /*
  39. {
  40. action: 'load',
  41. fileTypes: /^image\/(gif|jpeg|png)$/,
  42. maxFileSize: 20000000 // 20MB
  43. },
  44. {
  45. action: 'resize',
  46. maxWidth: 1920,
  47. maxHeight: 1200,
  48. minWidth: 800,
  49. minHeight: 600
  50. },
  51. {
  52. action: 'save'
  53. }
  54. */
  55. ],
  56. // The add callback is invoked as soon as files are added to the
  57. // fileupload widget (via file input selection, drag & drop or add
  58. // API call). See the basic file upload widget for more information:
  59. add: function (e, data) {
  60. $(this).fileupload('process', data).done(function () {
  61. data.submit();
  62. });
  63. }
  64. },
  65. processActions: {
  66. // Loads the image given via data.files and data.index
  67. // as img element if the browser supports canvas.
  68. // Accepts the options fileTypes (regular expression)
  69. // and maxFileSize (integer) to limit the files to load:
  70. load: function (data, options) {
  71. var that = this,
  72. file = data.files[data.index],
  73. dfd = $.Deferred();
  74. if (window.HTMLCanvasElement &&
  75. window.HTMLCanvasElement.prototype.toBlob &&
  76. ($.type(options.maxFileSize) !== 'number' ||
  77. file.size < options.maxFileSize) &&
  78. (!options.fileTypes ||
  79. options.fileTypes.test(file.type))) {
  80. loadImage(
  81. file,
  82. function (img) {
  83. data.img = img;
  84. dfd.resolveWith(that, [data]);
  85. }
  86. );
  87. } else {
  88. dfd.rejectWith(that, [data]);
  89. }
  90. return dfd.promise();
  91. },
  92. // Resizes the image given as data.img and updates
  93. // data.canvas with the resized image as canvas element.
  94. // Accepts the options maxWidth, maxHeight, minWidth and
  95. // minHeight to scale the given image:
  96. resize: function (data, options) {
  97. var img = data.img,
  98. canvas;
  99. options = $.extend({canvas: true}, options);
  100. if (img) {
  101. canvas = loadImage.scale(img, options);
  102. if (canvas.width !== img.width ||
  103. canvas.height !== img.height) {
  104. data.canvas = canvas;
  105. }
  106. }
  107. return data;
  108. },
  109. // Saves the processed image given as data.canvas
  110. // inplace at data.index of data.files:
  111. save: function (data, options) {
  112. // Do nothing if no processing has happened:
  113. if (!data.canvas) {
  114. return data;
  115. }
  116. var that = this,
  117. file = data.files[data.index],
  118. name = file.name,
  119. dfd = $.Deferred(),
  120. callback = function (blob) {
  121. if (!blob.name) {
  122. if (file.type === blob.type) {
  123. blob.name = file.name;
  124. } else if (file.name) {
  125. blob.name = file.name.replace(
  126. /\..+$/,
  127. '.' + blob.type.substr(6)
  128. );
  129. }
  130. }
  131. // Store the created blob at the position
  132. // of the original file in the files list:
  133. data.files[data.index] = blob;
  134. dfd.resolveWith(that, [data]);
  135. };
  136. // Use canvas.mozGetAsFile directly, to retain the filename, as
  137. // Gecko doesn't support the filename option for FormData.append:
  138. if (data.canvas.mozGetAsFile) {
  139. callback(data.canvas.mozGetAsFile(
  140. (/^image\/(jpeg|png)$/.test(file.type) && name) ||
  141. ((name && name.replace(/\..+$/, '')) ||
  142. 'blob') + '.png',
  143. file.type
  144. ));
  145. } else {
  146. data.canvas.toBlob(callback, file.type);
  147. }
  148. return dfd.promise();
  149. }
  150. },
  151. // Resizes the file at the given index and stores the created blob at
  152. // the original position of the files list, returns a Promise object:
  153. _processFile: function (files, index, options) {
  154. var that = this,
  155. dfd = $.Deferred().resolveWith(that, [{
  156. files: files,
  157. index: index
  158. }]),
  159. chain = dfd.promise();
  160. that._processing += 1;
  161. $.each(options.process, function (i, settings) {
  162. chain = chain.pipe(function (data) {
  163. return that.processActions[settings.action]
  164. .call(this, data, settings);
  165. });
  166. });
  167. chain.always(function () {
  168. that._processing -= 1;
  169. if (that._processing === 0) {
  170. that.element
  171. .removeClass('fileupload-processing');
  172. }
  173. });
  174. if (that._processing === 1) {
  175. that.element.addClass('fileupload-processing');
  176. }
  177. return chain;
  178. },
  179. // Processes the files given as files property of the data parameter,
  180. // returns a Promise object that allows to bind a done handler, which
  181. // will be invoked after processing all files (inplace) is done:
  182. process: function (data) {
  183. var that = this,
  184. options = $.extend({}, this.options, data);
  185. if (options.process && options.process.length &&
  186. this._isXHRUpload(options)) {
  187. $.each(data.files, function (index, file) {
  188. that._processingQueue = that._processingQueue.pipe(
  189. function () {
  190. var dfd = $.Deferred();
  191. that._processFile(data.files, index, options)
  192. .always(function () {
  193. dfd.resolveWith(that);
  194. });
  195. return dfd.promise();
  196. }
  197. );
  198. });
  199. }
  200. return this._processingQueue;
  201. },
  202. _create: function () {
  203. this._super();
  204. this._processing = 0;
  205. this._processingQueue = $.Deferred().resolveWith(this)
  206. .promise();
  207. }
  208. });
  209. }));