1/**! 2 * AngularJS file upload/drop directive with http post and progress 3 * @author Danial <[email protected]> 4 * @version 1.3.1 5 */ 6(function() { 7 8 var angularFileUpload = angular.module('angularFileUpload', []); 9 10 angularFileUpload.service('$upload', ['$http', '$timeout', function($http, $timeout) { 11 function sendHttp(config) { 12 config.method = config.method || 'POST'; 13 config.headers = config.headers || {}; 14 config.transformRequest = config.transformRequest || function(data, headersGetter) { 15 if (window.ArrayBuffer && data instanceof window.ArrayBuffer) { 16 return data; 17 } 18 return $http.defaults.transformRequest[0](data, headersGetter); 19 }; 20 21 if (window.XMLHttpRequest.__isShim) { 22 config.headers['__setXHR_'] = function() { 23 return function(xhr) { 24 config.__XHR = xhr; 25 config.xhrFn && config.xhrFn(xhr); 26 xhr.upload.addEventListener('progress', function(e) { 27 if (config.progress) { 28 $timeout(function() { 29 if(config.progress) config.progress(e); 30 }); 31 } 32 }, false); 33 //fix for firefox not firing upload progress end, also IE8-9 34 xhr.upload.addEventListener('load', function(e) { 35 if (e.lengthComputable) { 36 $timeout(function() { 37 if(config.progress) config.progress(e); 38 }); 39 } 40 }, false); 41 } 42 }; 43 } 44 45 var promise = $http(config); 46 47 promise.progress = function(fn) { 48 config.progress = fn; 49 return promise; 50 }; 51 promise.abort = function() { 52 if (config.__XHR) { 53 $timeout(function() { 54 config.__XHR.abort(); 55 }); 56 } 57 return promise; 58 }; 59 promise.xhr = function(fn) { 60 config.xhrFn = fn; 61 return promise; 62 }; 63 promise.then = (function(promise, origThen) { 64 return function(s, e, p) { 65 config.progress = p || config.progress; 66 var result = origThen.apply(promise, [s, e, p]); 67 result.abort = promise.abort; 68 result.progress = promise.progress; 69 result.xhr = promise.xhr; 70 return result; 71 }; 72 })(promise, promise.then); 73 74 return promise; 75 } 76 77 this.upload = function(config) { 78 config.headers = config.headers || {}; 79 config.headers['Content-Type'] = undefined; 80 config.transformRequest = config.transformRequest || $http.defaults.transformRequest; 81 var formData = new FormData(); 82 var origTransformRequest = config.transformRequest; 83 var origData = config.data; 84 config.transformRequest = function(formData, headerGetter) { 85 if (origData) { 86 if (config.formDataAppender) { 87 for (var key in origData) { 88 var val = origData[key]; 89 config.formDataAppender(formData, key, val); 90 } 91 } else { 92 for (var key in origData) { 93 var val = origData[key]; 94 if (typeof origTransformRequest == 'function') { 95 val = origTransformRequest(val, headerGetter); 96 } else { 97 for (var i = 0; i < origTransformRequest.length; i++) { 98 var transformFn = origTransformRequest[i]; 99 if (typeof transformFn == 'function') { 100 val = transformFn(val, headerGetter); 101 } 102 } 103 } 104 formData.append(key, val); 105 } 106 } 107 } 108 109 if (config.file != null) { 110 var fileFormName = config.fileFormDataName || 'file'; 111 112 if (Object.prototype.toString.call(config.file) === '[object Array]') { 113 var isFileFormNameString = Object.prototype.toString.call(fileFormName) === '[object String]'; 114 for (var i = 0; i < config.file.length; i++) { 115 formData.append(isFileFormNameString ? fileFormName + i : fileFormName[i], config.file[i], config.file[i].name); 116 } 117 } else { 118 formData.append(fileFormName, config.file, config.file.name); 119 } 120 } 121 return formData; 122 }; 123 124 config.data = formData; 125 126 return sendHttp(config); 127 }; 128 129 this.http = function(config) { 130 return sendHttp(config); 131 } 132 }]); 133 134 angularFileUpload.directive('ngFileSelect', [ '$parse', '$timeout', function($parse, $timeout) { 135 return function(scope, elem, attr) { 136 var fn = $parse(attr['ngFileSelect']); 137 elem.bind('change', function(evt) { 138 var files = [], fileList, i; 139 fileList = evt.target.files; 140 if (fileList != null) { 141 for (i = 0; i < fileList.length; i++) { 142 files.push(fileList.item(i)); 143 } 144 } 145 $timeout(function() { 146 fn(scope, { 147 $files : files, 148 $event : evt 149 }); 150 }); 151 }); 152 elem.bind('click', function(){ 153 this.value = null; 154 }); 155 }; 156 } ]); 157 158 angularFileUpload.directive('ngFileDropAvailable', [ '$parse', '$timeout', function($parse, $timeout) { 159 return function(scope, elem, attr) { 160 if ('draggable' in document.createElement('span')) { 161 var fn = $parse(attr['ngFileDropAvailable']); 162 $timeout(function() { 163 fn(scope); 164 }); 165 } 166 }; 167 } ]); 168 169 angularFileUpload.directive('ngFileDrop', [ '$parse', '$timeout', function($parse, $timeout) { 170 return function(scope, elem, attr) { 171 if ('draggable' in document.createElement('span')) { 172 var cancel = null; 173 var fn = $parse(attr['ngFileDrop']); 174 elem[0].addEventListener("dragover", function(evt) { 175 $timeout.cancel(cancel); 176 evt.stopPropagation(); 177 evt.preventDefault(); 178 elem.addClass(attr['ngFileDragOverClass'] || "dragover"); 179 }, false); 180 elem[0].addEventListener("dragleave", function(evt) { 181 cancel = $timeout(function() { 182 elem.removeClass(attr['ngFileDragOverClass'] || "dragover"); 183 }); 184 }, false); 185 186 var processing = 0; 187 function traverseFileTree(files, item) { 188 if (item.isDirectory) { 189 var dirReader = item.createReader(); 190 processing++; 191 dirReader.readEntries(function(entries) { 192 for (var i = 0; i < entries.length; i++) {
193 traverseFileTree(files, entries[i]); 194 } 195 processing--; 196 }); 197 } else { 198 processing++; 199 item.file(function(file) { 200 processing--; 201 files.push(file); 202 }); 203 } 204 } 205 206 elem[0].addEventListener("drop", function(evt) { 207 evt.stopPropagation(); 208 evt.preventDefault(); 209 elem.removeClass(attr['ngFileDragOverClass'] || "dragover"); 210 var files = [], items = evt.dataTransfer.items; 211 if (items && items.length > 0 && items[0].webkitGetAsEntry) { 212 for (var i = 0; i < items.length; i++) { 213 traverseFileTree(files, items[i].webkitGetAsEntry()); 214 } 215 } else { 216 var fileList = evt.dataTransfer.files; 217 if (fileList != null) { 218 for (var i = 0; i < fileList.length; i++) { 219 files.push(fileList.item(i)); 220 } 221 } 222 } 223 (function callback(delay) { 224 $timeout(function() { 225 if (!processing) { 226 fn(scope, { 227 $files : files, 228 $event : evt 229 }); 230 } else { 231 callback(10); 232 } 233 }, delay || 0) 234 })(); 235 }, false); 236 } 237 }; 238 } ]); 239 240})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.