Administrator
2022-09-14 58d006e05dcf2a20d0ec5367dd03d66a61db6849
提交 | 用户 | 时间
58d006 1 /*
A 2  * jQuery File Upload AngularJS Plugin 2.2.0
3  * https://github.com/blueimp/jQuery-File-Upload
4  *
5  * Copyright 2013, Sebastian Tschan
6  * https://blueimp.net
7  *
8  * Licensed under the MIT license:
9  * http://www.opensource.org/licenses/MIT
10  */
11
12 /* jshint nomen:false */
13 /* global define, angular */
14
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 () {
31     'use strict';
32
33     angular.module('blueimp.fileupload', [])
34
35         // The fileUpload service provides configuration options
36         // for the fileUpload directive and default handlers for
37         // File Upload events:
38         .provider('fileUpload', function () {
39             var scopeEvalAsync = function (expression) {
40                     var scope = angular.element(this)
41                             .fileupload('option', 'scope');
42                     // Schedule a new $digest cycle if not already inside of one
43                     // and evaluate the given expression:
44                     scope.$evalAsync(expression);
45                 },
46                 addFileMethods = function (scope, data) {
47                     var files = data.files,
48                         file = files[0];
49                     angular.forEach(files, function (file, index) {
50                         file._index = index;
51                         file.$state = function () {
52                             return data.state();
53                         };
54                         file.$processing = function () {
55                             return data.processing();
56                         };
57                         file.$progress = function () {
58                             return data.progress();
59                         };
60                         file.$response = function () {
61                             return data.response();
62                         };
63                     });
64                     file.$submit = function () {
65                         if (!file.error) {
66                             return data.submit();
67                         }
68                     };
69                     file.$cancel = function () {
70                         return data.abort();
71                     };
72                 },
73                 $config;
74             $config = this.defaults = {
75                 handleResponse: function (e, data) {
76                     var files = data.result && data.result.files;
77                     if (files) {
78                         data.scope.replace(data.files, files);
79                     } else if (data.errorThrown ||
80                             data.textStatus === 'error') {
81                         data.files[0].error = data.errorThrown ||
82                             data.textStatus;
83                     }
84                 },
85                 add: function (e, data) {
86                     if (e.isDefaultPrevented()) {
87                         return false;
88                     }
89                     var scope = data.scope,
90                         filesCopy = [];
91                     angular.forEach(data.files, function (file) {
92                         filesCopy.push(file);
93                     });
94                     scope.$apply(function () {
95                         addFileMethods(scope, data);
96                         var method = scope.option('prependFiles') ?
97                                 'unshift' : 'push';
98                         Array.prototype[method].apply(scope.queue, data.files);
99                     });
100                     data.process(function () {
101                         return scope.process(data);
102                     }).always(function () {
103                         scope.$apply(function () {
104                             addFileMethods(scope, data);
105                             scope.replace(filesCopy, data.files);
106                         });
107                     }).then(function () {
108                         if ((scope.option('autoUpload') ||
109                                 data.autoUpload) &&
110                                 data.autoUpload !== false) {
111                             data.submit();
112                         }
113                     });
114                 },
115                 progress: function (e, data) {
116                     if (e.isDefaultPrevented()) {
117                         return false;
118                     }
119                     data.scope.$apply();
120                 },
121                 done: function (e, data) {
122                     if (e.isDefaultPrevented()) {
123                         return false;
124                     }
125                     var that = this;
126                     data.scope.$apply(function () {
127                         data.handleResponse.call(that, e, data);
128                     });
129                 },
130                 fail: function (e, data) {
131                     if (e.isDefaultPrevented()) {
132                         return false;
133                     }
134                     var that = this,
135                         scope = data.scope;
136                     if (data.errorThrown === 'abort') {
137                         scope.clear(data.files);
138                         return;
139                     }
140                     scope.$apply(function () {
141                         data.handleResponse.call(that, e, data);
142                     });
143                 },
144                 stop: scopeEvalAsync,
145                 processstart: scopeEvalAsync,
146                 processstop: scopeEvalAsync,
147                 getNumberOfFiles: function () {
148                     var scope = this.scope;
149                     return scope.queue.length - scope.processing();
150                 },
151                 dataType: 'json',
152                 autoUpload: false
153             };
154             this.$get = [
155                 function () {
156                     return {
157                         defaults: $config
158                     };
159                 }
160             ];
161         })
162
163         // Format byte numbers to readable presentations:
164         .provider('formatFileSizeFilter', function () {
165             var $config = {
166                 // Byte units following the IEC format
167                 // http://en.wikipedia.org/wiki/Kilobyte
168                 units: [
169                     {size: 1000000000, suffix: ' GB'},
170                     {size: 1000000, suffix: ' MB'},
171                     {size: 1000, suffix: ' KB'}
172                 ]
173             };
174             this.defaults = $config;
175             this.$get = function () {
176                 return function (bytes) {
177                     if (!angular.isNumber(bytes)) {
178                         return '';
179                     }
180                     var unit = true,
181                         i = 0,
182                         prefix,
183                         suffix;
184                     while (unit) {
185                         unit = $config.units[i];
186                         prefix = unit.prefix || '';
187                         suffix = unit.suffix || '';
188                         if (i === $config.units.length - 1 || bytes >= unit.size) {
189                             return prefix + (bytes / unit.size).toFixed(2) + suffix;
190                         }
191                         i += 1;
192                     }
193                 };
194             };
195         })
196
197         // The FileUploadController initializes the fileupload widget and
198         // provides scope methods to control the File Upload functionality:
199         .controller('FileUploadController', [
200             '$scope', '$element', '$attrs', '$window', 'fileUpload',
201             function ($scope, $element, $attrs, $window, fileUpload) {
202                 var uploadMethods = {
203                     progress: function () {
204                         return $element.fileupload('progress');
205                     },
206                     active: function () {
207                         return $element.fileupload('active');
208                     },
209                     option: function (option, data) {
210                         if (arguments.length === 1) {
211                             return $element.fileupload('option', option);
212                         }
213                         $element.fileupload('option', option, data);
214                     },
215                     add: function (data) {
216                         return $element.fileupload('add', data);
217                     },
218                     send: function (data) {
219                         return $element.fileupload('send', data);
220                     },
221                     process: function (data) {
222                         return $element.fileupload('process', data);
223                     },
224                     processing: function (data) {
225                         return $element.fileupload('processing', data);
226                     }
227                 };
228                 $scope.disabled = !$window.jQuery.support.fileInput;
229                 $scope.queue = $scope.queue || [];
230                 $scope.clear = function (files) {
231                     var queue = this.queue,
232                         i = queue.length,
233                         file = files,
234                         length = 1;
235                     if (angular.isArray(files)) {
236                         file = files[0];
237                         length = files.length;
238                     }
239                     while (i) {
240                         i -= 1;
241                         if (queue[i] === file) {
242                             return queue.splice(i, length);
243                         }
244                     }
245                 };
246                 $scope.replace = function (oldFiles, newFiles) {
247                     var queue = this.queue,
248                         file = oldFiles[0],
249                         i,
250                         j;
251                     for (i = 0; i < queue.length; i += 1) {
252                         if (queue[i] === file) {
253                             for (j = 0; j < newFiles.length; j += 1) {
254                                 queue[i + j] = newFiles[j];
255                             }
256                             return;
257                         }
258                     }
259                 };
260                 $scope.applyOnQueue = function (method) {
261                     var list = this.queue.slice(0),
262                         i,
263                         file;
264                     for (i = 0; i < list.length; i += 1) {
265                         file = list[i];
266                         if (file[method]) {
267                             file[method]();
268                         }
269                     }
270                 };
271                 $scope.submit = function () {
272                     this.applyOnQueue('$submit');
273                 };
274                 $scope.cancel = function () {
275                     this.applyOnQueue('$cancel');
276                 };
277                 // Add upload methods to the scope:
278                 angular.extend($scope, uploadMethods);
279                 // The fileupload widget will initialize with
280                 // the options provided via "data-"-parameters,
281                 // as well as those given via options object:
282                 $element.fileupload(angular.extend(
283                     {scope: $scope},
284                     fileUpload.defaults
285                 )).on('fileuploadadd', function (e, data) {
286                     data.scope = $scope;
287                 }).on('fileuploadfail', function (e, data) {
288                     if (data.errorThrown === 'abort') {
289                         return;
290                     }
291                     if (data.dataType &&
292                             data.dataType.indexOf('json') === data.dataType.length - 4) {
293                         try {
294                             data.result = angular.fromJson(data.jqXHR.responseText);
295                         } catch (ignore) {}
296                     }
297                 }).on([
298                     'fileuploadadd',
299                     'fileuploadsubmit',
300                     'fileuploadsend',
301                     'fileuploaddone',
302                     'fileuploadfail',
303                     'fileuploadalways',
304                     'fileuploadprogress',
305                     'fileuploadprogressall',
306                     'fileuploadstart',
307                     'fileuploadstop',
308                     'fileuploadchange',
309                     'fileuploadpaste',
310                     'fileuploaddrop',
311                     'fileuploaddragover',
312                     'fileuploadchunksend',
313                     'fileuploadchunkdone',
314                     'fileuploadchunkfail',
315                     'fileuploadchunkalways',
316                     'fileuploadprocessstart',
317                     'fileuploadprocess',
318                     'fileuploadprocessdone',
319                     'fileuploadprocessfail',
320                     'fileuploadprocessalways',
321                     'fileuploadprocessstop'
322                 ].join(' '), function (e, data) {
323                     if ($scope.$emit(e.type, data).defaultPrevented) {
324                         e.preventDefault();
325                     }
326                 }).on('remove', function () {
327                     // Remove upload methods from the scope,
328                     // when the widget is removed:
329                     var method;
330                     for (method in uploadMethods) {
331                         if (uploadMethods.hasOwnProperty(method)) {
332                             delete $scope[method];
333                         }
334                     }
335                 });
336                 // Observe option changes:
337                 $scope.$watch(
338                     $attrs.fileUpload,
339                     function (newOptions) {
340                         if (newOptions) {
341                             $element.fileupload('option', newOptions);
342                         }
343                     }
344                 );
345             }
346         ])
347
348         // Provide File Upload progress feedback:
349         .controller('FileUploadProgressController', [
350             '$scope', '$attrs', '$parse',
351             function ($scope, $attrs, $parse) {
352                 var fn = $parse($attrs.fileUploadProgress),
353                     update = function () {
354                         var progress = fn($scope);
355                         if (!progress || !progress.total) {
356                             return;
357                         }
358                         $scope.num = Math.floor(
359                             progress.loaded / progress.total * 100
360                         );
361                     };
362                 update();
363                 $scope.$watch(
364                     $attrs.fileUploadProgress + '.loaded',
365                     function (newValue, oldValue) {
366                         if (newValue !== oldValue) {
367                             update();
368                         }
369                     }
370                 );
371             }
372         ])
373
374         // Display File Upload previews:
375         .controller('FileUploadPreviewController', [
376             '$scope', '$element', '$attrs',
377             function ($scope, $element, $attrs) {
378                 $scope.$watch(
379                     $attrs.fileUploadPreview + '.preview',
380                     function (preview) {
381                         $element.empty();
382                         if (preview) {
383                             $element.append(preview);
384                         }
385                     }
386                 );
387             }
388         ])
389
390         .directive('fileUpload', function () {
391             return {
392                 controller: 'FileUploadController',
393                 scope: true
394             };
395         })
396
397         .directive('fileUploadProgress', function () {
398             return {
399                 controller: 'FileUploadProgressController',
400                 scope: true
401             };
402         })
403
404         .directive('fileUploadPreview', function () {
405             return {
406                 controller: 'FileUploadPreviewController'
407             };
408         })
409
410         // Enhance the HTML5 download attribute to
411         // allow drag&drop of files to the desktop:
412         .directive('download', function () {
413             return function (scope, elm) {
414                 elm.on('dragstart', function (e) {
415                     try {
416                         e.originalEvent.dataTransfer.setData(
417                             'DownloadURL',
418                             [
419                                 'application/octet-stream',
420                                 elm.prop('download'),
421                                 elm.prop('href')
422                             ].join(':')
423                         );
424                     } catch (ignore) {}
425                 });
426             };
427         });
428
429 }));