@@ 824-1116 (lines=293) @@ | ||
821 | ||
822 | ]); |
|
823 | ||
824 | ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadExif', function ($parse, $timeout, $compile, $q, UploadExif) { |
|
825 | var upload = UploadExif; |
|
826 | upload.getAttrWithDefaults = function (attr, name) { |
|
827 | if (attr[name] != null) return attr[name]; |
|
828 | var def = upload.defaults[name]; |
|
829 | return (def == null ? def : (angular.isString(def) ? def : JSON.stringify(def))); |
|
830 | }; |
|
831 | ||
832 | upload.attrGetter = function (name, attr, scope, params) { |
|
833 | var attrVal = this.getAttrWithDefaults(attr, name); |
|
834 | if (scope) { |
|
835 | try { |
|
836 | if (params) { |
|
837 | return $parse(attrVal)(scope, params); |
|
838 | } else { |
|
839 | return $parse(attrVal)(scope); |
|
840 | } |
|
841 | } catch (e) { |
|
842 | // hangle string value without single qoute |
|
843 | if (name.search(/min|max|pattern/i)) { |
|
844 | return attrVal; |
|
845 | } else { |
|
846 | throw e; |
|
847 | } |
|
848 | } |
|
849 | } else { |
|
850 | return attrVal; |
|
851 | } |
|
852 | }; |
|
853 | ||
854 | upload.shouldUpdateOn = function (type, attr, scope) { |
|
855 | var modelOptions = upload.attrGetter('ngfModelOptions', attr, scope); |
|
856 | if (modelOptions && modelOptions.updateOn) { |
|
857 | return modelOptions.updateOn.split(' ').indexOf(type) > -1; |
|
858 | } |
|
859 | return true; |
|
860 | }; |
|
861 | ||
862 | upload.emptyPromise = function () { |
|
863 | var d = $q.defer(); |
|
864 | var args = arguments; |
|
865 | $timeout(function () { |
|
866 | d.resolve.apply(d, args); |
|
867 | }); |
|
868 | return d.promise; |
|
869 | }; |
|
870 | ||
871 | upload.rejectPromise = function () { |
|
872 | var d = $q.defer(); |
|
873 | var args = arguments; |
|
874 | $timeout(function () { |
|
875 | d.reject.apply(d, args); |
|
876 | }); |
|
877 | return d.promise; |
|
878 | }; |
|
879 | ||
880 | upload.happyPromise = function (promise, data) { |
|
881 | var d = $q.defer(); |
|
882 | promise.then(function (result) { |
|
883 | d.resolve(result); |
|
884 | }, function (error) { |
|
885 | $timeout(function () { |
|
886 | throw error; |
|
887 | }); |
|
888 | d.resolve(data); |
|
889 | }); |
|
890 | return d.promise; |
|
891 | }; |
|
892 | ||
893 | function applyExifRotations(files, attr, scope) { |
|
894 | var promises = [upload.emptyPromise()]; |
|
895 | angular.forEach(files, function (f, i) { |
|
896 | if (f.type.indexOf('image/jpeg') === 0 && upload.attrGetter('ngfFixOrientation', attr, scope, {$file: f})) { |
|
897 | promises.push(upload.happyPromise(upload.applyExifRotation(f), f).then(function (fixedFile) { |
|
898 | files.splice(i, 1, fixedFile); |
|
899 | })); |
|
900 | } |
|
901 | }); |
|
902 | return $q.all(promises); |
|
903 | } |
|
904 | ||
905 | function resizeFile(files, attr, scope, ngModel) { |
|
906 | var resizeVal = upload.attrGetter('ngfResize', attr, scope); |
|
907 | if (!resizeVal || !upload.isResizeSupported() || !files.length) return upload.emptyPromise(); |
|
908 | if (resizeVal instanceof Function) { |
|
909 | var defer = $q.defer(); |
|
910 | return resizeVal(files).then(function (p) { |
|
911 | resizeWithParams(p, files, attr, scope, ngModel).then(function (r) { |
|
912 | defer.resolve(r); |
|
913 | }, function (e) { |
|
914 | defer.reject(e); |
|
915 | }); |
|
916 | }, function (e) { |
|
917 | defer.reject(e); |
|
918 | }); |
|
919 | } else { |
|
920 | return resizeWithParams(resizeVal, files, attr, scope, ngModel); |
|
921 | } |
|
922 | } |
|
923 | ||
924 | function resizeWithParams(params, files, attr, scope, ngModel) { |
|
925 | var promises = [upload.emptyPromise()]; |
|
926 | ||
927 | function handleFile(f, i) { |
|
928 | if (f.type.indexOf('image') === 0) { |
|
929 | if (params.pattern && !upload.validatePattern(f, params.pattern)) return; |
|
930 | params.resizeIf = function (width, height) { |
|
931 | return upload.attrGetter('ngfResizeIf', attr, scope, |
|
932 | {$width: width, $height: height, $file: f}); |
|
933 | }; |
|
934 | var promise = upload.resize(f, params); |
|
935 | promises.push(promise); |
|
936 | promise.then(function (resizedFile) { |
|
937 | files.splice(i, 1, resizedFile); |
|
938 | }, function (e) { |
|
939 | f.$error = 'resize'; |
|
940 | (f.$errorMessages = (f.$errorMessages || {})).resize = true; |
|
941 | f.$errorParam = (e ? (e.message ? e.message : e) + ': ' : '') + (f && f.name); |
|
942 | ngModel.$ngfValidations.push({name: 'resize', valid: false}); |
|
943 | upload.applyModelValidation(ngModel, files); |
|
944 | }); |
|
945 | } |
|
946 | } |
|
947 | ||
948 | for (var i = 0; i < files.length; i++) { |
|
949 | handleFile(files[i], i); |
|
950 | } |
|
951 | return $q.all(promises); |
|
952 | } |
|
953 | ||
954 | upload.updateModel = function (ngModel, attr, scope, fileChange, files, evt, noDelay) { |
|
955 | function update(files, invalidFiles, newFiles, dupFiles, isSingleModel) { |
|
956 | attr.$$ngfPrevValidFiles = files; |
|
957 | attr.$$ngfPrevInvalidFiles = invalidFiles; |
|
958 | var file = files && files.length ? files[0] : null; |
|
959 | var invalidFile = invalidFiles && invalidFiles.length ? invalidFiles[0] : null; |
|
960 | ||
961 | if (ngModel) { |
|
962 | upload.applyModelValidation(ngModel, files); |
|
963 | ngModel.$setViewValue(isSingleModel ? file : files); |
|
964 | } |
|
965 | ||
966 | if (fileChange) { |
|
967 | $parse(fileChange)(scope, { |
|
968 | $files: files, |
|
969 | $file: file, |
|
970 | $newFiles: newFiles, |
|
971 | $duplicateFiles: dupFiles, |
|
972 | $invalidFiles: invalidFiles, |
|
973 | $invalidFile: invalidFile, |
|
974 | $event: evt |
|
975 | }); |
|
976 | } |
|
977 | ||
978 | var invalidModel = upload.attrGetter('ngfModelInvalid', attr); |
|
979 | if (invalidModel) { |
|
980 | $timeout(function () { |
|
981 | $parse(invalidModel).assign(scope, isSingleModel ? invalidFile : invalidFiles); |
|
982 | }); |
|
983 | } |
|
984 | $timeout(function () { |
|
985 | // scope apply changes |
|
986 | }); |
|
987 | } |
|
988 | ||
989 | var allNewFiles, dupFiles = [], prevValidFiles, prevInvalidFiles, |
|
990 | invalids = [], valids = []; |
|
991 | ||
992 | function removeDuplicates() { |
|
993 | function equals(f1, f2) { |
|
994 | return f1.name === f2.name && (f1.$ngfOrigSize || f1.size) === (f2.$ngfOrigSize || f2.size) && |
|
995 | f1.type === f2.type; |
|
996 | } |
|
997 | ||
998 | function isInPrevFiles(f) { |
|
999 | var j; |
|
1000 | for (j = 0; j < prevValidFiles.length; j++) { |
|
1001 | if (equals(f, prevValidFiles[j])) { |
|
1002 | return true; |
|
1003 | } |
|
1004 | } |
|
1005 | for (j = 0; j < prevInvalidFiles.length; j++) { |
|
1006 | if (equals(f, prevInvalidFiles[j])) { |
|
1007 | return true; |
|
1008 | } |
|
1009 | } |
|
1010 | return false; |
|
1011 | } |
|
1012 | ||
1013 | if (files) { |
|
1014 | allNewFiles = []; |
|
1015 | dupFiles = []; |
|
1016 | for (var i = 0; i < files.length; i++) { |
|
1017 | if (isInPrevFiles(files[i])) { |
|
1018 | dupFiles.push(files[i]); |
|
1019 | } else { |
|
1020 | allNewFiles.push(files[i]); |
|
1021 | } |
|
1022 | } |
|
1023 | } |
|
1024 | } |
|
1025 | ||
1026 | function toArray(v) { |
|
1027 | return angular.isArray(v) ? v : [v]; |
|
1028 | } |
|
1029 | ||
1030 | function resizeAndUpdate() { |
|
1031 | function updateModel() { |
|
1032 | $timeout(function () { |
|
1033 | update(keep ? prevValidFiles.concat(valids) : valids, |
|
1034 | keep ? prevInvalidFiles.concat(invalids) : invalids, |
|
1035 | files, dupFiles, isSingleModel); |
|
1036 | }, options && options.debounce ? options.debounce.change || options.debounce : 0); |
|
1037 | } |
|
1038 | ||
1039 | var resizingFiles = validateAfterResize ? allNewFiles : valids; |
|
1040 | resizeFile(resizingFiles, attr, scope, ngModel).then(function () { |
|
1041 | if (validateAfterResize) { |
|
1042 | upload.validate(allNewFiles, keep ? prevValidFiles.length : 0, ngModel, attr, scope) |
|
1043 | .then(function (validationResult) { |
|
1044 | valids = validationResult.validsFiles; |
|
1045 | invalids = validationResult.invalidsFiles; |
|
1046 | updateModel(); |
|
1047 | }); |
|
1048 | } else { |
|
1049 | updateModel(); |
|
1050 | } |
|
1051 | }, function () { |
|
1052 | for (var i = 0; i < resizingFiles.length; i++) { |
|
1053 | var f = resizingFiles[i]; |
|
1054 | if (f.$error === 'resize') { |
|
1055 | var index = valids.indexOf(f); |
|
1056 | if (index > -1) { |
|
1057 | valids.splice(index, 1); |
|
1058 | invalids.push(f); |
|
1059 | } |
|
1060 | updateModel(); |
|
1061 | } |
|
1062 | } |
|
1063 | }); |
|
1064 | } |
|
1065 | ||
1066 | prevValidFiles = attr.$$ngfPrevValidFiles || []; |
|
1067 | prevInvalidFiles = attr.$$ngfPrevInvalidFiles || []; |
|
1068 | if (ngModel && ngModel.$modelValue) { |
|
1069 | prevValidFiles = toArray(ngModel.$modelValue); |
|
1070 | } |
|
1071 | ||
1072 | var keep = upload.attrGetter('ngfKeep', attr, scope); |
|
1073 | allNewFiles = (files || []).slice(0); |
|
1074 | if (keep === 'distinct' || upload.attrGetter('ngfKeepDistinct', attr, scope) === true) { |
|
1075 | removeDuplicates(attr, scope); |
|
1076 | } |
|
1077 | ||
1078 | var isSingleModel = !keep && !upload.attrGetter('ngfMultiple', attr, scope) && !upload.attrGetter('multiple', attr); |
|
1079 | ||
1080 | if (keep && !allNewFiles.length) return; |
|
1081 | ||
1082 | upload.attrGetter('ngfBeforeModelChange', attr, scope, { |
|
1083 | $files: files, |
|
1084 | $file: files && files.length ? files[0] : null, |
|
1085 | $newFiles: allNewFiles, |
|
1086 | $duplicateFiles: dupFiles, |
|
1087 | $event: evt |
|
1088 | }); |
|
1089 | ||
1090 | var validateAfterResize = upload.attrGetter('ngfValidateAfterResize', attr, scope); |
|
1091 | ||
1092 | var options = upload.attrGetter('ngfModelOptions', attr, scope); |
|
1093 | upload.validate(allNewFiles, keep ? prevValidFiles.length : 0, ngModel, attr, scope) |
|
1094 | .then(function (validationResult) { |
|
1095 | if (noDelay) { |
|
1096 | update(allNewFiles, [], files, dupFiles, isSingleModel); |
|
1097 | } else { |
|
1098 | if ((!options || !options.allowInvalid) && !validateAfterResize) { |
|
1099 | valids = validationResult.validFiles; |
|
1100 | invalids = validationResult.invalidFiles; |
|
1101 | } else { |
|
1102 | valids = allNewFiles; |
|
1103 | } |
|
1104 | if (upload.attrGetter('ngfFixOrientation', attr, scope) && upload.isExifSupported()) { |
|
1105 | applyExifRotations(valids, attr, scope).then(function () { |
|
1106 | resizeAndUpdate(); |
|
1107 | }); |
|
1108 | } else { |
|
1109 | resizeAndUpdate(); |
|
1110 | } |
|
1111 | } |
|
1112 | }); |
|
1113 | }; |
|
1114 | ||
1115 | return upload; |
|
1116 | }]); |
|
1117 | ||
1118 | ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', function ($parse, $timeout, $compile, Upload) { |
|
1119 | var generatedElems = []; |
@@ 402-694 (lines=293) @@ | ||
399 | ||
400 | ]); |
|
401 | ||
402 | ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadExif', function ($parse, $timeout, $compile, $q, UploadExif) { |
|
403 | var upload = UploadExif; |
|
404 | upload.getAttrWithDefaults = function (attr, name) { |
|
405 | if (attr[name] != null) return attr[name]; |
|
406 | var def = upload.defaults[name]; |
|
407 | return (def == null ? def : (angular.isString(def) ? def : JSON.stringify(def))); |
|
408 | }; |
|
409 | ||
410 | upload.attrGetter = function (name, attr, scope, params) { |
|
411 | var attrVal = this.getAttrWithDefaults(attr, name); |
|
412 | if (scope) { |
|
413 | try { |
|
414 | if (params) { |
|
415 | return $parse(attrVal)(scope, params); |
|
416 | } else { |
|
417 | return $parse(attrVal)(scope); |
|
418 | } |
|
419 | } catch (e) { |
|
420 | // hangle string value without single qoute |
|
421 | if (name.search(/min|max|pattern/i)) { |
|
422 | return attrVal; |
|
423 | } else { |
|
424 | throw e; |
|
425 | } |
|
426 | } |
|
427 | } else { |
|
428 | return attrVal; |
|
429 | } |
|
430 | }; |
|
431 | ||
432 | upload.shouldUpdateOn = function (type, attr, scope) { |
|
433 | var modelOptions = upload.attrGetter('ngfModelOptions', attr, scope); |
|
434 | if (modelOptions && modelOptions.updateOn) { |
|
435 | return modelOptions.updateOn.split(' ').indexOf(type) > -1; |
|
436 | } |
|
437 | return true; |
|
438 | }; |
|
439 | ||
440 | upload.emptyPromise = function () { |
|
441 | var d = $q.defer(); |
|
442 | var args = arguments; |
|
443 | $timeout(function () { |
|
444 | d.resolve.apply(d, args); |
|
445 | }); |
|
446 | return d.promise; |
|
447 | }; |
|
448 | ||
449 | upload.rejectPromise = function () { |
|
450 | var d = $q.defer(); |
|
451 | var args = arguments; |
|
452 | $timeout(function () { |
|
453 | d.reject.apply(d, args); |
|
454 | }); |
|
455 | return d.promise; |
|
456 | }; |
|
457 | ||
458 | upload.happyPromise = function (promise, data) { |
|
459 | var d = $q.defer(); |
|
460 | promise.then(function (result) { |
|
461 | d.resolve(result); |
|
462 | }, function (error) { |
|
463 | $timeout(function () { |
|
464 | throw error; |
|
465 | }); |
|
466 | d.resolve(data); |
|
467 | }); |
|
468 | return d.promise; |
|
469 | }; |
|
470 | ||
471 | function applyExifRotations(files, attr, scope) { |
|
472 | var promises = [upload.emptyPromise()]; |
|
473 | angular.forEach(files, function (f, i) { |
|
474 | if (f.type.indexOf('image/jpeg') === 0 && upload.attrGetter('ngfFixOrientation', attr, scope, {$file: f})) { |
|
475 | promises.push(upload.happyPromise(upload.applyExifRotation(f), f).then(function (fixedFile) { |
|
476 | files.splice(i, 1, fixedFile); |
|
477 | })); |
|
478 | } |
|
479 | }); |
|
480 | return $q.all(promises); |
|
481 | } |
|
482 | ||
483 | function resizeFile(files, attr, scope, ngModel) { |
|
484 | var resizeVal = upload.attrGetter('ngfResize', attr, scope); |
|
485 | if (!resizeVal || !upload.isResizeSupported() || !files.length) return upload.emptyPromise(); |
|
486 | if (resizeVal instanceof Function) { |
|
487 | var defer = $q.defer(); |
|
488 | return resizeVal(files).then(function (p) { |
|
489 | resizeWithParams(p, files, attr, scope, ngModel).then(function (r) { |
|
490 | defer.resolve(r); |
|
491 | }, function (e) { |
|
492 | defer.reject(e); |
|
493 | }); |
|
494 | }, function (e) { |
|
495 | defer.reject(e); |
|
496 | }); |
|
497 | } else { |
|
498 | return resizeWithParams(resizeVal, files, attr, scope, ngModel); |
|
499 | } |
|
500 | } |
|
501 | ||
502 | function resizeWithParams(params, files, attr, scope, ngModel) { |
|
503 | var promises = [upload.emptyPromise()]; |
|
504 | ||
505 | function handleFile(f, i) { |
|
506 | if (f.type.indexOf('image') === 0) { |
|
507 | if (params.pattern && !upload.validatePattern(f, params.pattern)) return; |
|
508 | params.resizeIf = function (width, height) { |
|
509 | return upload.attrGetter('ngfResizeIf', attr, scope, |
|
510 | {$width: width, $height: height, $file: f}); |
|
511 | }; |
|
512 | var promise = upload.resize(f, params); |
|
513 | promises.push(promise); |
|
514 | promise.then(function (resizedFile) { |
|
515 | files.splice(i, 1, resizedFile); |
|
516 | }, function (e) { |
|
517 | f.$error = 'resize'; |
|
518 | (f.$errorMessages = (f.$errorMessages || {})).resize = true; |
|
519 | f.$errorParam = (e ? (e.message ? e.message : e) + ': ' : '') + (f && f.name); |
|
520 | ngModel.$ngfValidations.push({name: 'resize', valid: false}); |
|
521 | upload.applyModelValidation(ngModel, files); |
|
522 | }); |
|
523 | } |
|
524 | } |
|
525 | ||
526 | for (var i = 0; i < files.length; i++) { |
|
527 | handleFile(files[i], i); |
|
528 | } |
|
529 | return $q.all(promises); |
|
530 | } |
|
531 | ||
532 | upload.updateModel = function (ngModel, attr, scope, fileChange, files, evt, noDelay) { |
|
533 | function update(files, invalidFiles, newFiles, dupFiles, isSingleModel) { |
|
534 | attr.$$ngfPrevValidFiles = files; |
|
535 | attr.$$ngfPrevInvalidFiles = invalidFiles; |
|
536 | var file = files && files.length ? files[0] : null; |
|
537 | var invalidFile = invalidFiles && invalidFiles.length ? invalidFiles[0] : null; |
|
538 | ||
539 | if (ngModel) { |
|
540 | upload.applyModelValidation(ngModel, files); |
|
541 | ngModel.$setViewValue(isSingleModel ? file : files); |
|
542 | } |
|
543 | ||
544 | if (fileChange) { |
|
545 | $parse(fileChange)(scope, { |
|
546 | $files: files, |
|
547 | $file: file, |
|
548 | $newFiles: newFiles, |
|
549 | $duplicateFiles: dupFiles, |
|
550 | $invalidFiles: invalidFiles, |
|
551 | $invalidFile: invalidFile, |
|
552 | $event: evt |
|
553 | }); |
|
554 | } |
|
555 | ||
556 | var invalidModel = upload.attrGetter('ngfModelInvalid', attr); |
|
557 | if (invalidModel) { |
|
558 | $timeout(function () { |
|
559 | $parse(invalidModel).assign(scope, isSingleModel ? invalidFile : invalidFiles); |
|
560 | }); |
|
561 | } |
|
562 | $timeout(function () { |
|
563 | // scope apply changes |
|
564 | }); |
|
565 | } |
|
566 | ||
567 | var allNewFiles, dupFiles = [], prevValidFiles, prevInvalidFiles, |
|
568 | invalids = [], valids = []; |
|
569 | ||
570 | function removeDuplicates() { |
|
571 | function equals(f1, f2) { |
|
572 | return f1.name === f2.name && (f1.$ngfOrigSize || f1.size) === (f2.$ngfOrigSize || f2.size) && |
|
573 | f1.type === f2.type; |
|
574 | } |
|
575 | ||
576 | function isInPrevFiles(f) { |
|
577 | var j; |
|
578 | for (j = 0; j < prevValidFiles.length; j++) { |
|
579 | if (equals(f, prevValidFiles[j])) { |
|
580 | return true; |
|
581 | } |
|
582 | } |
|
583 | for (j = 0; j < prevInvalidFiles.length; j++) { |
|
584 | if (equals(f, prevInvalidFiles[j])) { |
|
585 | return true; |
|
586 | } |
|
587 | } |
|
588 | return false; |
|
589 | } |
|
590 | ||
591 | if (files) { |
|
592 | allNewFiles = []; |
|
593 | dupFiles = []; |
|
594 | for (var i = 0; i < files.length; i++) { |
|
595 | if (isInPrevFiles(files[i])) { |
|
596 | dupFiles.push(files[i]); |
|
597 | } else { |
|
598 | allNewFiles.push(files[i]); |
|
599 | } |
|
600 | } |
|
601 | } |
|
602 | } |
|
603 | ||
604 | function toArray(v) { |
|
605 | return angular.isArray(v) ? v : [v]; |
|
606 | } |
|
607 | ||
608 | function resizeAndUpdate() { |
|
609 | function updateModel() { |
|
610 | $timeout(function () { |
|
611 | update(keep ? prevValidFiles.concat(valids) : valids, |
|
612 | keep ? prevInvalidFiles.concat(invalids) : invalids, |
|
613 | files, dupFiles, isSingleModel); |
|
614 | }, options && options.debounce ? options.debounce.change || options.debounce : 0); |
|
615 | } |
|
616 | ||
617 | var resizingFiles = validateAfterResize ? allNewFiles : valids; |
|
618 | resizeFile(resizingFiles, attr, scope, ngModel).then(function () { |
|
619 | if (validateAfterResize) { |
|
620 | upload.validate(allNewFiles, keep ? prevValidFiles.length : 0, ngModel, attr, scope) |
|
621 | .then(function (validationResult) { |
|
622 | valids = validationResult.validsFiles; |
|
623 | invalids = validationResult.invalidsFiles; |
|
624 | updateModel(); |
|
625 | }); |
|
626 | } else { |
|
627 | updateModel(); |
|
628 | } |
|
629 | }, function () { |
|
630 | for (var i = 0; i < resizingFiles.length; i++) { |
|
631 | var f = resizingFiles[i]; |
|
632 | if (f.$error === 'resize') { |
|
633 | var index = valids.indexOf(f); |
|
634 | if (index > -1) { |
|
635 | valids.splice(index, 1); |
|
636 | invalids.push(f); |
|
637 | } |
|
638 | updateModel(); |
|
639 | } |
|
640 | } |
|
641 | }); |
|
642 | } |
|
643 | ||
644 | prevValidFiles = attr.$$ngfPrevValidFiles || []; |
|
645 | prevInvalidFiles = attr.$$ngfPrevInvalidFiles || []; |
|
646 | if (ngModel && ngModel.$modelValue) { |
|
647 | prevValidFiles = toArray(ngModel.$modelValue); |
|
648 | } |
|
649 | ||
650 | var keep = upload.attrGetter('ngfKeep', attr, scope); |
|
651 | allNewFiles = (files || []).slice(0); |
|
652 | if (keep === 'distinct' || upload.attrGetter('ngfKeepDistinct', attr, scope) === true) { |
|
653 | removeDuplicates(attr, scope); |
|
654 | } |
|
655 | ||
656 | var isSingleModel = !keep && !upload.attrGetter('ngfMultiple', attr, scope) && !upload.attrGetter('multiple', attr); |
|
657 | ||
658 | if (keep && !allNewFiles.length) return; |
|
659 | ||
660 | upload.attrGetter('ngfBeforeModelChange', attr, scope, { |
|
661 | $files: files, |
|
662 | $file: files && files.length ? files[0] : null, |
|
663 | $newFiles: allNewFiles, |
|
664 | $duplicateFiles: dupFiles, |
|
665 | $event: evt |
|
666 | }); |
|
667 | ||
668 | var validateAfterResize = upload.attrGetter('ngfValidateAfterResize', attr, scope); |
|
669 | ||
670 | var options = upload.attrGetter('ngfModelOptions', attr, scope); |
|
671 | upload.validate(allNewFiles, keep ? prevValidFiles.length : 0, ngModel, attr, scope) |
|
672 | .then(function (validationResult) { |
|
673 | if (noDelay) { |
|
674 | update(allNewFiles, [], files, dupFiles, isSingleModel); |
|
675 | } else { |
|
676 | if ((!options || !options.allowInvalid) && !validateAfterResize) { |
|
677 | valids = validationResult.validFiles; |
|
678 | invalids = validationResult.invalidFiles; |
|
679 | } else { |
|
680 | valids = allNewFiles; |
|
681 | } |
|
682 | if (upload.attrGetter('ngfFixOrientation', attr, scope) && upload.isExifSupported()) { |
|
683 | applyExifRotations(valids, attr, scope).then(function () { |
|
684 | resizeAndUpdate(); |
|
685 | }); |
|
686 | } else { |
|
687 | resizeAndUpdate(); |
|
688 | } |
|
689 | } |
|
690 | }); |
|
691 | }; |
|
692 | ||
693 | return upload; |
|
694 | }]); |
|
695 | ||
696 | ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', function ($parse, $timeout, $compile, Upload) { |
|
697 | var generatedElems = []; |
@@ 1-293 (lines=293) @@ | ||
1 | ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadExif', function ($parse, $timeout, $compile, $q, UploadExif) { |
|
2 | var upload = UploadExif; |
|
3 | upload.getAttrWithDefaults = function (attr, name) { |
|
4 | if (attr[name] != null) return attr[name]; |
|
5 | var def = upload.defaults[name]; |
|
6 | return (def == null ? def : (angular.isString(def) ? def : JSON.stringify(def))); |
|
7 | }; |
|
8 | ||
9 | upload.attrGetter = function (name, attr, scope, params) { |
|
10 | var attrVal = this.getAttrWithDefaults(attr, name); |
|
11 | if (scope) { |
|
12 | try { |
|
13 | if (params) { |
|
14 | return $parse(attrVal)(scope, params); |
|
15 | } else { |
|
16 | return $parse(attrVal)(scope); |
|
17 | } |
|
18 | } catch (e) { |
|
19 | // hangle string value without single qoute |
|
20 | if (name.search(/min|max|pattern/i)) { |
|
21 | return attrVal; |
|
22 | } else { |
|
23 | throw e; |
|
24 | } |
|
25 | } |
|
26 | } else { |
|
27 | return attrVal; |
|
28 | } |
|
29 | }; |
|
30 | ||
31 | upload.shouldUpdateOn = function (type, attr, scope) { |
|
32 | var modelOptions = upload.attrGetter('ngfModelOptions', attr, scope); |
|
33 | if (modelOptions && modelOptions.updateOn) { |
|
34 | return modelOptions.updateOn.split(' ').indexOf(type) > -1; |
|
35 | } |
|
36 | return true; |
|
37 | }; |
|
38 | ||
39 | upload.emptyPromise = function () { |
|
40 | var d = $q.defer(); |
|
41 | var args = arguments; |
|
42 | $timeout(function () { |
|
43 | d.resolve.apply(d, args); |
|
44 | }); |
|
45 | return d.promise; |
|
46 | }; |
|
47 | ||
48 | upload.rejectPromise = function () { |
|
49 | var d = $q.defer(); |
|
50 | var args = arguments; |
|
51 | $timeout(function () { |
|
52 | d.reject.apply(d, args); |
|
53 | }); |
|
54 | return d.promise; |
|
55 | }; |
|
56 | ||
57 | upload.happyPromise = function (promise, data) { |
|
58 | var d = $q.defer(); |
|
59 | promise.then(function (result) { |
|
60 | d.resolve(result); |
|
61 | }, function (error) { |
|
62 | $timeout(function () { |
|
63 | throw error; |
|
64 | }); |
|
65 | d.resolve(data); |
|
66 | }); |
|
67 | return d.promise; |
|
68 | }; |
|
69 | ||
70 | function applyExifRotations(files, attr, scope) { |
|
71 | var promises = [upload.emptyPromise()]; |
|
72 | angular.forEach(files, function (f, i) { |
|
73 | if (f.type.indexOf('image/jpeg') === 0 && upload.attrGetter('ngfFixOrientation', attr, scope, {$file: f})) { |
|
74 | promises.push(upload.happyPromise(upload.applyExifRotation(f), f).then(function (fixedFile) { |
|
75 | files.splice(i, 1, fixedFile); |
|
76 | })); |
|
77 | } |
|
78 | }); |
|
79 | return $q.all(promises); |
|
80 | } |
|
81 | ||
82 | function resizeFile(files, attr, scope, ngModel) { |
|
83 | var resizeVal = upload.attrGetter('ngfResize', attr, scope); |
|
84 | if (!resizeVal || !upload.isResizeSupported() || !files.length) return upload.emptyPromise(); |
|
85 | if (resizeVal instanceof Function) { |
|
86 | var defer = $q.defer(); |
|
87 | return resizeVal(files).then(function (p) { |
|
88 | resizeWithParams(p, files, attr, scope, ngModel).then(function (r) { |
|
89 | defer.resolve(r); |
|
90 | }, function (e) { |
|
91 | defer.reject(e); |
|
92 | }); |
|
93 | }, function (e) { |
|
94 | defer.reject(e); |
|
95 | }); |
|
96 | } else { |
|
97 | return resizeWithParams(resizeVal, files, attr, scope, ngModel); |
|
98 | } |
|
99 | } |
|
100 | ||
101 | function resizeWithParams(params, files, attr, scope, ngModel) { |
|
102 | var promises = [upload.emptyPromise()]; |
|
103 | ||
104 | function handleFile(f, i) { |
|
105 | if (f.type.indexOf('image') === 0) { |
|
106 | if (params.pattern && !upload.validatePattern(f, params.pattern)) return; |
|
107 | params.resizeIf = function (width, height) { |
|
108 | return upload.attrGetter('ngfResizeIf', attr, scope, |
|
109 | {$width: width, $height: height, $file: f}); |
|
110 | }; |
|
111 | var promise = upload.resize(f, params); |
|
112 | promises.push(promise); |
|
113 | promise.then(function (resizedFile) { |
|
114 | files.splice(i, 1, resizedFile); |
|
115 | }, function (e) { |
|
116 | f.$error = 'resize'; |
|
117 | (f.$errorMessages = (f.$errorMessages || {})).resize = true; |
|
118 | f.$errorParam = (e ? (e.message ? e.message : e) + ': ' : '') + (f && f.name); |
|
119 | ngModel.$ngfValidations.push({name: 'resize', valid: false}); |
|
120 | upload.applyModelValidation(ngModel, files); |
|
121 | }); |
|
122 | } |
|
123 | } |
|
124 | ||
125 | for (var i = 0; i < files.length; i++) { |
|
126 | handleFile(files[i], i); |
|
127 | } |
|
128 | return $q.all(promises); |
|
129 | } |
|
130 | ||
131 | upload.updateModel = function (ngModel, attr, scope, fileChange, files, evt, noDelay) { |
|
132 | function update(files, invalidFiles, newFiles, dupFiles, isSingleModel) { |
|
133 | attr.$$ngfPrevValidFiles = files; |
|
134 | attr.$$ngfPrevInvalidFiles = invalidFiles; |
|
135 | var file = files && files.length ? files[0] : null; |
|
136 | var invalidFile = invalidFiles && invalidFiles.length ? invalidFiles[0] : null; |
|
137 | ||
138 | if (ngModel) { |
|
139 | upload.applyModelValidation(ngModel, files); |
|
140 | ngModel.$setViewValue(isSingleModel ? file : files); |
|
141 | } |
|
142 | ||
143 | if (fileChange) { |
|
144 | $parse(fileChange)(scope, { |
|
145 | $files: files, |
|
146 | $file: file, |
|
147 | $newFiles: newFiles, |
|
148 | $duplicateFiles: dupFiles, |
|
149 | $invalidFiles: invalidFiles, |
|
150 | $invalidFile: invalidFile, |
|
151 | $event: evt |
|
152 | }); |
|
153 | } |
|
154 | ||
155 | var invalidModel = upload.attrGetter('ngfModelInvalid', attr); |
|
156 | if (invalidModel) { |
|
157 | $timeout(function () { |
|
158 | $parse(invalidModel).assign(scope, isSingleModel ? invalidFile : invalidFiles); |
|
159 | }); |
|
160 | } |
|
161 | $timeout(function () { |
|
162 | // scope apply changes |
|
163 | }); |
|
164 | } |
|
165 | ||
166 | var allNewFiles, dupFiles = [], prevValidFiles, prevInvalidFiles, |
|
167 | invalids = [], valids = []; |
|
168 | ||
169 | function removeDuplicates() { |
|
170 | function equals(f1, f2) { |
|
171 | return f1.name === f2.name && (f1.$ngfOrigSize || f1.size) === (f2.$ngfOrigSize || f2.size) && |
|
172 | f1.type === f2.type; |
|
173 | } |
|
174 | ||
175 | function isInPrevFiles(f) { |
|
176 | var j; |
|
177 | for (j = 0; j < prevValidFiles.length; j++) { |
|
178 | if (equals(f, prevValidFiles[j])) { |
|
179 | return true; |
|
180 | } |
|
181 | } |
|
182 | for (j = 0; j < prevInvalidFiles.length; j++) { |
|
183 | if (equals(f, prevInvalidFiles[j])) { |
|
184 | return true; |
|
185 | } |
|
186 | } |
|
187 | return false; |
|
188 | } |
|
189 | ||
190 | if (files) { |
|
191 | allNewFiles = []; |
|
192 | dupFiles = []; |
|
193 | for (var i = 0; i < files.length; i++) { |
|
194 | if (isInPrevFiles(files[i])) { |
|
195 | dupFiles.push(files[i]); |
|
196 | } else { |
|
197 | allNewFiles.push(files[i]); |
|
198 | } |
|
199 | } |
|
200 | } |
|
201 | } |
|
202 | ||
203 | function toArray(v) { |
|
204 | return angular.isArray(v) ? v : [v]; |
|
205 | } |
|
206 | ||
207 | function resizeAndUpdate() { |
|
208 | function updateModel() { |
|
209 | $timeout(function () { |
|
210 | update(keep ? prevValidFiles.concat(valids) : valids, |
|
211 | keep ? prevInvalidFiles.concat(invalids) : invalids, |
|
212 | files, dupFiles, isSingleModel); |
|
213 | }, options && options.debounce ? options.debounce.change || options.debounce : 0); |
|
214 | } |
|
215 | ||
216 | var resizingFiles = validateAfterResize ? allNewFiles : valids; |
|
217 | resizeFile(resizingFiles, attr, scope, ngModel).then(function () { |
|
218 | if (validateAfterResize) { |
|
219 | upload.validate(allNewFiles, keep ? prevValidFiles.length : 0, ngModel, attr, scope) |
|
220 | .then(function (validationResult) { |
|
221 | valids = validationResult.validsFiles; |
|
222 | invalids = validationResult.invalidsFiles; |
|
223 | updateModel(); |
|
224 | }); |
|
225 | } else { |
|
226 | updateModel(); |
|
227 | } |
|
228 | }, function () { |
|
229 | for (var i = 0; i < resizingFiles.length; i++) { |
|
230 | var f = resizingFiles[i]; |
|
231 | if (f.$error === 'resize') { |
|
232 | var index = valids.indexOf(f); |
|
233 | if (index > -1) { |
|
234 | valids.splice(index, 1); |
|
235 | invalids.push(f); |
|
236 | } |
|
237 | updateModel(); |
|
238 | } |
|
239 | } |
|
240 | }); |
|
241 | } |
|
242 | ||
243 | prevValidFiles = attr.$$ngfPrevValidFiles || []; |
|
244 | prevInvalidFiles = attr.$$ngfPrevInvalidFiles || []; |
|
245 | if (ngModel && ngModel.$modelValue) { |
|
246 | prevValidFiles = toArray(ngModel.$modelValue); |
|
247 | } |
|
248 | ||
249 | var keep = upload.attrGetter('ngfKeep', attr, scope); |
|
250 | allNewFiles = (files || []).slice(0); |
|
251 | if (keep === 'distinct' || upload.attrGetter('ngfKeepDistinct', attr, scope) === true) { |
|
252 | removeDuplicates(attr, scope); |
|
253 | } |
|
254 | ||
255 | var isSingleModel = !keep && !upload.attrGetter('ngfMultiple', attr, scope) && !upload.attrGetter('multiple', attr); |
|
256 | ||
257 | if (keep && !allNewFiles.length) return; |
|
258 | ||
259 | upload.attrGetter('ngfBeforeModelChange', attr, scope, { |
|
260 | $files: files, |
|
261 | $file: files && files.length ? files[0] : null, |
|
262 | $newFiles: allNewFiles, |
|
263 | $duplicateFiles: dupFiles, |
|
264 | $event: evt |
|
265 | }); |
|
266 | ||
267 | var validateAfterResize = upload.attrGetter('ngfValidateAfterResize', attr, scope); |
|
268 | ||
269 | var options = upload.attrGetter('ngfModelOptions', attr, scope); |
|
270 | upload.validate(allNewFiles, keep ? prevValidFiles.length : 0, ngModel, attr, scope) |
|
271 | .then(function (validationResult) { |
|
272 | if (noDelay) { |
|
273 | update(allNewFiles, [], files, dupFiles, isSingleModel); |
|
274 | } else { |
|
275 | if ((!options || !options.allowInvalid) && !validateAfterResize) { |
|
276 | valids = validationResult.validFiles; |
|
277 | invalids = validationResult.invalidFiles; |
|
278 | } else { |
|
279 | valids = allNewFiles; |
|
280 | } |
|
281 | if (upload.attrGetter('ngfFixOrientation', attr, scope) && upload.isExifSupported()) { |
|
282 | applyExifRotations(valids, attr, scope).then(function () { |
|
283 | resizeAndUpdate(); |
|
284 | }); |
|
285 | } else { |
|
286 | resizeAndUpdate(); |
|
287 | } |
|
288 | } |
|
289 | }); |
|
290 | }; |
|
291 | ||
292 | return upload; |
|
293 | }]); |
|
294 |