{"version":3,"sources":["angular-base64-upload.js"],"names":["window","undefined","_arrayBufferToBase64","buffer","binary","bytes","Uint8Array","len","byteLength","i","String","fromCharCode","btoa","angular","module","directive","$window","$q","isolateScope","onChange","onAfterValidate","parser","FILE_READER_EVENTS","forEach","e","restrict","require","scope","link","elem","attrs","ngModel","_maxnum","val","maxnum","multiple","valid","length","parseInt","$setValidity","_minnum","minnum","_maxsize","maxsize","max","parseFloat","file","filesize","_minsize","min","minsize","_accept","regExp","exp","fileExt","accept","trim","replace","RegExp","filename","split","pop","test","filetype","_setViewValue","newVal","fileObjects","$setViewValue","_attachHandlerForEvent","eventName","handler","fReader","fileObject","rawFiles","_readerOnLoad","promise","target","result","exceedsMaxSize","size","doNotParseIfOversize","base64","when","then","fileObj","push","deferredObj","resolve","onload","_attachEventHandlers","_readFiles","promises","defer","all","reader","FileReader","type","name","readAsArrayBuffer","_onChange","_onAfterValidate","$isEmpty","isArray","_clearInput","value","$watch","$viewValue","$dirty","on","copy","files"],"mappings":"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","file":"angular-base64-upload.min.js","sourcesContent":["(function(window, undefined) {\n\n 'use strict';\n\n /* istanbul ignore next */\n //http://stackoverflow.com/questions/9267899/arraybuffer-to-base64-encoded-string\n window._arrayBufferToBase64 = function(buffer) {\n var binary = '';\n var bytes = new Uint8Array(buffer);\n var len = bytes.byteLength;\n\n for (var i = 0; i < len; i += 1) {\n binary += String.fromCharCode(bytes[i]);\n }\n return window.btoa(binary);\n };\n\n\n var mod = window.angular.module('naif.base64', []);\n\n mod.directive('baseSixtyFourInput', [\n '$window',\n '$q',\n function($window, $q) {\n\n var isolateScope = {\n onChange: '&',\n onAfterValidate: '&',\n parser: '&'\n };\n\n var FILE_READER_EVENTS = ['onabort', 'onerror', 'onloadstart', 'onloadend', 'onprogress', 'onload'];\n\n FILE_READER_EVENTS.forEach(function(e) {\n isolateScope[e] = '&';\n });\n\n return {\n restrict: 'A',\n require: 'ngModel',\n scope: isolateScope,\n link: function(scope, elem, attrs, ngModel) {\n\n var rawFiles = [];\n var fileObjects = [];\n\n /* istanbul ignore if */\n if (!ngModel) {\n return;\n }\n\n // VALIDATIONS =========================================================\n\n function _maxnum(val) {\n if (attrs.maxnum && attrs.multiple && val) {\n var valid = val.length <= parseInt(attrs.maxnum);\n ngModel.$setValidity('maxnum', valid);\n }\n return val;\n }\n\n function _minnum(val) {\n if (attrs.minnum && attrs.multiple && val) {\n var valid = val.length >= parseInt(attrs.minnum);\n ngModel.$setValidity('minnum', valid);\n }\n return val;\n }\n\n function _maxsize(val) {\n var valid = true;\n\n if (attrs.maxsize && val) {\n var max = parseFloat(attrs.maxsize) * 1000;\n\n if (attrs.multiple) {\n for (var i = 0; i < val.length; i++) {\n var file = val[i];\n if (file.filesize > max) {\n valid = false;\n break;\n }\n }\n } else {\n valid = val.filesize <= max;\n }\n ngModel.$setValidity('maxsize', valid);\n }\n\n return val;\n }\n\n function _minsize(val) {\n var valid = true;\n var min = parseFloat(attrs.minsize) * 1000;\n\n if (attrs.minsize && val) {\n if (attrs.multiple) {\n for (var i = 0; i < val.length; i++) {\n var file = val[i];\n if (file.filesize < min) {\n valid = false;\n break;\n }\n }\n } else {\n valid = val.filesize >= min;\n }\n ngModel.$setValidity('minsize', valid);\n }\n\n return val;\n }\n\n function _accept(val) {\n var valid = true;\n var regExp, exp, fileExt;\n if (attrs.accept) {\n exp = attrs.accept.trim().replace(/[,\\s]+/gi, \"|\").replace(/\\./g, \"\\\\.\").replace(/\\/\\*/g, \"/.*\");\n regExp = new RegExp(exp);\n }\n\n if (attrs.accept && val) {\n if (attrs.multiple) {\n for (var i = 0; i < val.length; i++) {\n var file = val[i];\n fileExt = \".\" + file.filename.split('.').pop();\n valid = regExp.test(file.filetype) || regExp.test(fileExt);\n\n if (!valid) {\n break;\n }\n }\n } else {\n fileExt = \".\" + val.filename.split('.').pop();\n valid = regExp.test(val.filetype) || regExp.test(fileExt);\n }\n ngModel.$setValidity('accept', valid);\n }\n\n return val;\n }\n\n //end validations ===============\n\n function _setViewValue() {\n var newVal = attrs.multiple ? fileObjects : fileObjects[0];\n ngModel.$setViewValue(newVal);\n _maxsize(newVal);\n _minsize(newVal);\n _maxnum(newVal);\n _minnum(newVal);\n _accept(newVal);\n }\n\n function _attachHandlerForEvent(eventName, handler, fReader, file, fileObject) {\n fReader[eventName] = function(e) {\n handler()(e, fReader, file, rawFiles, fileObjects, fileObject);\n };\n }\n\n function _readerOnLoad(fReader, file, fileObject) {\n\n return function(e) {\n\n var buffer = e.target.result;\n var promise;\n\n // do not convert the image to base64 if it exceeds the maximum\n // size to prevent the browser from freezing\n var exceedsMaxSize = attrs.maxsize && file.size > attrs.maxsize * 1024;\n if (attrs.doNotParseIfOversize !== undefined && exceedsMaxSize) {\n fileObject.base64 = null;\n } else {\n fileObject.base64 = $window._arrayBufferToBase64(buffer);\n }\n\n if (attrs.parser) {\n promise = $q.when(scope.parser()(file, fileObject));\n } else {\n promise = $q.when(fileObject);\n }\n\n promise.then(function(fileObj) {\n fileObjects.push(fileObj);\n // fulfill the promise here.\n file.deferredObj.resolve();\n });\n\n if (attrs.onload) {\n if (scope.onload && typeof scope.onload() === \"function\") {\n scope.onload()(e, fReader, file, rawFiles, fileObjects, fileObject);\n } else {\n scope.onload(e, rawFiles);\n }\n }\n\n };\n\n }\n\n function _attachEventHandlers(fReader, file, fileObject) {\n\n for (var i = FILE_READER_EVENTS.length - 1; i >= 0; i--) {\n var e = FILE_READER_EVENTS[i];\n if (attrs[e] && e !== 'onload') { // don't attach handler to onload yet\n _attachHandlerForEvent(e, scope[e], fReader, file, fileObject);\n }\n }\n\n fReader.onload = _readerOnLoad(fReader, file, fileObject);\n }\n\n function _readFiles() {\n var promises = [];\n var i;\n for (i = rawFiles.length - 1; i >= 0; i--) {\n // append file a new promise, that waits until resolved\n rawFiles[i].deferredObj = $q.defer();\n promises.push(rawFiles[i].deferredObj.promise);\n // TODO: Make sure all promises are resolved even during file reader error, otherwise view value wont be updated\n }\n\n // set view value once all files are read\n $q.all(promises).then(_setViewValue);\n\n for (i = rawFiles.length - 1; i >= 0; i--) {\n var reader = new $window.FileReader();\n var file = rawFiles[i];\n var fileObject = {};\n\n fileObject.filetype = file.type;\n fileObject.filename = file.name;\n fileObject.filesize = file.size;\n\n _attachEventHandlers(reader, file, fileObject);\n reader.readAsArrayBuffer(file);\n }\n }\n\n function _onChange(e) {\n if (attrs.onChange) {\n if (scope.onChange && typeof scope.onChange() === \"function\") {\n scope.onChange()(e, rawFiles);\n } else {\n scope.onChange(e, rawFiles);\n }\n }\n }\n\n function _onAfterValidate(e) {\n if (attrs.onAfterValidate) {\n // wait for all promises, in rawFiles,\n // then call onAfterValidate\n var promises = [];\n for (var i = rawFiles.length - 1; i >= 0; i--) {\n promises.push(rawFiles[i].deferredObj.promise);\n }\n $q.all(promises).then(function() {\n if (scope.onAfterValidate && typeof scope.onAfterValidate() === \"function\") {\n scope.onAfterValidate()(e, fileObjects, rawFiles);\n } else {\n scope.onAfterValidate(e, fileObjects, rawFiles);\n }\n });\n }\n }\n\n ngModel.$isEmpty = function(val) {\n return !val || (angular.isArray(val) ? val.length === 0 : !val.base64);\n };\n\n // http://stackoverflow.com/questions/1703228/how-can-i-clear-an-html-file-input-with-javascript\n scope._clearInput = function() {\n elem[0].value = '';\n };\n\n scope.$watch(function() {\n return ngModel.$viewValue;\n }, function(val) {\n if (ngModel.$isEmpty(val) && ngModel.$dirty) {\n scope._clearInput();\n // Remove validation errors\n ngModel.$setValidity('maxnum', true);\n ngModel.$setValidity('minnum', true);\n ngModel.$setValidity('maxsize', true);\n ngModel.$setValidity('minsize', true);\n ngModel.$setValidity('accept', true);\n }\n });\n\n elem.on('change', function(e) {\n\n fileObjects = [];\n fileObjects = angular.copy(fileObjects);\n\n if (e.target.files.length === 0) {\n rawFiles = [];\n _setViewValue();\n } else {\n rawFiles = e.target.files; // use event target so we can mock the files from test\n _readFiles();\n _onChange(e);\n _onAfterValidate(e);\n }\n\n scope._clearInput();\n\n });\n\n }\n };\n\n }\n ]);\n\n})(window);\n"]}