1/*! 2 * jQuery Upload File Plugin 3 * version: 3.1.2 4 * @requires jQuery v1.5 or later & form plugin 5 * Copyright (c) 2013 Ravishanker Kusuma 6 * http://hayageek.com/ 7 */ 8(function ($) { 9 if ($.fn.ajaxForm == undefined) { 10 $.getScript("http://malsup.github.io/jquery.form.js"); 11 } 12 var feature = {}; 13 feature.fileapi = $("<input type='file'/>").get(0).files !== undefined; 14 feature.formdata = window.FormData !== undefined; 15 $.fn.uploadFile = function (options) { 16 // This is the easiest way to have default options. 17 var s = $.extend({ 18 // These are the defaults. 19 url: "", 20 method: "POST", 21 enctype: "multipart/form-data", 22 formData: null, 23 returnType: null, 24 allowedTypes: "*", 25 //For list of acceptFiles 26 // http://stackoverflow.com/questions/11832930/html-input-file-accept-attribute-file-type-csv 27 acceptFiles: "*", 28 fileName: "file", 29 formData: {}, 30 dynamicFormData: function () { 31 return {}; 32 }, 33 maxFileSize: -1, 34 maxFileCount:-1, 35 multiple: true, 36 dragDrop: true, 37 autoSubmit: true, 38 showCancel: true, 39 showAbort: true, 40 showDone: true, 41 showDelete:false, 42 showError: true, 43 showStatusAfterSuccess: true, 44 showStatusAfterError: true, 45 showFileCounter:true, 46 fileCounterStyle:"). ", 47 showProgress:false, 48 onSelect:function(files){ return true;}, 49 onSubmit: function (files, xhr) {}, 50 onSuccess: function (files, response, xhr) {}, 51 onError: function (files, status, message) {}, 52 deleteCallback: false, 53 afterUploadAll: false, 54 uploadButtonClass: "upload", 55 dragDropStr: "<span><b>Drag & Drop Files</b></span>", 56 abortStr: "Abort", 57 cancelStr: "Cancel", 58 deletelStr: "Delete", 59 doneStr: "Done", 60 multiDragErrorStr: "Multiple File Drag & Drop is not allowed.", 61 extErrorStr: "is not allowed. Allowed extensions: ", 62 sizeErrorStr: "is not allowed. Allowed Max size: ", 63 uploadErrorStr: "Upload is not allowed", 64 maxFileCountErrorStr: " is not allowed. Maximum allowed files are:" 65 66 }, options); 67 68 this.fileCounter = 1; 69 this.selectedFiles=0; 70 this.fCounter = 0; //failed uploads 71 this.sCounter = 0; //success uploads 72 this.tCounter = 0; //total uploads 73 var formGroup = "upload-" + (new Date().getTime()); 74 this.formGroup = formGroup; 75 this.hide(); 76 this.errorLog = $("<div></div>"); //Writing errors 77 this.after(this.errorLog); 78 this.responses = []; 79 if (!feature.formdata) //check drag drop enabled. 80 { 81 s.dragDrop = false; 82 } 83 if(!feature.formdata) 84 { 85 s.multiple = false; 86 } 87 88 var obj = this; 89 var uploadLabel = $('<div>' + $(this).html() + '</div>'); 90 $(uploadLabel).addClass(s.uploadButtonClass); 91 92 //wait form ajax Form plugin and initialize 93 (function checkAjaxFormLoaded() { 94 if ($.fn.ajaxForm) { 95 96 if (s.dragDrop) { 97 var dragDrop = $('<div class="ajax-upload-dragdrop" style="vertical-align:top;"></div>'); 98 $(obj).before(dragDrop); 99 $(dragDrop).append(uploadLabel); 100 $(dragDrop).prepend($(s.dragDropStr)); 101 setDragDropHandlers(obj, s, dragDrop); 102 103 } else { 104 $(obj).before(uploadLabel); 105 } 106 107 createCutomInputFile(obj, formGroup, s, uploadLabel); 108 109 } else window.setTimeout(checkAjaxFormLoaded, 10); 110 })(); 111 112 this.startUpload = function () { 113 $("." + this.formGroup).each(function (i, items) { 114 if ($(this).is('form')) $(this).submit(); 115 }); 116 } 117 this.stopUpload = function () { 118 $(".upload-red").each(function (i, items) { 119 if ($(this).hasClass(obj.formGroup)) $(this).click(); 120 }); 121 } 122 123 this.getResponses = function () { 124 return this.responses; 125 } 126 var checking = false;
127 128 function checkPendingUploads() { 129 if (s.afterUploadAll && !checking) { 130 checking = true; 131 (function checkPending() { 132 if (obj.sCounter != 0 && (obj.sCounter + obj.fCounter == obj.tCounter)) { 133 s.afterUploadAll(obj); 134 checking = false; 135 } else window.setTimeout(checkPending, 100); 136 })(); 137 } 138 139 } 140 141 function setDragDropHandlers(obj, s, ddObj) { 142 ddObj.on('dragenter', function (e) { 143 e.stopPropagation(); 144 e.preventDefault(); 145 $(this).css('border', '2px solid #A5A5C7'); 146 }); 147 ddObj.on('dragover', function (e) { 148 e.stopPropagation(); 149 e.preventDefault(); 150 }); 151 ddObj.on('drop', function (e) { 152 $(this).css('border', '2px dotted #A5A5C7'); 153 e.preventDefault(); 154 obj.errorLog.html(""); 155 var files = e.originalEvent.dataTransfer.files; 156 if (!s.multiple && files.length > 1) { 157 if (s.showError) $("<div style='color:red;'>" + s.multiDragErrorStr + "</div>").appendTo(obj.errorLog); 158 return; 159 } 160 if(s.onSelect(files) == false) 161 return; 162 serializeAndUploadFiles(s, obj, files); 163 }); 164 165 $(document).on('dragenter', function (e) { 166 e.stopPropagation(); 167 e.preventDefault(); 168 }); 169 $(document).on('dragover', function (e) { 170 e.stopPropagation(); 171 e.preventDefault(); 172 ddObj.css('border', '2px dotted #A5A5C7'); 173 }); 174 $(document).on('drop', function (e) { 175 e.stopPropagation(); 176 e.preventDefault(); 177 ddObj.css('border', '2px dotted #A5A5C7'); 178 }); 179 180 } 181 182 function getSizeStr(size) { 183 var sizeStr = ""; 184 var sizeKB = size / 1024; 185 if (parseInt(sizeKB) > 1024) { 186 var sizeMB = sizeKB / 1024; 187 sizeStr = sizeMB.toFixed(2) + " MB"; 188 } else { 189 sizeStr = sizeKB.toFixed(2) + " KB"; 190 } 191 return sizeStr; 192 } 193 194 function serializeData(extraData) { 195 var serialized = []; 196 if (jQuery.type(extraData) == "string") { 197 serialized = extraData.split('&'); 198 } else { 199 serialized = $.param(extraData).split('&'); 200 } 201 var len = serialized.length; 202 var result = []; 203 var i, part; 204 for (i = 0; i < len; i++) { 205 serialized[i] = serialized[i].replace(/\+/g, ' '); 206 part = serialized[i].split('='); 207 result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]); 208 } 209 return result; 210 } 211 212 function serializeAndUploadFiles(s, obj, files) { 213 for (var i = 0; i < files.length; i++) { 214 if (!isFileTypeAllowed(obj, s, files[i].name)) { 215 if (s.showError) $("<div style='color:red;'><b>" + files[i].name + "</b> " + s.extErrorStr + s.allowedTypes + "</div>").appendTo(obj.errorLog); 216 continue; 217 } 218 if (s.maxFileSize != -1 && files[i].size > s.maxFileSize) { 219 if (s.showError) $("<div style='color:red;'><b>" + files[i].name + "</b> " + s.sizeErrorStr + getSizeStr(s.maxFileSize) + "</div>").appendTo(obj.errorLog); 220 continue; 221 } 222 if(s.maxFileCount != -1 && obj.selectedFiles >= s.maxFileCount) 223 { 224 if (s.showError) $("<div style='color:red;'><b>" + files[i].name + "</b> " + s.maxFileCountErrorStr + s.maxFileCount + "</div>").appendTo(obj.errorLog); 225 continue; 226 } 227 obj.selectedFiles++; 228 var ts = s; 229 var fd = new FormData(); 230 var fileName = s.fileName.replace("[]", ""); 231 fd.append(fileName, files[i]); 232 var extraData = s.formData; 233 if (extraData) { 234 var sData = serializeData(extraData); 235 for (var j = 0; j < sData.length; j++) { 236 if (sData[j]) { 237 fd.append(sData[j][0], sData[j][1]); 238 } 239 } 240 } 241 ts.fileData = fd; 242 243 var pd = new createProgressDiv(obj, s); 244 var fileNameStr=""; 245 if(s.showFileCounter) 246 fileNameStr = obj.fileCounter + s.fileCounterStyle + files[i].name 247 else
248 fileNameStr = files[i].name; 249 250 pd.filename.html(fileNameStr); 251 var form = $("<form style='display:block; position:absolute;left: 150px;' class='" + obj.formGroup + "' method='" + s.method + "' action='" + s.url + "' enctype='" + s.enctype + "'></form>"); 252 form.appendTo('body'); 253 var fileArray = []; 254 fileArray.push(files[i].name); 255 ajaxFormSubmit(form, ts, pd, fileArray, obj); 256 obj.fileCounter++; 257 258 259 } 260 } 261 262 function isFileTypeAllowed(obj, s, fileName) { 263 var fileExtensions = s.allowedTypes.toLowerCase().split(","); 264 var ext = fileName.split('.').pop().toLowerCase(); 265 if (s.allowedTypes != "*" && jQuery.inArray(ext, fileExtensions) < 0) { 266 return false; 267 } 268 return true; 269 } 270 function updateFileCounter(s,obj) 271 { 272 if(s.showFileCounter) 273 { 274 var count=$(".upload-filename").length; 275 obj.fileCounter=count+1; 276 $(".upload-filename").each(function (i, items) 277 { 278 var arr=$(this).html().split(s.fileCounterStyle); 279 var fileNum = parseInt(arr[0]) -1;//decrement; 280 var name = count+s.fileCounterStyle+arr[1]; 281 $(this).html(name); 282 count--; 283 }); 284 } 285 } 286 287 function createCutomInputFile(obj, group, s, uploadLabel) { 288 289 var fileUploadId = "ajax-upload-id-" + (new Date().getTime()); 290 291 var form = $("<form method='" + s.method + "' action='" + s.url + "' enctype='" + s.enctype + "'></form>"); 292 var fileInputStr = "<input type='file' id='" + fileUploadId + "' name='" + s.fileName + "' accept='" + s.acceptFiles + "'/>"; 293 if (s.multiple) { 294 if (s.fileName.indexOf("[]") != s.fileName.length - 2) // if it does not endwith 295 { 296 s.fileName += "[]"; 297 } 298 fileInputStr = "<input type='file' id='" + fileUploadId + "' name='" + s.fileName + "' accept='" + s.acceptFiles + "' multiple/>"; 299 } 300 var fileInput = $(fileInputStr).appendTo(form); 301 302 fileInput.change(function () { 303 304 obj.errorLog.html(""); 305 var fileExtensions = s.allowedTypes.toLowerCase().split(","); 306 var fileArray = []; 307 if (this.files) //support reading files 308 { 309 for (i = 0; i < this.files.length; i++) 310 { 311 fileArray.push(this.files[i].name); 312 } 313 314 if(s.onSelect(this.files) == false) 315 return; 316 } else { 317 var filenameStr = $(this).val(); 318 var flist = []; 319 fileArray.push(filenameStr); 320 if (!isFileTypeAllowed(obj, s, filenameStr)) { 321 if (s.showError) $("<div style='color:red;'><b>" + filenameStr + "</b> " + s.extErrorStr + s.allowedTypes + "</div>").appendTo(obj.errorLog); 322 return; 323 } 324 //fallback for browser without FileAPI 325 flist.push({name:filenameStr,size:'NA'}); 326 if(s.onSelect(flist) == false) 327 return; 328 329 } 330 updateFileCounter(s,obj); 331 332 uploadLabel.unbind("click"); 333 form.hide(); 334 createCutomInputFile(obj, group, s, uploadLabel); 335 336 form.addClass(group); 337 if (feature.fileapi && feature.formdata) //use HTML5 support and split file submission 338 { 339 form.removeClass(group); //Stop Submitting when. 340 var files = this.files; 341 serializeAndUploadFiles(s, obj, files); 342 } else { 343 var fileList = ""; 344 for (var i = 0; i < fileArray.length; i++) 345 { 346 if(s.showFileCounter) 347 fileList += obj.fileCounter + s.fileCounterStyle + fileArray[i]+"<br>"; 348 else 349 fileList += fileArray[i]+"<br>";; 350 obj.fileCounter++; 351 352 }
353 if(s.maxFileCount != -1 && (obj.selectedFiles+fileArray.length) > s.maxFileCount) 354 { 355 if (s.showError) $("<div style='color:red;'><b>" + fileList + "</b> " + s.maxFileCountErrorStr + s.maxFileCount + "</div>").appendTo(obj.errorLog); 356 return; 357 } 358 obj.selectedFiles += fileArray.length; 359 360 var pd = new createProgressDiv(obj, s); 361 pd.filename.html(fileList); 362 ajaxFormSubmit(form, s, pd, fileArray, obj); 363 } 364 365 366 367 }); 368 369 form.css({'margin':0,'padding':0}); 370 var uwidth=$(uploadLabel).width()+10; 371 if(uwidth == 10) 372 uwidth =120; 373 374 var uheight=uploadLabel.height()+10; 375 if(uheight == 10) 376 uheight = 35; 377 378 uploadLabel.css({position: 'relative',overflow:'hidden',cursor:'default'}); 379 fileInput.css({position: 'absolute','cursor':'pointer', 380 'top': '0px', 381 'width': uwidth, 382 'height':uheight, 383 'left': '0px', 384 'z-index': '100', 385 'opacity': '0.0', 386 'filter':'alpha(opacity=0)', 387 '-ms-filter':"alpha(opacity=0)", 388 '-khtml-opacity':'0.0', 389 '-moz-opacity':'0.0' 390 }); 391 form.appendTo(uploadLabel); 392 393 //dont hide it, but move it to 394 /* form.css({ 395 margin: 0, 396 padding: 0, 397 display: 'block', 398 position: 'absolute', 399 left: '50px' 400 }); 401 if (navigator.appVersion.indexOf("MSIE ") != -1) //IE Browser 402 { 403 uploadLabel.attr('for', fileUploadId); 404 } else { 405 uploadLabel.click(function () { 406 fileInput.click(); 407 }); 408 }*/ 409 410 411 } 412 413 414 function createProgressDiv(obj, s) { 415 this.statusbar = $("<div class='upload-statusbar'></div>"); 416 this.filename = $("<div class='upload-filename'></div>").appendTo(this.statusbar); 417 this.progressDiv = $("<div class='upload-progress'>").appendTo(this.statusbar).hide(); 418 this.progressbar = $("<div class='upload-bar " + obj.formGroup + "'></div>").appendTo(this.progressDiv); 419 this.abort = $("<div class='upload-red " + obj.formGroup + "'>" + s.abortStr + "</div>").appendTo(this.statusbar).hide(); 420 this.cancel = $("<div class='upload-red'>" + s.cancelStr + "</div>").appendTo(this.statusbar).hide(); 421 this.done = $("<div class='upload-green'>" + s.doneStr + "</div>").appendTo(this.statusbar).hide(); 422 this.del = $("<div class='upload-red'>" + s.deletelStr + "</div>").appendTo(this.statusbar).hide(); 423 obj.errorLog.after(this.statusbar); 424 return this; 425 } 426 427 428 function ajaxFormSubmit(form, s, pd, fileArray, obj) { 429 var currentXHR = null; 430 var options = { 431 cache: false, 432 contentType: false, 433 processData: false, 434 forceSync: false, 435 data: s.formData, 436 formData: s.fileData, 437 dataType: s.returnType, 438 beforeSubmit: function (formData, $form, options) { 439 if (s.onSubmit.call(this, fileArray) != false) { 440 var dynData = s.dynamicFormData(); 441 if (dynData) { 442 var sData = serializeData(dynData); 443 if (sData) { 444 for (var j = 0; j < sData.length; j++) { 445 if (sData[j]) { 446 if (s.fileData != undefined) options.formData.append(sData[j][0], sData[j][1]); 447 else options.data[sData[j][0]] = sData[j][1]; 448 } 449 } 450 } 451 } 452 obj.tCounter += fileArray.length; 453 //window.setTimeout(checkPendingUploads, 1000); //not so critical 454 checkPendingUploads(); 455 return true; 456 } 457 pd.statusbar.append("<div style='color:red;'>" + s.uploadErrorStr + "</div>"); 458 pd.cancel.show() 459 form.remove(); 460 pd.cancel.click(function () { 461 pd.statusbar.remove(); 462 }); 463 return false;
464 }, 465 beforeSend: function (xhr, o) { 466 467 pd.progressDiv.show(); 468 pd.cancel.hide(); 469 pd.done.hide(); 470 if (s.showAbort) { 471 pd.abort.show(); 472 pd.abort.click(function () { 473 xhr.abort(); 474 obj.selectedFiles -= fileArray.length; //reduce selected File count 475 }); 476 } 477 if (!feature.formdata) //For iframe based push 478 { 479 pd.progressbar.width('5%'); 480 } else pd.progressbar.width('1%'); //Fix for small files 481 }, 482 uploadProgress: function (event, position, total, percentComplete) { 483 //Fix for smaller file uploads in MAC 484 if(percentComplete > 98) percentComplete =98; 485 486 var percentVal = percentComplete + '%'; 487 if (percentComplete > 1) pd.progressbar.width(percentVal) 488 if(s.showProgress) 489 { 490 pd.progressbar.html(percentVal); 491 pd.progressbar.css('text-align', 'center'); 492 } 493 494 }, 495 success: function (data, message, xhr) { 496 obj.responses.push(data); 497 pd.progressbar.width('100%') 498 if(s.showProgress) 499 { 500 pd.progressbar.html('100%'); 501 pd.progressbar.css('text-align', 'center'); 502 } 503 504 pd.abort.hide(); 505 s.onSuccess.call(this, fileArray, data, xhr); 506 if (s.showStatusAfterSuccess) { 507 if (s.showDone) { 508 pd.done.show(); 509 pd.done.click(function () { 510 pd.statusbar.hide("slow"); 511 pd.statusbar.remove(); 512 }); 513 } else { 514 pd.done.hide(); 515 } 516 if(s.showDelete) 517 { 518 pd.del.show(); 519 pd.del.click(function () { 520 pd.statusbar.hide().remove(); 521 if(s.deleteCallback) s.deleteCallback.call(this, data,pd); 522 obj.selectedFiles -= fileArray.length; //reduce selected File count 523 updateFileCounter(s,obj); 524 525 }); 526 } 527 else 528 { 529 pd.del.hide(); 530 } 531 } else { 532 pd.statusbar.hide("slow"); 533 pd.statusbar.remove(); 534 535 } 536 form.remove(); 537 obj.sCounter += fileArray.length; 538 }, 539 error: function (xhr, status, errMsg) { 540 pd.abort.hide(); 541 if (xhr.statusText == "abort") //we aborted it 542 { 543 pd.statusbar.hide("slow").remove(); 544 updateFileCounter(s,obj); 545 546 } else { 547 s.onError.call(this, fileArray, status, errMsg); 548 if (s.showStatusAfterError) { 549 pd.progressDiv.hide(); 550 pd.statusbar.append("<span style='color:red;'>ERROR: " + errMsg + "</span>"); 551 } else { 552 pd.statusbar.hide(); 553 pd.statusbar.remove(); 554 } 555 obj.selectedFiles -= fileArray.length; //reduce selected File count 556 } 557 558 form.remove(); 559 obj.fCounter += fileArray.length; 560 561 } 562 }; 563 if (s.autoSubmit) { 564 form.ajaxSubmit(options); 565 } else { 566 if (s.showCancel) { 567 pd.cancel.show(); 568 pd.cancel.click(function () { 569 form.remove(); 570 pd.statusbar.remove(); 571 obj.selectedFiles -= fileArray.length; //reduce selected File count 572 updateFileCounter(s,obj); 573 }); 574 } 575 form.ajaxForm(options); 576 577 } 578 579 } 580 return this; 581 582 } 583 584 585}(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.