|
1 | 1 | /* |
2 | | - * jQuery File Upload AngularJS Plugin 1.0.1 |
| 2 | + * jQuery File Upload AngularJS Plugin 1.4.4 |
3 | 3 | * https://github.com/blueimp/jQuery-File-Upload |
4 | 4 | * |
5 | 5 | * Copyright 2013, Sebastian Tschan |
|
10 | 10 | */ |
11 | 11 |
|
12 | 12 | /*jslint nomen: true, unparam: true */ |
13 | | -/*global angular */ |
| 13 | +/*global define, angular */ |
14 | 14 |
|
15 | | -(function () { |
| 15 | +(function (factory) { |
| 16 | + 'use strict'; |
| 17 | + if (typeof define === 'function' && define.amd) { |
| 18 | + // Register as an anonymous AMD module: |
| 19 | + define([ |
| 20 | + 'jquery', |
| 21 | + 'angular', |
| 22 | + './jquery.fileupload-image', |
| 23 | + './jquery.fileupload-audio', |
| 24 | + './jquery.fileupload-video', |
| 25 | + './jquery.fileupload-validate' |
| 26 | + ], factory); |
| 27 | + } else { |
| 28 | + factory(); |
| 29 | + } |
| 30 | +}(function () { |
16 | 31 | 'use strict'; |
17 | 32 |
|
18 | 33 | angular.module('blueimp.fileupload', []) |
19 | 34 |
|
| 35 | + // The fileUpload service provides configuration options |
| 36 | + // for the fileUpload directive and default handlers for |
| 37 | + // File Upload events: |
20 | 38 | .provider('fileUpload', function () { |
21 | 39 | var scopeApply = function () { |
22 | 40 | var scope = angular.element(this) |
23 | | - .fileupload('option', 'scope')(); |
24 | | - if (!scope.$$phase) { |
| 41 | + .fileupload('option', 'scope')(), |
| 42 | + $timeout = angular.injector(['ng']) |
| 43 | + .get('$timeout'); |
| 44 | + // Safe apply, makes sure $apply is called |
| 45 | + // asynchronously outside of the $digest cycle: |
| 46 | + $timeout(function () { |
25 | 47 | scope.$apply(); |
26 | | - } |
| 48 | + }); |
27 | 49 | }, |
28 | 50 | $config; |
29 | 51 | $config = this.defaults = { |
|
47 | 69 | submit = function () { |
48 | 70 | return data.submit(); |
49 | 71 | }; |
| 72 | + angular.forEach(data.files, function (file, index) { |
| 73 | + file._index = index; |
| 74 | + file.$state = function () { |
| 75 | + return data.state(); |
| 76 | + }; |
| 77 | + file.$progress = function () { |
| 78 | + return data.progress(); |
| 79 | + }; |
| 80 | + file.$response = function () { |
| 81 | + return data.response(); |
| 82 | + }; |
| 83 | + }); |
50 | 84 | file.$cancel = function () { |
51 | 85 | scope.clear(data.files); |
52 | 86 | return data.abort(); |
53 | 87 | }; |
54 | | - file.$state = function () { |
55 | | - return data.state(); |
56 | | - }; |
57 | | - file.$progress = function () { |
58 | | - return data.progress(); |
59 | | - }; |
60 | | - file.$response = function () { |
61 | | - return data.response(); |
62 | | - }; |
63 | 88 | if (file.$state() === 'rejected') { |
64 | 89 | file._$submit = submit; |
65 | 90 | } else { |
|
96 | 121 | if (data.errorThrown === 'abort') { |
97 | 122 | return; |
98 | 123 | } |
99 | | - if (data.dataType.indexOf('json') === data.dataType.length - 4) { |
| 124 | + if (data.dataType && |
| 125 | + data.dataType.indexOf('json') === data.dataType.length - 4) { |
100 | 126 | try { |
101 | 127 | data.result = angular.fromJson(data.jqXHR.responseText); |
102 | | - } catch (err) {} |
| 128 | + } catch (ignore) {} |
103 | 129 | } |
104 | 130 | data.scope().$apply(function () { |
105 | 131 | data.handleResponse.call(that, e, data); |
|
112 | 138 | return this.scope().queue.length; |
113 | 139 | }, |
114 | 140 | dataType: 'json', |
115 | | - prependFiles: true, |
116 | 141 | autoUpload: false |
117 | 142 | }; |
118 | 143 | this.$get = [ |
|
124 | 149 | ]; |
125 | 150 | }) |
126 | 151 |
|
| 152 | + // Format byte numbers to readable presentations: |
127 | 153 | .provider('formatFileSizeFilter', function () { |
128 | | - var $config = this.defaults = { |
| 154 | + var $config = { |
129 | 155 | // Byte units following the IEC format |
130 | 156 | // http://en.wikipedia.org/wiki/Kilobyte |
131 | 157 | units: [ |
|
134 | 160 | {size: 1000, suffix: ' KB'} |
135 | 161 | ] |
136 | 162 | }; |
| 163 | + this.defaults = $config; |
137 | 164 | this.$get = function () { |
138 | 165 | return function (bytes) { |
139 | 166 | if (!angular.isNumber(bytes)) { |
140 | 167 | return ''; |
141 | 168 | } |
142 | 169 | var unit = true, |
143 | | - i = -1; |
| 170 | + i = 0, |
| 171 | + prefix, |
| 172 | + suffix; |
144 | 173 | while (unit) { |
145 | | - unit = $config.units[i += 1]; |
| 174 | + unit = $config.units[i]; |
| 175 | + prefix = unit.prefix || ''; |
| 176 | + suffix = unit.suffix || ''; |
146 | 177 | if (i === $config.units.length - 1 || bytes >= unit.size) { |
147 | | - return (bytes / unit.size).toFixed(2) + unit.suffix; |
| 178 | + return prefix + (bytes / unit.size).toFixed(2) + suffix; |
148 | 179 | } |
| 180 | + i += 1; |
149 | 181 | } |
150 | 182 | }; |
151 | 183 | }; |
152 | 184 | }) |
153 | 185 |
|
| 186 | + // The FileUploadController initializes the fileupload widget and |
| 187 | + // provides scope methods to control the File Upload functionality: |
154 | 188 | .controller('FileUploadController', [ |
155 | | - '$scope', '$element', '$attrs', 'fileUpload', |
156 | | - function ($scope, $element, $attrs, fileUpload) { |
157 | | - $scope.disabled = angular.element('<input type="file">') |
158 | | - .prop('disabled'); |
| 189 | + '$scope', '$element', '$attrs', '$window', 'fileUpload', |
| 190 | + function ($scope, $element, $attrs, $window, fileUpload) { |
| 191 | + var uploadMethods = { |
| 192 | + progress: function () { |
| 193 | + return $element.fileupload('progress'); |
| 194 | + }, |
| 195 | + active: function () { |
| 196 | + return $element.fileupload('active'); |
| 197 | + }, |
| 198 | + option: function (option, data) { |
| 199 | + return $element.fileupload('option', option, data); |
| 200 | + }, |
| 201 | + add: function (data) { |
| 202 | + return $element.fileupload('add', data); |
| 203 | + }, |
| 204 | + send: function (data) { |
| 205 | + return $element.fileupload('send', data); |
| 206 | + }, |
| 207 | + process: function (data) { |
| 208 | + return $element.fileupload('process', data); |
| 209 | + }, |
| 210 | + processing: function (data) { |
| 211 | + return $element.fileupload('processing', data); |
| 212 | + } |
| 213 | + }; |
| 214 | + $scope.disabled = !$window.jQuery.support.fileInput; |
159 | 215 | $scope.queue = $scope.queue || []; |
160 | 216 | $scope.clear = function (files) { |
161 | 217 | var queue = this.queue, |
|
167 | 223 | length = files.length; |
168 | 224 | } |
169 | 225 | while (i) { |
170 | | - if (queue[i -= 1] === file) { |
| 226 | + i -= 1; |
| 227 | + if (queue[i] === file) { |
171 | 228 | return queue.splice(i, length); |
172 | 229 | } |
173 | 230 | } |
|
186 | 243 | } |
187 | 244 | } |
188 | 245 | }; |
189 | | - $scope.progress = function () { |
190 | | - return $element.fileupload('progress'); |
191 | | - }; |
192 | | - $scope.active = function () { |
193 | | - return $element.fileupload('active'); |
194 | | - }; |
195 | | - $scope.option = function (option, data) { |
196 | | - return $element.fileupload('option', option, data); |
197 | | - }; |
198 | | - $scope.add = function (data) { |
199 | | - return $element.fileupload('add', data); |
200 | | - }; |
201 | | - $scope.send = function (data) { |
202 | | - return $element.fileupload('send', data); |
203 | | - }; |
204 | | - $scope.process = function (data) { |
205 | | - return $element.fileupload('process', data); |
206 | | - }; |
207 | | - $scope.processing = function (data) { |
208 | | - return $element.fileupload('processing', data); |
209 | | - }; |
210 | 246 | $scope.applyOnQueue = function (method) { |
211 | 247 | var list = this.queue.slice(0), |
212 | 248 | i, |
|
224 | 260 | $scope.cancel = function () { |
225 | 261 | this.applyOnQueue('$cancel'); |
226 | 262 | }; |
| 263 | + // Add upload methods to the scope: |
| 264 | + angular.extend($scope, uploadMethods); |
227 | 265 | // The fileupload widget will initialize with |
228 | 266 | // the options provided via "data-"-parameters, |
229 | 267 | // as well as those given via options object: |
|
260 | 298 | 'fileuploadprocessalways', |
261 | 299 | 'fileuploadprocessstop' |
262 | 300 | ].join(' '), function (e, data) { |
263 | | - $scope.$emit(e.type, data); |
| 301 | + if ($scope.$emit(e.type, data).defaultPrevented) { |
| 302 | + e.preventDefault(); |
| 303 | + } |
| 304 | + }).on('remove', function () { |
| 305 | + // Remove upload methods from the scope, |
| 306 | + // when the widget is removed: |
| 307 | + var method; |
| 308 | + for (method in uploadMethods) { |
| 309 | + if (uploadMethods.hasOwnProperty(method)) { |
| 310 | + delete $scope[method]; |
| 311 | + } |
| 312 | + } |
264 | 313 | }); |
265 | 314 | // Observe option changes: |
266 | 315 | $scope.$watch( |
267 | | - $attrs.fileupload, |
268 | | - function (newOptions, oldOptions) { |
| 316 | + $attrs.fileUpload, |
| 317 | + function (newOptions) { |
269 | 318 | if (newOptions) { |
270 | 319 | $element.fileupload('option', newOptions); |
271 | 320 | } |
|
274 | 323 | } |
275 | 324 | ]) |
276 | 325 |
|
| 326 | + // Provide File Upload progress feedback: |
277 | 327 | .controller('FileUploadProgressController', [ |
278 | 328 | '$scope', '$attrs', '$parse', |
279 | 329 | function ($scope, $attrs, $parse) { |
280 | | - var fn = $parse($attrs.progress), |
| 330 | + var fn = $parse($attrs.fileUploadProgress), |
281 | 331 | update = function () { |
282 | 332 | var progress = fn($scope); |
283 | 333 | if (!progress || !progress.total) { |
|
289 | 339 | }; |
290 | 340 | update(); |
291 | 341 | $scope.$watch( |
292 | | - $attrs.progress + '.loaded', |
| 342 | + $attrs.fileUploadProgress + '.loaded', |
293 | 343 | function (newValue, oldValue) { |
294 | 344 | if (newValue !== oldValue) { |
295 | 345 | update(); |
|
299 | 349 | } |
300 | 350 | ]) |
301 | 351 |
|
| 352 | + // Display File Upload previews: |
302 | 353 | .controller('FileUploadPreviewController', [ |
303 | 354 | '$scope', '$element', '$attrs', '$parse', |
304 | 355 | function ($scope, $element, $attrs, $parse) { |
305 | | - var fn = $parse($attrs.preview), |
| 356 | + var fn = $parse($attrs.fileUploadPreview), |
306 | 357 | file = fn($scope); |
307 | 358 | if (file.preview) { |
308 | 359 | $element.append(file.preview); |
309 | 360 | } |
310 | 361 | } |
311 | 362 | ]) |
312 | 363 |
|
313 | | - .directive('fileupload', function () { |
| 364 | + .directive('fileUpload', function () { |
314 | 365 | return { |
315 | 366 | controller: 'FileUploadController' |
316 | 367 | }; |
317 | 368 | }) |
318 | 369 |
|
319 | | - .directive('progress', function () { |
| 370 | + .directive('fileUploadProgress', function () { |
320 | 371 | return { |
321 | 372 | controller: 'FileUploadProgressController' |
322 | 373 | }; |
323 | 374 | }) |
324 | 375 |
|
325 | | - .directive('preview', function () { |
| 376 | + .directive('fileUploadPreview', function () { |
326 | 377 | return { |
327 | 378 | controller: 'FileUploadPreviewController' |
328 | 379 | }; |
329 | 380 | }) |
330 | 381 |
|
| 382 | + // Enhance the HTML5 download attribute to |
| 383 | + // allow drag&drop of files to the desktop: |
331 | 384 | .directive('download', function () { |
332 | | - return function (scope, elm, attrs) { |
| 385 | + return function (scope, elm) { |
333 | 386 | elm.on('dragstart', function (e) { |
334 | 387 | try { |
335 | 388 | e.originalEvent.dataTransfer.setData( |
|
340 | 393 | elm.prop('href') |
341 | 394 | ].join(':') |
342 | 395 | ); |
343 | | - } catch (err) {} |
| 396 | + } catch (ignore) {} |
344 | 397 | }); |
345 | 398 | }; |
346 | 399 | }); |
347 | 400 |
|
348 | | -}()); |
| 401 | +})); |
0 commit comments