/* * jQuery File Upload AngularJS Plugin 1.4.4 * 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 */ /*jslint nomen: true, unparam: true */ /*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 scopeApply = function () { var scope = angular.element(this) .fileupload('option', 'scope')(), $timeout = angular.injector(['ng']) .get('$timeout'); // Safe apply, makes sure $apply is called // asynchronously outside of the $digest cycle: $timeout(function () { scope.$apply(); }); }, $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) { var scope = data.scope(); data.process(function () { return scope.process(data); }).always( function () { var file = data.files[0], submit = function () { return data.submit(); }; angular.forEach(data.files, function (file, index) { file._index = index; file.$state = function () { return data.state(); }; file.$progress = function () { return data.progress(); }; file.$response = function () { return data.response(); }; }); file.$cancel = function () { scope.clear(data.files); return data.abort(); }; if (file.$state() === 'rejected') { file._$submit = submit; } else { file.$submit = submit; } scope.$apply(function () { var method = scope.option('prependFiles') ? 'unshift' : 'push'; Array.prototype[method].apply( scope.queue, data.files ); if (file.$submit && (scope.option('autoUpload') || data.autoUpload) && data.autoUpload !== false) { file.$submit(); } }); } ); }, progress: function (e, data) { data.scope().$apply(); }, done: function (e, data) { var that = this; data.scope().$apply(function () { data.handleResponse.call(that, e, data); }); }, fail: function (e, data) { var that = this; 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) {} } data.scope().$apply(function () { data.handleResponse.call(that, e, data); }); }, stop: scopeApply, processstart: scopeApply, processstop: scopeApply, getNumberOfFiles: function () { return this.scope().queue.length; }, 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) { return $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: function () { return $scope; }}, fileUpload.defaults )).on('fileuploadadd', function (e, data) { data.scope = $scope.option('scope'); }).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', '$parse', function ($scope, $element, $attrs, $parse) { var fn = $parse($attrs.fileUploadPreview), file = fn($scope); if (file.preview) { $element.append(file.preview); } } ]) .directive('fileUpload', function () { return { controller: 'FileUploadController' }; }) .directive('fileUploadProgress', function () { return { controller: 'FileUploadProgressController' }; }) .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) {} }); }; }); }));