From ebff2be265624ecb5fc7ec8796888500276cc487 Mon Sep 17 00:00:00 2001 From: Danial Farid Date: Sat, 13 Feb 2016 19:05:08 -0500 Subject: [PATCH] 12.0.0 --- .versions | 2 +- FileAPI.min.js | 2 +- ng-file-upload-all.js | 284 +++++++++++++++++++++---------------- ng-file-upload-all.min.js | 6 +- ng-file-upload-shim.js | 2 +- ng-file-upload-shim.min.js | 2 +- ng-file-upload.js | 282 ++++++++++++++++++++---------------- ng-file-upload.min.js | 7 +- package.js | 2 +- 9 files changed, 338 insertions(+), 251 deletions(-) diff --git a/.versions b/.versions index 071fa42..e6da899 100644 --- a/.versions +++ b/.versions @@ -1,4 +1,4 @@ angular:angular@1.2.24 -danialf:ng-file-upload@11.2.2 +danialf:ng-file-upload@11.2.3 meteor@1.1.10 underscore@1.0.4 diff --git a/FileAPI.min.js b/FileAPI.min.js index dc63b21..6988d96 100755 --- a/FileAPI.min.js +++ b/FileAPI.min.js @@ -1,4 +1,4 @@ -/*! 11.2.3 */ +/*! 12.0.0 */ /*! 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. */ diff --git a/ng-file-upload-all.js b/ng-file-upload-all.js index d2f7f60..54f55c6 100644 --- a/ng-file-upload-all.js +++ b/ng-file-upload-all.js @@ -3,7 +3,7 @@ * progress, resize, thumbnail, preview, validation and CORS * FileAPI Flash shim for old browsers not supporting FormData * @author Danial - * @version 11.2.3 + * @version 12.0.0 */ (function () { @@ -424,7 +424,7 @@ if (!window.FileReader) { * AngularJS file upload directives and services. Supoorts: file upload/drop/paste, resume, cancel/abort, * progress, resize, thumbnail, preview, validation and CORS * @author Danial - * @version 11.2.3 + * @version 12.0.0 */ if (window.XMLHttpRequest && !(window.FileAPI && FileAPI.shouldLoad)) { @@ -445,7 +445,7 @@ if (window.XMLHttpRequest && !(window.FileAPI && FileAPI.shouldLoad)) { var ngFileUpload = angular.module('ngFileUpload', []); -ngFileUpload.version = '11.2.3'; +ngFileUpload.version = '12.0.0'; ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, $q, $timeout) { var upload = this; @@ -491,7 +491,7 @@ ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, if (!config.disableProgress) { config.headers.__setXHR_ = function () { return function (xhr) { - if (!xhr) return; + if (!xhr || !xhr.upload || !xhr.upload.addEventListener) return; config.__XHR = xhr; if (config.xhrFn) config.xhrFn(xhr); xhr.upload.addEventListener('progress', function (e) { @@ -769,11 +769,11 @@ ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, this.translateScalars = function (str) { if (angular.isString(str)) { if (str.search(/kb/i) === str.length - 2) { - return parseFloat(str.substring(0, str.length - 2) * 1000); + return parseFloat(str.substring(0, str.length - 2) * 1024); } else if (str.search(/mb/i) === str.length - 2) { - return parseFloat(str.substring(0, str.length - 2) * 1000000); + return parseFloat(str.substring(0, str.length - 2) * 1048576); } else if (str.search(/gb/i) === str.length - 2) { - return parseFloat(str.substring(0, str.length - 2) * 1000000000); + return parseFloat(str.substring(0, str.length - 2) * 1073741824); } else if (str.search(/b/i) === str.length - 1) { return parseFloat(str.substring(0, str.length - 1)); } else if (str.search(/s/i) === str.length - 1) { @@ -897,7 +897,8 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE var param = upload.attrGetter('ngfResize', attr, scope); if (!param || !angular.isObject(param) || !upload.isResizeSupported() || !files.length) return upload.emptyPromise(); var promises = [upload.emptyPromise()]; - angular.forEach(files, function (f, i) { + + function handleFile(f, i) { if (f.type.indexOf('image') === 0) { if (param.pattern && !upload.validatePattern(f, param.pattern)) return; var promise = upload.resize(f, param.width, param.height, param.quality, @@ -913,43 +914,20 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE f.$errorParam = (e ? (e.message ? e.message : e) + ': ' : '') + (f && f.name); }); } - }); - return $q.all(promises); - } + } - function handleKeep(files, prevFiles, attr, scope) { - var dupFiles = []; - var keep = upload.attrGetter('ngfKeep', attr, scope); - if (keep) { - var hasNew = false; - - if (keep === 'distinct' || upload.attrGetter('ngfKeepDistinct', attr, scope) === true) { - var len = prevFiles.length; - if (files) { - for (var i = 0; i < files.length; i++) { - for (var j = 0; j < len; j++) { - if (files[i].name === prevFiles[j].name) { - dupFiles.push(files[i]); - break; - } - } - if (j === len) { - prevFiles.push(files[i]); - hasNew = true; - } - } - } - files = prevFiles; - } else { - files = prevFiles.concat(files || []); - } + for (var i = 0; i < files.length; i++) { + handleFile(files[i], i); } - return {files: files, dupFiles: dupFiles, keep: keep}; + return $q.all(promises); } upload.updateModel = function (ngModel, attr, scope, fileChange, files, evt, noDelay) { function update(files, invalidFiles, newFiles, dupFiles, isSingleModel) { + attr.$$ngfPrevValidFiles = files; + attr.$$ngfPrevInvalidFiles = invalidFiles; var file = files && files.length ? files[0] : null; + var invalidFile = invalidFiles && invalidFiles.length ? invalidFiles[0] : null; if (ngModel) { upload.applyModelValidation(ngModel, files); @@ -963,6 +941,7 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE $newFiles: newFiles, $duplicateFiles: dupFiles, $invalidFiles: invalidFiles, + $invalidFile: invalidFile, $event: evt }); } @@ -970,7 +949,7 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE var invalidModel = upload.attrGetter('ngfModelInvalid', attr); if (invalidModel) { $timeout(function () { - $parse(invalidModel).assign(scope, invalidFiles); + $parse(invalidModel).assign(scope, isSingleModel ? invalidFile : invalidFiles); }); } $timeout(function () { @@ -978,83 +957,128 @@ ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadE }); } - var newFiles = files; - var prevFiles = ngModel && ngModel.$modelValue && (angular.isArray(ngModel.$modelValue) ? - ngModel.$modelValue : [ngModel.$modelValue]); - prevFiles = (prevFiles || attr.$$ngfPrevFiles || []).slice(0); - var keepResult = handleKeep(files, prevFiles, attr, scope); - files = keepResult.files; - var dupFiles = keepResult.dupFiles; - var isSingleModel = !upload.attrGetter('ngfMultiple', attr, scope) && !upload.attrGetter('multiple', attr) && !keepResult.keep; + var allNewFiles, dupFiles = [], prevValidFiles, prevInvalidFiles, + invalids = [], valids = []; - attr.$$ngfPrevFiles = files; + function removeDuplicates() { + function equals(f1, f2) { + return f1.name === f2.name && (f1.$ngfOrigSize || f1.size) === (f2.$ngfOrigSize || f2.size) && + f1.type === f2.type; + } - if (keepResult.keep && (!newFiles || !newFiles.length)) return; + function isInPrevFiles(f) { + var j; + for (j = 0; j < prevValidFiles.length; j++) { + if (equals(f, prevValidFiles[j])) { + return true; + } + } + for (j = 0; j < prevInvalidFiles.length; j++) { + if (equals(f, prevInvalidFiles[j])) { + return true; + } + } + return false; + } - upload.attrGetter('ngfBeforeModelChange', attr, scope, { - $files: files, - $file: files && files.length ? files[0] : null, - $duplicateFiles: dupFiles, - $event: evt - }); + if (files) { + allNewFiles = []; + dupFiles = []; + for (var i = 0; i < files.length; i++) { + if (isInPrevFiles(files[i])) { + dupFiles.push(files[i]); + } else { + allNewFiles.push(files[i]); + } + } + } + } + + function toArray(v) { + return angular.isArray(v) ? v : [v]; + } - var validateAfterResize = upload.attrGetter('ngfValidateAfterResize', attr, scope); - var invalids = []; function separateInvalids() { - var valids = []; - angular.forEach(files, function (file) { + valids = []; + invalids = []; + angular.forEach(allNewFiles, function (file) { if (file.$error) { invalids.push(file); } else { valids.push(file); } }); - files = valids; } - upload.validate(newFiles, ngModel, attr, scope).then(function () { + function resizeAndUpdate() { + function updateModel() { + $timeout(function () { + update(keep ? prevValidFiles.concat(valids) : valids, + keep ? prevInvalidFiles.concat(invalids) : invalids, + files, dupFiles, isSingleModel); + }, options && options.debounce ? options.debounce.change || options.debounce : 0); + } + + resize(validateAfterResize ? allNewFiles : valids, attr, scope).then(function () { + if (validateAfterResize) { + upload.validate(allNewFiles, allLength, ngModel, attr, scope).then(function () { + separateInvalids(); + updateModel(); + }); + } else { + updateModel(); + } + }, function (e) { + throw 'Could not resize files ' + e; + }); + } + + prevValidFiles = attr.$$ngfPrevValidFiles || []; + prevInvalidFiles = attr.$$ngfPrevInvalidFiles || []; + if (ngModel && ngModel.$modelValue) { + prevValidFiles = toArray(ngModel.$modelValue); + } + + var keep = upload.attrGetter('ngfKeep', attr, scope); + allNewFiles = (files || []).slice(0); + if (keep === 'distinct' || upload.attrGetter('ngfKeepDistinct', attr, scope) === true) { + removeDuplicates(attr, scope); + } + + var isSingleModel = !keep && !upload.attrGetter('ngfMultiple', attr, scope) && !upload.attrGetter('multiple', attr); + + if (keep && !allNewFiles.length) return; + + upload.attrGetter('ngfBeforeModelChange', attr, scope, { + $files: files, + $file: files && files.length ? files[0] : null, + $newFiles: allNewFiles, + $duplicateFiles: dupFiles, + $event: evt + }); + + var validateAfterResize = upload.attrGetter('ngfValidateAfterResize', attr, scope); + + var allLength = allNewFiles.length + prevValidFiles.length + prevInvalidFiles.length; + var options = upload.attrGetter('ngModelOptions', attr, scope); + upload.validate(allNewFiles, allLength, ngModel, attr, scope).then(function () { if (noDelay) { - update(files, [], newFiles, dupFiles, isSingleModel); + update(allNewFiles, [], files, dupFiles, isSingleModel); } else { - var options = upload.attrGetter('ngModelOptions', attr, scope); if ((!options || !options.allowInvalid) && !validateAfterResize) { separateInvalids(); + } else { + valids = allNewFiles; } - var fixOrientation = upload.emptyPromise(files); if (upload.attrGetter('ngfFixOrientation', attr, scope) && upload.isExifSupported()) { - fixOrientation = applyExifRotations(files, attr, scope); - } - fixOrientation.then(function () { - function updateModel() { - $timeout(function () { - update(files, invalids, newFiles, dupFiles, isSingleModel); - }, options && options.debounce ? options.debounce.change || options.debounce : 0); - } - resize(files, attr, scope).then(function () { - if (validateAfterResize) { - upload.validate(files, ngModel, attr, scope).then(function () { - separateInvalids(); - updateModel(); - }); - } else { - updateModel(); - } - }, function (e) { - throw 'Could not resize files ' + e; + applyExifRotations(valids, attr, scope).then(function () { + resizeAndUpdate(); }); - }); + } else { + resizeAndUpdate(); + } } }); - - // cleaning object url memories - var l = prevFiles.length; - while (l--) { - var prevFile = prevFiles[l]; - if (window.URL && prevFile.blobUrl) { - URL.revokeObjectURL(prevFile.blobUrl); - delete prevFile.blobUrl; - } - } }; return upload; @@ -1347,7 +1371,20 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', } $timeout(function () { file.$ngfBlobUrl = url; - if (url) deferred.resolve(url, file); + if (url) { + deferred.resolve(url, file); + upload.blobUrls = upload.blobUrls || []; + upload.blobUrlsTotalSize = upload.blobUrlsTotalSize || 0; + upload.blobUrls.push({url: url, size: file.size}); + upload.blobUrlsTotalSize += file.size || 0; + var maxMemory = upload.defaults.blobUrlsMaxMemory || 268435456; + var maxLength = upload.defaults.blobUrlsMaxQueueSize || 200; + while ((upload.blobUrlsTotalSize > maxMemory || upload.blobUrls.length > maxLength) && upload.blobUrls.length > 1) { + var obj = upload.blobUrls.splice(0, 1)[0]; + URL.revokeObjectURL(obj.url); + upload.blobUrlsTotalSize -= obj.size; + } + } }); } else { var fileReader = new FileReader(); @@ -1355,6 +1392,9 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', $timeout(function () { file.$ngfDataUrl = e.target.result; deferred.resolve(e.target.result, file); + $timeout(function () { + delete file.$ngfDataUrl; + }, 1000); }); }; fileReader.onerror = function () { @@ -1367,7 +1407,7 @@ ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', } } else { $timeout(function () { - file[disallowObjectUrl ? 'dataUrl' : 'blobUrl'] = ''; + file[disallowObjectUrl ? '$ngfDataUrl' : '$ngfBlobUrl'] = ''; deferred.reject(); }); } @@ -1598,7 +1638,7 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct if (files && !angular.isArray(files)) { files = [files]; } - upload.validate(files, ngModel, attr, scope).then(function () { + upload.validate(files, files ? files.length : 0, ngModel, attr, scope).then(function () { upload.applyModelValidation(ngModel, files); }); } @@ -1639,7 +1679,7 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct return val; }; - upload.validate = function (files, ngModel, attr, scope) { + upload.validate = function (files, allLength, ngModel, attr, scope) { ngModel = ngModel || {}; ngModel.$ngfValidations = ngModel.$ngfValidations || []; @@ -1667,6 +1707,7 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct if (val != null) { if (!fn(file, val)) { file.$error = name; + (file.$errorMessages = (file.$errorMessages || {})).name = true; file.$errorParam = val; files.splice(i, 1); valid = false; @@ -1680,16 +1721,15 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct } } - var filesLength = files.length; validateSync('maxFiles', null, function (file, val) { - return filesLength <= val; + return allLength <= val; }); validateSync('pattern', null, upload.validatePattern); validateSync('minSize', 'size.min', function (file, val) { - return file.size >= upload.translateScalars(val); + return file.size + 0.1 >= upload.translateScalars(val); }); validateSync('maxSize', 'size.max', function (file, val) { - return file.size <= upload.translateScalars(val); + return file.size - 0.1 <= upload.translateScalars(val); }); var totalSize = 0; validateSync('maxTotalSize', null, function (file, val) { @@ -1715,6 +1755,7 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct asyncFn(file, val).then(function (d) { if (!fn(d, val)) { file.$error = name; + (file.$errorMessages = (file.$errorMessages || {})).name = true; file.$errorParam = val; defer.reject(); } else { @@ -1723,6 +1764,7 @@ ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', funct }, function () { if (attrGetter('ngfValidateForce', {$file: file})) { file.$error = name; + (file.$errorMessages = (file.$errorMessages || {})).name = true; file.$errorParam = val; defer.reject(); } else { @@ -2046,7 +2088,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa return deferred.promise; }; - upload.dataUrltoBlob = function (dataurl, name) { + upload.dataUrltoBlob = function (dataurl, name, origSize) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { @@ -2054,6 +2096,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa } var blob = new window.Blob([u8arr], {type: mime}); blob.name = name; + blob.$ngfOrigSize = origSize; return blob; }; @@ -2089,7 +2132,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa setTimeout(function () {throw e;}, 1); } } - deferred.resolve(upload.dataUrltoBlob(dataUrl, file.name)); + deferred.resolve(upload.dataUrltoBlob(dataUrl, file.name, file.size)); }, function (r) { if (r === 'resizeIf') { deferred.resolve(file); @@ -2213,12 +2256,19 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa if (stopPropagation(scope)) evt.stopPropagation(); if (actualDragOverClass) elem.removeClass(actualDragOverClass); actualDragOverClass = null; - extractFiles(evt, attrGetter('ngfAllowDir', scope) !== false, + var items = evt.dataTransfer.items; + 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', evt.dataTransfer).then(function (files) { + extractFilesFromHtml('dropUrl', html).then(function (files) { updateModel(files, evt); }); } @@ -2262,12 +2312,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa upload.updateModel(ngModel, attr, scope, attrGetter('ngfChange') || attrGetter('ngfDrop'), files, evt); } - function extractFilesFromHtml(updateOn, obj) { - var html; - try { - html = (obj && obj.getData && obj.getData('text/html')); - } catch (e) {/* Fix IE11 that throw error calling getData */ - } + function extractFilesFromHtml(updateOn, html) { if (!upload.shouldUpdateOn(updateOn, attr, scope) || !html) return upload.rejectPromise([]); var urls = []; html.replace(/<(img src|img [^>]* src) *=\"([^\"]*)\"/gi, function (m, n, src) { @@ -2317,18 +2362,19 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa callback(dClass); } - function extractFiles(evt, allowDir, multiple) { + function extractFiles(items, fileList, allowDir, multiple) { var maxFiles = upload.getValidationAttr(attr, scope, 'maxFiles') || Number.MAX_VALUE; var maxTotalSize = upload.getValidationAttr(attr, scope, 'maxTotalSize') || Number.MAX_VALUE; var includeDir = attrGetter('ngfIncludeDir', scope); var files = [], totalSize = 0; + function traverseFileTree(entry, path) { var defer = $q.defer(); if (entry != null) { if (entry.isDirectory) { var promises = [upload.emptyPromise()]; if (includeDir) { - var file = {type : 'directory'}; + var file = {type: 'directory'}; file.name = file.path = (path || '') + entry.name + entry.name; files.push(file); } @@ -2338,7 +2384,7 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa dirReader.readEntries(function (results) { try { if (!results.length) { - angular.forEach(entries.slice(0), function(e) { + angular.forEach(entries.slice(0), function (e) { if (files.length <= maxFiles && totalSize <= maxTotalSize) { promises.push(traverseFileTree(e, (path ? path : '') + entry.name + '/')); } @@ -2383,7 +2429,6 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa var promises = [upload.emptyPromise()]; - var items = evt.dataTransfer.items; if (items && items.length > 0 && $location.protocol() !== 'file') { for (var i = 0; i < items.length; i++) { if (items[i].webkitGetAsEntry && items[i].webkitGetAsEntry() && items[i].webkitGetAsEntry().isDirectory) { @@ -2405,7 +2450,6 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa (!multiple && files.length > 0)) break; } } else { - var fileList = evt.dataTransfer.files; if (fileList != null) { for (var j = 0; j < fileList.length; j++) { var file = fileList.item(j); @@ -2421,12 +2465,12 @@ ngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadVa var defer = $q.defer(); $q.all(promises).then(function () { - if (!multiple) { + if (!multiple && !includeDir) { var i = 0; - while (files.length && files[i].type === 'directory') i++; + while (files[i] && files[i].type === 'directory') i++; defer.resolve([files[i]]); } else { - defer.resolve(files); + defer.resolve(files); } }, function (e) { defer.reject(e); diff --git a/ng-file-upload-all.min.js b/ng-file-upload-all.min.js index 159ca7c..c383446 100644 --- a/ng-file-upload-all.min.js +++ b/ng-file-upload-all.min.js @@ -1,4 +1,4 @@ -/*! 11.2.3 */ -!function(){function a(a,b){window.XMLHttpRequest.prototype[a]=b(window.XMLHttpRequest.prototype[a])}function b(a,b,c){try{Object.defineProperty(a,b,{get:c})}catch(d){}}if(window.FileAPI||(window.FileAPI={}),!window.XMLHttpRequest)throw"AJAX is not supported. XMLHttpRequest is not defined.";if(FileAPI.shouldLoad=!window.FormData||FileAPI.forceLoad,FileAPI.shouldLoad){var c=function(a){if(!a.__listeners){a.upload||(a.upload={}),a.__listeners=[];var b=a.upload.addEventListener;a.upload.addEventListener=function(c,d){a.__listeners[c]=d,b&&b.apply(this,arguments)}}};a("open",function(a){return function(b,d,e){c(this),this.__url=d;try{a.apply(this,[b,d,e])}catch(f){f.message.indexOf("Access is denied")>-1&&(this.__origError=f,a.apply(this,[b,"_fix_for_ie_crossdomain__",e]))}}}),a("getResponseHeader",function(a){return function(b){return this.__fileApiXHR&&this.__fileApiXHR.getResponseHeader?this.__fileApiXHR.getResponseHeader(b):null==a?null:a.apply(this,[b])}}),a("getAllResponseHeaders",function(a){return function(){return this.__fileApiXHR&&this.__fileApiXHR.getAllResponseHeaders?this.__fileApiXHR.getAllResponseHeaders():null==a?null:a.apply(this)}}),a("abort",function(a){return function(){return this.__fileApiXHR&&this.__fileApiXHR.abort?this.__fileApiXHR.abort():null==a?null:a.apply(this)}}),a("setRequestHeader",function(a){return function(b,d){if("__setXHR_"===b){c(this);var e=d(this);e instanceof Function&&e(this)}else this.__requestHeaders=this.__requestHeaders||{},this.__requestHeaders[b]=d,a.apply(this,arguments)}}),a("send",function(a){return function(){var c=this;if(arguments[0]&&arguments[0].__isFileAPIShim){var d=arguments[0],e={url:c.__url,jsonp:!1,cache:!0,complete:function(a,d){a&&angular.isString(a)&&-1!==a.indexOf("#2174")&&(a=null),c.__completed=!0,!a&&c.__listeners.load&&c.__listeners.load({type:"load",loaded:c.__loaded,total:c.__total,target:c,lengthComputable:!0}),!a&&c.__listeners.loadend&&c.__listeners.loadend({type:"loadend",loaded:c.__loaded,total:c.__total,target:c,lengthComputable:!0}),"abort"===a&&c.__listeners.abort&&c.__listeners.abort({type:"abort",loaded:c.__loaded,total:c.__total,target:c,lengthComputable:!0}),void 0!==d.status&&b(c,"status",function(){return 0===d.status&&a&&"abort"!==a?500:d.status}),void 0!==d.statusText&&b(c,"statusText",function(){return d.statusText}),b(c,"readyState",function(){return 4}),void 0!==d.response&&b(c,"response",function(){return d.response});var e=d.responseText||(a&&0===d.status&&"abort"!==a?a:void 0);b(c,"responseText",function(){return e}),b(c,"response",function(){return e}),a&&b(c,"err",function(){return a}),c.__fileApiXHR=d,c.onreadystatechange&&c.onreadystatechange(),c.onload&&c.onload()},progress:function(a){if(a.target=c,c.__listeners.progress&&c.__listeners.progress(a),c.__total=a.total,c.__loaded=a.loaded,a.total===a.loaded){var b=this;setTimeout(function(){c.__completed||(c.getAllResponseHeaders=function(){},b.complete(null,{status:204,statusText:"No Content"}))},FileAPI.noContentTimeout||1e4)}},headers:c.__requestHeaders};e.data={},e.files={};for(var f=0;f-1){e=h.substring(0,g+1);break}null==FileAPI.staticPath&&(FileAPI.staticPath=e),i.setAttribute("src",d||e+"FileAPI.min.js"),document.getElementsByTagName("head")[0].appendChild(i)}FileAPI.ngfFixIE=function(d,e,f){if(!b())throw'Adode Flash Player need to be installed. To check ahead use "FileAPI.hasFlash"';var g=function(){var b=e.parent();d.attr("disabled")?b&&b.removeClass("js-fileapi-wrapper"):(e.attr("__ngf_flash_")||(e.unbind("change"),e.unbind("click"),e.bind("change",function(a){h.apply(this,[a]),f.apply(this,[a])}),e.attr("__ngf_flash_","true")),b.addClass("js-fileapi-wrapper"),a(d)||(b.css("position","absolute").css("top",c(d[0]).top+"px").css("left",c(d[0]).left+"px").css("width",d[0].offsetWidth+"px").css("height",d[0].offsetHeight+"px").css("filter","alpha(opacity=0)").css("display",d.css("display")).css("overflow","hidden").css("z-index","900000").css("visibility","visible"),e.css("width",d[0].offsetWidth+"px").css("height",d[0].offsetHeight+"px").css("position","absolute").css("top","0px").css("left","0px")))};d.bind("mouseenter",g);var h=function(a){for(var b=FileAPI.getFiles(a),c=0;c0},this.rename=function(a,b){return a.ngfName=b,a},this.jsonBlob=function(a){null==a||angular.isString(a)||(a=JSON.stringify(a));var b=new window.Blob([a],{type:"application/json"});return b._ngfBlob=!0,b},this.json=function(a){return angular.toJson(a)},this.isFile=function(a){return null!=a&&(a instanceof window.Blob||a.flashId&&a.name&&a.size)},this.upload=function(a,b){function c(b,c){if(b._ngfBlob)return b;if(a._file=a._file||b,null!=a._start&&g){a._end&&a._end>=b.size&&(a._finished=!0,a._end=b.size);var d=b.slice(a._start,a._end||b.size);return d.name=b.name,d.ngfName=b.ngfName,a._chunkSize&&(c.append("_chunkSize",a._chunkSize),c.append("_currentChunkSize",a._end-a._start),c.append("_chunkNumber",Math.floor(a._start/a._chunkSize)),c.append("_totalSize",a._file.size)),d}return b}function h(b,d,e){if(void 0!==d)if(angular.isDate(d)&&(d=d.toISOString()),angular.isString(d))b.append(e,d);else if(f.isFile(d)){var g=c(d,b),i=e.split(",");i[1]&&(g.ngfName=i[1].replace(/^\s+|\s+$/g,""),e=i[0]),a._fileKey=a._fileKey||e,b.append(e,g,g.ngfName||g.name)}else if(angular.isObject(d)){if(d.$$ngfCircularDetection)throw"ngFileUpload: Circular reference in config.data. Make sure specified data for Upload.upload() has no circular reference: "+e;d.$$ngfCircularDetection=!0;try{for(var j in d)if(d.hasOwnProperty(j)&&"$$ngfCircularDetection"!==j){var k=null==a.objectKey?"[i]":a.objectKey;d.length&&parseInt(j)>-1&&(k=null==a.arrayKey?k:a.arrayKey),h(b,d[j],e+k.replace(/[ik]/g,j))}}finally{delete d.$$ngfCircularDetection}}else b.append(e,d)}function i(){a._chunkSize=f.translateScalars(a.resumeChunkSize),a._chunkSize=a._chunkSize?parseInt(a._chunkSize.toString()):null,a.headers=a.headers||{},a.headers["Content-Type"]=void 0,a.transformRequest=a.transformRequest?angular.isArray(a.transformRequest)?a.transformRequest:[a.transformRequest]:[],a.transformRequest.push(function(b){var c,d=new window.FormData;b=b||a.fields||{},a.file&&(b.file=a.file);for(c in b)if(b.hasOwnProperty(c)){var e=b[c];a.formDataAppender?a.formDataAppender(d,c,e):h(d,e,c)}return d})}return b||(a=e(a)),a._isDigested||(a._isDigested=!0,i()),d(a)},this.http=function(b){return b=e(b),b.transformRequest=b.transformRequest||function(b){return window.ArrayBuffer&&b instanceof window.ArrayBuffer||b instanceof window.Blob?b:a.defaults.transformRequest[0].apply(this,arguments)},b._chunkSize=f.translateScalars(b.resumeChunkSize),b._chunkSize=b._chunkSize?parseInt(b._chunkSize.toString()):null,d(b)},this.translateScalars=function(a){if(angular.isString(a)){if(a.search(/kb/i)===a.length-2)return parseFloat(1e3*a.substring(0,a.length-2));if(a.search(/mb/i)===a.length-2)return parseFloat(1e6*a.substring(0,a.length-2));if(a.search(/gb/i)===a.length-2)return parseFloat(1e9*a.substring(0,a.length-2));if(a.search(/b/i)===a.length-1)return parseFloat(a.substring(0,a.length-1));if(a.search(/s/i)===a.length-1)return parseFloat(a.substring(0,a.length-1));if(a.search(/m/i)===a.length-1)return parseFloat(60*a.substring(0,a.length-1));if(a.search(/h/i)===a.length-1)return parseFloat(3600*a.substring(0,a.length-1))}return a},this.urlToBlob=function(c){var d=b.defer();return a({url:c,method:"get",responseType:"arraybuffer"}).then(function(a){var b=new Uint8Array(a.data),c=a.headers("content-type")||"image/WebP",e=new window.Blob([b],{type:c});d.resolve(e)},function(a){d.reject(a)}),d.promise},this.setDefaults=function(a){this.defaults=a||{}},this.defaults={},this.version=ngFileUpload.version}]),ngFileUpload.service("Upload",["$parse","$timeout","$compile","$q","UploadExif",function(a,b,c,d,e){function f(a,b,c){var e=[i.emptyPromise()];return angular.forEach(a,function(d,f){0===d.type.indexOf("image/jpeg")&&i.attrGetter("ngfFixOrientation",b,c,{$file:d})&&e.push(i.happyPromise(i.applyExifRotation(d),d).then(function(b){a.splice(f,1,b)}))}),d.all(e)}function g(a,b,c){var e=i.attrGetter("ngfResize",b,c);if(!(e&&angular.isObject(e)&&i.isResizeSupported()&&a.length))return i.emptyPromise();var f=[i.emptyPromise()];return angular.forEach(a,function(d,g){if(0===d.type.indexOf("image")){if(e.pattern&&!i.validatePattern(d,e.pattern))return;var h=i.resize(d,e.width,e.height,e.quality,e.type,e.ratio,e.centerCrop,function(a,e){return i.attrGetter("ngfResizeIf",b,c,{$width:a,$height:e,$file:d})},e.restoreExif!==!1);f.push(h),h.then(function(b){a.splice(g,1,b)},function(a){d.$error="resize",d.$errorParam=(a?(a.message?a.message:a)+": ":"")+(d&&d.name)})}}),d.all(f)}function h(a,b,c,d){var e=[],f=i.attrGetter("ngfKeep",c,d);if(f){var g=!1;if("distinct"===f||i.attrGetter("ngfKeepDistinct",c,d)===!0){var h=b.length;if(a)for(var j=0;jk;k++)if(a[j].name===b[k].name){e.push(a[j]);break}k===h&&(b.push(a[j]),g=!0)}a=b}else a=b.concat(a||[])}return{files:a,dupFiles:e,keep:f}}var i=e;return i.getAttrWithDefaults=function(a,b){if(null!=a[b])return a[b];var c=i.defaults[b];return null==c?c:angular.isString(c)?c:JSON.stringify(c)},i.attrGetter=function(b,c,d,e){var f=this.getAttrWithDefaults(c,b);if(!d)return f;try{return e?a(f)(d,e):a(f)(d)}catch(g){if(b.search(/min|max|pattern/i))return f;throw g}},i.shouldUpdateOn=function(a,b,c){var d=i.attrGetter("ngModelOptions",b,c);return d&&d.updateOn?d.updateOn.split(" ").indexOf(a)>-1:!0},i.emptyPromise=function(){var a=d.defer(),c=arguments;return b(function(){a.resolve.apply(a,c)}),a.promise},i.rejectPromise=function(){var a=d.defer(),c=arguments;return b(function(){a.reject.apply(a,c)}),a.promise},i.happyPromise=function(a,c){var e=d.defer();return a.then(function(a){e.resolve(a)},function(a){b(function(){throw a}),e.resolve(c)}),e.promise},i.updateModel=function(c,d,e,j,k,l,m){function n(f,g,h,k,m){var n=f&&f.length?f[0]:null;c&&(i.applyModelValidation(c,f),c.$setViewValue(m?n:f)),j&&a(j)(e,{$files:f,$file:n,$newFiles:h,$duplicateFiles:k,$invalidFiles:g,$event:l});var o=i.attrGetter("ngfModelInvalid",d);o&&b(function(){a(o).assign(e,g)}),b(function(){})}function o(){var a=[];angular.forEach(k,function(b){b.$error?v.push(b):a.push(b)}),k=a}var p=k,q=c&&c.$modelValue&&(angular.isArray(c.$modelValue)?c.$modelValue:[c.$modelValue]);q=(q||d.$$ngfPrevFiles||[]).slice(0);var r=h(k,q,d,e);k=r.files;var s=r.dupFiles,t=!i.attrGetter("ngfMultiple",d,e)&&!i.attrGetter("multiple",d)&&!r.keep;if(d.$$ngfPrevFiles=k,!r.keep||p&&p.length){i.attrGetter("ngfBeforeModelChange",d,e,{$files:k,$file:k&&k.length?k[0]:null,$duplicateFiles:s,$event:l});var u=i.attrGetter("ngfValidateAfterResize",d,e),v=[];i.validate(p,c,d,e).then(function(){if(m)n(k,[],p,s,t);else{var a=i.attrGetter("ngModelOptions",d,e);a&&a.allowInvalid||u||o();var h=i.emptyPromise(k);i.attrGetter("ngfFixOrientation",d,e)&&i.isExifSupported()&&(h=f(k,d,e)),h.then(function(){function f(){b(function(){n(k,v,p,s,t)},a&&a.debounce?a.debounce.change||a.debounce:0)}g(k,d,e).then(function(){u?i.validate(k,c,d,e).then(function(){o(),f()}):f()},function(a){throw"Could not resize files "+a})})}});for(var w=q.length;w--;){var x=q[w];window.URL&&x.blobUrl&&(URL.revokeObjectURL(x.blobUrl),delete x.blobUrl)}}},i}]),ngFileUpload.directive("ngfSelect",["$parse","$timeout","$compile","Upload",function(a,b,c,d){function e(a){var b=a.match(/Android[^\d]*(\d+)\.(\d+)/);if(b&&b.length>2){var c=d.defaults.androidFixMinorVersion||4;return parseInt(b[1])<4||parseInt(b[1])===c&&parseInt(b[2])');n(a);var c=angular.element("");return c.css("visibility","hidden").css("position","absolute").css("overflow","hidden").css("width","0px").css("height","0px").css("border","none").css("margin","0px").css("padding","0px").attr("tabindex","-1"),g.push({el:b,ref:c}),document.body.appendChild(c.append(a)[0]),a}function p(c){if(b.attr("disabled"))return!1;if(!t("ngfSelectDisabled",a)){var d=q(c);if(null!=d)return d;r(c);try{k()||document.body.contains(w[0])||(g.push({el:b,ref:w.parent()}),document.body.appendChild(w[0].parent()),w.bind("change",m))}catch(f){}return e(navigator.userAgent)?setTimeout(function(){w[0].click()},0):w[0].click(),!1}}function q(a){var b=a.changedTouches||a.originalEvent&&a.originalEvent.changedTouches;if("touchstart"===a.type)return v=b?b[0].clientY:0,!0;if(a.stopPropagation(),a.preventDefault(),"touchend"===a.type){var c=b?b[0].clientY:0;if(Math.abs(c-v)>20)return!1}}function r(b){j.shouldUpdateOn("click",c,a)&&w.val()&&(w.val(null),j.updateModel(d,c,a,l(),null,b,!0))}function s(a){if(w&&!w.attr("__ngf_ie10_Fix_")){if(!w[0].parentNode)return void(w=null);a.preventDefault(),a.stopPropagation(),w.unbind("click");var b=w.clone();return w.replaceWith(b),w=b,w.attr("__ngf_ie10_Fix_","true"),w.bind("change",m),w.bind("click",s),w[0].click(),!1}w.removeAttr("__ngf_ie10_Fix_")}var t=function(a,b){return j.attrGetter(a,c,b)};j.registerModelChangeValidator(d,c,a);var u=[];u.push(a.$watch(t("ngfMultiple"),function(){w.attr("multiple",t("ngfMultiple",a))})),u.push(a.$watch(t("ngfCapture"),function(){w.attr("capture",t("ngfCapture",a))})),u.push(a.$watch(t("ngfAccept"),function(){w.attr("accept",t("ngfAccept",a))})),c.$observe("accept",function(){w.attr("accept",t("accept"))}),u.push(function(){c.$$observers&&delete c.$$observers.accept});var v=0,w=b;k()||(w=o()),w.bind("change",m),k()?b.bind("click",r):b.bind("click touchstart touchend",p),-1!==navigator.appVersion.indexOf("MSIE 10")&&w.bind("click",s),d&&d.$formatters.push(function(a){return(null==a||0===a.length)&&w.val()&&w.val(null),a}),a.$on("$destroy",function(){k()||w.parent().remove(),angular.forEach(u,function(a){a()})}),h(function(){for(var a=0;a2&&"/"===a[0]&&"/"===a[a.length-1])b=a.substring(1,a.length-1);else{var e=a.split(",");if(e.length>1)for(var f=0;f|:\\-]","g"),"\\$&")+"$",b=b.replace(/\\\*/g,".*").replace(/\\\?/g,"."))}return{regexp:b,excludes:c}}function e(a,b){null==b||a.$dirty||(a.$setDirty?a.$setDirty():a.$dirty=!0)}var f=a;return f.validatePattern=function(a,b){if(!b)return!0;var c=d(b),e=!0;if(c.regexp&&c.regexp.length){var f=new RegExp(c.regexp,"i");e=null!=a.type&&f.test(a.type)||null!=a.name&&f.test(a.name)}for(var g=c.excludes.length;g--;){var h=new RegExp(c.excludes[g],"i");e=e&&(null==a.type||h.test(a.type))&&(null==a.name||h.test(a.name))}return e},f.ratioToFloat=function(a){var b=a.toString(),c=b.search(/[x:]/i);return b=c>-1?parseFloat(b.substring(0,c))/parseFloat(b.substring(c+1)):parseFloat(b)},f.registerModelChangeValidator=function(a,b,c){a&&a.$formatters.push(function(d){a.$dirty&&(d&&!angular.isArray(d)&&(d=[d]),f.validate(d,a,b,c).then(function(){f.applyModelValidation(a,d)}))})},f.applyModelValidation=function(a,b){e(a,b),angular.forEach(a.$ngfValidations,function(b){a.$setValidity(b.name,b.valid)})},f.getValidationAttr=function(a,b,c,d,e){var g="ngf"+c[0].toUpperCase()+c.substr(1),h=f.attrGetter(g,a,b,{$file:e});if(null==h&&(h=f.attrGetter("ngfValidate",a,b,{$file:e}))){var i=(d||c).split(".");h=h[i[0]],i.length>1&&(h=h&&h[i[1]])}return h},f.validate=function(a,c,d,e){function g(b,g,h){if(a){for(var i=a.length,j=null;i--;){var k=a[i];if(k){var l=f.getValidationAttr(d,e,b,g,k);null!=l&&(h(k,l)||(k.$error=b,k.$errorParam=l,a.splice(i,1),j=!1))}}null!==j&&c.$ngfValidations.push({name:b,valid:j})}}function h(g,h,j,k,l){function m(a,b,c){null!=c?k(b,c).then(function(d){l(d,c)?a.resolve():(b.$error=g,b.$errorParam=c,a.reject())},function(){i("ngfValidateForce",{$file:b})?(b.$error=g,b.$errorParam=c,a.reject()):a.resolve()}):a.resolve()}var n=[f.emptyPromise()];return a?(a=void 0===a.length?[a]:a,angular.forEach(a,function(a){var c=b.defer();return n.push(c.promise),!j||null!=a.type&&0===a.type.search(j)?void("dimensions"===g&&null!=f.attrGetter("ngfDimensions",d)?f.imageDimensions(a).then(function(b){m(c,a,i("ngfDimensions",{$file:a,$width:b.width,$height:b.height}))},function(){c.reject()}):"duration"===g&&null!=f.attrGetter("ngfDuration",d)?f.mediaDuration(a).then(function(b){m(c,a,i("ngfDuration",{$file:a,$duration:b}))},function(){c.reject()}):m(c,a,f.getValidationAttr(d,e,g,h,a))):void c.resolve()}),b.all(n).then(function(){c.$ngfValidations.push({name:g,valid:!0})},function(){c.$ngfValidations.push({name:g,valid:!1})})):void 0}c=c||{},c.$ngfValidations=c.$ngfValidations||[],angular.forEach(c.$ngfValidations,function(a){a.valid=!0});var i=function(a,b){return f.attrGetter(a,d,e,b)};if(null==a||0===a.length)return f.emptyPromise(c);a=void 0===a.length?[a]:a.slice(0);var j=a.length;g("maxFiles",null,function(a,b){return b>=j}),g("pattern",null,f.validatePattern),g("minSize","size.min",function(a,b){return a.size>=f.translateScalars(b)}),g("maxSize","size.max",function(a,b){return a.size<=f.translateScalars(b)});var k=0;if(g("maxTotalSize",null,function(b,c){return k+=b.size,k>f.translateScalars(c)?(a.splice(0,a.length),!1):!0}),g("validateFn",null,function(a,b){return b===!0||null===b||""===b}),!a.length)return f.emptyPromise(c,c.$ngfValidations);var l=b.defer(),m=[];return m.push(f.happyPromise(h("maxHeight","height.max",/image/,this.imageDimensions,function(a,b){return a.height<=b}))),m.push(f.happyPromise(h("minHeight","height.min",/image/,this.imageDimensions,function(a,b){return a.height>=b}))),m.push(f.happyPromise(h("maxWidth","width.max",/image/,this.imageDimensions,function(a,b){return a.width<=b}))),m.push(f.happyPromise(h("minWidth","width.min",/image/,this.imageDimensions,function(a,b){return a.width>=b}))),m.push(f.happyPromise(h("dimensions",null,/image/,function(a,b){return f.emptyPromise(b)},function(a){return a}))),m.push(f.happyPromise(h("ratio",null,/image/,this.imageDimensions,function(a,b){for(var c=b.toString().split(","),d=!1,e=0;e-1e-4}))),m.push(f.happyPromise(h("maxDuration","duration.max",/audio|video/,this.mediaDuration,function(a,b){return a<=f.translateScalars(b)}))),m.push(f.happyPromise(h("minDuration","duration.min",/audio|video/,this.mediaDuration,function(a,b){return a>=f.translateScalars(b)}))),m.push(f.happyPromise(h("duration",null,/audio|video/,function(a,b){return f.emptyPromise(b)},function(a){return a}))),m.push(f.happyPromise(h("validateAsyncFn",null,null,function(a,b){return b},function(a){return a===!0||null===a||""===a}))),b.all(m).then(function(){l.resolve(c,c.$ngfValidations)})},f.imageDimensions=function(a){if(a.$ngfWidth&&a.$ngfHeight){var d=b.defer();return c(function(){d.resolve({width:a.$ngfWidth,height:a.$ngfHeight})}),d.promise}if(a.$ngfDimensionPromise)return a.$ngfDimensionPromise;var e=b.defer();return c(function(){return 0!==a.type.indexOf("image")?void e.reject("not image"):void f.dataUrl(a).then(function(b){function d(){var b=h[0].clientWidth,c=h[0].clientHeight;h.remove(),a.$ngfWidth=b,a.$ngfHeight=c,e.resolve({width:b,height:c})}function f(){h.remove(),e.reject("load error")}function g(){c(function(){h[0].parentNode&&(h[0].clientWidth?d():i>10?f():g())},1e3)}var h=angular.element("").attr("src",b).css("visibility","hidden").css("position","fixed");h.on("load",d),h.on("error",f);var i=0;g(),angular.element(document.getElementsByTagName("body")[0]).append(h)},function(){e.reject("load error")})}),a.$ngfDimensionPromise=e.promise,a.$ngfDimensionPromise["finally"](function(){delete a.$ngfDimensionPromise}),a.$ngfDimensionPromise},f.mediaDuration=function(a){if(a.$ngfDuration){var d=b.defer();return c(function(){d.resolve(a.$ngfDuration)}),d.promise}if(a.$ngfDurationPromise)return a.$ngfDurationPromise;var e=b.defer();return c(function(){return 0!==a.type.indexOf("audio")&&0!==a.type.indexOf("video")?void e.reject("not media"):void f.dataUrl(a).then(function(b){function d(){var b=h[0].duration;a.$ngfDuration=b,h.remove(),e.resolve(b)}function f(){h.remove(),e.reject("load error")}function g(){c(function(){h[0].parentNode&&(h[0].duration?d():i>10?f():g())},1e3)}var h=angular.element(0===a.type.indexOf("audio")?"