1/* 2UploadiFive 1.2.3 3Copyright (c) 2012 Reactive Apps, Ronnie Garcia 4Released under the MIT License 5*/ 6;(function($) { 7 8 var methods = { 9 10 init : function(options) { 11 12 return this.each(function() { 13 14 // Create a reference to the jQuery DOM object 15 var $this = $(this); 16 $this.data('uploadifive', { 17 inputs : {}, // The object that contains all the file inputs 18 inputCount : 0, // The total number of file inputs created 19 fileID : 0, 20 queue : { 21 count : 0, // Total number of files in the queue 22 selected : 0, // Number of files selected in the last select operation 23 replaced : 0, // Number of files replaced in the last select operation 24 errors : 0, // Number of files that returned an error in the last select operation 25 queued : 0, // Number of files added to the queue in the last select operation 26 cancelled : 0 // Total number of files that have been cancelled or removed from the queue 27 }, 28 uploads : { 29 current : 0, // Number of files currently being uploaded 30 attempts : 0, // Number of file uploads attempted in the last upload operation 31 successful : 0, // Number of files successfully uploaded in the last upload operation 32 errors : 0, // Number of files returning errors in the last upload operation 33 count : 0 // Total number of files uploaded successfully 34 } 35 }); 36 var $data = $this.data('uploadifive'); 37 38 // Set the default options 39 var settings = $data.settings = $.extend({ 40 'auto' : true, // Automatically upload a file when it's added to the queue 41 'buttonClass' : false, // A class to add to the UploadiFive button 42 'buttonText' : 'Select Files', // The text that appears on the UploadiFive button 43 'checkScript' : false, // Path to the script that checks for existing file names 44 'dnd' : true, // Allow drag and drop into the queue 45 'dropTarget' : false, // Selector for the drop target 46 'fileObjName' : 'Filedata', // The name of the file object to use in your server-side script 47 'fileSizeLimit' : 0, // Maximum allowed size of files to upload 48 'fileType' : false, // Type of files allowed (image, etc), separate with a pipe character | 49 'formData' : {}, // Additional data to send to the upload script 50 'height' : 30, // The height of the button 51 'itemTemplate' : false, // The HTML markup for the item in the queue 52 'method' : 'post', // The method to use when submitting the upload 53 'multi' : true, // Set to true to allow multiple file selections 54 'overrideEvents' : [], // An array of events to override 55 'queueID' : false, // The ID of the file queue 56 'queueSizeLimit' : 0, // The maximum number of files that can be in the queue 57 'removeCompleted' : false, // Set to true to remove files that have completed uploading 58 'simUploadLimit' : 0, // The maximum number of files to upload at once 59 'truncateLength' : 0, // The length to truncate the file names to 60 'uploadLimit' : 0, // The maximum number of files you can upload 61 'uploadScript' : 'uploadifive.php', // The path to the upload script 62 'width' : 100 // The width of the button 63 64 /* 65 // Events 66 'onAddQueueItem' : function(file) {}, // Triggered for each file that is added to the queue 67 'onCancel' : function(file) {}, // Triggered when a file is cancelled or removed from the queue 68 'onCheck' : function(file, exists) {}, // Triggered when the server is checked for an existing file 69 'onClearQueue' : function(queue) {}, // Triggered during the clearQueue function 70 'onDestroy' : function() {} // Triggered during the destroy function 71 'onDrop' : function(files, numberOfFilesDropped) {}, // Triggered when files are dropped into the file queue 72 'onError' : function(file, fileType, data) {}, // Triggered when an error occurs 73 'onFallback' : function() {}, // Triggered if the HTML5 File API is not supported by the browser 74 'onInit' : function() {}, // Triggered when UploadiFive if initialized 75 'onQueueComplete' : function() {}, // Triggered once when an upload queue is done 76 'onProgress' : function(file, event) {}, // Triggered during each progress update of an upload 77 'onSelect' : function() {}, // Triggered once when files are selected from a dialog box 78 'onUpload' : function(file) {}, // Triggered when an upload queue is started 79 'onUploadComplete' : function(file, data) {}, // Triggered when a file is successfully uploaded 80 'onUploadFile' : function(file) {}, // Triggered for each file being uploaded 81 */ 82 }, options); 83 84 // Create an array of file types 85 var file_types; 86 if (settings.fileType) { 87 file_types = settings.fileType.split('|'); 88 } 89 90 // Calculate the file size limit 91 if (isNaN(settings.fileSizeLimit)) { 92 var fileSizeLimitBytes = parseInt(settings.fileSizeLimit) * 1.024; 93 if (settings.fileSizeLimit.indexOf('KB') > -1) { 94 settings.fileSizeLimit = fileSizeLimitBytes * 1000; 95 } else if (settings.fileSizeLimit.indexOf('MB') > -1) { 96 settings.fileSizeLimit = fileSizeLimitBytes * 1000000; 97 } else if (settings.fileSizeLimit.indexOf('GB') > -1) { 98 settings.fileSizeLimit = fileSizeLimitBytes * 1000000000; 99 } 100 } else { 101 settings.fileSizeLimit = settings.fileSizeLimit * 1024; 102 } 103 104 // Create a template for a file input 105 $data.inputTemplate = $('<input type="file">') 106 .css({ 107 'font-size' : settings.height + 'px', 108 'opacity' : 0, 109 'position' : 'absolute', 110 'right' : '-3px', 111 'top' : '-3px', 112 'z-index' : 999 113 }); 114 115 // Create a new input 116 $data.createInput = function() { 117 118 // Create a clone of the file input 119 var input = $data.inputTemplate.clone(); 120 // Create a unique name for the input item 121 var inputName = input.name = 'input' + $data.inputCount++; 122 // Set the multiple attribute 123 if (settings.multi) { 124 input.attr('multiple', true); 125 } 126 // Set the accept attribute on the input 127 if (settings.fileType) { 128 input.attr('accept', settings.fileType); 129 } 130 // Set the onchange event for the input 131 input.bind('change', function() { 132 $data.queue.selected = 0; 133 $data.queue.replaced = 0; 134 $data.queue.errors = 0; 135 $data.queue.queued = 0; 136 // Add a queue item to the queue for each file 137 var limit = this.files.length; 138 $data.queue.selected = limit; 139 if (($data.queue.count + limit) > settings.queueSizeLimit && settings.queueSizeLimit !== 0) { 140 if ($.inArray('onError', settings.overrideEvents) < 0) { 141 alert('The maximum number of queue items has been reached (' + settings.queueSizeLimit + '). Please select fewer files.'); 142 } 143 // Trigger the error event 144 if (typeof settings.onError === 'function') { 145 settings.onError.call($this, 'QUEUE_LIMIT_EXCEEDED'); 146 } 147 } else { 148 for (var n = 0; n < limit; n++) { 149 file = this.files[n]; 150 $data.addQueueItem(file); 151 } 152 $data.inputs[inputName] = this; 153 $data.createInput(); 154 } 155 // Upload the file if auto-uploads are enabled 156 if (settings.auto) { 157 methods.upload.call($this); 158 } 159 // Trigger the select event 160 if (typeof settings.onSelect === 'function') { 161 settings.onSelect.call($this, $data.queue); 162 } 163 }); 164 // Hide the existing current item and add the new one 165 if ($data.currentInput) { 166 $data.currentInput.hide(); 167 } 168 $data.button.append(input); 169 $data.currentInput = input; 170 }; 171 172 // Remove an input 173 $data.destroyInput = function(key) { 174 $($data.inputs[key]).remove(); 175 delete $data.inputs[key]; 176 $data.inputCount--; 177 }; 178 179 // Drop a file into the queue 180 $data.drop = function(e) { 181 // Stop FireFox from opening the dropped file(s) 182 e.preventDefault(); 183 e.stopPropagation(); 184 185 $data.queue.selected = 0; 186 $data.queue.replaced = 0; 187 $data.queue.errors = 0; 188 $data.queue.queued = 0; 189 190 var fileData = e.dataTransfer; 191 192 var inputName = fileData.name = 'input' + $data.inputCount++; 193 // Add a queue item to the queue for each file 194 var limit = fileData.files.length; 195 $data.queue.selected = limit; 196 if (($data.queue.count + limit) > settings.queueSizeLimit && settings.queueSizeLimit !== 0) { 197 // Check if the queueSizeLimit was reached 198 if ($.inArray('onError', settings.overrideEvents) < 0) { 199 alert('The maximum number of queue items has been reached (' + settings.queueSizeLimit + '). Please select fewer files.'); 200 } 201 // Trigger the onError event 202 if (typeof settings.onError === 'function') { 203 settings.onError.call($this, 'QUEUE_LIMIT_EXCEEDED'); 204 } 205 } else { 206 // Add a queue item for each file 207 for (var n = 0; n < limit; n++) { 208 file = fileData.files[n]; 209 $data.addQueueItem(file); 210 if (file_types && file_types.indexOf(file.type) === -1) { 211 $data.error('FORBIDDEN_FILE_TYPE', file); 212 } 213 } 214 // Save the data to the inputs object 215 $data.inputs[inputName] = fileData; 216 } 217 218 // Upload the file if auto-uploads are enabled 219 if (settings.auto) { 220 methods.upload.call($this); 221 } 222 223 // Trigger the onDrop event 224 if (typeof settings.onDrop === 'function') { 225 settings.onDrop.call($this, fileData.files, fileData.files.length); 226 } 227 }; 228 229 // Check if a filename exists in the queue 230 $data.fileExistsInQueue = function(file) { 231 for (var key in $data.inputs) { 232 input = $data.inputs[key]; 233 limit = input.files.length; 234 for (var n = 0; n < limit; n++) { 235 existingFile = input.files[n]; 236 // Check if the filename matches 237 if (existingFile.name == file.name && !existingFile.complete) { 238 return true; 239 } 240 } 241 } 242 return false;
243 }; 244 245 // Remove an existing file in the queue 246 $data.removeExistingFile = function(file) { 247 for (var key in $data.inputs) { 248 input = $data.inputs[key]; 249 limit = input.files.length; 250 for (var n = 0; n < limit; n++) { 251 existingFile = input.files[n]; 252 // Check if the filename matches 253 if (existingFile.name == file.name && !existingFile.complete) { 254 $data.queue.replaced++; 255 methods.cancel.call($this, existingFile, true); 256 } 257 } 258 } 259 }; 260 261 // Create the file item template 262 if (settings.itemTemplate === false) { 263 $data.queueItem = $('<div class="uploadifive-queue-item">' + 264 '<a class="close" href="#">X</a>' + 265 '<div><span class="filename"></span><span class="fileinfo"></span></div>' + 266 '<div class="progress">' + 267 '<div class="progress-bar"></div>' + 268 '</div>' + 269 '</div>'); 270 } else { 271 $data.queueItem = $(settings.itemTemplate); 272 } 273 274 // Add an item to the queue 275 $data.addQueueItem = function(file) { 276 if ($.inArray('onAddQueueItem', settings.overrideEvents) < 0) { 277 // Check if the filename already exists in the queue 278 $data.removeExistingFile(file); 279 // Create a clone of the queue item template 280 file.queueItem = $data.queueItem.clone(); 281 // Add an ID to the queue item 282 file.queueItem.attr('id', settings.id + '-file-' + $data.fileID++); 283 // Bind the close event to the close button 284 file.queueItem.find('.close').bind('click', function() { 285 methods.cancel.call($this, file); 286 return false; 287 }); 288 var fileName = file.name; 289 if (fileName.length > settings.truncateLength && settings.truncateLength !== 0) { 290 fileName = fileName.substring(0, settings.truncateLength) + '...'; 291 } 292 file.queueItem.find('.filename').html(fileName); 293 // Add a reference to the file 294 file.queueItem.data('file', file); 295 $data.queueEl.append(file.queueItem); 296 } 297 // Trigger the addQueueItem event 298 if (typeof settings.onAddQueueItem === 'function') { 299 settings.onAddQueueItem.call($this, file); 300 } 301 // Check the filesize 302 if (file.size > settings.fileSizeLimit && settings.fileSizeLimit !== 0) { 303 $data.error('FILE_SIZE_LIMIT_EXCEEDED', file); 304 } else { 305 $data.queue.queued++; 306 $data.queue.count++; 307 } 308 }; 309 310 // Remove an item from the queue 311 $data.removeQueueItem = function(file, instant, delay) { 312 // Set the default delay 313 if (!delay) delay = 0; 314 var fadeTime = instant ? 0 : 500; 315 if (file.queueItem) { 316 if (file.queueItem.find('.fileinfo').html() != ' - Completed') { 317 file.queueItem.find('.fileinfo').html(' - Cancelled'); 318 } 319 file.queueItem.find('.progress-bar').width(0); 320 file.queueItem.delay(delay).fadeOut(fadeTime, function() { 321 $(this).remove(); 322 }); 323 delete file.queueItem; 324 $data.queue.count--; 325 } 326 }; 327 328 // Count the number of files that need to be uploaded 329 $data.filesToUpload = function() { 330 var filesToUpload = 0; 331 for (var key in $data.inputs) { 332 input = $data.inputs[key]; 333 limit = input.files.length; 334 for (var n = 0; n < limit; n++) { 335 file = input.files[n]; 336 if (!file.skip && !file.complete) { 337 filesToUpload++; 338 } 339 } 340 } 341 return filesToUpload; 342 }; 343 344 // Check if a file exists 345 $data.checkExists = function(file) { 346 if ($.inArray('onCheck', settings.overrideEvents) < 0) { 347 // This request needs to be synchronous 348 $.ajaxSetup({ 349 'async' : false 350 }); 351 // Send the filename to the check script 352 var checkData = $.extend(settings.formData, {filename: file.name});
353 $.post(settings.checkScript, checkData, function(fileExists) { 354 file.exists = parseInt(fileExists); 355 }); 356 if (file.exists) { 357 if (!confirm('A file named ' + file.name + ' already exists in the upload folder.\nWould you like to replace it?')) { 358 // If not replacing the file, cancel the upload 359 methods.cancel.call($this, file); 360 return true; 361 } 362 } 363 } 364 // Trigger the check event 365 if (typeof settings.onCheck === 'function') { 366 settings.onCheck.call($this, file, file.exists); 367 } 368 return false; 369 }; 370 371 // Upload a single file 372 $data.uploadFile = function(file, uploadAll) { 373 if (!file.skip && !file.complete && !file.uploading) { 374 file.uploading = true; 375 $data.uploads.current++; 376 $data.uploads.attempted++; 377 378 // Create a new AJAX request 379 xhr = file.xhr = new XMLHttpRequest(); 380 381 // Start the upload 382 // Use the faster FormData if it exists 383 if (typeof FormData === 'function' || typeof FormData === 'object') { 384 385 // Create a new FormData object 386 var formData = new FormData(); 387 388 // Add the form data 389 formData.append(settings.fileObjName, file); 390 391 // Add the rest of the formData 392 for (var i in settings.formData) { 393 formData.append(i, settings.formData[i]); 394 } 395 396 // Open the AJAX call 397 xhr.open(settings.method, settings.uploadScript, true); 398 399 // On progress function 400 xhr.upload.addEventListener('progress', function(e) { 401 if (e.lengthComputable) { 402 $data.progress(e, file); 403 } 404 }, false); 405 406 // On complete function 407 xhr.addEventListener('load', function(e) { 408 if (this.readyState == 4) { 409 file.uploading = false; 410 if (this.status == 200) { 411 if (file.xhr.responseText !== 'Invalid file type.') { 412 $data.uploadComplete(e, file, uploadAll); 413 } else { 414 $data.error(file.xhr.responseText, file, uploadAll); 415 } 416 } else if (this.status == 404) { 417 $data.error('404_FILE_NOT_FOUND', file, uploadAll); 418 } else if (this.status == 403) { 419 $data.error('403_FORBIDDEN', file, uploadAll); 420 } else { 421 $data.error('Unknown Error', file, uploadAll); 422 } 423 } 424 }); 425 426 // Send the form data (multipart/form-data) 427 xhr.send(formData); 428 429 } else { 430 431 // Send as binary 432 var reader = new FileReader(); 433 reader.onload = function(e) { 434 435 // Set some file builder variables 436 var boundary = '-------------------------' + (new Date()).getTime(), 437 dashes = '--', 438 eol = '\r\n', 439 binFile = ''; 440 441 // Build an RFC2388 String 442 binFile += dashes + boundary + eol; 443 // Generate the headers 444 binFile += 'Content-Disposition: form-data; name="' + settings.fileObjName + '"'; 445 if (file.name) { 446 binFile += '; filename="' + file.name + '"'; 447 } 448 binFile += eol; 449 binFile += 'Content-Type: application/octet-stream' + eol + eol; 450 binFile += e.target.result + eol; 451 452 for (var key in settings.formData) { 453 binFile += dashes + boundary + eol; 454 binFile += 'Content-Disposition: form-data; name="' + key + '"' + eol + eol; 455 binFile += settings.formData[key] + eol; 456 } 457 458 binFile += dashes + boundary + dashes + eol; 459 460 // On progress function 461 xhr.upload.addEventListener('progress', function(e) { 462 $data.progress(e, file); 463 }, false); 464 465 // On complete function 466 xhr.addEventListener('load', function(e) { 467 file.uploading = false;
468 var status = this.status; 469 if (status == 404) { 470 $data.error('404_FILE_NOT_FOUND', file, uploadAll); 471 } else { 472 if (file.xhr.responseText != 'Invalid file type.') { 473 $data.uploadComplete(e, file, uploadAll); 474 } else { 475 $data.error(file.xhr.responseText, file, uploadAll); 476 } 477 } 478 }, false); 479 480 // Open the ajax request 481 var url = settings.uploadScript; 482 if (settings.method == 'get') { 483 var params = $(settings.formData).param(); 484 url += params; 485 } 486 xhr.open(settings.method, settings.uploadScript, true); 487 xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary); 488 489 // Trigger the uploadFile event 490 if (typeof settings.onUploadFile === 'function') { 491 settings.onUploadFile.call($this, file); 492 } 493 494 // Send the file for upload 495 xhr.sendAsBinary(binFile); 496 }; 497 reader.readAsBinaryString(file); 498 499 } 500 } 501 }; 502 503 // Update a file upload's progress 504 $data.progress = function(e, file) { 505 var percent; 506 if ($.inArray('onProgress', settings.overrideEvents) < 0) { 507 if (e.lengthComputable) { 508 percent = Math.round((e.loaded / e.total) * 100); 509 } 510 file.queueItem.find('.fileinfo').html(' - ' + percent + '%'); 511 file.queueItem.find('.progress-bar').css('width', percent + '%'); 512 } 513 // Trigger the progress event 514 if (typeof settings.onProgress === 'function') { 515 settings.onProgress.call($this, file, e); 516 } 517 }; 518 519 // Trigger an error 520 $data.error = function(errorType, file, uploadAll) { 521 if ($.inArray('onError', settings.overrideEvents) < 0) { 522 // Get the error message 523 switch(errorType) { 524 case '404_FILE_NOT_FOUND': 525 errorMsg = '404 Error'; 526 break; 527 case '403_FORBIDDEN': 528 errorMsg = '403 Forbidden'; 529 break; 530 case 'FORBIDDEN_FILE_TYPE': 531 errorMsg = 'Forbidden File Type'; 532 break; 533 case 'FILE_SIZE_LIMIT_EXCEEDED': 534 errorMsg = 'File Too Large'; 535 break; 536 default: 537 errorMsg = 'Unknown Error'; 538 break; 539 } 540 541 // Add the error class to the queue item 542 file.queueItem.addClass('error') 543 // Output the error in the queue item 544 .find('.fileinfo').html(' - ' + errorMsg); 545 // Hide the 546 file.queueItem.find('.progress').remove(); 547 } 548 // Trigger the error event 549 if (typeof settings.onError === 'function') { 550 settings.onError.call($this, errorType, file); 551 } 552 file.skip = true; 553 if (errorType == '404_FILE_NOT_FOUND') { 554 $data.uploads.errors++; 555 } else { 556 $data.queue.errors++; 557 } 558 if (uploadAll) { 559 methods.upload.call($this, null, true); 560 } 561 }; 562 563 // Trigger when a single file upload is complete 564 $data.uploadComplete = function(e, file, uploadAll) { 565 if ($.inArray('onUploadComplete', settings.overrideEvents) < 0) {
566 file.queueItem.find('.progress-bar').css('width', '100%'); 567 file.queueItem.find('.fileinfo').html(' - Completed'); 568 file.queueItem.find('.progress').slideUp(250); 569 file.queueItem.addClass('complete'); 570 } 571 // Trigger the complete event 572 if (typeof settings.onUploadComplete === 'function') { 573 settings.onUploadComplete.call($this, file, file.xhr.responseText); 574 } 575 if (settings.removeCompleted) { 576 setTimeout(function() { methods.cancel.call($this, file); }, 3000); 577 } 578 file.complete = true; 579 $data.uploads.successful++; 580 $data.uploads.count++; 581 $data.uploads.current--; 582 delete file.xhr; 583 if (uploadAll) { 584 methods.upload.call($this, null, true); 585 } 586 }; 587 588 // Trigger when all the files are done uploading 589 $data.queueComplete = function() { 590 // Trigger the queueComplete event 591 if (typeof settings.onQueueComplete === 'function') { 592 settings.onQueueComplete.call($this, $data.uploads); 593 } 594 }; 595 596 // ---------------------- 597 // Initialize UploadiFive 598 // ---------------------- 599 600 // Check if HTML5 is available 601 if (window.File && window.FileList && window.Blob && (window.FileReader || window.FormData)) { 602 // Assign an ID to the object 603 settings.id = 'uploadifive-' + $this.attr('id'); 604 605 // Wrap the file input in a div with overflow set to hidden 606 $data.button = $('<div id="' + settings.id + '" class="uploadifive-button">' + settings.buttonText + '</div>'); 607 if (settings.buttonClass) $data.button.addClass(settings.buttonClass); 608 609 // Style the button wrapper 610 $data.button.css({ 611 'height' : settings.height, 612 'line-height' : settings.height + 'px', 613 'overflow' : 'hidden', 614 'position' : 'relative', 615 'text-align' : 'center', 616 'width' : settings.width 617 }); 618 619 // Insert the button above the file input 620 $this.before($data.button) 621 // Add the file input to the button 622 .appendTo($data.button) 623 // Modify the styles of the file input 624 .hide(); 625 626 // Create a new input 627 $data.createInput.call($this); 628 629 // Create the queue container 630 if (!settings.queueID) { 631 settings.queueID = settings.id + '-queue'; 632 $data.queueEl = $('<div id="' + settings.queueID + '" class="uploadifive-queue" />'); 633 $data.button.after($data.queueEl); 634 } else { 635 $data.queueEl = $('#' + settings.queueID); 636 } 637 638 // Add drag and drop functionality 639 if (settings.dnd) { 640 var $dropTarget = settings.dropTarget ? $(settings.dropTarget) : $data.queueEl.get(0); 641 $dropTarget.addEventListener('dragleave', function(e) { 642 // Stop FireFox from opening the dropped file(s) 643 e.preventDefault(); 644 e.stopPropagation(); 645 }, false); 646 $dropTarget.addEventListener('dragenter', function(e) { 647 // Stop FireFox from opening the dropped file(s) 648 e.preventDefault(); 649 e.stopPropagation(); 650 }, false); 651 $dropTarget.addEventListener('dragover', function(e) { 652 // Stop FireFox from opening the dropped file(s) 653 e.preventDefault(); 654 e.stopPropagation(); 655 }, false); 656 $dropTarget.addEventListener('drop', $data.drop, false); 657 } 658 659 // Send as binary workaround for Chrome 660 if (!XMLHttpRequest.prototype.sendAsBinary) { 661 XMLHttpRequest.prototype.sendAsBinary = function(datastr) {
662 function byteValue(x) { 663 return x.charCodeAt(0) & 0xff; 664 } 665 var ords = Array.prototype.map.call(datastr, byteValue); 666 var ui8a = new Uint8Array(ords); 667 this.send(ui8a.buffer); 668 }; 669 } 670 671 // Trigger the oninit event 672 if (typeof settings.onInit === 'function') { 673 settings.onInit.call($this); 674 } 675 676 } else { 677 678 // Trigger the fallback event 679 if (typeof settings.onFallback === 'function') { 680 settings.onFallback.call($this); 681 } 682 return false; 683 684 } 685 686 }); 687 688 }, 689 690 691 // Write some data to the console 692 debug : function() { 693 694 return this.each(function() { 695 696 console.log($(this).data('uploadifive')); 697 698 }); 699 700 }, 701 702 // Clear all the items from the queue 703 clearQueue : function() { 704 705 this.each(function() { 706 707 var $this = $(this), 708 $data = $this.data('uploadifive'), 709 settings = $data.settings; 710 711 for (var key in $data.inputs) { 712 input = $data.inputs[key]; 713 limit = input.files.length; 714 for (i = 0; i < limit; i++) { 715 file = input.files[i]; 716 methods.cancel.call($this, file); 717 } 718 } 719 // Trigger the onClearQueue event 720 if (typeof settings.onClearQueue === 'function') { 721 settings.onClearQueue.call($this, $('#' + $data.settings.queueID)); 722 } 723 724 }); 725 726 }, 727 728 // Cancel a file upload in progress or remove a file from the queue 729 cancel : function(file, fast) { 730 731 this.each(function() { 732 733 var $this = $(this), 734 $data = $this.data('uploadifive'), 735 settings = $data.settings; 736 737 // If user passed a queue item ID instead of file... 738 if (typeof file === 'string') { 739 if (!isNaN(file)) { 740 fileID = 'uploadifive-' + $(this).attr('id') + '-file-' + file; 741 } 742 file = $('#' + fileID).data('file'); 743 } 744 745 file.skip = true; 746 $data.filesCancelled++; 747 if (file.uploading) { 748 $data.uploads.current--; 749 file.uploading = false; 750 file.xhr.abort(); 751 delete file.xhr; 752 methods.upload.call($this); 753 } 754 if ($.inArray('onCancel', settings.overrideEvents) < 0) { 755 $data.removeQueueItem(file, fast); 756 } 757 758 // Trigger the cancel event 759 if (typeof settings.onCancel === 'function') { 760 settings.onCancel.call($this, file); 761 } 762 763 }); 764 765 }, 766 767 // Upload the files in the queue 768 upload : function(file, keepVars) { 769 770 this.each(function() { 771 772 var $this = $(this), 773 $data = $this.data('uploadifive'), 774 settings = $data.settings; 775 776 if (file) { 777 778 $data.uploadFile.call($this, file); 779 780 } else { 781 782 // Check if the upload limit was reached 783 if (($data.uploads.count + $data.uploads.current) < settings.uploadLimit || settings.uploadLimit === 0) { 784 if (!keepVars) { 785 $data.uploads.attempted = 0; 786 $data.uploads.successsful = 0; 787 $data.uploads.errors = 0; 788 var filesToUpload = $data.filesToUpload(); 789 // Trigger the onUpload event 790 if (typeof settings.onUpload === 'function') { 791 settings.onUpload.call($this, filesToUpload); 792 } 793 } 794 795 // Loop through the files 796 $('#' + settings.queueID).find('.uploadifive-queue-item').not('.error, .complete').each(function() { 797 _file = $(this).data('file'); 798 // Check if the simUpload limit was reached 799 if (($data.uploads.current >= settings.simUploadLimit && settings.simUploadLimit !== 0) || ($data.uploads.current >= settings.uploadLimit && settings.uploadLimit !== 0) || ($data.uploads.count >= settings.uploadLimit && settings.uploadLimit !== 0)) { 800 return false;
801 } 802 if (settings.checkScript) { 803 // Let the loop know that we're already processing this file 804 _file.checking = true; 805 skipFile = $data.checkExists(_file); 806 _file.checking = false; 807 if (!skipFile) { 808 $data.uploadFile(_file, true); 809 } 810 } else { 811 $data.uploadFile(_file, true); 812 } 813 }); 814 if ($('#' + settings.queueID).find('.uploadifive-queue-item').not('.error, .complete').length === 0) { 815 $data.queueComplete(); 816 } 817 } else { 818 if ($data.uploads.current === 0) { 819 if ($.inArray('onError', settings.overri
819deEvents) < 0) { 820 if ($data.filesToUpload() > 0 && settings.uploadLimit !== 0) { 821 alert('The maximum upload limit has been reached.'); 822 } 823 } 824 // Trigger the onError event 825 if (typeof settings.onError === 'function') { 826 settings.onError.call($this, 'UPLOAD_LIMIT_EXCEEDED', $data.filesToUpload()); 827 } 828 } 829 } 830 831 } 832 833 }); 834 835 }, 836 837 // Destroy an instance of UploadiFive 838 destroy : function() { 839 840 this.each(function() { 841 842 var $this = $(this), 843 $data = $this.data('uploadifive'), 844 settings = $data.settings; 845 846 // Clear the queue 847 methods.clearQueue.call($this); 848 // Destroy the queue if it was created 849 if (!settings.queueID) $('#' + settings.queueID).remove(); 850 // Remove extra inputs 851 $this.siblings('input').remove(); 852 // Show the original file input 853 $this.show() 854 // Move the file input out of the button 855 .insertBefore($data.button); 856 // Delete the button 857 $data.button.remove(); 858 // Trigger the destroy event 859 if (typeof settings.onDestroy === 'function') { 860 settings.onDestroy.call($this); 861 } 862 863 }); 864 865 } 866 867 }; 868 869 $.fn.uploadifive = function(method) { 870 871 if (methods[method]) { 872 return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 873 } else if (typeof method === 'object' || !method) { 874 return methods.init.apply(this, arguments); 875 } else { 876 $.error('The method ' + method + ' does not exist in $.uploadify'); 877 } 878 879 }; 880 881})(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.