1/* 2 * dmuploader.js - Jquery File Uploader - 0.1 3 * http://www.daniel.com.uy/projects/jquery-file-uploader/ 4 * 5 * Copyright (c) 2013 Daniel Morales 6 * Dual licensed under the MIT and GPL licenses. 7 * http://www.daniel.com.uy/doc/license/ 8 */ 9 10(function($) { 11 var pluginName = 'dmUploader'; 12 13 // These are the plugin defaults values 14 var defaults = { 15 url: document.URL, 16 method: 'POST', 17 extraData: {}, 18 maxFileSize: 0, 19 maxFiles: 0, 20 allowedTypes: '*', 21 extFilter: null, 22 dataType: null, 23 fileName: 'file', 24 onInit: function(){}, 25 onFallbackMode: function() {message}, 26 onNewFile: function(id, file){}, 27 onBeforeUpload: function(id){}, 28 onComplete: function(){}, 29 onUploadProgress: function(id, percent){}, 30 onUploadSuccess: function(id, data){}, 31 onUploadError: function(id, message){}, 32 onFileTypeError: function(file){}, 33 onFileSizeError: function(file){}, 34 onFileExtError: function(file){}, 35 onFilesMaxError: function(file){} 36 }; 37 38 var DmUploader = function(element, options) 39 { 40 this.element = $(element); 41 42 this.settings = $.extend({}, defaults, options); 43 44 if(!this.checkBrowser()){ 45 return false; 46 } 47 48 this.init(); 49 50 return true; 51 }; 52 53 DmUploader.prototype.checkBrowser = function() 54 { 55 if(window.FormData === undefined){ 56 this.settings.onFallbackMode.call(this.element, 'Browser doesn\'t support Form API'); 57 58 return false; 59 } 60 61 if(this.element.find('input[type=file]').length > 0){ 62 return true; 63 } 64 65 if (!this.checkEvent('drop', this.element) || !this.checkEvent('dragstart', this.element)){ 66 this.settings.onFallbackMode.call(this.element, 'Browser doesn\'t support Ajax Drag and Drop'); 67 68 return false; 69 } 70 71 return true; 72 }; 73 74 DmUploader.prototype.checkEvent = function(eventName, element) 75 { 76 var element = element || document.createElement('div'); 77 var eventName = 'on' + eventName; 78 79 var isSupported = eventName in element; 80 81 if(!isSupported){ 82 if(!element.setAttribute){ 83 element = document.createElement('div'); 84 } 85 if(element.setAttribute && element.removeAttribute){ 86 element.setAttribute(eventName, ''); 87 isSupported = typeof element[eventName] == 'function'; 88 89 if(typeof element[eventName] != 'undefined'){ 90 element[eventName] = undefined; 91 } 92 element.removeAttribute(eventName); 93 } 94 } 95 96 element = null; 97 return isSupported; 98 }; 99 100 DmUploader.prototype.init = function() 101 { 102 var widget = this; 103 104 widget.queue = new Array(); 105 widget.queuePos = -1; 106 widget.queueRunning = false; 107 108 // -- Drag and drop event 109 widget.element.on('drop', function (evt){ 110 evt.preventDefault(); 111 var files = evt.originalEvent.dataTransfer.files; 112 113 widget.queueFiles(files); 114 }); 115 116 //-- Optional File input to make a clickable area 117 widget.element.find('input[type=file]').on('change', function(evt){ 118 var files = evt.target.files; 119 120 widget.queueFiles(files); 121 122 $(this).val(''); 123 }); 124 125 this.settings.onInit.call(this.element); 126 }; 127 128 DmUploader.prototype.queueFiles = function(files) 129 { 130 var j = this.queue.length; 131 132 for (var i= 0; i < files.length; i++) 133 { 134 var file = files[i]; 135 136 // Check file size 137 if((this.settings.maxFileSize > 0) && 138 (file.size > this.settings.maxFileSize)){ 139 140 this.settings.onFileSizeError.call(this.element, file); 141 142 continue; 143 } 144 145 // Check file type 146 if((this.settings.allowedTypes != '*') && 147 !file.type.match(this.settings.allowedTypes)){ 148 149 this.settings.onFileTypeError.call(this.element, file); 150 151 continue; 152 } 153 154 // Check file extension 155 if(this.settings.extFilter != null){ 156 var extList = this.settings.extFilter.toLowerCase().split(';'); 157 158 var ext = file.name.toLowerCase().split('.').pop(); 159 160 if($.inArray(ext, extList) < 0){ 161 this.settings.onFileExtError.call(this.element, file); 162 163 continue; 164 } 165 } 166 167 // Check max files 168 if(this.settings.maxFiles > 0) { 169 if(this.queue.length >= this.settings.maxFiles) { 170 this.settings.onFilesMaxError.call(this.element, file); 171 172 continue; 173 } 174 } 175 176 this.queue.push(file); 177 178 var index = this.queue.length - 1; 179 180 this.settings.onNewFile.call(this.element, index, file); 181 } 182 183 // Only start Queue if we haven't! 184 if(this.queueRunning){ 185 return false;
186 } 187 188 // and only if new Failes were successfully added 189 if(this.queue.length == j){ 190 return false; 191 } 192 193 this.processQueue(); 194 195 return true; 196 }; 197 198 DmUploader.prototype.processQueue = function() 199 { 200 var widget = this; 201 202 widget.queuePos++; 203 204 if(widget.queuePos >= widget.queue.length){ 205 // Cleanup 206 207 widget.settings.onComplete.call(widget.element); 208 209 // Wait until new files are droped 210 widget.queuePos = (widget.queue.length - 1); 211 212 widget.queueRunning = false; 213 214 return; 215 } 216 217 var file = widget.queue[widget.queuePos]; 218 219 // Form Data 220 var fd = new FormData(); 221 fd.append(widget.settings.fileName, file); 222 223 // Return from client function (default === undefined) 224 var can_continue = widget.settings.onBeforeUpload.call(widget.element, widget.queuePos); 225 226 // If the client function doesn't return FALSE then continue 227 if( false === can_continue ) { 228 return; 229 } 230 231 // Append extra Form Data 232 $.each(widget.settings.extraData, function(exKey, exVal){ 233 fd.append(exKey, exVal); 234 }); 235 236 widget.queueRunning = true; 237 238 // Ajax Submit 239 $.ajax({ 240 url: widget.settings.url, 241 type: widget.settings.method, 242 dataType: widget.settings.dataType, 243 data: fd, 244 cache: false, 245 contentType: false, 246 processData: false, 247 forceSync: false, 248 xhr: function(){ 249 var xhrobj = $.ajaxSettings.xhr(); 250 if(xhrobj.upload){ 251 xhrobj.upload.addEventListener('progress', function(event) { 252 var percent = 0; 253 var position = event.loaded || event.position; 254 var total = event.total || e.totalSize; 255 if(event.lengthComputable){ 256 percent = Math.ceil(position / total * 100); 257 } 258 259 widget.settings.onUploadProgress.call(widget.element, widget.queuePos, percent); 260 }, false); 261 } 262 263 return xhrobj; 264 }, 265 success: function (data, message, xhr){ 266 widget.settings.onUploadSuccess.call(widget.element, widget.queuePos, data); 267 }, 268 error: function (xhr, status, errMsg){ 269 widget.settings.onUploadError.call(widget.element, widget.queuePos, errMsg); 270 }, 271 complete: function(xhr, textStatus){ 272 widget.processQueue(); 273 } 274 }); 275 } 276 277 $.fn.dmUploader = function(options){ 278 return this.each(function(){ 279 if(!$.data(this, pluginName)){ 280 $.data(this, pluginName, new DmUploader(this, options)); 281 } 282 }); 283 }; 284 285 // -- Disable Document D&D events to prevent opening the file on browser when we drop them 286 $(document).on('dragenter', function (e) { e.stopPropagation(); e.preventDefault(); }); 287 $(document).on('dragover', function (e) { e.stopPropagation(); e.preventDefault(); }); 288 $(document).on('drop', function (e) { e.stopPropagation(); e.preventDefault(); }); 289})(jQuery);
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.