From 8e673e3a9d47a5dd5d559308dc5898260bf4fd1a Mon Sep 17 00:00:00 2001 From: Danial Farid Date: Thu, 21 Jan 2016 14:10:45 -0500 Subject: [PATCH] minor fixes --- README.md | 3 +- demo/src/main/webapp/js/FileAPI.min.js | 2 +- demo/src/main/webapp/js/ng-file-upload-all.js | 33 +++++++++++-------- .../main/webapp/js/ng-file-upload-all.min.js | 6 ++-- .../src/main/webapp/js/ng-file-upload-shim.js | 2 +- .../main/webapp/js/ng-file-upload-shim.min.js | 2 +- demo/src/main/webapp/js/ng-file-upload.js | 31 ++++++++++------- demo/src/main/webapp/js/ng-file-upload.min.js | 7 ++-- dist/FileAPI.min.js | 2 +- dist/ng-file-upload-all.js | 33 +++++++++++-------- dist/ng-file-upload-all.min.js | 6 ++-- dist/ng-file-upload-shim.js | 2 +- dist/ng-file-upload-shim.min.js | 2 +- dist/ng-file-upload.js | 31 ++++++++++------- dist/ng-file-upload.min.js | 7 ++-- nuget/Package.nuspec | 2 +- package.json | 2 +- src/exif.js | 23 +++++++------ src/upload.js | 4 +++ 19 files changed, 117 insertions(+), 83 deletions(-) diff --git a/README.md b/README.md index 556b384d..aa39d3af 100644 --- a/README.md +++ b/README.md @@ -420,12 +420,13 @@ On your server you need to keep track of what files are being uploaded and how m Make sure when the file is fully uploaded without any error/abort this endpoint returns zero for the file size if you want to let the user to upload the same file again. Or optionally you could have a restart endpoint to set that back to zero to allow re-uploading the same file. - * Optionally you can specify `resumeChunkSize` to upload the file in chunks to the server. This will allow uploading to GAE or other servers that have + * `resumeChunkSize` optionally you can specify this to upload the file in chunks to the server. This will allow uploading to GAE or other servers that have file size limitation and trying to upload the whole request before passing it for internal processing.
If this option is set the requests will have the following extra fields: `_chunkSize`, `_currentChunkSize`, `_chunkNumber` (zero starting), and `_totalSize` to help the server to write the uploaded chunk to the correct position. Uploading in chunks could slow down the overall upload time specially if the chunk size is too small. + When you provide `resumeChunkSize` option one of the `resumeSizeUrl` or `resumeSize` is mandatory to know how much of the file is uploaded so far. diff --git a/demo/src/main/webapp/js/FileAPI.min.js b/demo/src/main/webapp/js/FileAPI.min.js index df6985af..feea878c 100644 --- a/demo/src/main/webapp/js/FileAPI.min.js +++ b/demo/src/main/webapp/js/FileAPI.min.js @@ -1,4 +1,4 @@ -/*! 11.2.0 */ +/*! 11.2.1 */ /*! 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/demo/src/main/webapp/js/ng-file-upload-all.js b/demo/src/main/webapp/js/ng-file-upload-all.js index 3242f3ee..815c8f82 100644 --- a/demo/src/main/webapp/js/ng-file-upload-all.js +++ b/demo/src/main/webapp/js/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.0 + * @version 11.2.1 */ (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.0 + * @version 11.2.1 */ 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.0'; +ngFileUpload.version = '11.2.1'; ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, $q, $timeout) { var upload = this; @@ -559,6 +559,10 @@ ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, throw e; }); } else { + if (config._chunkSize) { + config._start = 0; + config._end = config._start + config._chunkSize; + } uploadWithAngular(); } @@ -2453,7 +2457,7 @@ ngFileUpload.service('UploadExif', ['UploadResize', '$q', function (UploadResize } } - upload.readOrientation = function(file) { + upload.readOrientation = function (file) { var defer = $q.defer(); var reader = new FileReader(); var slicedFile = file.slice(0, 64 * 1024); @@ -2462,15 +2466,18 @@ ngFileUpload.service('UploadExif', ['UploadResize', '$q', function (UploadResize return defer.reject(e); }; reader.onload = function (e) { + var result = {orientation: 1}; var view = new DataView(this.result); - if (view.getUint16(0, false) !== 0xFFD8) return defer.reject(); + if (view.getUint16(0, false) !== 0xFFD8) return defer.resolve(result); + var length = view.byteLength, offset = 2; while (offset < length) { var marker = view.getUint16(offset, false); offset += 2; if (marker === 0xFFE1) { - if (view.getUint32(offset += 2, false) !== 0x45786966) return defer.reject(); + if (view.getUint32(offset += 2, false) !== 0x45786966) return defer.resolve(result); + var little = view.getUint16(offset += 6, false) === 0x4949; offset += view.getUint32(offset + 4, little); var tags = view.getUint16(offset, little); @@ -2478,29 +2485,29 @@ ngFileUpload.service('UploadExif', ['UploadResize', '$q', function (UploadResize for (var i = 0; i < tags; i++) if (view.getUint16(offset + (i * 12), little) === 0x0112) { var orientation = view.getUint16(offset + (i * 12) + 8, little); - var result = {orientation: orientation}; if (orientation >= 2 && orientation <= 8) { view.setUint16(offset + (i * 12) + 8, 1, little); result.fixedArrayBuffer = e.target.result; } + result.orientation = orientation; return defer.resolve(result); } } else if ((marker & 0xFF00) !== 0xFF00) break; else offset += view.getUint16(offset, false); } - defer.reject(); + return defer.resolve(result); }; return defer.promise; }; - function arrayBufferToBase64( buffer ) { + function arrayBufferToBase64(buffer) { var binary = ''; - var bytes = new Uint8Array( buffer ); + var bytes = new Uint8Array(buffer); var len = bytes.byteLength; for (var i = 0; i < len; i++) { - binary += String.fromCharCode( bytes[ i ] ); + binary += String.fromCharCode(bytes[i]); } - return window.btoa( binary ); + return window.btoa(binary); } upload.applyExifRotation = function (file) { @@ -2545,7 +2552,7 @@ ngFileUpload.service('UploadExif', ['UploadResize', '$q', function (UploadResize return deferred.promise; }; - upload.restoreExif = function(orig, resized) { + upload.restoreExif = function (orig, resized) { var ExifRestorer = {}; ExifRestorer.KEY_STR = 'ABCDEFGHIJKLMNOP' + diff --git a/demo/src/main/webapp/js/ng-file-upload-all.min.js b/demo/src/main/webapp/js/ng-file-upload-all.min.js index f668804f..b48fd433 100644 --- a/demo/src/main/webapp/js/ng-file-upload-all.min.js +++ b/demo/src/main/webapp/js/ng-file-upload-all.min.js @@ -1,3 +1,3 @@ -/*! 11.2.0 */ -!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.upload=function(a,b){function c(a){return null!=a&&(a instanceof window.Blob||a.flashId&&a.name&&a.size)}function h(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 i(b,d,e){if(void 0!==d)if(angular.isDate(d)&&(d=d.toISOString()),angular.isString(d))b.append(e,d);else if(c(d)){var f=h(d,b),g=e.split(",");g[1]&&(f.ngfName=g[1].replace(/^\s+|\s+$/g,""),e=g[0]),a._fileKey=a._fileKey||e,b.append(e,f,f.ngfName||f.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),i(b,d[j],e+k.replace(/[ik]/g,j))}}finally{delete d.$$ngfCircularDetection}}else b.append(e,d)}function j(){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):i(d,e,c)}return d})}return b||(a=e(a)),a._isDigested||(a._isDigested=!0,j()),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.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&&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")?"