Update to 12.2.13
Change-Id: Ie35ede414b46e28b0377d55ecdd4662ba964d8bf
This commit is contained in:
		| @@ -1,8 +1,6 @@ | |||||||
| include README.txt | include README.txt | ||||||
| recursive-include xstatic/pkg/angular_fileupload * | recursive-include xstatic * | ||||||
|  |  | ||||||
| global-exclude *.pyc | global-exclude *.pyc | ||||||
| global-exclude *.pyo | global-exclude *.pyo | ||||||
| global-exclude *.orig | global-exclude *.orig | ||||||
| global-exclude *.rej | global-exclude *.rej | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								setup.cfg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								setup.cfg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | [metadata] | ||||||
|  | name = XStatic-Angular-FileUpload | ||||||
|  | description = Angular-FileUpload 12.2.13 (XStatic packaging standard) | ||||||
|  | description-file = README.rst | ||||||
|  | maintainer = Radomir Dopieralski | ||||||
|  | maintainer-email = openstack@sheep.art.pl | ||||||
|  | home-page = https://github.com/danialfarid/angular-file-upload | ||||||
|  | keywords = angular_fileupload xstatic | ||||||
|  | license = (same as Angular-FileUpload) | ||||||
|  | zip_safe = False | ||||||
|  | namespace_packages = | ||||||
|  |     xstatic | ||||||
|  |     xstatic.pkg | ||||||
|  |  | ||||||
|  | [files] | ||||||
|  | packages = | ||||||
|  |     xstatic | ||||||
|  |  | ||||||
|  | [bdist_wheel] | ||||||
|  | universal = True | ||||||
							
								
								
									
										8
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								setup.py
									
									
									
									
									
								
							| @@ -1,11 +1,10 @@ | |||||||
