addon/utils/ember-uploader.js

  1. // this file contains source code from https://github.com/benefitcloud/ember-uploader
  2. // thanks to this great project
  3.  
  4. import { get, set } from '@ember/object';
  5. import EmberObject from '@ember/object';
  6. import Evented from '@ember/object/evented';
  7. import { isArray } from '@ember/array';
  8. import { Promise } from 'rsvp';
  9. import { run } from '@ember/runloop';
  10. import $ from 'jquery';
  11.  
  12.  
  13.  
  14.  
  15. /**
  16. EmberUploader class
  17.  
  18. @module utils
  19. @namespace utils
  20. @class EmberUploader
  21. @constructor
  22. */
  23. export default EmberObject.extend(Evented, {
  24. /**
  25. * upload url
  26. *
  27. * @property {String} url
  28. *
  29. */
  30. url: null,
  31. paramNamespace: null,
  32. /**
  33. * upload file parameter name
  34. *
  35. * @property {String} paramName
  36. * @default 'file'
  37. */
  38. paramName: 'file',
  39. /**
  40. * ajax request settings traditional, by default false
  41. *
  42. * @property {Boolean} traditional
  43. * @default true
  44. */
  45. traditional: true,
  46.  
  47. /**
  48. * ajax request status
  49. *
  50. * @property {Boolean} isUploading
  51. * @default false
  52. */
  53. isUploading: false,
  54.  
  55. /**
  56. * ajax request type (method), by default it will be POST
  57. *
  58. * @property {String} type
  59. * @default 'POST'
  60. */
  61. type: 'POST',
  62.  
  63. /**
  64. * Start upload of files and extra data
  65. *
  66. * @param {object|array} files One file object or one array of files object
  67. * @param {array} extra
  68. * @return {object} jquery promise from ajax object
  69. */
  70. upload: function(files, extra) {
  71. extra = extra || {};
  72. var data = this.setupFormData(files, extra);
  73. var url = get(this, 'url');
  74. var type = get(this, 'type');
  75. set(this, 'isUploading', true);
  76.  
  77. return this.ajax(url, data, type);
  78. },
  79.  
  80. setupFormData: function(files, extra) {
  81. var formData = new FormData();
  82.  
  83. for (var prop in extra) {
  84. if (extra.hasOwnProperty(prop)) {
  85. formData.append(this.toNamespacedParam(prop), extra[prop]);
  86. }
  87. }
  88.  
  89. // if is a array of files ...
  90. if (isArray(files)) {
  91. var paramName;
  92.  
  93. for (var i = files.length - 1; i >= 0; i--) {
  94. if(get(this, 'traditional')){
  95. paramName = this.toNamespacedParam(this.paramName);
  96. }else {
  97. paramName = this.toNamespacedParam(this.paramName) + '[' + i + ']';
  98. }
  99. formData.append(paramName , files[i]);
  100. }
  101. } else {
  102. // if has only one file object ...
  103. formData.append(this.toNamespacedParam(this.paramName), files);
  104. }
  105.  
  106. return formData;
  107. },
  108.  
  109. toNamespacedParam: function(name) {
  110. if (this.paramNamespace) {
  111. return this.paramNamespace + '[' + name + ']';
  112. }
  113.  
  114. return name;
  115. },
  116.  
  117. didUpload: function(data) {
  118. set(this, 'isUploading', false);
  119. this.trigger('didUpload', data);
  120. return data;
  121. },
  122.  
  123. didError: function(jqXHR, textStatus, errorThrown) {
  124. set(this, 'isUploading', false);
  125.  
  126. // Borrowed from Ember Data
  127. var isObject = jqXHR !== null && typeof jqXHR === 'object';
  128.  
  129. if (isObject) {
  130. jqXHR.then = null;
  131. if (!jqXHR.errorThrown) {
  132. if (typeof errorThrown === 'string') {
  133. jqXHR.errorThrown = new Error(errorThrown);
  134. } else {
  135. jqXHR.errorThrown = errorThrown;
  136. }
  137. }
  138. }
  139.  
  140. this.trigger('didError', jqXHR, textStatus, errorThrown);
  141.  
  142. return jqXHR;
  143. },
  144.  
  145. didProgress: function(e) {
  146. e.percent = e.loaded / e.total * 100;
  147. this.trigger('progress', e);
  148. },
  149.  
  150. abort: function() {
  151. set(this, 'isUploading', false);
  152.  
  153. this.trigger('isAborting');
  154. },
  155.  
  156. ajaxSettings: function(url, params, method) {
  157. var self = this;
  158. return {
  159. url: url,
  160. type: method || 'POST',
  161. contentType: false,
  162. processData: false,
  163. traditional: get(self, 'traditional'),
  164. dataType: 'json',
  165. xhr: function() {
  166. var xhr = $.ajaxSettings.xhr();
  167. xhr.upload.onprogress = function(e) {
  168. self.didProgress(e);
  169. };
  170. self.one('isAborting', function() { xhr.abort(); });
  171. return xhr;
  172. },
  173. data: params
  174. };
  175. },
  176.  
  177. ajax: function(url, params, method) {
  178. return this._ajax(this.ajaxSettings(url, params, method));
  179. },
  180.  
  181. _ajax: function(settings) {
  182. var self = this;
  183.  
  184. return new Promise(function(resolve, reject) {
  185. settings.success = function(data) {
  186. run(null, resolve, self.didUpload(data));
  187. };
  188.  
  189. settings.error = function(jqXHR, responseText, errorThrown) {
  190. run(null, reject, self.didError(jqXHR, responseText, errorThrown));
  191. };
  192.  
  193. $.ajax(settings);
  194. });
  195. }
  196. });
  197.