430 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			430 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
|  * jQuery File Upload AngularJS Plugin 2.2.0
 | |
|  * https://github.com/blueimp/jQuery-File-Upload
 | |
|  *
 | |
|  * Copyright 2013, Sebastian Tschan
 | |
|  * https://blueimp.net
 | |
|  *
 | |
|  * Licensed under the MIT license:
 | |
|  * http://www.opensource.org/licenses/MIT
 | |
|  */
 | |
| 
 | |
| /* jshint nomen:false */
 | |
| /* global define, angular */
 | |
| 
 | |
| (function (factory) {
 | |
|     'use strict';
 | |
|     if (typeof define === 'function' && define.amd) {
 | |
|         // Register as an anonymous AMD module:
 | |
|         define([
 | |
|             'jquery',
 | |
|             'angular',
 | |
|             './jquery.fileupload-image',
 | |
|             './jquery.fileupload-audio',
 | |
|             './jquery.fileupload-video',
 | |
|             './jquery.fileupload-validate'
 | |
|         ], factory);
 | |
|     } else {
 | |
|         factory();
 | |
|     }
 | |
| }(function () {
 | |
|     'use strict';
 | |
| 
 | |
|     angular.module('blueimp.fileupload', [])
 | |
| 
 | |
|         // The fileUpload service provides configuration options
 | |
|         // for the fileUpload directive and default handlers for
 | |
|         // File Upload events:
 | |
|         .provider('fileUpload', function () {
 | |
|             var scopeEvalAsync = function (expression) {
 | |
|                     var scope = angular.element(this)
 | |
|                             .fileupload('option', 'scope');
 | |
|                     // Schedule a new $digest cycle if not already inside of one
 | |
|                     // and evaluate the given expression:
 | |
|                     scope.$evalAsync(expression);
 | |
|                 },
 | |
|                 addFileMethods = function (scope, data) {
 | |
|                     var files = data.files,
 | |
|                         file = files[0];
 | |
|                     angular.forEach(files, function (file, index) {
 | |
|                         file._index = index;
 | |
|                         file.$state = function () {
 | |
|                             return data.state();
 | |
|                         };
 | |
|                         file.$processing = function () {
 | |
|                             return data.processing();
 | |
|                         };
 | |
|                         file.$progress = function () {
 | |
|                             return data.progress();
 | |
|                         };
 | |
|                         file.$response = function () {
 | |
|                             return data.response();
 | |
|                         };
 | |
|                     });
 | |
|                     file.$submit = function () {
 | |
|                         if (!file.error) {
 | |
|                             return data.submit();
 | |
|                         }
 | |
|                     };
 | |
|                     file.$cancel = function () {
 | |
|                         return data.abort();
 | |
|                     };
 | |
|                 },
 | |
|                 $config;
 | |
|             $config = this.defaults = {
 | |
|                 handleResponse: function (e, data) {
 | |
|                     var files = data.result && data.result.files;
 | |
|                     if (files) {
 | |
|                         data.scope.replace(data.files, files);
 | |
|                     } else if (data.errorThrown ||
 | |
|                             data.textStatus === 'error') {
 | |
|                         data.files[0].error = data.errorThrown ||
 | |
|                             data.textStatus;
 | |
|                     }
 | |
|                 },
 | |
|                 add: function (e, data) {
 | |
|                     if (e.isDefaultPrevented()) {
 | |
|                         return false;
 | |
|                     }
 | |
|                     var scope = data.scope,
 | |
|                         filesCopy = [];
 | |
|                     angular.forEach(data.files, function (file) {
 | |
|                         filesCopy.push(file);
 | |
|                     });
 | |
|                     scope.$apply(function () {
 | |
|                         addFileMethods(scope, data);
 | |
|                         var method = scope.option('prependFiles') ?
 | |
|                                 'unshift' : 'push';
 | |
|                         Array.prototype[method].apply(scope.queue, data.files);
 | |
|                     });
 | |
|                     data.process(function () {
 | |
|                         return scope.process(data);
 | |
|                     }).always(function () {
 | |
|                         scope.$apply(function () {
 | |
|                             addFileMethods(scope, data);
 | |
|                             scope.replace(filesCopy, data.files);
 | |
|                         });
 | |
|                     }).then(function () {
 | |
|                         if ((scope.option('autoUpload') ||
 | |
|                                 data.autoUpload) &&
 | |
|                                 data.autoUpload !== false) {
 | |
|                             data.submit();
 | |
|                         }
 | |
|                     });
 | |
|                 },
 | |
|                 progress: function (e, data) {
 | |
|                     if (e.isDefaultPrevented()) {
 | |
|                         return false;
 | |
|                     }
 | |
|                     data.scope.$apply();
 | |
|                 },
 | |
|                 done: function (e, data) {
 | |
|                     if (e.isDefaultPrevented()) {
 | |
|                         return false;
 | |
|                     }
 | |
|                     var that = this;
 | |
|                     data.scope.$apply(function () {
 | |
|                         data.handleResponse.call(that, e, data);
 | |
|                     });
 | |
|                 },
 | |
|                 fail: function (e, data) {
 | |
|                     if (e.isDefaultPrevented()) {
 | |
|                         return false;
 | |
|                     }
 | |
|                     var that = this,
 | |
|                         scope = data.scope;
 | |
|                     if (data.errorThrown === 'abort') {
 | |
|                         scope.clear(data.files);
 | |
|                         return;
 | |
|                     }
 | |
|                     scope.$apply(function () {
 | |
|                         data.handleResponse.call(that, e, data);
 | |
|                     });
 | |
|                 },
 | |
|                 stop: scopeEvalAsync,
 | |
|                 processstart: scopeEvalAsync,
 | |
|                 processstop: scopeEvalAsync,
 | |
|                 getNumberOfFiles: function () {
 | |
|                     var scope = this.scope;
 | |
|                     return scope.queue.length - scope.processing();
 | |
|                 },
 | |
|                 dataType: 'json',
 | |
|                 autoUpload: false
 | |
|             };
 | |
|             this.$get = [
 | |
|                 function () {
 | |
|                     return {
 | |
|                         defaults: $config
 | |
|                     };
 | |
|                 }
 | |
|             ];
 | |
|         })
 | |
| 
 | |
|         // Format byte numbers to readable presentations:
 | |
|         .provider('formatFileSizeFilter', function () {
 | |
|             var $config = {
 | |
|                 // Byte units following the IEC format
 | |
|                 // http://en.wikipedia.org/wiki/Kilobyte
 | |
|                 units: [
 | |
|                     {size: 1000000000, suffix: ' GB'},
 | |
|                     {size: 1000000, suffix: ' MB'},
 | |
|                     {size: 1000, suffix: ' KB'}
 | |
|                 ]
 | |
|             };
 | |
|             this.defaults = $config;
 | |
|             this.$get = function () {
 | |
|                 return function (bytes) {
 | |
|                     if (!angular.isNumber(bytes)) {
 | |
|                         return '';
 | |
|                     }
 | |
|                     var unit = true,
 | |
|                         i = 0,
 | |
|                         prefix,
 | |
|                         suffix;
 | |
|                     while (unit) {
 | |
|                         unit = $config.units[i];
 | |
|                         prefix = unit.prefix || '';
 | |
|                         suffix = unit.suffix || '';
 | |
|                         if (i === $config.units.length - 1 || bytes >= unit.size) {
 | |
|                             return prefix + (bytes / unit.size).toFixed(2) + suffix;
 | |
|                         }
 | |
|                         i += 1;
 | |
|                     }
 | |
|                 };
 | |
|             };
 | |
|         })
 | |
| 
 | |
|         // The FileUploadController initializes the fileupload widget and
 | |
|         // provides scope methods to control the File Upload functionality:
 | |
|         .controller('FileUploadController', [
 | |
|             '$scope', '$element', '$attrs', '$window', 'fileUpload',
 | |
|             function ($scope, $element, $attrs, $window, fileUpload) {
 | |
|                 var uploadMethods = {
 | |
|                     progress: function () {
 | |
|                         return $element.fileupload('progress');
 | |
|                     },
 | |
|                     active: function () {
 | |
|                         return $element.fileupload('active');
 | |
|                     },
 | |
|                     option: function (option, data) {
 | |
|                         if (arguments.length === 1) {
 | |
|                             return $element.fileupload('option', option);
 | |
|                         }
 | |
|                         $element.fileupload('option', option, data);
 | |
|                     },
 | |
|                     add: function (data) {
 | |
|                         return $element.fileupload('add', data);
 | |
|                     },
 | |
|                     send: function (data) {
 | |
|                         return $element.fileupload('send', data);
 | |
|                     },
 | |
|                     process: function (data) {
 | |
|                         return $element.fileupload('process', data);
 | |
|                     },
 | |
|                     processing: function (data) {
 | |
|                         return $element.fileupload('processing', data);
 | |
|                     }
 | |
|                 };
 | |
|                 $scope.disabled = !$window.jQuery.support.fileInput;
 | |
|                 $scope.queue = $scope.queue || [];
 | |
|                 $scope.clear = function (files) {
 | |
|                     var queue = this.queue,
 | |
|                         i = queue.length,
 | |
|                         file = files,
 | |
|                         length = 1;
 | |
|                     if (angular.isArray(files)) {
 | |
|                         file = files[0];
 | |
|                         length = files.length;
 | |
|                     }
 | |
|                     while (i) {
 | |
|                         i -= 1;
 | |
|                         if (queue[i] === file) {
 | |
|                             return queue.splice(i, length);
 | |
|                         }
 | |
|                     }
 | |
|                 };
 | |
|                 $scope.replace = function (oldFiles, newFiles) {
 | |
|                     var queue = this.queue,
 | |
|                         file = oldFiles[0],
 | |
|                         i,
 | |
|                         j;
 | |
|                     for (i = 0; i < queue.length; i += 1) {
 | |
|                         if (queue[i] === file) {
 | |
|                             for (j = 0; j < newFiles.length; j += 1) {
 | |
|                                 queue[i + j] = newFiles[j];
 | |
|                             }
 | |
|                             return;
 | |
|                         }
 | |
|                     }
 | |
|                 };
 | |
|                 $scope.applyOnQueue = function (method) {
 | |
|                     var list = this.queue.slice(0),
 | |
|                         i,
 | |
|                         file;
 | |
|                     for (i = 0; i < list.length; i += 1) {
 | |
|                         file = list[i];
 | |
|                         if (file[method]) {
 | |
|                             file[method]();
 | |
|                         }
 | |
|                     }
 | |
|                 };
 | |
|                 $scope.submit = function () {
 | |
|                     this.applyOnQueue('$submit');
 | |
|                 };
 | |
|                 $scope.cancel = function () {
 | |
|                     this.applyOnQueue('$cancel');
 | |
|                 };
 | |
|                 // Add upload methods to the scope:
 | |
|                 angular.extend($scope, uploadMethods);
 | |
|                 // The fileupload widget will initialize with
 | |
|                 // the options provided via "data-"-parameters,
 | |
|                 // as well as those given via options object:
 | |
|                 $element.fileupload(angular.extend(
 | |
|                     {scope: $scope},
 | |
|                     fileUpload.defaults
 | |
|                 )).on('fileuploadadd', function (e, data) {
 | |
|                     data.scope = $scope;
 | |
|                 }).on('fileuploadfail', function (e, data) {
 | |
|                     if (data.errorThrown === 'abort') {
 | |
|                         return;
 | |
|                     }
 | |
|                     if (data.dataType &&
 | |
|                             data.dataType.indexOf('json') === data.dataType.length - 4) {
 | |
|                         try {
 | |
|                             data.result = angular.fromJson(data.jqXHR.responseText);
 | |
|                         } catch (ignore) {}
 | |
|                     }
 | |
|                 }).on([
 | |
|                     'fileuploadadd',
 | |
|                     'fileuploadsubmit',
 | |
|                     'fileuploadsend',
 | |
|                     'fileuploaddone',
 | |
|                     'fileuploadfail',
 | |
|                     'fileuploadalways',
 | |
|                     'fileuploadprogress',
 | |
|                     'fileuploadprogressall',
 | |
|                     'fileuploadstart',
 | |
|                     'fileuploadstop',
 | |
|                     'fileuploadchange',
 | |
|                     'fileuploadpaste',
 | |
|                     'fileuploaddrop',
 | |
|                     'fileuploaddragover',
 | |
|                     'fileuploadchunksend',
 | |
|                     'fileuploadchunkdone',
 | |
|                     'fileuploadchunkfail',
 | |
|                     'fileuploadchunkalways',
 | |
|                     'fileuploadprocessstart',
 | |
|                     'fileuploadprocess',
 | |
|                     'fileuploadprocessdone',
 | |
|                     'fileuploadprocessfail',
 | |
|                     'fileuploadprocessalways',
 | |
|                     'fileuploadprocessstop'
 | |
|                 ].join(' '), function (e, data) {
 | |
|                     if ($scope.$emit(e.type, data).defaultPrevented) {
 | |
|                         e.preventDefault();
 | |
|                     }
 | |
|                 }).on('remove', function () {
 | |
|                     // Remove upload methods from the scope,
 | |
|                     // when the widget is removed:
 | |
|                     var method;
 | |
|                     for (method in uploadMethods) {
 | |
|                         if (uploadMethods.hasOwnProperty(method)) {
 | |
|                             delete $scope[method];
 | |
|                         }
 | |
|                     }
 | |
|                 });
 | |
|                 // Observe option changes:
 | |
|                 $scope.$watch(
 | |
|                     $attrs.fileUpload,
 | |
|                     function (newOptions) {
 | |
|                         if (newOptions) {
 | |
|                             $element.fileupload('option', newOptions);
 | |
|                         }
 | |
|                     }
 | |
|                 );
 | |
|             }
 | |
|         ])
 | |
| 
 | |
|         // Provide File Upload progress feedback:
 | |
|         .controller('FileUploadProgressController', [
 | |
|             '$scope', '$attrs', '$parse',
 | |
|             function ($scope, $attrs, $parse) {
 | |
|                 var fn = $parse($attrs.fileUploadProgress),
 | |
|                     update = function () {
 | |
|                         var progress = fn($scope);
 | |
|                         if (!progress || !progress.total) {
 | |
|                             return;
 | |
|                         }
 | |
|                         $scope.num = Math.floor(
 | |
|                             progress.loaded / progress.total * 100
 | |
|                         );
 | |
|                     };
 | |
|                 update();
 | |
|                 $scope.$watch(
 | |
|                     $attrs.fileUploadProgress + '.loaded',
 | |
|                     function (newValue, oldValue) {
 | |
|                         if (newValue !== oldValue) {
 | |
|                             update();
 | |
|                         }
 | |
|                     }
 | |
|                 );
 | |
|             }
 | |
|         ])
 | |
| 
 | |
|         // Display File Upload previews:
 | |
|         .controller('FileUploadPreviewController', [
 | |
|             '$scope', '$element', '$attrs',
 | |
|             function ($scope, $element, $attrs) {
 | |
|                 $scope.$watch(
 | |
|                     $attrs.fileUploadPreview + '.preview',
 | |
|                     function (preview) {
 | |
|                         $element.empty();
 | |
|                         if (preview) {
 | |
|                             $element.append(preview);
 | |
|                         }
 | |
|                     }
 | |
|                 );
 | |
|             }
 | |
|         ])
 | |
| 
 | |
|         .directive('fileUpload', function () {
 | |
|             return {
 | |
|                 controller: 'FileUploadController',
 | |
|                 scope: true
 | |
|             };
 | |
|         })
 | |
| 
 | |
|         .directive('fileUploadProgress', function () {
 | |
|             return {
 | |
|                 controller: 'FileUploadProgressController',
 | |
|                 scope: true
 | |
|             };
 | |
|         })
 | |
| 
 | |
|         .directive('fileUploadPreview', function () {
 | |
|             return {
 | |
|                 controller: 'FileUploadPreviewController'
 | |
|             };
 | |
|         })
 | |
| 
 | |
|         // Enhance the HTML5 download attribute to
 | |
|         // allow drag&drop of files to the desktop:
 | |
|         .directive('download', function () {
 | |
|             return function (scope, elm) {
 | |
|                 elm.on('dragstart', function (e) {
 | |
|                     try {
 | |
|                         e.originalEvent.dataTransfer.setData(
 | |
|                             'DownloadURL',
 | |
|                             [
 | |
|                                 'application/octet-stream',
 | |
|                                 elm.prop('download'),
 | |
|                                 elm.prop('href')
 | |
|                             ].join(':')
 | |
|                         );
 | |
|                     } catch (ignore) {}
 | |
|                 });
 | |
|             };
 | |
|         });
 | |
| 
 | |
| }));
 |