|  | from setuptools import setup, find_packages | ||||||
| from xstatic.pkg import angular_fileupload as xs | from xstatic.pkg import angular_fileupload as xs | ||||||
|  |  | ||||||
| # The README.txt file should be written in reST so that PyPI can use | # The README.txt file should be written in reST so that PyPI can use | ||||||
| # it to generate your project's PyPI page. | # it to generate your project's PyPI page. | ||||||
| long_description = open('README.txt').read() | long_description = open('README.txt').read() | ||||||
|  |  | ||||||
| from setuptools import setup, find_packages |  | ||||||
|  |  | ||||||
| setup( | setup( | ||||||
|     name=xs.PACKAGE_NAME, |     name=xs.PACKAGE_NAME, | ||||||
|     version=xs.PACKAGE_VERSION, |     version=xs.PACKAGE_VERSION, | ||||||
| @@ -19,9 +18,8 @@ setup( | |||||||
|     url=xs.HOMEPAGE, |     url=xs.HOMEPAGE, | ||||||
|     platforms=xs.PLATFORMS, |     platforms=xs.PLATFORMS, | ||||||
|     packages=find_packages(), |     packages=find_packages(), | ||||||
|     namespace_packages=['xstatic', 'xstatic.pkg', ], |     namespace_packages=['xstatic', 'xstatic.pkg'], | ||||||
|     include_package_data=True, |     include_package_data=True, | ||||||
|     zip_safe=False, |     zip_safe=False, | ||||||
|     install_requires=[],  # nothing! :) |     install_requires=[], | ||||||
|                           # if you like, you MAY use the 'XStatic' package. |  | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ NAME = __name__.split('.')[-1] # package name (e.g. 'foo' or 'foo_bar') | |||||||
|                                # please use a all-lowercase valid python |                                # please use a all-lowercase valid python | ||||||
|                                # package name |                                # package name | ||||||
|  |  | ||||||
| VERSION = '12.0.4' # version of the packaged files, please use the upstream | VERSION = '12.2.13' # version of the packaged files, please use the upstream | ||||||
|                   # version number |                   # version number | ||||||
| BUILD = '0' # our package build number, so we can release new builds | BUILD = '0' # our package build number, so we can release new builds | ||||||
|              # with fixes for xstatic stuff. |              # with fixes for xstatic stuff. | ||||||
| @@ -24,8 +24,8 @@ CLASSIFIERS = [] | |||||||
| KEYWORDS = '%s xstatic' % NAME | KEYWORDS = '%s xstatic' % NAME | ||||||
|  |  | ||||||
| # XStatic-* package maintainer: | # XStatic-* package maintainer: | ||||||
| MAINTAINER = 'Rob Cresswell' | MAINTAINER = 'Radomir Dopieralski' | ||||||
| MAINTAINER_EMAIL = 'robert.cresswell@outlook.com' | MAINTAINER_EMAIL = 'openstack@sheep.art.pl' | ||||||
|  |  | ||||||
| # this refers to the project homepage of the stuff we packaged: | # this refers to the project homepage of the stuff we packaged: | ||||||
| HOMEPAGE = 'https://github.com/danialfarid/angular-file-upload' | HOMEPAGE = 'https://github.com/danialfarid/angular-file-upload' | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| /*! 12.0.4 */ | /*! 12.2.13 */ | ||||||
| /*! FileAPI 2.0.7 - BSD | git://github.com/mailru/FileAPI.git | /*! FileAPI 2.0.7 - BSD | git://github.com/mailru/FileAPI.git | ||||||
|  * FileAPI — a set of  javascript tools for working with files. Multiupload, drag'n'drop and chunked file upload. Images: crop, resize and auto orientation by EXIF. |  * FileAPI — a set of  javascript tools for working with files. Multiupload, drag'n'drop and chunked file upload. Images: crop, resize and auto orientation by EXIF. | ||||||
|  */ |  */ | ||||||
|   | |||||||
| @@ -1,9 +1,9 @@ | |||||||
| /**! | /**! | ||||||
|  * AngularJS file upload directives and services. Supoorts: file upload/drop/paste, resume, cancel/abort, |  * AngularJS file upload directives and services. Supports: file upload/drop/paste, resume, cancel/abort, | ||||||
|  * progress, resize, thumbnail, preview, validation and CORS |  * progress, resize, thumbnail, preview, validation and CORS | ||||||
|  * FileAPI Flash shim for old browsers not supporting FormData |  * FileAPI Flash shim for old browsers not supporting FormData | ||||||
|  * @author  Danial  <danial.farid@gmail.com> |  * @author  Danial  <danial.farid@gmail.com> | ||||||
|  * @version 12.0.4 |  * @version 12.2.13 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| (function () { | (function () { | ||||||
| @@ -424,7 +424,7 @@ if (!window.FileReader) { | |||||||
|  * AngularJS file upload directives and services. Supoorts: file upload/drop/paste, resume, cancel/abort, |  * AngularJS file upload directives and services. Supoorts: file upload/drop/paste, resume, cancel/abort, | ||||||
|  * progress, resize, thumbnail, preview, validation and CORS |  * progress, resize, thumbnail, preview, validation and CORS | ||||||
|  * @author  Danial  <danial.farid@gmail.com> |  * @author  Danial  <danial.farid@gmail.com> | ||||||
|  * @version 12.0.4 |  * @version 12.2.13 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| if (window.XMLHttpRequest && !(window.FileAPI && FileAPI.shouldLoad)) { | if (window.XMLHttpRequest && !(window.FileAPI && FileAPI.shouldLoad)) { | ||||||
| @@ -445,7 +445,7 @@ if (window.XMLHttpRequest && !(window.FileAPI && FileAPI.shouldLoad)) { | |||||||
|  |  | ||||||
| var ngFileUpload = angular.module('ngFileUpload', []); | var ngFileUpload = angular.module('ngFileUpload', []); | ||||||
|  |  | ||||||
| ngFileUpload.version = '12.0.4'; | ngFileUpload.version = '12.2.13'; | ||||||
|  |  | ||||||
| ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, $q, $timeout) { | ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, $q, $timeout) { | ||||||
|   var upload = this; |   var upload = this; | ||||||
| @@ -512,10 +512,12 @@ ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, | |||||||
|     function uploadWithAngular() { |     function uploadWithAngular() { | ||||||
|       $http(config).then(function (r) { |       $http(config).then(function (r) { | ||||||
|           if (resumeSupported && config._chunkSize && !config._finished && config._file) { |           if (resumeSupported && config._chunkSize && !config._finished && config._file) { | ||||||
|  |             var fileSize = config._file && config._file.size || 0; | ||||||
|             notifyProgress({ |             notifyProgress({ | ||||||
|                 loaded: config._end, |                 loaded: Math.min(config._end, fileSize), | ||||||
|                 total: config._file && config._file.size, |                 total: fileSize, | ||||||
|                 config: config, type: 'progress' |                 config: config, | ||||||
|  |                 type: 'progress' | ||||||
|               } |               } | ||||||
|             ); |             ); | ||||||
|             upload.upload(config, true); |             upload.upload(config, true); | ||||||
| @@ -554,6 +556,9 @@ ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, | |||||||
|     } else if (config.resumeSize) { |     } else if (config.resumeSize) { | ||||||
|       config.resumeSize().then(function (size) { |       config.resumeSize().then(function (size) { | ||||||
|         config._start = size; |         config._start = size; | ||||||
|  |         if (config._chunkSize) { | ||||||
|  |           config._end = config._start + config._chunkSize; | ||||||
|  |         } | ||||||
|         uploadWithAngular(); |         uploadWithAngular(); | ||||||
|       }, function (e) { |       }, function (e) { | ||||||
|         throw e; |         throw e; | ||||||
| @@ -607,9 +612,11 @@ ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     upload.promisesCount++; |     upload.promisesCount++; | ||||||
|     promise['finally'](function () { |     if (promise['finally'] && promise['finally'] instanceof Function) { | ||||||
|       upload.promisesCount--; |       promise['finally'](function () { | ||||||
|     }); |         upload.promisesCount--; | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|     return promise; |     return promise; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -793,9 +800,11 @@ ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, | |||||||
|       var arrayBufferView = new Uint8Array(resp.data); |       var arrayBufferView = new Uint8Array(resp.data); | ||||||
|       var type = resp.headers('content-type') || 'image/WebP'; |       var type = resp.headers('content-type') || 'image/WebP'; | ||||||
|       var blob = new window.Blob([arrayBufferView], {type: type}); |       var blob = new window.Blob([arrayBufferView], {type: type}); | ||||||
|  |       var matches = url.match(/.*\/(.+?)(\?.*)?$/); | ||||||
|  |       if (matches.length > 1) { | ||||||
|  |         blob.name = matches[1]; | ||||||
|  |       } | ||||||
|       defer.resolve(blob); |       defer.resolve(blob); | ||||||
|       //var split = type.split('[/;]'); |  | ||||||
|       //blob.name = url.substring(0, 150).replace(/\W+/g, '') + '.' + (split.length > 1 ? split[1] : 'jpg'); |  | ||||||
|     }, function (e) { |     }, function (e) { | ||||||
|       defer.reject(e); |       defer.reject(e); | ||||||
|     }); |     }); | ||||||
| @@ -843,7 +852,7 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE | |||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   upload.shouldUpdateOn = function (type, attr, scope) { |   upload.shouldUpdateOn = function (type, attr, scope) { | ||||||
|     var modelOptions = upload.attrGetter('ngModelOptions', attr, scope); |     var modelOptions = upload.attrGetter('ngfModelOptions', attr, scope); | ||||||
|     if (modelOptions && modelOptions.updateOn) { |     if (modelOptions && modelOptions.updateOn) { | ||||||
|       return modelOptions.updateOn.split(' ').indexOf(type) > -1; |       return modelOptions.updateOn.split(' ').indexOf(type) > -1; | ||||||
|     } |     } | ||||||
| @@ -893,13 +902,13 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE | |||||||
|     return $q.all(promises); |     return $q.all(promises); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   function resize(files, attr, scope) { |   function resizeFile(files, attr, scope, ngModel) { | ||||||
|     var resizeVal = upload.attrGetter('ngfResize', attr, scope); |     var resizeVal = upload.attrGetter('ngfResize', attr, scope); | ||||||
|     if (!resizeVal || !upload.isResizeSupported() || !files.length) return upload.emptyPromise(); |     if (!resizeVal || !upload.isResizeSupported() || !files.length) return upload.emptyPromise(); | ||||||
|     if (resizeVal instanceof Function) { |     if (resizeVal instanceof Function) { | ||||||
|       var defer = $q.defer(); |       var defer = $q.defer(); | ||||||
|       resizeVal(files).then(function (p) { |       return resizeVal(files).then(function (p) { | ||||||
|         resizeWithParams(p, files, attr, scope).then(function (r) { |         resizeWithParams(p, files, attr, scope, ngModel).then(function (r) { | ||||||
|           defer.resolve(r); |           defer.resolve(r); | ||||||
|         }, function (e) { |         }, function (e) { | ||||||
|           defer.reject(e); |           defer.reject(e); | ||||||
| @@ -908,27 +917,30 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE | |||||||
|         defer.reject(e); |         defer.reject(e); | ||||||
|       }); |       }); | ||||||
|     } else { |     } else { | ||||||
|       return resizeWithParams(resizeVal, files, attr, scope); |       return resizeWithParams(resizeVal, files, attr, scope, ngModel); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   function resizeWithParams(param, files, attr, scope) { |   function resizeWithParams(params, files, attr, scope, ngModel) { | ||||||
|     var promises = [upload.emptyPromise()]; |     var promises = [upload.emptyPromise()]; | ||||||
|  |  | ||||||
|     function handleFile(f, i) { |     function handleFile(f, i) { | ||||||
|       if (f.type.indexOf('image') === 0) { |       if (f.type.indexOf('image') === 0) { | ||||||
|         if (param.pattern && !upload.validatePattern(f, param.pattern)) return; |         if (params.pattern && !upload.validatePattern(f, params.pattern)) return; | ||||||
|         var promise = upload.resize(f, param.width, param.height, param.quality, |         params.resizeIf = function (width, height) { | ||||||
|           param.type, param.ratio, param.centerCrop, function (width, height) { |           return upload.attrGetter('ngfResizeIf', attr, scope, | ||||||
|             return upload.attrGetter('ngfResizeIf', attr, scope, |             {$width: width, $height: height, $file: f}); | ||||||
|               {$width: width, $height: height, $file: f}); |         }; | ||||||
|           }, param.restoreExif !== false); |         var promise = upload.resize(f, params); | ||||||
|         promises.push(promise); |         promises.push(promise); | ||||||
|         promise.then(function (resizedFile) { |         promise.then(function (resizedFile) { | ||||||
|           files.splice(i, 1, resizedFile); |           files.splice(i, 1, resizedFile); | ||||||
|         }, function (e) { |         }, function (e) { | ||||||
|           f.$error = 'resize'; |           f.$error = 'resize'; | ||||||
|  |           (f.$errorMessages = (f.$errorMessages || {})).resize = true; | ||||||
|           f.$errorParam = (e ? (e.message ? e.message : e) + ': ' : '') + (f && f.name); |           f.$errorParam = (e ? (e.message ? e.message : e) + ': ' : '') + (f && f.name); | ||||||
|  |           ngModel.$ngfValidations.push({name: 'resize', valid: false}); | ||||||
|  |           upload.applyModelValidation(ngModel, files); | ||||||
|         }); |         }); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -1015,18 +1027,6 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE | |||||||
|       return angular.isArray(v) ? v : [v]; |       return angular.isArray(v) ? v : [v]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function separateInvalids() { |  | ||||||
|       valids = []; |  | ||||||
|       invalids = []; |  | ||||||
|       angular.forEach(allNewFiles, function (file) { |  | ||||||
|         if (file.$error) { |  | ||||||
|           invalids.push(file); |  | ||||||
|         } else { |  | ||||||
|           valids.push(file); |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     function resizeAndUpdate() { |     function resizeAndUpdate() { | ||||||
|       function updateModel() { |       function updateModel() { | ||||||
|         $timeout(function () { |         $timeout(function () { | ||||||
| @@ -1036,17 +1036,30 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE | |||||||
|         }, options && options.debounce ? options.debounce.change || options.debounce : 0); |         }, options && options.debounce ? options.debounce.change || options.debounce : 0); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       resize(validateAfterResize ? allNewFiles : valids, attr, scope).then(function () { |       var resizingFiles = validateAfterResize ? allNewFiles : valids; | ||||||
|  |       resizeFile(resizingFiles, attr, scope, ngModel).then(function () { | ||||||
|         if (validateAfterResize) { |         if (validateAfterResize) { | ||||||
|           upload.validate(allNewFiles, prevValidFiles.length, ngModel, attr, scope).then(function () { |           upload.validate(allNewFiles, keep ? prevValidFiles.length : 0, ngModel, attr, scope) | ||||||
|             separateInvalids(); |             .then(function (validationResult) { | ||||||
|             updateModel(); |               valids = validationResult.validsFiles; | ||||||
|           }); |               invalids = validationResult.invalidsFiles; | ||||||
|  |               updateModel(); | ||||||
|  |             }); | ||||||
|         } else { |         } else { | ||||||
|           updateModel(); |           updateModel(); | ||||||
|         } |         } | ||||||
|       }, function (e) { |       }, function () { | ||||||
|         throw 'Could not resize files ' + e; |         for (var i = 0; i < resizingFiles.length; i++) { | ||||||
|  |           var f = resizingFiles[i]; | ||||||
|  |           if (f.$error === 'resize') { | ||||||
|  |             var index = valids.indexOf(f); | ||||||
|  |             if (index > -1) { | ||||||
|  |               valids.splice(index, 1); | ||||||
|  |               invalids.push(f); | ||||||
|  |             } | ||||||
|  |             updateModel(); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1076,13 +1089,15 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE | |||||||
|  |  | ||||||
|     var validateAfterResize = upload.attrGetter('ngfValidateAfterResize', attr, scope); |     var validateAfterResize = upload.attrGetter('ngfValidateAfterResize', attr, scope); | ||||||
|  |  | ||||||
|     var options = upload.attrGetter('ngModelOptions', attr, scope); |     var options = upload.attrGetter('ngfModelOptions', attr, scope); | ||||||
|     upload.validate(allNewFiles, prevValidFiles.length, ngModel, attr, scope).then(function () { |     upload.validate(allNewFiles, keep ? prevValidFiles.length : 0, ngModel, attr, scope) | ||||||
|  |       .then(function (validationResult) { | ||||||
|       if (noDelay) { |       if (noDelay) { | ||||||
|         update(allNewFiles, [], files, dupFiles, isSingleModel); |         update(allNewFiles, [], files, dupFiles, isSingleModel); | ||||||
|       } else { |       } else { | ||||||
|         if ((!options || !options.allowInvalid) && !validateAfterResize) { |         if ((!options || !options.allowInvalid) && !validateAfterResize) { | ||||||
|           separateInvalids(); |           valids = validationResult.validFiles; | ||||||
|  |           invalids = validationResult.invalidFiles; | ||||||
|         } else { |         } else { | ||||||
|           valids = allNewFiles; |           valids = allNewFiles; | ||||||
|         } |         } | ||||||
| @@ -1119,7 +1134,7 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|     /** @namespace attr.ngfSelect */ |     /** @namespace attr.ngfSelect */ | ||||||
|     /** @namespace attr.ngfChange */ |     /** @namespace attr.ngfChange */ | ||||||
|     /** @namespace attr.ngModel */ |     /** @namespace attr.ngModel */ | ||||||
|     /** @namespace attr.ngModelOptions */ |     /** @namespace attr.ngfModelOptions */ | ||||||
|     /** @namespace attr.ngfMultiple */ |     /** @namespace attr.ngfMultiple */ | ||||||
|     /** @namespace attr.ngfCapture */ |     /** @namespace attr.ngfCapture */ | ||||||
|     /** @namespace attr.ngfValidate */ |     /** @namespace attr.ngfValidate */ | ||||||
| @@ -1139,6 +1154,8 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|     function changeFn(evt) { |     function changeFn(evt) { | ||||||
|       if (upload.shouldUpdateOn('change', attr, scope)) { |       if (upload.shouldUpdateOn('change', attr, scope)) { | ||||||
|         var fileList = evt.__files_ || (evt.target && evt.target.files), files = []; |         var fileList = evt.__files_ || (evt.target && evt.target.files), files = []; | ||||||
|  |         /* Handle duplicate call in  IE11 */ | ||||||
|  |         if (!fileList) return; | ||||||
|         for (var i = 0; i < fileList.length; i++) { |         for (var i = 0; i < fileList.length; i++) { | ||||||
|           files.push(fileList[i]); |           files.push(fileList[i]); | ||||||
|         } |         } | ||||||
| @@ -1150,31 +1167,39 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|     upload.registerModelChangeValidator(ngModel, attr, scope); |     upload.registerModelChangeValidator(ngModel, attr, scope); | ||||||
|  |  | ||||||
|     var unwatches = []; |     var unwatches = []; | ||||||
|     unwatches.push(scope.$watch(attrGetter('ngfMultiple'), function () { |     if (attrGetter('ngfMultiple')) { | ||||||
|       fileElem.attr('multiple', attrGetter('ngfMultiple', scope)); |       unwatches.push(scope.$watch(attrGetter('ngfMultiple'), function () { | ||||||
|     })); |         fileElem.attr('multiple', attrGetter('ngfMultiple', scope)); | ||||||
|     unwatches.push(scope.$watch(attrGetter('ngfCapture'), function () { |       })); | ||||||
|       fileElem.attr('capture', attrGetter('ngfCapture', scope)); |     } | ||||||
|     })); |     if (attrGetter('ngfCapture')) { | ||||||
|     unwatches.push(scope.$watch(attrGetter('ngfAccept'), function () { |       unwatches.push(scope.$watch(attrGetter('ngfCapture'), function () { | ||||||
|       fileElem.attr('accept', attrGetter('ngfAccept', scope)); |         fileElem.attr('capture', attrGetter('ngfCapture', scope)); | ||||||
|     })); |       })); | ||||||
|     attr.$observe('accept', function () { |     } | ||||||
|  |     if (attrGetter('ngfAccept')) { | ||||||
|  |       unwatches.push(scope.$watch(attrGetter('ngfAccept'), function () { | ||||||
|  |         fileElem.attr('accept', attrGetter('ngfAccept', scope)); | ||||||
|  |       })); | ||||||
|  |     } | ||||||
|  |     unwatches.push(attr.$observe('accept', function () { | ||||||
|       fileElem.attr('accept', attrGetter('accept')); |       fileElem.attr('accept', attrGetter('accept')); | ||||||
|     }); |     })); | ||||||
|     unwatches.push(function () { |     function bindAttrToFileInput(fileElem, label) { | ||||||
|       if (attr.$$observers) delete attr.$$observers.accept; |       function updateId(val) { | ||||||
|     }); |         fileElem.attr('id', 'ngf-' + val); | ||||||
|     function bindAttrToFileInput(fileElem) { |         label.attr('id', 'ngf-label-' + val); | ||||||
|       if (elem !== fileElem) { |       } | ||||||
|         for (var i = 0; i < elem[0].attributes.length; i++) { |  | ||||||
|           var attribute = elem[0].attributes[i]; |       for (var i = 0; i < elem[0].attributes.length; i++) { | ||||||
|           if (attribute.name !== 'type' && attribute.name !== 'class' && attribute.name !== 'style') { |         var attribute = elem[0].attributes[i]; | ||||||
|             if (attribute.value == null || attribute.value === '') { |         if (attribute.name !== 'type' && attribute.name !== 'class' && attribute.name !== 'style') { | ||||||
|               if (attribute.name === 'required') attribute.value = 'required'; |           if (attribute.name === 'id') { | ||||||
|               if (attribute.name === 'multiple') attribute.value = 'multiple'; |             updateId(attribute.value); | ||||||
|             } |             unwatches.push(attr.$observe('id', updateId)); | ||||||
|             fileElem.attr(attribute.name, attribute.name === 'id' ? 'ngf-' + attribute.value : attribute.value); |           } else { | ||||||
|  |             fileElem.attr(attribute.name, (!attribute.value && (attribute.name === 'required' || | ||||||
|  |             attribute.name === 'multiple')) ? attribute.name : attribute.value); | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @@ -1187,12 +1212,12 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|  |  | ||||||
|       var fileElem = angular.element('<input type="file">'); |       var fileElem = angular.element('<input type="file">'); | ||||||
|  |  | ||||||
|       bindAttrToFileInput(fileElem); |  | ||||||
|  |  | ||||||
|       var label = angular.element('<label>upload</label>'); |       var label = angular.element('<label>upload</label>'); | ||||||
|       label.css('visibility', 'hidden').css('position', 'absolute').css('overflow', 'hidden') |       label.css('visibility', 'hidden').css('position', 'absolute').css('overflow', 'hidden') | ||||||
|         .css('width', '0px').css('height', '0px').css('border', 'none') |         .css('width', '0px').css('height', '0px').css('border', 'none') | ||||||
|         .css('margin', '0px').css('padding', '0px').attr('tabindex', '-1'); |         .css('margin', '0px').css('padding', '0px').attr('tabindex', '-1'); | ||||||
|  |       bindAttrToFileInput(fileElem, label); | ||||||
|  |  | ||||||
|       generatedElems.push({el: elem, ref: label}); |       generatedElems.push({el: elem, ref: label}); | ||||||
|  |  | ||||||
|       document.body.appendChild(label.append(fileElem)[0]); |       document.body.appendChild(label.append(fileElem)[0]); | ||||||
| @@ -1200,13 +1225,12 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|       return fileElem; |       return fileElem; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     var initialTouchStartY = 0; |  | ||||||
|  |  | ||||||
|     function clickHandler(evt) { |     function clickHandler(evt) { | ||||||
|       if (elem.attr('disabled')) return false; |       if (elem.attr('disabled')) return false; | ||||||
|       if (attrGetter('ngfSelectDisabled', scope)) return; |       if (attrGetter('ngfSelectDisabled', scope)) return; | ||||||
|  |  | ||||||
|       var r = handleTouch(evt); |       var r = detectSwipe(evt); | ||||||
|  |       // prevent the click if it is a swipe | ||||||
|       if (r != null) return r; |       if (r != null) return r; | ||||||
|  |  | ||||||
|       resetModel(evt); |       resetModel(evt); | ||||||
| @@ -1218,7 +1242,8 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|           document.body.appendChild(fileElem.parent()[0]); |           document.body.appendChild(fileElem.parent()[0]); | ||||||
|           fileElem.bind('change', changeFn); |           fileElem.bind('change', changeFn); | ||||||
|         } |         } | ||||||
|       } catch(e){/*ignore*/} |       } catch (e) {/*ignore*/ | ||||||
|  |       } | ||||||
|  |  | ||||||
|       if (isDelayedClickSupported(navigator.userAgent)) { |       if (isDelayedClickSupported(navigator.userAgent)) { | ||||||
|         setTimeout(function () { |         setTimeout(function () { | ||||||
| @@ -1231,19 +1256,30 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function handleTouch(evt) { |  | ||||||
|       var touches = evt.changedTouches || (evt.originalEvent && evt.originalEvent.changedTouches); |  | ||||||
|       if (evt.type === 'touchstart') { |  | ||||||
|         initialTouchStartY = touches ? touches[0].clientY : 0; |  | ||||||
|         return true; // don't block event default |  | ||||||
|       } else { |  | ||||||
|         evt.stopPropagation(); |  | ||||||
|         evt.preventDefault(); |  | ||||||
|  |  | ||||||
|         // prevent scroll from triggering event |     var initialTouchStartY = 0; | ||||||
|         if (evt.type === 'touchend') { |     var initialTouchStartX = 0; | ||||||
|           var currentLocation = touches ? touches[0].clientY : 0; |  | ||||||
|           if (Math.abs(currentLocation - initialTouchStartY) > 20) return false; |     function detectSwipe(evt) { | ||||||
|  |       var touches = evt.changedTouches || (evt.originalEvent && evt.originalEvent.changedTouches); | ||||||
|  |       if (touches) { | ||||||
|  |         if (evt.type === 'touchstart') { | ||||||
|  |           initialTouchStartX = touches[0].clientX; | ||||||
|  |           initialTouchStartY = touches[0].clientY; | ||||||
|  |           return true; // don't block event default | ||||||
|  |         } else { | ||||||
|  |           // prevent scroll from triggering event | ||||||
|  |           if (evt.type === 'touchend') { | ||||||
|  |             var currentX = touches[0].clientX; | ||||||
|  |             var currentY = touches[0].clientY; | ||||||
|  |             if ((Math.abs(currentX - initialTouchStartX) > 20) || | ||||||
|  |               (Math.abs(currentY - initialTouchStartY) > 20)) { | ||||||
|  |               evt.stopPropagation(); | ||||||
|  |               evt.preventDefault(); | ||||||
|  |               return false; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |           return true; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -1474,14 +1510,19 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|         var size = resizeParams; |         var size = resizeParams; | ||||||
|         if (directiveName === 'ngfThumbnail') { |         if (directiveName === 'ngfThumbnail') { | ||||||
|           if (!size) { |           if (!size) { | ||||||
|             size = {width: elem[0].clientWidth, height: elem[0].clientHeight}; |             size = { | ||||||
|  |               width: elem[0].naturalWidth || elem[0].clientWidth, | ||||||
|  |               height: elem[0].naturalHeight || elem[0].clientHeight | ||||||
|  |             }; | ||||||
|           } |           } | ||||||
|           if (size.width === 0 && window.getComputedStyle) { |           if (size.width === 0 && window.getComputedStyle) { | ||||||
|             var style = getComputedStyle(elem[0]); |             var style = getComputedStyle(elem[0]); | ||||||
|             size = { |             if (style.width && style.width.indexOf('px') > -1 && style.height && style.height.indexOf('px') > -1) { | ||||||
|               width: parseInt(style.width.slice(0, -2)), |               size = { | ||||||
|               height: parseInt(style.height.slice(0, -2)) |                 width: parseInt(style.width.slice(0, -2)), | ||||||
|             }; |                 height: parseInt(style.height.slice(0, -2)) | ||||||
|  |               }; | ||||||
|  |             } | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -1496,7 +1537,11 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|         if (file && file.type && file.type.search(getTagType(elem[0])) === 0 && |         if (file && file.type && file.type.search(getTagType(elem[0])) === 0 && | ||||||
|           (!isBackground || file.type.indexOf('image') === 0)) { |           (!isBackground || file.type.indexOf('image') === 0)) { | ||||||
|           if (size && Upload.isResizeSupported()) { |           if (size && Upload.isResizeSupported()) { | ||||||
|             Upload.resize(file, size.width, size.height, size.quality).then( |             size.resizeIf = function (width, height) { | ||||||
|  |               return Upload.attrGetter('ngfResizeIf', attr, scope, | ||||||
|  |                 {$width: width, $height: height, $file: file}); | ||||||
|  |             }; | ||||||
|  |             Upload.resize(file, size).then( | ||||||
|               function (f) { |               function (f) { | ||||||
|                 constructDataUrl(f); |                 constructDataUrl(f); | ||||||
|               }, function (e) { |               }, function (e) { | ||||||
| @@ -1558,8 +1603,8 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|   }]); |   }]); | ||||||
|  |  | ||||||
|   ngFileUpload.config(['$compileProvider', function ($compileProvider) { |   ngFileUpload.config(['$compileProvider', function ($compileProvider) { | ||||||
|     if ($compileProvider.imgSrcSanitizationWhitelist) $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|local|file|data|blob):/); |     if ($compileProvider.imgSrcSanitizationWhitelist) $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|webcal|local|file|data|blob):/); | ||||||
|     if ($compileProvider.aHrefSanitizationWhitelist) $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|local|file|data|blob):/); |     if ($compileProvider.aHrefSanitizationWhitelist) $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|webcal|local|file|data|blob):/); | ||||||
|   }]); |   }]); | ||||||
|  |  | ||||||
|   ngFileUpload.filter('ngfDataUrl', ['UploadDataUrl', '$sce', function (UploadDataUrl, $sce) { |   ngFileUpload.filter('ngfDataUrl', ['UploadDataUrl', '$sce', function (UploadDataUrl, $sce) { | ||||||
| @@ -1651,13 +1696,15 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|     if (ngModel) { |     if (ngModel) { | ||||||
|       ngModel.$formatters.push(function (files) { |       ngModel.$formatters.push(function (files) { | ||||||
|         if (ngModel.$dirty) { |         if (ngModel.$dirty) { | ||||||
|  |           var filesArray = files; | ||||||
|           if (files && !angular.isArray(files)) { |           if (files && !angular.isArray(files)) { | ||||||
|             files = [files]; |             filesArray = [files]; | ||||||
|           } |           } | ||||||
|           upload.validate(files, 0, ngModel, attr, scope).then(function () { |           upload.validate(filesArray, 0, ngModel, attr, scope).then(function () { | ||||||
|             upload.applyModelValidation(ngModel, files); |             upload.applyModelValidation(ngModel, filesArray); | ||||||
|           }); |           }); | ||||||
|         } |         } | ||||||
|  |         return files; | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
| @@ -1707,11 +1754,15 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|       return upload.attrGetter(name, attr, scope, params); |       return upload.attrGetter(name, attr, scope, params); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  |     var ignoredErrors = (upload.attrGetter('ngfIgnoreInvalid', attr, scope) || '').split(' '); | ||||||
|  |     var runAllValidation = upload.attrGetter('ngfRunAllValidations', attr, scope); | ||||||
|  |  | ||||||
|     if (files == null || files.length === 0) { |     if (files == null || files.length === 0) { | ||||||
|       return upload.emptyPromise(ngModel); |       return upload.emptyPromise({'validFiles': files, 'invalidFiles': []}); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     files = files.length === undefined ? [files] : files.slice(0); |     files = files.length === undefined ? [files] : files.slice(0); | ||||||
|  |     var invalidFiles = []; | ||||||
|  |  | ||||||
|     function validateSync(name, validationName, fn) { |     function validateSync(name, validationName, fn) { | ||||||
|       if (files) { |       if (files) { | ||||||
| @@ -1722,11 +1773,20 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|             var val = upload.getValidationAttr(attr, scope, name, validationName, file); |             var val = upload.getValidationAttr(attr, scope, name, validationName, file); | ||||||
|             if (val != null) { |             if (val != null) { | ||||||
|               if (!fn(file, val, i)) { |               if (!fn(file, val, i)) { | ||||||
|                 file.$error = name; |                 if (ignoredErrors.indexOf(name) === -1) { | ||||||
|                 (file.$errorMessages = (file.$errorMessages || {}))[name] = true; |                   file.$error = name; | ||||||
|                 file.$errorParam = val; |                   (file.$errorMessages = (file.$errorMessages || {}))[name] = true; | ||||||
|                 files.splice(i, 1); |                   file.$errorParam = val; | ||||||
|                 valid = false; |                   if (invalidFiles.indexOf(file) === -1) { | ||||||
|  |                     invalidFiles.push(file); | ||||||
|  |                   } | ||||||
|  |                   if (!runAllValidation) { | ||||||
|  |                     files.splice(i, 1); | ||||||
|  |                   } | ||||||
|  |                   valid = false; | ||||||
|  |                 } else { | ||||||
|  |                   files.splice(i, 1); | ||||||
|  |                 } | ||||||
|               } |               } | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
| @@ -1737,9 +1797,6 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     validateSync('maxFiles', null, function (file, val, i) { |  | ||||||
|       return prevLength + i < val; |  | ||||||
|     }); |  | ||||||
|     validateSync('pattern', null, upload.validatePattern); |     validateSync('pattern', null, upload.validatePattern); | ||||||
|     validateSync('minSize', 'size.min', function (file, val) { |     validateSync('minSize', 'size.min', function (file, val) { | ||||||
|       return file.size + 0.1 >= upload.translateScalars(val); |       return file.size + 0.1 >= upload.translateScalars(val); | ||||||
| @@ -1762,44 +1819,58 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     if (!files.length) { |     if (!files.length) { | ||||||
|       return upload.emptyPromise(ngModel, ngModel.$ngfValidations); |       return upload.emptyPromise({'validFiles': [], 'invalidFiles': invalidFiles}); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function validateAsync(name, validationName, type, asyncFn, fn) { |     function validateAsync(name, validationName, type, asyncFn, fn) { | ||||||
|       function resolveResult(defer, file, val) { |       function resolveResult(defer, file, val) { | ||||||
|  |         function resolveInternal(fn) { | ||||||
|  |           if (fn()) { | ||||||
|  |             if (ignoredErrors.indexOf(name) === -1) { | ||||||
|  |               file.$error = name; | ||||||
|  |               (file.$errorMessages = (file.$errorMessages || {}))[name] = true; | ||||||
|  |               file.$errorParam = val; | ||||||
|  |               if (invalidFiles.indexOf(file) === -1) { | ||||||
|  |                 invalidFiles.push(file); | ||||||
|  |               } | ||||||
|  |               if (!runAllValidation) { | ||||||
|  |                 var i = files.indexOf(file); | ||||||
|  |                 if (i > -1) files.splice(i, 1); | ||||||
|  |               } | ||||||
|  |               defer.resolve(false); | ||||||
|  |             } else { | ||||||
|  |               var j = files.indexOf(file); | ||||||
|  |               if (j > -1) files.splice(j, 1); | ||||||
|  |               defer.resolve(true); | ||||||
|  |             } | ||||||
|  |           } else { | ||||||
|  |             defer.resolve(true); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if (val != null) { |         if (val != null) { | ||||||
|           asyncFn(file, val).then(function (d) { |           asyncFn(file, val).then(function (d) { | ||||||
|             if (!fn(d, val)) { |             resolveInternal(function () { | ||||||
|               file.$error = name; |               return !fn(d, val); | ||||||
|               (file.$errorMessages = (file.$errorMessages || {}))[name] = true; |             }); | ||||||
|               file.$errorParam = val; |  | ||||||
|               defer.reject(); |  | ||||||
|             } else { |  | ||||||
|               defer.resolve(); |  | ||||||
|             } |  | ||||||
|           }, function () { |           }, function () { | ||||||
|             if (attrGetter('ngfValidateForce', {$file: file})) { |             resolveInternal(function () { | ||||||
|               file.$error = name; |               return attrGetter('ngfValidateForce', {$file: file}); | ||||||
|               (file.$errorMessages = (file.$errorMessages || {}))[name] = true; |             }); | ||||||
|               file.$errorParam = val; |  | ||||||
|               defer.reject(); |  | ||||||
|             } else { |  | ||||||
|               defer.resolve(); |  | ||||||
|             } |  | ||||||
|           }); |           }); | ||||||
|         } else { |         } else { | ||||||
|           defer.resolve(); |           defer.resolve(true); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       var promises = [upload.emptyPromise()]; |       var promises = [upload.emptyPromise(true)]; | ||||||
|       if (files) { |       if (files) { | ||||||
|         files = files.length === undefined ? [files] : files; |         files = files.length === undefined ? [files] : files; | ||||||
|         angular.forEach(files, function (file) { |         angular.forEach(files, function (file) { | ||||||
|           var defer = $q.defer(); |           var defer = $q.defer(); | ||||||
|           promises.push(defer.promise); |           promises.push(defer.promise); | ||||||
|           if (type && (file.type == null || file.type.search(type) !== 0)) { |           if (type && (file.type == null || file.type.search(type) !== 0)) { | ||||||
|             defer.resolve(); |             defer.resolve(true); | ||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
|           if (name === 'dimensions' && upload.attrGetter('ngfDimensions', attr) != null) { |           if (name === 'dimensions' && upload.attrGetter('ngfDimensions', attr) != null) { | ||||||
| @@ -1807,96 +1878,120 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|               resolveResult(defer, file, |               resolveResult(defer, file, | ||||||
|                 attrGetter('ngfDimensions', {$file: file, $width: d.width, $height: d.height})); |                 attrGetter('ngfDimensions', {$file: file, $width: d.width, $height: d.height})); | ||||||
|             }, function () { |             }, function () { | ||||||
|               defer.reject(); |               defer.resolve(false); | ||||||
|             }); |             }); | ||||||
|           } else if (name === 'duration' && upload.attrGetter('ngfDuration', attr) != null) { |           } else if (name === 'duration' && upload.attrGetter('ngfDuration', attr) != null) { | ||||||
|             upload.mediaDuration(file).then(function (d) { |             upload.mediaDuration(file).then(function (d) { | ||||||
|               resolveResult(defer, file, |               resolveResult(defer, file, | ||||||
|                 attrGetter('ngfDuration', {$file: file, $duration: d})); |                 attrGetter('ngfDuration', {$file: file, $duration: d})); | ||||||
|             }, function () { |             }, function () { | ||||||
|               defer.reject(); |               defer.resolve(false); | ||||||
|             }); |             }); | ||||||
|           } else { |           } else { | ||||||
|             resolveResult(defer, file, |             resolveResult(defer, file, | ||||||
|               upload.getValidationAttr(attr, scope, name, validationName, file)); |               upload.getValidationAttr(attr, scope, name, validationName, file)); | ||||||
|           } |           } | ||||||
|         }); |         }); | ||||||
|         return $q.all(promises).then(function () { |  | ||||||
|           ngModel.$ngfValidations.push({name: name, valid: true}); |  | ||||||
|         }, function () { |  | ||||||
|           ngModel.$ngfValidations.push({name: name, valid: false}); |  | ||||||
|         }); |  | ||||||
|       } |       } | ||||||
|  |       var deffer = $q.defer(); | ||||||
|  |       $q.all(promises).then(function (values) { | ||||||
|  |         var isValid = true; | ||||||
|  |         for (var i = 0; i < values.length; i++) { | ||||||
|  |           if (!values[i]) { | ||||||
|  |             isValid = false; | ||||||
|  |             break; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         ngModel.$ngfValidations.push({name: name, valid: isValid}); | ||||||
|  |         deffer.resolve(isValid); | ||||||
|  |       }); | ||||||
|  |       return deffer.promise; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     var deffer = $q.defer(); |     var deffer = $q.defer(); | ||||||
|     var promises = []; |     var promises = []; | ||||||
|  |  | ||||||
|     promises.push(upload.happyPromise(validateAsync('maxHeight', 'height.max', /image/, |     promises.push(validateAsync('maxHeight', 'height.max', /image/, | ||||||
|       this.imageDimensions, function (d, val) { |       this.imageDimensions, function (d, val) { | ||||||
|         return d.height <= val; |         return d.height <= val; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('minHeight', 'height.min', /image/, |     promises.push(validateAsync('minHeight', 'height.min', /image/, | ||||||
|       this.imageDimensions, function (d, val) { |       this.imageDimensions, function (d, val) { | ||||||
|         return d.height >= val; |         return d.height >= val; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('maxWidth', 'width.max', /image/, |     promises.push(validateAsync('maxWidth', 'width.max', /image/, | ||||||
|       this.imageDimensions, function (d, val) { |       this.imageDimensions, function (d, val) { | ||||||
|         return d.width <= val; |         return d.width <= val; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('minWidth', 'width.min', /image/, |     promises.push(validateAsync('minWidth', 'width.min', /image/, | ||||||
|       this.imageDimensions, function (d, val) { |       this.imageDimensions, function (d, val) { | ||||||
|         return d.width >= val; |         return d.width >= val; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('dimensions', null, /image/, |     promises.push(validateAsync('dimensions', null, /image/, | ||||||
|       function (file, val) { |       function (file, val) { | ||||||
|         return upload.emptyPromise(val); |         return upload.emptyPromise(val); | ||||||
|       }, function (r) { |       }, function (r) { | ||||||
|         return r; |         return r; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('ratio', null, /image/, |     promises.push(validateAsync('ratio', null, /image/, | ||||||
|       this.imageDimensions, function (d, val) { |       this.imageDimensions, function (d, val) { | ||||||
|         var split = val.toString().split(','), valid = false; |         var split = val.toString().split(','), valid = false; | ||||||
|         for (var i = 0; i < split.length; i++) { |         for (var i = 0; i < split.length; i++) { | ||||||
|           if (Math.abs((d.width / d.height) - upload.ratioToFloat(split[i])) < 0.0001) { |           if (Math.abs((d.width / d.height) - upload.ratioToFloat(split[i])) < 0.01) { | ||||||
|             valid = true; |             valid = true; | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|         return valid; |         return valid; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('maxRatio', 'ratio.max', /image/, |     promises.push(validateAsync('maxRatio', 'ratio.max', /image/, | ||||||
|       this.imageDimensions, function (d, val) { |       this.imageDimensions, function (d, val) { | ||||||
|         return (d.width / d.height) - upload.ratioToFloat(val) < 0.0001; |         return (d.width / d.height) - upload.ratioToFloat(val) < 0.0001; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('minRatio', 'ratio.min', /image/, |     promises.push(validateAsync('minRatio', 'ratio.min', /image/, | ||||||
|       this.imageDimensions, function (d, val) { |       this.imageDimensions, function (d, val) { | ||||||
|         return (d.width / d.height) - upload.ratioToFloat(val) > -0.0001; |         return (d.width / d.height) - upload.ratioToFloat(val) > -0.0001; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('maxDuration', 'duration.max', /audio|video/, |     promises.push(validateAsync('maxDuration', 'duration.max', /audio|video/, | ||||||
|       this.mediaDuration, function (d, val) { |       this.mediaDuration, function (d, val) { | ||||||
|         return d <= upload.translateScalars(val); |         return d <= upload.translateScalars(val); | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('minDuration', 'duration.min', /audio|video/, |     promises.push(validateAsync('minDuration', 'duration.min', /audio|video/, | ||||||
|       this.mediaDuration, function (d, val) { |       this.mediaDuration, function (d, val) { | ||||||
|         return d >= upload.translateScalars(val); |         return d >= upload.translateScalars(val); | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('duration', null, /audio|video/, |     promises.push(validateAsync('duration', null, /audio|video/, | ||||||
|       function (file, val) { |       function (file, val) { | ||||||
|         return upload.emptyPromise(val); |         return upload.emptyPromise(val); | ||||||
|       }, function (r) { |       }, function (r) { | ||||||
|         return r; |         return r; | ||||||
|       }))); |       })); | ||||||
|  |  | ||||||
|     promises.push(upload.happyPromise(validateAsync('validateAsyncFn', null, null, |     promises.push(validateAsync('validateAsyncFn', null, null, | ||||||
|       function (file, val) { |       function (file, val) { | ||||||
|         return val; |         return val; | ||||||
|       }, function (r) { |       }, function (r) { | ||||||
|         return r === true || r === null || r === ''; |         return r === true || r === null || r === ''; | ||||||
|       }))); |       })); | ||||||
|  |  | ||||||
|     return $q.all(promises).then(function () { |     $q.all(promises).then(function () { | ||||||
|       deffer.resolve(ngModel, ngModel.$ngfValidations); |  | ||||||
|  |       if (runAllValidation) { | ||||||
|  |         for (var i = 0; i < files.length; i++) { | ||||||
|  |           var file = files[i]; | ||||||
|  |           if (file.$error) { | ||||||
|  |             files.splice(i--, 1); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       runAllValidation = false; | ||||||
|  |       validateSync('maxFiles', null, function (file, val, i) { | ||||||
|  |         return prevLength + i < val; | ||||||
|  |       }); | ||||||
|  |  | ||||||
|  |       deffer.resolve({'validFiles': files, 'invalidFiles': invalidFiles}); | ||||||
|     }); |     }); | ||||||
|  |     return deffer.promise; | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   upload.imageDimensions = function (file) { |   upload.imageDimensions = function (file) { | ||||||
| @@ -1921,8 +2016,8 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|           .css('max-width', 'none !important').css('max-height', 'none !important'); |           .css('max-width', 'none !important').css('max-height', 'none !important'); | ||||||
|  |  | ||||||
|         function success() { |         function success() { | ||||||
|           var width = img[0].clientWidth; |           var width = img[0].naturalWidth || img[0].clientWidth; | ||||||
|           var height = img[0].clientHeight; |           var height = img[0].naturalHeight || img[0].clientHeight; | ||||||
|           img.remove(); |           img.remove(); | ||||||
|           file.$ngfWidth = width; |           file.$ngfWidth = width; | ||||||
|           file.$ngfHeight = height; |           file.$ngfHeight = height; | ||||||
| @@ -1936,23 +2031,23 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|  |  | ||||||
|         img.on('load', success); |         img.on('load', success); | ||||||
|         img.on('error', error); |         img.on('error', error); | ||||||
|         var count = 0; |  | ||||||
|  |  | ||||||
|         function checkLoadError() { |         var secondsCounter = 0; | ||||||
|  |         function checkLoadErrorInCaseOfNoCallback() { | ||||||
|           $timeout(function () { |           $timeout(function () { | ||||||
|             if (img[0].parentNode) { |             if (img[0].parentNode) { | ||||||
|               if (img[0].clientWidth) { |               if (img[0].clientWidth) { | ||||||
|                 success(); |                 success(); | ||||||
|               } else if (count > 10) { |               } else if (secondsCounter++ > 10) { | ||||||
|                 error(); |                 error(); | ||||||
|               } else { |               } else { | ||||||
|                 checkLoadError(); |                 checkLoadErrorInCaseOfNoCallback(); | ||||||
|               } |               } | ||||||
|             } |             } | ||||||
|           }, 1000); |           }, 1000); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         checkLoadError(); |         checkLoadErrorInCaseOfNoCallback(); | ||||||
|  |  | ||||||
|         angular.element(document.getElementsByTagName('body')[0]).append(img); |         angular.element(document.getElementsByTagName('body')[0]).append(img); | ||||||
|       }, function () { |       }, function () { | ||||||
| @@ -2063,31 +2158,35 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|     var deferred = $q.defer(); |     var deferred = $q.defer(); | ||||||
|     var canvasElement = document.createElement('canvas'); |     var canvasElement = document.createElement('canvas'); | ||||||
|     var imageElement = document.createElement('img'); |     var imageElement = document.createElement('img'); | ||||||
|  |     imageElement.setAttribute('style', 'visibility:hidden;position:fixed;z-index:-100000'); | ||||||
|  |     document.body.appendChild(imageElement); | ||||||
|  |  | ||||||
|     imageElement.onload = function () { |     imageElement.onload = function () { | ||||||
|       if (resizeIf != null && resizeIf(imageElement.width, imageElement.height) === false) { |       var imgWidth = imageElement.width, imgHeight = imageElement.height; | ||||||
|  |       imageElement.parentNode.removeChild(imageElement); | ||||||
|  |       if (resizeIf != null && resizeIf(imgWidth, imgHeight) === false) { | ||||||
|         deferred.reject('resizeIf'); |         deferred.reject('resizeIf'); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|       try { |       try { | ||||||
|         if (ratio) { |         if (ratio) { | ||||||
|           var ratioFloat = upload.ratioToFloat(ratio); |           var ratioFloat = upload.ratioToFloat(ratio); | ||||||
|           var imgRatio = imageElement.width / imageElement.height; |           var imgRatio = imgWidth / imgHeight; | ||||||
|           if (imgRatio < ratioFloat) { |           if (imgRatio < ratioFloat) { | ||||||
|             width = imageElement.width; |             width = imgWidth; | ||||||
|             height = width / ratioFloat; |             height = width / ratioFloat; | ||||||
|           } else { |           } else { | ||||||
|             height = imageElement.height; |             height = imgHeight; | ||||||
|             width = height * ratioFloat; |             width = height * ratioFloat; | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|         if (!width) { |         if (!width) { | ||||||
|           width = imageElement.width; |           width = imgWidth; | ||||||
|         } |         } | ||||||
|         if (!height) { |         if (!height) { | ||||||
|           height = imageElement.height; |           height = imgHeight; | ||||||
|         } |         } | ||||||
|         var dimensions = calculateAspectRatioFit(imageElement.width, imageElement.height, width, height, centerCrop); |         var dimensions = calculateAspectRatioFit(imgWidth, imgHeight, width, height, centerCrop); | ||||||
|         canvasElement.width = Math.min(dimensions.width, width); |         canvasElement.width = Math.min(dimensions.width, width); | ||||||
|         canvasElement.height = Math.min(dimensions.height, height); |         canvasElement.height = Math.min(dimensions.height, height); | ||||||
|         var context = canvasElement.getContext('2d'); |         var context = canvasElement.getContext('2d'); | ||||||
| @@ -2100,6 +2199,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|       } |       } | ||||||
|     }; |     }; | ||||||
|     imageElement.onerror = function () { |     imageElement.onerror = function () { | ||||||
|  |       imageElement.parentNode.removeChild(imageElement); | ||||||
|       deferred.reject(); |       deferred.reject(); | ||||||
|     }; |     }; | ||||||
|     imageElement.src = imagen; |     imageElement.src = imagen; | ||||||
| @@ -2136,14 +2236,15 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   upload.resize = function (file, width, height, quality, type, ratio, centerCrop, resizeIf, restoreExif) { |   upload.resize = function (file, options) { | ||||||
|     if (file.type.indexOf('image') !== 0) return upload.emptyPromise(file); |     if (file.type.indexOf('image') !== 0) return upload.emptyPromise(file); | ||||||
|  |  | ||||||
|     var deferred = $q.defer(); |     var deferred = $q.defer(); | ||||||
|     upload.dataUrl(file, true).then(function (url) { |     upload.dataUrl(file, true).then(function (url) { | ||||||
|       resize(url, width, height, quality, type || file.type, ratio, centerCrop, resizeIf) |       resize(url, options.width, options.height, options.quality, options.type || file.type, | ||||||
|  |         options.ratio, options.centerCrop, options.resizeIf) | ||||||
|         .then(function (dataUrl) { |         .then(function (dataUrl) { | ||||||
|           if (file.type === 'image/jpeg' && restoreExif) { |           if (file.type === 'image/jpeg' && options.restoreExif !== false) { | ||||||
|             try { |             try { | ||||||
|               dataUrl = upload.restoreExif(url, dataUrl); |               dataUrl = upload.restoreExif(url, dataUrl); | ||||||
|             } catch (e) { |             } catch (e) { | ||||||
| @@ -2172,13 +2273,13 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
| }]); | }]); | ||||||
|  |  | ||||||
| (function () { | (function () { | ||||||
|   ngFileUpload.directive('ngfDrop', ['$parse', '$timeout', '$location', 'Upload', '$http', '$q', |   ngFileUpload.directive('ngfDrop', ['$parse', '$timeout', '$window', 'Upload', '$http', '$q', | ||||||
|     function ($parse, $timeout, $location, Upload, $http, $q) { |     function ($parse, $timeout, $window, Upload, $http, $q) { | ||||||
|       return { |       return { | ||||||
|         restrict: 'AEC', |         restrict: 'AEC', | ||||||
|         require: '?ngModel', |         require: '?ngModel', | ||||||
|         link: function (scope, elem, attr, ngModel) { |         link: function (scope, elem, attr, ngModel) { | ||||||
|           linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $location, Upload, $http, $q); |           linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $window, Upload, $http, $q); | ||||||
|         } |         } | ||||||
|       }; |       }; | ||||||
|     }]); |     }]); | ||||||
| @@ -2203,7 +2304,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|     }; |     }; | ||||||
|   }]); |   }]); | ||||||
|  |  | ||||||
|   function linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $location, upload, $http, $q) { |   function linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $window, upload, $http, $q) { | ||||||
|     var available = dropAvailable(); |     var available = dropAvailable(); | ||||||
|  |  | ||||||
|     var attrGetter = function (name, scope, params) { |     var attrGetter = function (name, scope, params) { | ||||||
| @@ -2279,23 +2380,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|       if (stopPropagation(scope)) evt.stopPropagation(); |       if (stopPropagation(scope)) evt.stopPropagation(); | ||||||
|       if (actualDragOverClass) elem.removeClass(actualDragOverClass); |       if (actualDragOverClass) elem.removeClass(actualDragOverClass); | ||||||
|       actualDragOverClass = null; |       actualDragOverClass = null; | ||||||
|       var items = evt.dataTransfer.items; |       extractFilesAndUpdateModel(evt.dataTransfer, evt, 'dropUrl'); | ||||||
|       var html; |  | ||||||
|       try { |  | ||||||
|         html = evt.dataTransfer && evt.dataTransfer.getData && evt.dataTransfer.getData('text/html'); |  | ||||||
|       } catch (e) {/* Fix IE11 that throw error calling getData */ |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       extractFiles(items, evt.dataTransfer.files, attrGetter('ngfAllowDir', scope) !== false, |  | ||||||
|         attrGetter('multiple') || attrGetter('ngfMultiple', scope)).then(function (files) { |  | ||||||
|         if (files.length) { |  | ||||||
|           updateModel(files, evt); |  | ||||||
|         } else { |  | ||||||
|           extractFilesFromHtml('dropUrl', html).then(function (files) { |  | ||||||
|             updateModel(files, evt); |  | ||||||
|           }); |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|     }, false); |     }, false); | ||||||
|     elem[0].addEventListener('paste', function (evt) { |     elem[0].addEventListener('paste', function (evt) { | ||||||
|       if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && |       if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && | ||||||
| @@ -2303,22 +2388,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|         evt.preventDefault(); |         evt.preventDefault(); | ||||||
|       } |       } | ||||||
|       if (isDisabled() || !upload.shouldUpdateOn('paste', attr, scope)) return; |       if (isDisabled() || !upload.shouldUpdateOn('paste', attr, scope)) return; | ||||||
|       var files = []; |       extractFilesAndUpdateModel(evt.clipboardData || evt.originalEvent.clipboardData, evt, 'pasteUrl'); | ||||||
|       var clipboard = evt.clipboardData || evt.originalEvent.clipboardData; |  | ||||||
|       if (clipboard && clipboard.items) { |  | ||||||
|         for (var k = 0; k < clipboard.items.length; k++) { |  | ||||||
|           if (clipboard.items[k].type.indexOf('image') !== -1) { |  | ||||||
|             files.push(clipboard.items[k].getAsFile()); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|       if (files.length) { |  | ||||||
|         updateModel(files, evt); |  | ||||||
|       } else { |  | ||||||
|         extractFilesFromHtml('pasteUrl', clipboard).then(function (files) { |  | ||||||
|           updateModel(files, evt); |  | ||||||
|         }); |  | ||||||
|       } |  | ||||||
|     }, false); |     }, false); | ||||||
|  |  | ||||||
|     if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && |     if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && | ||||||
| @@ -2331,12 +2401,33 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     function extractFilesAndUpdateModel(source, evt, updateOnType) { | ||||||
|  |       if (!source) return; | ||||||
|  |       // html needs to be calculated on the same process otherwise the data will be wiped | ||||||
|  |       // after promise resolve or setTimeout. | ||||||
|  |       var html; | ||||||
|  |       try { | ||||||
|  |         html = source && source.getData && source.getData('text/html'); | ||||||
|  |       } catch (e) {/* Fix IE11 that throw error calling getData */ | ||||||
|  |       } | ||||||
|  |       extractFiles(source.items, source.files, attrGetter('ngfAllowDir', scope) !== false, | ||||||
|  |         attrGetter('multiple') || attrGetter('ngfMultiple', scope)).then(function (files) { | ||||||
|  |         if (files.length) { | ||||||
|  |           updateModel(files, evt); | ||||||
|  |         } else { | ||||||
|  |           extractFilesFromHtml(updateOnType, html).then(function (files) { | ||||||
|  |             updateModel(files, evt); | ||||||
|  |           }); | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     function updateModel(files, evt) { |     function updateModel(files, evt) { | ||||||
|       upload.updateModel(ngModel, attr, scope, attrGetter('ngfChange') || attrGetter('ngfDrop'), files, evt); |       upload.updateModel(ngModel, attr, scope, attrGetter('ngfChange') || attrGetter('ngfDrop'), files, evt); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function extractFilesFromHtml(updateOn, html) { |     function extractFilesFromHtml(updateOn, html) { | ||||||
|       if (!upload.shouldUpdateOn(updateOn, attr, scope) || !html) return upload.rejectPromise([]); |       if (!upload.shouldUpdateOn(updateOn, attr, scope) || typeof html !== 'string') return upload.rejectPromise([]); | ||||||
|       var urls = []; |       var urls = []; | ||||||
|       html.replace(/<(img src|img [^>]* src) *=\"([^\"]*)\"/gi, function (m, n, src) { |       html.replace(/<(img src|img [^>]* src) *=\"([^\"]*)\"/gi, function (m, n, src) { | ||||||
|         urls.push(src); |         urls.push(src); | ||||||
| @@ -2387,8 +2478,14 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     function extractFiles(items, fileList, allowDir, multiple) { |     function extractFiles(items, fileList, allowDir, multiple) { | ||||||
|       var maxFiles = upload.getValidationAttr(attr, scope, 'maxFiles') || Number.MAX_VALUE; |       var maxFiles = upload.getValidationAttr(attr, scope, 'maxFiles'); | ||||||
|       var maxTotalSize = upload.getValidationAttr(attr, scope, 'maxTotalSize') || Number.MAX_VALUE; |       if (maxFiles == null) { | ||||||
|  |         maxFiles = Number.MAX_VALUE; | ||||||
|  |       } | ||||||
|  |       var maxTotalSize = upload.getValidationAttr(attr, scope, 'maxTotalSize'); | ||||||
|  |       if (maxTotalSize == null) { | ||||||
|  |         maxTotalSize = Number.MAX_VALUE; | ||||||
|  |       } | ||||||
|       var includeDir = attrGetter('ngfIncludeDir', scope); |       var includeDir = attrGetter('ngfIncludeDir', scope); | ||||||
|       var files = [], totalSize = 0; |       var files = [], totalSize = 0; | ||||||
|  |  | ||||||
| @@ -2399,7 +2496,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|             var promises = [upload.emptyPromise()]; |             var promises = [upload.emptyPromise()]; | ||||||
|             if (includeDir) { |             if (includeDir) { | ||||||
|               var file = {type: 'directory'}; |               var file = {type: 'directory'}; | ||||||
|               file.name = file.path = (path || '') + entry.name + entry.name; |               file.name = file.path = (path || '') + entry.name; | ||||||
|               files.push(file); |               files.push(file); | ||||||
|             } |             } | ||||||
|             var dirReader = entry.createReader(); |             var dirReader = entry.createReader(); | ||||||
| @@ -2453,7 +2550,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|  |  | ||||||
|       var promises = [upload.emptyPromise()]; |       var promises = [upload.emptyPromise()]; | ||||||
|  |  | ||||||
|       if (items && items.length > 0 && $location.protocol() !== 'file') { |       if (items && items.length > 0 && $window.location.protocol !== 'file:') { | ||||||
|         for (var i = 0; i < items.length; i++) { |         for (var i = 0; i < items.length; i++) { | ||||||
|           if (items[i].webkitGetAsEntry && items[i].webkitGetAsEntry() && items[i].webkitGetAsEntry().isDirectory) { |           if (items[i].webkitGetAsEntry && items[i].webkitGetAsEntry() && items[i].webkitGetAsEntry().isDirectory) { | ||||||
|             var entry = items[i].webkitGetAsEntry(); |             var entry = items[i].webkitGetAsEntry(); | ||||||
|   | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -1,9 +1,9 @@ | |||||||
| /**! | /**! | ||||||
|  * AngularJS file upload directives and services. Supoorts: file upload/drop/paste, resume, cancel/abort, |  * AngularJS file upload directives and services. Supports: file upload/drop/paste, resume, cancel/abort, | ||||||
|  * progress, resize, thumbnail, preview, validation and CORS |  * progress, resize, thumbnail, preview, validation and CORS | ||||||
|  * FileAPI Flash shim for old browsers not supporting FormData |  * FileAPI Flash shim for old browsers not supporting FormData | ||||||
|  * @author  Danial  <danial.farid@gmail.com> |  * @author  Danial  <danial.farid@gmail.com> | ||||||
|  * @version 12.0.4 |  * @version 12.2.13 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| (function () { | (function () { | ||||||
|   | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -2,7 +2,7 @@ | |||||||
|  * AngularJS file upload directives and services. Supoorts: file upload/drop/paste, resume, cancel/abort, |  * AngularJS file upload directives and services. Supoorts: file upload/drop/paste, resume, cancel/abort, | ||||||
|  * progress, resize, thumbnail, preview, validation and CORS |  * progress, resize, thumbnail, preview, validation and CORS | ||||||
|  * @author  Danial  <danial.farid@gmail.com> |  * @author  Danial  <danial.farid@gmail.com> | ||||||
|  * @version 12.0.4 |  * @version 12.2.13 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| if (window.XMLHttpRequest && !(window.FileAPI && FileAPI.shouldLoad)) { | if (window.XMLHttpRequest && !(window.FileAPI && FileAPI.shouldLoad)) { | ||||||
| @@ -23,7 +23,7 @@ if (window.XMLHttpRequest && !(window.FileAPI && FileAPI.shouldLoad)) { | |||||||
|  |  | ||||||
| var ngFileUpload = angular.module('ngFileUpload', []); | var ngFileUpload = angular.module('ngFileUpload', []); | ||||||
|  |  | ||||||
| ngFileUpload.version = '12.0.4'; | ngFileUpload.version = '12.2.13'; | ||||||
|  |  | ||||||
| ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, $q, $timeout) { | ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, $q, $timeout) { | ||||||
|   var upload = this; |   var upload = this; | ||||||
| @@ -90,10 +90,12 @@ ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, | |||||||
|     function uploadWithAngular() { |     function uploadWithAngular() { | ||||||
|       $http(config).then(function (r) { |       $http(config).then(function (r) { | ||||||
|           if (resumeSupported && config._chunkSize && !config._finished && config._file) { |           if (resumeSupported && config._chunkSize && !config._finished && config._file) { | ||||||
|  |             var fileSize = config._file && config._file.size || 0; | ||||||
|             notifyProgress({ |             notifyProgress({ | ||||||
|                 loaded: config._end, |                 loaded: Math.min(config._end, fileSize), | ||||||
|                 total: config._file && config._file.size, |                 total: fileSize, | ||||||
|                 config: config, type: 'progress' |                 config: config, | ||||||
|  |                 type: 'progress' | ||||||
|               } |               } | ||||||
|             ); |             ); | ||||||
|             upload.upload(config, true); |             upload.upload(config, true); | ||||||
| @@ -132,6 +134,9 @@ ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, | |||||||
|     } else if (config.resumeSize) { |     } else if (config.resumeSize) { | ||||||
|       config.resumeSize().then(function (size) { |       config.resumeSize().then(function (size) { | ||||||
|         config._start = size; |         config._start = size; | ||||||
|  |         if (config._chunkSize) { | ||||||
|  |           config._end = config._start + config._chunkSize; | ||||||
|  |         } | ||||||
|         uploadWithAngular(); |         uploadWithAngular(); | ||||||
|       }, function (e) { |       }, function (e) { | ||||||
|         throw e; |         throw e; | ||||||
| @@ -185,9 +190,11 @@ ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     upload.promisesCount++; |     upload.promisesCount++; | ||||||
|     promise['finally'](function () { |     if (promise['finally'] && promise['finally'] instanceof Function) { | ||||||
|       upload.promisesCount--; |       promise['finally'](function () { | ||||||
|     }); |         upload.promisesCount--; | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|     return promise; |     return promise; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -371,9 +378,11 @@ ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, | |||||||
|       var arrayBufferView = new Uint8Array(resp.data); |       var arrayBufferView = new Uint8Array(resp.data); | ||||||
|       var type = resp.headers('content-type') || 'image/WebP'; |       var type = resp.headers('content-type') || 'image/WebP'; | ||||||
|       var blob = new window.Blob([arrayBufferView], {type: type}); |       var blob = new window.Blob([arrayBufferView], {type: type}); | ||||||
|  |       var matches = url.match(/.*\/(.+?)(\?.*)?$/); | ||||||
|  |       if (matches.length > 1) { | ||||||
|  |         blob.name = matches[1]; | ||||||
|  |       } | ||||||
|       defer.resolve(blob); |       defer.resolve(blob); | ||||||
|       //var split = type.split('[/;]'); |  | ||||||
|       //blob.name = url.substring(0, 150).replace(/\W+/g, '') + '.' + (split.length > 1 ? split[1] : 'jpg'); |  | ||||||
|     }, function (e) { |     }, function (e) { | ||||||
|       defer.reject(e); |       defer.reject(e); | ||||||
|     }); |     }); | ||||||
| @@ -421,7 +430,7 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE | |||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   upload.shouldUpdateOn = function (type, attr, scope) { |   upload.shouldUpdateOn = function (type, attr, scope) { | ||||||
|     var modelOptions = upload.attrGetter('ngModelOptions', attr, scope); |     var modelOptions = upload.attrGetter('ngfModelOptions', attr, scope); | ||||||
|     if (modelOptions && modelOptions.updateOn) { |     if (modelOptions && modelOptions.updateOn) { | ||||||
|       return modelOptions.updateOn.split(' ').indexOf(type) > -1; |       return modelOptions.updateOn.split(' ').indexOf(type) > -1; | ||||||
|     } |     } | ||||||
| @@ -471,13 +480,13 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE | |||||||
|     return $q.all(promises); |     return $q.all(promises); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   function resize(files, attr, scope) { |   function resizeFile(files, attr, scope, ngModel) { | ||||||
|     var resizeVal = upload.attrGetter('ngfResize', attr, scope); |     var resizeVal = upload.attrGetter('ngfResize', attr, scope); | ||||||
|     if (!resizeVal || !upload.isResizeSupported() || !files.length) return upload.emptyPromise(); |     if (!resizeVal || !upload.isResizeSupported() || !files.length) return upload.emptyPromise(); | ||||||
|     if (resizeVal instanceof Function) { |     if (resizeVal instanceof Function) { | ||||||
|       var defer = $q.defer(); |       var defer = $q.defer(); | ||||||
|       resizeVal(files).then(function (p) { |       return resizeVal(files).then(function (p) { | ||||||
|         resizeWithParams(p, files, attr, scope).then(function (r) { |         resizeWithParams(p, files, attr, scope, ngModel).then(function (r) { | ||||||
|           defer.resolve(r); |           defer.resolve(r); | ||||||
|         }, function (e) { |         }, function (e) { | ||||||
|           defer.reject(e); |           defer.reject(e); | ||||||
| @@ -486,27 +495,30 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE | |||||||
|         defer.reject(e); |         defer.reject(e); | ||||||
|       }); |       }); | ||||||
|     } else { |     } else { | ||||||
|       return resizeWithParams(resizeVal, files, attr, scope); |       return resizeWithParams(resizeVal, files, attr, scope, ngModel); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   function resizeWithParams(param, files, attr, scope) { |   function resizeWithParams(params, files, attr, scope, ngModel) { | ||||||
|     var promises = [upload.emptyPromise()]; |     var promises = [upload.emptyPromise()]; | ||||||
|  |  | ||||||
|     function handleFile(f, i) { |     function handleFile(f, i) { | ||||||
|       if (f.type.indexOf('image') === 0) { |       if (f.type.indexOf('image') === 0) { | ||||||
|         if (param.pattern && !upload.validatePattern(f, param.pattern)) return; |         if (params.pattern && !upload.validatePattern(f, params.pattern)) return; | ||||||
|         var promise = upload.resize(f, param.width, param.height, param.quality, |         params.resizeIf = function (width, height) { | ||||||
|           param.type, param.ratio, param.centerCrop, function (width, height) { |           return upload.attrGetter('ngfResizeIf', attr, scope, | ||||||
|             return upload.attrGetter('ngfResizeIf', attr, scope, |             {$width: width, $height: height, $file: f}); | ||||||
|               {$width: width, $height: height, $file: f}); |         }; | ||||||
|           }, param.restoreExif !== false); |         var promise = upload.resize(f, params); | ||||||
|         promises.push(promise); |         promises.push(promise); | ||||||
|         promise.then(function (resizedFile) { |         promise.then(function (resizedFile) { | ||||||
|           files.splice(i, 1, resizedFile); |           files.splice(i, 1, resizedFile); | ||||||
|         }, function (e) { |         }, function (e) { | ||||||
|           f.$error = 'resize'; |           f.$error = 'resize'; | ||||||
|  |           (f.$errorMessages = (f.$errorMessages || {})).resize = true; | ||||||
|           f.$errorParam = (e ? (e.message ? e.message : e) + ': ' : '') + (f && f.name); |           f.$errorParam = (e ? (e.message ? e.message : e) + ': ' : '') + (f && f.name); | ||||||
|  |           ngModel.$ngfValidations.push({name: 'resize', valid: false}); | ||||||
|  |           upload.applyModelValidation(ngModel, files); | ||||||
|         }); |         }); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -593,18 +605,6 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE | |||||||
|       return angular.isArray(v) ? v : [v]; |       return angular.isArray(v) ? v : [v]; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function separateInvalids() { |  | ||||||
|       valids = []; |  | ||||||
|       invalids = []; |  | ||||||
|       angular.forEach(allNewFiles, function (file) { |  | ||||||
|         if (file.$error) { |  | ||||||
|           invalids.push(file); |  | ||||||
|         } else { |  | ||||||
|           valids.push(file); |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     function resizeAndUpdate() { |     function resizeAndUpdate() { | ||||||
|       function updateModel() { |       function updateModel() { | ||||||
|         $timeout(function () { |         $timeout(function () { | ||||||
| @@ -614,17 +614,30 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE | |||||||
|         }, options && options.debounce ? options.debounce.change || options.debounce : 0); |         }, options && options.debounce ? options.debounce.change || options.debounce : 0); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       resize(validateAfterResize ? allNewFiles : valids, attr, scope).then(function () { |       var resizingFiles = validateAfterResize ? allNewFiles : valids; | ||||||
|  |       resizeFile(resizingFiles, attr, scope, ngModel).then(function () { | ||||||
|         if (validateAfterResize) { |         if (validateAfterResize) { | ||||||
|           upload.validate(allNewFiles, prevValidFiles.length, ngModel, attr, scope).then(function () { |           upload.validate(allNewFiles, keep ? prevValidFiles.length : 0, ngModel, attr, scope) | ||||||
|             separateInvalids(); |             .then(function (validationResult) { | ||||||
|             updateModel(); |               valids = validationResult.validsFiles; | ||||||
|           }); |               invalids = validationResult.invalidsFiles; | ||||||
|  |               updateModel(); | ||||||
|  |             }); | ||||||
|         } else { |         } else { | ||||||
|           updateModel(); |           updateModel(); | ||||||
|         } |         } | ||||||
|       }, function (e) { |       }, function () { | ||||||
|         throw 'Could not resize files ' + e; |         for (var i = 0; i < resizingFiles.length; i++) { | ||||||
|  |           var f = resizingFiles[i]; | ||||||
|  |           if (f.$error === 'resize') { | ||||||
|  |             var index = valids.indexOf(f); | ||||||
|  |             if (index > -1) { | ||||||
|  |               valids.splice(index, 1); | ||||||
|  |               invalids.push(f); | ||||||
|  |             } | ||||||
|  |             updateModel(); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -654,13 +667,15 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE | |||||||
|  |  | ||||||
|     var validateAfterResize = upload.attrGetter('ngfValidateAfterResize', attr, scope); |     var validateAfterResize = upload.attrGetter('ngfValidateAfterResize', attr, scope); | ||||||
|  |  | ||||||
|     var options = upload.attrGetter('ngModelOptions', attr, scope); |     var options = upload.attrGetter('ngfModelOptions', attr, scope); | ||||||
|     upload.validate(allNewFiles, prevValidFiles.length, ngModel, attr, scope).then(function () { |     upload.validate(allNewFiles, keep ? prevValidFiles.length : 0, ngModel, attr, scope) | ||||||
|  |       .then(function (validationResult) { | ||||||
|       if (noDelay) { |       if (noDelay) { | ||||||
|         update(allNewFiles, [], files, dupFiles, isSingleModel); |         update(allNewFiles, [], files, dupFiles, isSingleModel); | ||||||
|       } else { |       } else { | ||||||
|         if ((!options || !options.allowInvalid) && !validateAfterResize) { |         if ((!options || !options.allowInvalid) && !validateAfterResize) { | ||||||
|           separateInvalids(); |           valids = validationResult.validFiles; | ||||||
|  |           invalids = validationResult.invalidFiles; | ||||||
|         } else { |         } else { | ||||||
|           valids = allNewFiles; |           valids = allNewFiles; | ||||||
|         } |         } | ||||||
| @@ -697,7 +712,7 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|     /** @namespace attr.ngfSelect */ |     /** @namespace attr.ngfSelect */ | ||||||
|     /** @namespace attr.ngfChange */ |     /** @namespace attr.ngfChange */ | ||||||
|     /** @namespace attr.ngModel */ |     /** @namespace attr.ngModel */ | ||||||
|     /** @namespace attr.ngModelOptions */ |     /** @namespace attr.ngfModelOptions */ | ||||||
|     /** @namespace attr.ngfMultiple */ |     /** @namespace attr.ngfMultiple */ | ||||||
|     /** @namespace attr.ngfCapture */ |     /** @namespace attr.ngfCapture */ | ||||||
|     /** @namespace attr.ngfValidate */ |     /** @namespace attr.ngfValidate */ | ||||||
| @@ -717,6 +732,8 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|     function changeFn(evt) { |     function changeFn(evt) { | ||||||
|       if (upload.shouldUpdateOn('change', attr, scope)) { |       if (upload.shouldUpdateOn('change', attr, scope)) { | ||||||
|         var fileList = evt.__files_ || (evt.target && evt.target.files), files = []; |         var fileList = evt.__files_ || (evt.target && evt.target.files), files = []; | ||||||
|  |         /* Handle duplicate call in  IE11 */ | ||||||
|  |         if (!fileList) return; | ||||||
|         for (var i = 0; i < fileList.length; i++) { |         for (var i = 0; i < fileList.length; i++) { | ||||||
|           files.push(fileList[i]); |           files.push(fileList[i]); | ||||||
|         } |         } | ||||||
| @@ -728,31 +745,39 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|     upload.registerModelChangeValidator(ngModel, attr, scope); |     upload.registerModelChangeValidator(ngModel, attr, scope); | ||||||
|  |  | ||||||
|     var unwatches = []; |     var unwatches = []; | ||||||
|     unwatches.push(scope.$watch(attrGetter('ngfMultiple'), function () { |     if (attrGetter('ngfMultiple')) { | ||||||
|       fileElem.attr('multiple', attrGetter('ngfMultiple', scope)); |       unwatches.push(scope.$watch(attrGetter('ngfMultiple'), function () { | ||||||
|     })); |         fileElem.attr('multiple', attrGetter('ngfMultiple', scope)); | ||||||
|     unwatches.push(scope.$watch(attrGetter('ngfCapture'), function () { |       })); | ||||||
|       fileElem.attr('capture', attrGetter('ngfCapture', scope)); |     } | ||||||
|     })); |     if (attrGetter('ngfCapture')) { | ||||||
|     unwatches.push(scope.$watch(attrGetter('ngfAccept'), function () { |       unwatches.push(scope.$watch(attrGetter('ngfCapture'), function () { | ||||||
|       fileElem.attr('accept', attrGetter('ngfAccept', scope)); |         fileElem.attr('capture', attrGetter('ngfCapture', scope)); | ||||||
|     })); |       })); | ||||||
|     attr.$observe('accept', function () { |     } | ||||||
|  |     if (attrGetter('ngfAccept')) { | ||||||
|  |       unwatches.push(scope.$watch(attrGetter('ngfAccept'), function () { | ||||||
|  |         fileElem.attr('accept', attrGetter('ngfAccept', scope)); | ||||||
|  |       })); | ||||||
|  |     } | ||||||
|  |     unwatches.push(attr.$observe('accept', function () { | ||||||
|       fileElem.attr('accept', attrGetter('accept')); |       fileElem.attr('accept', attrGetter('accept')); | ||||||
|     }); |     })); | ||||||
|     unwatches.push(function () { |     function bindAttrToFileInput(fileElem, label) { | ||||||
|       if (attr.$$observers) delete attr.$$observers.accept; |       function updateId(val) { | ||||||
|     }); |         fileElem.attr('id', 'ngf-' + val); | ||||||
|     function bindAttrToFileInput(fileElem) { |         label.attr('id', 'ngf-label-' + val); | ||||||
|       if (elem !== fileElem) { |       } | ||||||
|         for (var i = 0; i < elem[0].attributes.length; i++) { |  | ||||||
|           var attribute = elem[0].attributes[i]; |       for (var i = 0; i < elem[0].attributes.length; i++) { | ||||||
|           if (attribute.name !== 'type' && attribute.name !== 'class' && attribute.name !== 'style') { |         var attribute = elem[0].attributes[i]; | ||||||
|             if (attribute.value == null || attribute.value === '') { |         if (attribute.name !== 'type' && attribute.name !== 'class' && attribute.name !== 'style') { | ||||||
|               if (attribute.name === 'required') attribute.value = 'required'; |           if (attribute.name === 'id') { | ||||||
|               if (attribute.name === 'multiple') attribute.value = 'multiple'; |             updateId(attribute.value); | ||||||
|             } |             unwatches.push(attr.$observe('id', updateId)); | ||||||
|             fileElem.attr(attribute.name, attribute.name === 'id' ? 'ngf-' + attribute.value : attribute.value); |           } else { | ||||||
|  |             fileElem.attr(attribute.name, (!attribute.value && (attribute.name === 'required' || | ||||||
|  |             attribute.name === 'multiple')) ? attribute.name : attribute.value); | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @@ -765,12 +790,12 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|  |  | ||||||
|       var fileElem = angular.element('<input type="file">'); |       var fileElem = angular.element('<input type="file">'); | ||||||
|  |  | ||||||
|       bindAttrToFileInput(fileElem); |  | ||||||
|  |  | ||||||
|       var label = angular.element('<label>upload</label>'); |       var label = angular.element('<label>upload</label>'); | ||||||
|       label.css('visibility', 'hidden').css('position', 'absolute').css('overflow', 'hidden') |       label.css('visibility', 'hidden').css('position', 'absolute').css('overflow', 'hidden') | ||||||
|         .css('width', '0px').css('height', '0px').css('border', 'none') |         .css('width', '0px').css('height', '0px').css('border', 'none') | ||||||
|         .css('margin', '0px').css('padding', '0px').attr('tabindex', '-1'); |         .css('margin', '0px').css('padding', '0px').attr('tabindex', '-1'); | ||||||
|  |       bindAttrToFileInput(fileElem, label); | ||||||
|  |  | ||||||
|       generatedElems.push({el: elem, ref: label}); |       generatedElems.push({el: elem, ref: label}); | ||||||
|  |  | ||||||
|       document.body.appendChild(label.append(fileElem)[0]); |       document.body.appendChild(label.append(fileElem)[0]); | ||||||
| @@ -778,13 +803,12 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|       return fileElem; |       return fileElem; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     var initialTouchStartY = 0; |  | ||||||
|  |  | ||||||
|     function clickHandler(evt) { |     function clickHandler(evt) { | ||||||
|       if (elem.attr('disabled')) return false; |       if (elem.attr('disabled')) return false; | ||||||
|       if (attrGetter('ngfSelectDisabled', scope)) return; |       if (attrGetter('ngfSelectDisabled', scope)) return; | ||||||
|  |  | ||||||
|       var r = handleTouch(evt); |       var r = detectSwipe(evt); | ||||||
|  |       // prevent the click if it is a swipe | ||||||
|       if (r != null) return r; |       if (r != null) return r; | ||||||
|  |  | ||||||
|       resetModel(evt); |       resetModel(evt); | ||||||
| @@ -796,7 +820,8 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|           document.body.appendChild(fileElem.parent()[0]); |           document.body.appendChild(fileElem.parent()[0]); | ||||||
|           fileElem.bind('change', changeFn); |           fileElem.bind('change', changeFn); | ||||||
|         } |         } | ||||||
|       } catch(e){/*ignore*/} |       } catch (e) {/*ignore*/ | ||||||
|  |       } | ||||||
|  |  | ||||||
|       if (isDelayedClickSupported(navigator.userAgent)) { |       if (isDelayedClickSupported(navigator.userAgent)) { | ||||||
|         setTimeout(function () { |         setTimeout(function () { | ||||||
| @@ -809,19 +834,30 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function handleTouch(evt) { |  | ||||||
|       var touches = evt.changedTouches || (evt.originalEvent && evt.originalEvent.changedTouches); |  | ||||||
|       if (evt.type === 'touchstart') { |  | ||||||
|         initialTouchStartY = touches ? touches[0].clientY : 0; |  | ||||||
|         return true; // don't block event default |  | ||||||
|       } else { |  | ||||||
|         evt.stopPropagation(); |  | ||||||
|         evt.preventDefault(); |  | ||||||
|  |  | ||||||
|         // prevent scroll from triggering event |     var initialTouchStartY = 0; | ||||||
|         if (evt.type === 'touchend') { |     var initialTouchStartX = 0; | ||||||
|           var currentLocation = touches ? touches[0].clientY : 0; |  | ||||||
|           if (Math.abs(currentLocation - initialTouchStartY) > 20) return false; |     function detectSwipe(evt) { | ||||||
|  |       var touches = evt.changedTouches || (evt.originalEvent && evt.originalEvent.changedTouches); | ||||||
|  |       if (touches) { | ||||||
|  |         if (evt.type === 'touchstart') { | ||||||
|  |           initialTouchStartX = touches[0].clientX; | ||||||
|  |           initialTouchStartY = touches[0].clientY; | ||||||
|  |           return true; // don't block event default | ||||||
|  |         } else { | ||||||
|  |           // prevent scroll from triggering event | ||||||
|  |           if (evt.type === 'touchend') { | ||||||
|  |             var currentX = touches[0].clientX; | ||||||
|  |             var currentY = touches[0].clientY; | ||||||
|  |             if ((Math.abs(currentX - initialTouchStartX) > 20) || | ||||||
|  |               (Math.abs(currentY - initialTouchStartY) > 20)) { | ||||||
|  |               evt.stopPropagation(); | ||||||
|  |               evt.preventDefault(); | ||||||
|  |               return false; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |           return true; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -1052,14 +1088,19 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|         var size = resizeParams; |         var size = resizeParams; | ||||||
|         if (directiveName === 'ngfThumbnail') { |         if (directiveName === 'ngfThumbnail') { | ||||||
|           if (!size) { |           if (!size) { | ||||||
|             size = {width: elem[0].clientWidth, height: elem[0].clientHeight}; |             size = { | ||||||
|  |               width: elem[0].naturalWidth || elem[0].clientWidth, | ||||||
|  |               height: elem[0].naturalHeight || elem[0].clientHeight | ||||||
|  |             }; | ||||||
|           } |           } | ||||||
|           if (size.width === 0 && window.getComputedStyle) { |           if (size.width === 0 && window.getComputedStyle) { | ||||||
|             var style = getComputedStyle(elem[0]); |             var style = getComputedStyle(elem[0]); | ||||||
|             size = { |             if (style.width && style.width.indexOf('px') > -1 && style.height && style.height.indexOf('px') > -1) { | ||||||
|               width: parseInt(style.width.slice(0, -2)), |               size = { | ||||||
|               height: parseInt(style.height.slice(0, -2)) |                 width: parseInt(style.width.slice(0, -2)), | ||||||
|             }; |                 height: parseInt(style.height.slice(0, -2)) | ||||||
|  |               }; | ||||||
|  |             } | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -1074,7 +1115,11 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|         if (file && file.type && file.type.search(getTagType(elem[0])) === 0 && |         if (file && file.type && file.type.search(getTagType(elem[0])) === 0 && | ||||||
|           (!isBackground || file.type.indexOf('image') === 0)) { |           (!isBackground || file.type.indexOf('image') === 0)) { | ||||||
|           if (size && Upload.isResizeSupported()) { |           if (size && Upload.isResizeSupported()) { | ||||||
|             Upload.resize(file, size.width, size.height, size.quality).then( |             size.resizeIf = function (width, height) { | ||||||
|  |               return Upload.attrGetter('ngfResizeIf', attr, scope, | ||||||
|  |                 {$width: width, $height: height, $file: file}); | ||||||
|  |             }; | ||||||
|  |             Upload.resize(file, size).then( | ||||||
|               function (f) { |               function (f) { | ||||||
|                 constructDataUrl(f); |                 constructDataUrl(f); | ||||||
|               }, function (e) { |               }, function (e) { | ||||||
| @@ -1136,8 +1181,8 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', | |||||||
|   }]); |   }]); | ||||||
|  |  | ||||||
|   ngFileUpload.config(['$compileProvider', function ($compileProvider) { |   ngFileUpload.config(['$compileProvider', function ($compileProvider) { | ||||||
|     if ($compileProvider.imgSrcSanitizationWhitelist) $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|local|file|data|blob):/); |     if ($compileProvider.imgSrcSanitizationWhitelist) $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|webcal|local|file|data|blob):/); | ||||||
|     if ($compileProvider.aHrefSanitizationWhitelist) $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|local|file|data|blob):/); |     if ($compileProvider.aHrefSanitizationWhitelist) $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|webcal|local|file|data|blob):/); | ||||||
|   }]); |   }]); | ||||||
|  |  | ||||||
|   ngFileUpload.filter('ngfDataUrl', ['UploadDataUrl', '$sce', function (UploadDataUrl, $sce) { |   ngFileUpload.filter('ngfDataUrl', ['UploadDataUrl', '$sce', function (UploadDataUrl, $sce) { | ||||||
| @@ -1229,13 +1274,15 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|     if (ngModel) { |     if (ngModel) { | ||||||
|       ngModel.$formatters.push(function (files) { |       ngModel.$formatters.push(function (files) { | ||||||
|         if (ngModel.$dirty) { |         if (ngModel.$dirty) { | ||||||
|  |           var filesArray = files; | ||||||
|           if (files && !angular.isArray(files)) { |           if (files && !angular.isArray(files)) { | ||||||
|             files = [files]; |             filesArray = [files]; | ||||||
|           } |           } | ||||||
|           upload.validate(files, 0, ngModel, attr, scope).then(function () { |           upload.validate(filesArray, 0, ngModel, attr, scope).then(function () { | ||||||
|             upload.applyModelValidation(ngModel, files); |             upload.applyModelValidation(ngModel, filesArray); | ||||||
|           }); |           }); | ||||||
|         } |         } | ||||||
|  |         return files; | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
| @@ -1285,11 +1332,15 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|       return upload.attrGetter(name, attr, scope, params); |       return upload.attrGetter(name, attr, scope, params); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  |     var ignoredErrors = (upload.attrGetter('ngfIgnoreInvalid', attr, scope) || '').split(' '); | ||||||
|  |     var runAllValidation = upload.attrGetter('ngfRunAllValidations', attr, scope); | ||||||
|  |  | ||||||
|     if (files == null || files.length === 0) { |     if (files == null || files.length === 0) { | ||||||
|       return upload.emptyPromise(ngModel); |       return upload.emptyPromise({'validFiles': files, 'invalidFiles': []}); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     files = files.length === undefined ? [files] : files.slice(0); |     files = files.length === undefined ? [files] : files.slice(0); | ||||||
|  |     var invalidFiles = []; | ||||||
|  |  | ||||||
|     function validateSync(name, validationName, fn) { |     function validateSync(name, validationName, fn) { | ||||||
|       if (files) { |       if (files) { | ||||||
| @@ -1300,11 +1351,20 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|             var val = upload.getValidationAttr(attr, scope, name, validationName, file); |             var val = upload.getValidationAttr(attr, scope, name, validationName, file); | ||||||
|             if (val != null) { |             if (val != null) { | ||||||
|               if (!fn(file, val, i)) { |               if (!fn(file, val, i)) { | ||||||
|                 file.$error = name; |                 if (ignoredErrors.indexOf(name) === -1) { | ||||||
|                 (file.$errorMessages = (file.$errorMessages || {}))[name] = true; |                   file.$error = name; | ||||||
|                 file.$errorParam = val; |                   (file.$errorMessages = (file.$errorMessages || {}))[name] = true; | ||||||
|                 files.splice(i, 1); |                   file.$errorParam = val; | ||||||
|                 valid = false; |                   if (invalidFiles.indexOf(file) === -1) { | ||||||
|  |                     invalidFiles.push(file); | ||||||
|  |                   } | ||||||
|  |                   if (!runAllValidation) { | ||||||
|  |                     files.splice(i, 1); | ||||||
|  |                   } | ||||||
|  |                   valid = false; | ||||||
|  |                 } else { | ||||||
|  |                   files.splice(i, 1); | ||||||
|  |                 } | ||||||
|               } |               } | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
| @@ -1315,9 +1375,6 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     validateSync('maxFiles', null, function (file, val, i) { |  | ||||||
|       return prevLength + i < val; |  | ||||||
|     }); |  | ||||||
|     validateSync('pattern', null, upload.validatePattern); |     validateSync('pattern', null, upload.validatePattern); | ||||||
|     validateSync('minSize', 'size.min', function (file, val) { |     validateSync('minSize', 'size.min', function (file, val) { | ||||||
|       return file.size + 0.1 >= upload.translateScalars(val); |       return file.size + 0.1 >= upload.translateScalars(val); | ||||||
| @@ -1340,44 +1397,58 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     if (!files.length) { |     if (!files.length) { | ||||||
|       return upload.emptyPromise(ngModel, ngModel.$ngfValidations); |       return upload.emptyPromise({'validFiles': [], 'invalidFiles': invalidFiles}); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function validateAsync(name, validationName, type, asyncFn, fn) { |     function validateAsync(name, validationName, type, asyncFn, fn) { | ||||||
|       function resolveResult(defer, file, val) { |       function resolveResult(defer, file, val) { | ||||||
|  |         function resolveInternal(fn) { | ||||||
|  |           if (fn()) { | ||||||
|  |             if (ignoredErrors.indexOf(name) === -1) { | ||||||
|  |               file.$error = name; | ||||||
|  |               (file.$errorMessages = (file.$errorMessages || {}))[name] = true; | ||||||
|  |               file.$errorParam = val; | ||||||
|  |               if (invalidFiles.indexOf(file) === -1) { | ||||||
|  |                 invalidFiles.push(file); | ||||||
|  |               } | ||||||
|  |               if (!runAllValidation) { | ||||||
|  |                 var i = files.indexOf(file); | ||||||
|  |                 if (i > -1) files.splice(i, 1); | ||||||
|  |               } | ||||||
|  |               defer.resolve(false); | ||||||
|  |             } else { | ||||||
|  |               var j = files.indexOf(file); | ||||||
|  |               if (j > -1) files.splice(j, 1); | ||||||
|  |               defer.resolve(true); | ||||||
|  |             } | ||||||
|  |           } else { | ||||||
|  |             defer.resolve(true); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if (val != null) { |         if (val != null) { | ||||||
|           asyncFn(file, val).then(function (d) { |           asyncFn(file, val).then(function (d) { | ||||||
|             if (!fn(d, val)) { |             resolveInternal(function () { | ||||||
|               file.$error = name; |               return !fn(d, val); | ||||||
|               (file.$errorMessages = (file.$errorMessages || {}))[name] = true; |             }); | ||||||
|               file.$errorParam = val; |  | ||||||
|               defer.reject(); |  | ||||||
|             } else { |  | ||||||
|               defer.resolve(); |  | ||||||
|             } |  | ||||||
|           }, function () { |           }, function () { | ||||||
|             if (attrGetter('ngfValidateForce', {$file: file})) { |             resolveInternal(function () { | ||||||
|               file.$error = name; |               return attrGetter('ngfValidateForce', {$file: file}); | ||||||
|               (file.$errorMessages = (file.$errorMessages || {}))[name] = true; |             }); | ||||||
|               file.$errorParam = val; |  | ||||||
|               defer.reject(); |  | ||||||
|             } else { |  | ||||||
|               defer.resolve(); |  | ||||||
|             } |  | ||||||
|           }); |           }); | ||||||
|         } else { |         } else { | ||||||
|           defer.resolve(); |           defer.resolve(true); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       var promises = [upload.emptyPromise()]; |       var promises = [upload.emptyPromise(true)]; | ||||||
|       if (files) { |       if (files) { | ||||||
|         files = files.length === undefined ? [files] : files; |         files = files.length === undefined ? [files] : files; | ||||||
|         angular.forEach(files, function (file) { |         angular.forEach(files, function (file) { | ||||||
|           var defer = $q.defer(); |           var defer = $q.defer(); | ||||||
|           promises.push(defer.promise); |           promises.push(defer.promise); | ||||||
|           if (type && (file.type == null || file.type.search(type) !== 0)) { |           if (type && (file.type == null || file.type.search(type) !== 0)) { | ||||||
|             defer.resolve(); |             defer.resolve(true); | ||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
|           if (name === 'dimensions' && upload.attrGetter('ngfDimensions', attr) != null) { |           if (name === 'dimensions' && upload.attrGetter('ngfDimensions', attr) != null) { | ||||||
| @@ -1385,96 +1456,120 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|               resolveResult(defer, file, |               resolveResult(defer, file, | ||||||
|                 attrGetter('ngfDimensions', {$file: file, $width: d.width, $height: d.height})); |                 attrGetter('ngfDimensions', {$file: file, $width: d.width, $height: d.height})); | ||||||
|             }, function () { |             }, function () { | ||||||
|               defer.reject(); |               defer.resolve(false); | ||||||
|             }); |             }); | ||||||
|           } else if (name === 'duration' && upload.attrGetter('ngfDuration', attr) != null) { |           } else if (name === 'duration' && upload.attrGetter('ngfDuration', attr) != null) { | ||||||
|             upload.mediaDuration(file).then(function (d) { |             upload.mediaDuration(file).then(function (d) { | ||||||
|               resolveResult(defer, file, |               resolveResult(defer, file, | ||||||
|                 attrGetter('ngfDuration', {$file: file, $duration: d})); |                 attrGetter('ngfDuration', {$file: file, $duration: d})); | ||||||
|             }, function () { |             }, function () { | ||||||
|               defer.reject(); |               defer.resolve(false); | ||||||
|             }); |             }); | ||||||
|           } else { |           } else { | ||||||
|             resolveResult(defer, file, |             resolveResult(defer, file, | ||||||
|               upload.getValidationAttr(attr, scope, name, validationName, file)); |               upload.getValidationAttr(attr, scope, name, validationName, file)); | ||||||
|           } |           } | ||||||
|         }); |         }); | ||||||
|         return $q.all(promises).then(function () { |  | ||||||
|           ngModel.$ngfValidations.push({name: name, valid: true}); |  | ||||||
|         }, function () { |  | ||||||
|           ngModel.$ngfValidations.push({name: name, valid: false}); |  | ||||||
|         }); |  | ||||||
|       } |       } | ||||||
|  |       var deffer = $q.defer(); | ||||||
|  |       $q.all(promises).then(function (values) { | ||||||
|  |         var isValid = true; | ||||||
|  |         for (var i = 0; i < values.length; i++) { | ||||||
|  |           if (!values[i]) { | ||||||
|  |             isValid = false; | ||||||
|  |             break; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         ngModel.$ngfValidations.push({name: name, valid: isValid}); | ||||||
|  |         deffer.resolve(isValid); | ||||||
|  |       }); | ||||||
|  |       return deffer.promise; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     var deffer = $q.defer(); |     var deffer = $q.defer(); | ||||||
|     var promises = []; |     var promises = []; | ||||||
|  |  | ||||||
|     promises.push(upload.happyPromise(validateAsync('maxHeight', 'height.max', /image/, |     promises.push(validateAsync('maxHeight', 'height.max', /image/, | ||||||
|       this.imageDimensions, function (d, val) { |       this.imageDimensions, function (d, val) { | ||||||
|         return d.height <= val; |         return d.height <= val; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('minHeight', 'height.min', /image/, |     promises.push(validateAsync('minHeight', 'height.min', /image/, | ||||||
|       this.imageDimensions, function (d, val) { |       this.imageDimensions, function (d, val) { | ||||||
|         return d.height >= val; |         return d.height >= val; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('maxWidth', 'width.max', /image/, |     promises.push(validateAsync('maxWidth', 'width.max', /image/, | ||||||
|       this.imageDimensions, function (d, val) { |       this.imageDimensions, function (d, val) { | ||||||
|         return d.width <= val; |         return d.width <= val; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('minWidth', 'width.min', /image/, |     promises.push(validateAsync('minWidth', 'width.min', /image/, | ||||||
|       this.imageDimensions, function (d, val) { |       this.imageDimensions, function (d, val) { | ||||||
|         return d.width >= val; |         return d.width >= val; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('dimensions', null, /image/, |     promises.push(validateAsync('dimensions', null, /image/, | ||||||
|       function (file, val) { |       function (file, val) { | ||||||
|         return upload.emptyPromise(val); |         return upload.emptyPromise(val); | ||||||
|       }, function (r) { |       }, function (r) { | ||||||
|         return r; |         return r; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('ratio', null, /image/, |     promises.push(validateAsync('ratio', null, /image/, | ||||||
|       this.imageDimensions, function (d, val) { |       this.imageDimensions, function (d, val) { | ||||||
|         var split = val.toString().split(','), valid = false; |         var split = val.toString().split(','), valid = false; | ||||||
|         for (var i = 0; i < split.length; i++) { |         for (var i = 0; i < split.length; i++) { | ||||||
|           if (Math.abs((d.width / d.height) - upload.ratioToFloat(split[i])) < 0.0001) { |           if (Math.abs((d.width / d.height) - upload.ratioToFloat(split[i])) < 0.01) { | ||||||
|             valid = true; |             valid = true; | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|         return valid; |         return valid; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('maxRatio', 'ratio.max', /image/, |     promises.push(validateAsync('maxRatio', 'ratio.max', /image/, | ||||||
|       this.imageDimensions, function (d, val) { |       this.imageDimensions, function (d, val) { | ||||||
|         return (d.width / d.height) - upload.ratioToFloat(val) < 0.0001; |         return (d.width / d.height) - upload.ratioToFloat(val) < 0.0001; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('minRatio', 'ratio.min', /image/, |     promises.push(validateAsync('minRatio', 'ratio.min', /image/, | ||||||
|       this.imageDimensions, function (d, val) { |       this.imageDimensions, function (d, val) { | ||||||
|         return (d.width / d.height) - upload.ratioToFloat(val) > -0.0001; |         return (d.width / d.height) - upload.ratioToFloat(val) > -0.0001; | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('maxDuration', 'duration.max', /audio|video/, |     promises.push(validateAsync('maxDuration', 'duration.max', /audio|video/, | ||||||
|       this.mediaDuration, function (d, val) { |       this.mediaDuration, function (d, val) { | ||||||
|         return d <= upload.translateScalars(val); |         return d <= upload.translateScalars(val); | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('minDuration', 'duration.min', /audio|video/, |     promises.push(validateAsync('minDuration', 'duration.min', /audio|video/, | ||||||
|       this.mediaDuration, function (d, val) { |       this.mediaDuration, function (d, val) { | ||||||
|         return d >= upload.translateScalars(val); |         return d >= upload.translateScalars(val); | ||||||
|       }))); |       })); | ||||||
|     promises.push(upload.happyPromise(validateAsync('duration', null, /audio|video/, |     promises.push(validateAsync('duration', null, /audio|video/, | ||||||
|       function (file, val) { |       function (file, val) { | ||||||
|         return upload.emptyPromise(val); |         return upload.emptyPromise(val); | ||||||
|       }, function (r) { |       }, function (r) { | ||||||
|         return r; |         return r; | ||||||
|       }))); |       })); | ||||||
|  |  | ||||||
|     promises.push(upload.happyPromise(validateAsync('validateAsyncFn', null, null, |     promises.push(validateAsync('validateAsyncFn', null, null, | ||||||
|       function (file, val) { |       function (file, val) { | ||||||
|         return val; |         return val; | ||||||
|       }, function (r) { |       }, function (r) { | ||||||
|         return r === true || r === null || r === ''; |         return r === true || r === null || r === ''; | ||||||
|       }))); |       })); | ||||||
|  |  | ||||||
|     return $q.all(promises).then(function () { |     $q.all(promises).then(function () { | ||||||
|       deffer.resolve(ngModel, ngModel.$ngfValidations); |  | ||||||
|  |       if (runAllValidation) { | ||||||
|  |         for (var i = 0; i < files.length; i++) { | ||||||
|  |           var file = files[i]; | ||||||
|  |           if (file.$error) { | ||||||
|  |             files.splice(i--, 1); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       runAllValidation = false; | ||||||
|  |       validateSync('maxFiles', null, function (file, val, i) { | ||||||
|  |         return prevLength + i < val; | ||||||
|  |       }); | ||||||
|  |  | ||||||
|  |       deffer.resolve({'validFiles': files, 'invalidFiles': invalidFiles}); | ||||||
|     }); |     }); | ||||||
|  |     return deffer.promise; | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   upload.imageDimensions = function (file) { |   upload.imageDimensions = function (file) { | ||||||
| @@ -1499,8 +1594,8 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|           .css('max-width', 'none !important').css('max-height', 'none !important'); |           .css('max-width', 'none !important').css('max-height', 'none !important'); | ||||||
|  |  | ||||||
|         function success() { |         function success() { | ||||||
|           var width = img[0].clientWidth; |           var width = img[0].naturalWidth || img[0].clientWidth; | ||||||
|           var height = img[0].clientHeight; |           var height = img[0].naturalHeight || img[0].clientHeight; | ||||||
|           img.remove(); |           img.remove(); | ||||||
|           file.$ngfWidth = width; |           file.$ngfWidth = width; | ||||||
|           file.$ngfHeight = height; |           file.$ngfHeight = height; | ||||||
| @@ -1514,23 +1609,23 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct | |||||||
|  |  | ||||||
|         img.on('load', success); |         img.on('load', success); | ||||||
|         img.on('error', error); |         img.on('error', error); | ||||||
|         var count = 0; |  | ||||||
|  |  | ||||||
|         function checkLoadError() { |         var secondsCounter = 0; | ||||||
|  |         function checkLoadErrorInCaseOfNoCallback() { | ||||||
|           $timeout(function () { |           $timeout(function () { | ||||||
|             if (img[0].parentNode) { |             if (img[0].parentNode) { | ||||||
|               if (img[0].clientWidth) { |               if (img[0].clientWidth) { | ||||||
|                 success(); |                 success(); | ||||||
|               } else if (count > 10) { |               } else if (secondsCounter++ > 10) { | ||||||
|                 error(); |                 error(); | ||||||
|               } else { |               } else { | ||||||
|                 checkLoadError(); |                 checkLoadErrorInCaseOfNoCallback(); | ||||||
|               } |               } | ||||||
|             } |             } | ||||||
|           }, 1000); |           }, 1000); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         checkLoadError(); |         checkLoadErrorInCaseOfNoCallback(); | ||||||
|  |  | ||||||
|         angular.element(document.getElementsByTagName('body')[0]).append(img); |         angular.element(document.getElementsByTagName('body')[0]).append(img); | ||||||
|       }, function () { |       }, function () { | ||||||
| @@ -1641,31 +1736,35 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|     var deferred = $q.defer(); |     var deferred = $q.defer(); | ||||||
|     var canvasElement = document.createElement('canvas'); |     var canvasElement = document.createElement('canvas'); | ||||||
|     var imageElement = document.createElement('img'); |     var imageElement = document.createElement('img'); | ||||||
|  |     imageElement.setAttribute('style', 'visibility:hidden;position:fixed;z-index:-100000'); | ||||||
|  |     document.body.appendChild(imageElement); | ||||||
|  |  | ||||||
|     imageElement.onload = function () { |     imageElement.onload = function () { | ||||||
|       if (resizeIf != null && resizeIf(imageElement.width, imageElement.height) === false) { |       var imgWidth = imageElement.width, imgHeight = imageElement.height; | ||||||
|  |       imageElement.parentNode.removeChild(imageElement); | ||||||
|  |       if (resizeIf != null && resizeIf(imgWidth, imgHeight) === false) { | ||||||
|         deferred.reject('resizeIf'); |         deferred.reject('resizeIf'); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|       try { |       try { | ||||||
|         if (ratio) { |         if (ratio) { | ||||||
|           var ratioFloat = upload.ratioToFloat(ratio); |           var ratioFloat = upload.ratioToFloat(ratio); | ||||||
|           var imgRatio = imageElement.width / imageElement.height; |           var imgRatio = imgWidth / imgHeight; | ||||||
|           if (imgRatio < ratioFloat) { |           if (imgRatio < ratioFloat) { | ||||||
|             width = imageElement.width; |             width = imgWidth; | ||||||
|             height = width / ratioFloat; |             height = width / ratioFloat; | ||||||
|           } else { |           } else { | ||||||
|             height = imageElement.height; |             height = imgHeight; | ||||||
|             width = height * ratioFloat; |             width = height * ratioFloat; | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|         if (!width) { |         if (!width) { | ||||||
|           width = imageElement.width; |           width = imgWidth; | ||||||
|         } |         } | ||||||
|         if (!height) { |         if (!height) { | ||||||
|           height = imageElement.height; |           height = imgHeight; | ||||||
|         } |         } | ||||||
|         var dimensions = calculateAspectRatioFit(imageElement.width, imageElement.height, width, height, centerCrop); |         var dimensions = calculateAspectRatioFit(imgWidth, imgHeight, width, height, centerCrop); | ||||||
|         canvasElement.width = Math.min(dimensions.width, width); |         canvasElement.width = Math.min(dimensions.width, width); | ||||||
|         canvasElement.height = Math.min(dimensions.height, height); |         canvasElement.height = Math.min(dimensions.height, height); | ||||||
|         var context = canvasElement.getContext('2d'); |         var context = canvasElement.getContext('2d'); | ||||||
| @@ -1678,6 +1777,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|       } |       } | ||||||
|     }; |     }; | ||||||
|     imageElement.onerror = function () { |     imageElement.onerror = function () { | ||||||
|  |       imageElement.parentNode.removeChild(imageElement); | ||||||
|       deferred.reject(); |       deferred.reject(); | ||||||
|     }; |     }; | ||||||
|     imageElement.src = imagen; |     imageElement.src = imagen; | ||||||
| @@ -1714,14 +1814,15 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   upload.resize = function (file, width, height, quality, type, ratio, centerCrop, resizeIf, restoreExif) { |   upload.resize = function (file, options) { | ||||||
|     if (file.type.indexOf('image') !== 0) return upload.emptyPromise(file); |     if (file.type.indexOf('image') !== 0) return upload.emptyPromise(file); | ||||||
|  |  | ||||||
|     var deferred = $q.defer(); |     var deferred = $q.defer(); | ||||||
|     upload.dataUrl(file, true).then(function (url) { |     upload.dataUrl(file, true).then(function (url) { | ||||||
|       resize(url, width, height, quality, type || file.type, ratio, centerCrop, resizeIf) |       resize(url, options.width, options.height, options.quality, options.type || file.type, | ||||||
|  |         options.ratio, options.centerCrop, options.resizeIf) | ||||||
|         .then(function (dataUrl) { |         .then(function (dataUrl) { | ||||||
|           if (file.type === 'image/jpeg' && restoreExif) { |           if (file.type === 'image/jpeg' && options.restoreExif !== false) { | ||||||
|             try { |             try { | ||||||
|               dataUrl = upload.restoreExif(url, dataUrl); |               dataUrl = upload.restoreExif(url, dataUrl); | ||||||
|             } catch (e) { |             } catch (e) { | ||||||
| @@ -1750,13 +1851,13 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
| }]); | }]); | ||||||
|  |  | ||||||
| (function () { | (function () { | ||||||
|   ngFileUpload.directive('ngfDrop', ['$parse', '$timeout', '$location', 'Upload', '$http', '$q', |   ngFileUpload.directive('ngfDrop', ['$parse', '$timeout', '$window', 'Upload', '$http', '$q', | ||||||
|     function ($parse, $timeout, $location, Upload, $http, $q) { |     function ($parse, $timeout, $window, Upload, $http, $q) { | ||||||
|       return { |       return { | ||||||
|         restrict: 'AEC', |         restrict: 'AEC', | ||||||
|         require: '?ngModel', |         require: '?ngModel', | ||||||
|         link: function (scope, elem, attr, ngModel) { |         link: function (scope, elem, attr, ngModel) { | ||||||
|           linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $location, Upload, $http, $q); |           linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $window, Upload, $http, $q); | ||||||
|         } |         } | ||||||
|       }; |       }; | ||||||
|     }]); |     }]); | ||||||
| @@ -1781,7 +1882,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|     }; |     }; | ||||||
|   }]); |   }]); | ||||||
|  |  | ||||||
|   function linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $location, upload, $http, $q) { |   function linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $window, upload, $http, $q) { | ||||||
|     var available = dropAvailable(); |     var available = dropAvailable(); | ||||||
|  |  | ||||||
|     var attrGetter = function (name, scope, params) { |     var attrGetter = function (name, scope, params) { | ||||||
| @@ -1857,23 +1958,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|       if (stopPropagation(scope)) evt.stopPropagation(); |       if (stopPropagation(scope)) evt.stopPropagation(); | ||||||
|       if (actualDragOverClass) elem.removeClass(actualDragOverClass); |       if (actualDragOverClass) elem.removeClass(actualDragOverClass); | ||||||
|       actualDragOverClass = null; |       actualDragOverClass = null; | ||||||
|       var items = evt.dataTransfer.items; |       extractFilesAndUpdateModel(evt.dataTransfer, evt, 'dropUrl'); | ||||||
|       var html; |  | ||||||
|       try { |  | ||||||
|         html = evt.dataTransfer && evt.dataTransfer.getData && evt.dataTransfer.getData('text/html'); |  | ||||||
|       } catch (e) {/* Fix IE11 that throw error calling getData */ |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       extractFiles(items, evt.dataTransfer.files, attrGetter('ngfAllowDir', scope) !== false, |  | ||||||
|         attrGetter('multiple') || attrGetter('ngfMultiple', scope)).then(function (files) { |  | ||||||
|         if (files.length) { |  | ||||||
|           updateModel(files, evt); |  | ||||||
|         } else { |  | ||||||
|           extractFilesFromHtml('dropUrl', html).then(function (files) { |  | ||||||
|             updateModel(files, evt); |  | ||||||
|           }); |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|     }, false); |     }, false); | ||||||
|     elem[0].addEventListener('paste', function (evt) { |     elem[0].addEventListener('paste', function (evt) { | ||||||
|       if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && |       if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && | ||||||
| @@ -1881,22 +1966,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|         evt.preventDefault(); |         evt.preventDefault(); | ||||||
|       } |       } | ||||||
|       if (isDisabled() || !upload.shouldUpdateOn('paste', attr, scope)) return; |       if (isDisabled() || !upload.shouldUpdateOn('paste', attr, scope)) return; | ||||||
|       var files = []; |       extractFilesAndUpdateModel(evt.clipboardData || evt.originalEvent.clipboardData, evt, 'pasteUrl'); | ||||||
|       var clipboard = evt.clipboardData || evt.originalEvent.clipboardData; |  | ||||||
|       if (clipboard && clipboard.items) { |  | ||||||
|         for (var k = 0; k < clipboard.items.length; k++) { |  | ||||||
|           if (clipboard.items[k].type.indexOf('image') !== -1) { |  | ||||||
|             files.push(clipboard.items[k].getAsFile()); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|       if (files.length) { |  | ||||||
|         updateModel(files, evt); |  | ||||||
|       } else { |  | ||||||
|         extractFilesFromHtml('pasteUrl', clipboard).then(function (files) { |  | ||||||
|           updateModel(files, evt); |  | ||||||
|         }); |  | ||||||
|       } |  | ||||||
|     }, false); |     }, false); | ||||||
|  |  | ||||||
|     if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && |     if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && | ||||||
| @@ -1909,12 +1979,33 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     function extractFilesAndUpdateModel(source, evt, updateOnType) { | ||||||
|  |       if (!source) return; | ||||||
|  |       // html needs to be calculated on the same process otherwise the data will be wiped | ||||||
|  |       // after promise resolve or setTimeout. | ||||||
|  |       var html; | ||||||
|  |       try { | ||||||
|  |         html = source && source.getData && source.getData('text/html'); | ||||||
|  |       } catch (e) {/* Fix IE11 that throw error calling getData */ | ||||||
|  |       } | ||||||
|  |       extractFiles(source.items, source.files, attrGetter('ngfAllowDir', scope) !== false, | ||||||
|  |         attrGetter('multiple') || attrGetter('ngfMultiple', scope)).then(function (files) { | ||||||
|  |         if (files.length) { | ||||||
|  |           updateModel(files, evt); | ||||||
|  |         } else { | ||||||
|  |           extractFilesFromHtml(updateOnType, html).then(function (files) { | ||||||
|  |             updateModel(files, evt); | ||||||
|  |           }); | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     function updateModel(files, evt) { |     function updateModel(files, evt) { | ||||||
|       upload.updateModel(ngModel, attr, scope, attrGetter('ngfChange') || attrGetter('ngfDrop'), files, evt); |       upload.updateModel(ngModel, attr, scope, attrGetter('ngfChange') || attrGetter('ngfDrop'), files, evt); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function extractFilesFromHtml(updateOn, html) { |     function extractFilesFromHtml(updateOn, html) { | ||||||
|       if (!upload.shouldUpdateOn(updateOn, attr, scope) || !html) return upload.rejectPromise([]); |       if (!upload.shouldUpdateOn(updateOn, attr, scope) || typeof html !== 'string') return upload.rejectPromise([]); | ||||||
|       var urls = []; |       var urls = []; | ||||||
|       html.replace(/<(img src|img [^>]* src) *=\"([^\"]*)\"/gi, function (m, n, src) { |       html.replace(/<(img src|img [^>]* src) *=\"([^\"]*)\"/gi, function (m, n, src) { | ||||||
|         urls.push(src); |         urls.push(src); | ||||||
| @@ -1965,8 +2056,14 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     function extractFiles(items, fileList, allowDir, multiple) { |     function extractFiles(items, fileList, allowDir, multiple) { | ||||||
|       var maxFiles = upload.getValidationAttr(attr, scope, 'maxFiles') || Number.MAX_VALUE; |       var maxFiles = upload.getValidationAttr(attr, scope, 'maxFiles'); | ||||||
|       var maxTotalSize = upload.getValidationAttr(attr, scope, 'maxTotalSize') || Number.MAX_VALUE; |       if (maxFiles == null) { | ||||||
|  |         maxFiles = Number.MAX_VALUE; | ||||||
|  |       } | ||||||
|  |       var maxTotalSize = upload.getValidationAttr(attr, scope, 'maxTotalSize'); | ||||||
|  |       if (maxTotalSize == null) { | ||||||
|  |         maxTotalSize = Number.MAX_VALUE; | ||||||
|  |       } | ||||||
|       var includeDir = attrGetter('ngfIncludeDir', scope); |       var includeDir = attrGetter('ngfIncludeDir', scope); | ||||||
|       var files = [], totalSize = 0; |       var files = [], totalSize = 0; | ||||||
|  |  | ||||||
| @@ -1977,7 +2074,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|             var promises = [upload.emptyPromise()]; |             var promises = [upload.emptyPromise()]; | ||||||
|             if (includeDir) { |             if (includeDir) { | ||||||
|               var file = {type: 'directory'}; |               var file = {type: 'directory'}; | ||||||
|               file.name = file.path = (path || '') + entry.name + entry.name; |               file.name = file.path = (path || '') + entry.name; | ||||||
|               files.push(file); |               files.push(file); | ||||||
|             } |             } | ||||||
|             var dirReader = entry.createReader(); |             var dirReader = entry.createReader(); | ||||||
| @@ -2031,7 +2128,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa | |||||||
|  |  | ||||||
|       var promises = [upload.emptyPromise()]; |       var promises = [upload.emptyPromise()]; | ||||||
|  |  | ||||||
|       if (items && items.length > 0 && $location.protocol() !== 'file') { |       if (items && items.length > 0 && $window.location.protocol !== 'file:') { | ||||||
|         for (var i = 0; i < items.length; i++) { |         for (var i = 0; i < items.length; i++) { | ||||||
|           if (items[i].webkitGetAsEntry && items[i].webkitGetAsEntry() && items[i].webkitGetAsEntry().isDirectory) { |           if (items[i].webkitGetAsEntry && items[i].webkitGetAsEntry() && items[i].webkitGetAsEntry().isDirectory) { | ||||||
|             var entry = items[i].webkitGetAsEntry(); |             var entry = items[i].webkitGetAsEntry(); | ||||||
|   | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Reference in New Issue
	
	Block a user
	 Radomir Dopieralski
					Radomir Dopieralski