1/** 2 * jquery.plupload.queue.js 3 * 4 * Copyright 2009, Moxiecode Systems AB 5 * Released under GPL License. 6 * 7 * License: http://www.plupload.com/license 8 * Contributing: http://www.plupload.com/contributing 9 */ 10 11/* global jQuery:true, alert:true */ 12 13/** 14jQuery based implementation of the Plupload API - multi-runtime file uploading API. 15 16To use the widget you must include _jQuery_. It is not meant to be extended in any way and is provided to be 17used as it is. 18 19@example 20 <!-- Instantiating: --> 21 <div id="uploader"> 22 <p>Your browser doesn't have Flash, Silverlight or HTML5 support.</p> 23 </div> 24 25 <script> 26 $('#uploader').pluploadQueue({ 27 url : '../upload.php', 28 filters : [ 29 {title : "Image files", extensions : "jpg,gif,png"} 30 ], 31 rename: true, 32 flash_swf_url : '../../js/Moxie.swf', 33 silverlight_xap_url : '../../js/Moxie.xap', 34 }); 35 </script> 36 37@example 38 // Retrieving a reference to plupload.Uploader object 39 var uploader = $('#uploader').pluploadQueue(); 40 41 uploader.bind('FilesAdded', function() { 42 43 // Autostart 44 setTimeout(uploader.start, 1); // "detach" from the main thread 45 }); 46 47@class pluploadQueue 48@constructor 49@param {Object} settings For detailed information about each option check documentation. 50 @param {String} settings.url URL of the server-side upload handler. 51 @param {Number|String} [settings.chunk_size=0] Chunk size in bytes to slice the file into. Shorcuts with b, kb, mb, gb, tb suffixes also supported. `e.g. 204800 or "204800b" or "200kb"`. By default - disabled. 52 @param {String} [settings.file_data_name="file"] Name for the file field in Multipart formated message. 53 @param {Array} [settings.filters=[]] Set of file type filters, each one defined by hash of title and extensions. `e.g. {title : "Image files", extensions : "jpg,jpeg,gif,png"}`. Dispatches `plupload.FILE_EXTENSION_ERROR` 54 @param {String} [settings.flash_swf_url] URL of the Flash swf. 55 @param {Object} [settings.headers] Custom headers to send with the upload. Hash of name/value pairs. 56 @param {Number|String} [settings.max_file_size] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`. 57 @param {Number} [settings.max_retries=0] How many times to retry the chunk or file, before triggering Error event. 58 @param {Boolean} [settings.multipart=true] Whether to send file and additional parameters as Multipart formated message. 59 @param {Object} [settings.multipart_params] Hash of key/value pairs to send with every file upload. 60 @param {Boolean} [settings.multi_selection=true] Enable ability to select multiple files at once in file dialog. 61 @param {Boolean} [settings.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`. 62 @param {String|Object} [settings.required_features] Either comma-separated list or hash of required features that chosen runtime should absolutely possess. 63 @param {Object} [settings.resize] Enable resizng of images on client-side. Applies to `image/jpeg` and `image/png` only. `e.g. {width : 200, height : 200, quality : 90, crop: true}` 64 @param {Number} [settings.resize.width] If image is bigger, it will be resized. 65 @param {Number} [settings.resize.height] If image is bigger, it will be resized. 66 @param {Number} [settings.resize.quality=90] Compression quality for jpegs (1-100). 67 @param {Boolean} [settings.resize.crop=false] Whether to crop images to exact dimensions. By default they will be resized proportionally. 68 @param {String} [settings.runtimes="html5,flash,silverlight,html4"] Comma separated list of runtimes, that Plupload will try in turn, moving to the next if previous fails. 69 @param {String} [settings.silverlight_xap_url] URL of the Silverlight xap. 70 @param {Boolean} [settings.unique_names=false] If true will generate unique filenames for uploaded files. 71 72 @param {Boolean} [settings.dragdrop=true] Enable ability to add file to the queue by drag'n'dropping them from the desktop. 73 @param {Boolean} [settings.rename=false] Enable ability to rename files in the queue. 74 @param {Boolean} [settings.multiple_queues=true] Re-activate the widget after each upload procedure. 75*/ 76var plupload_stack = {}; 77;(function($, o) { 78 var uploaders = {}; 79 80 function _(str) { 81 return plupload.translate(str) || str; 82 } 83 84 function renderUI(id, target) { 85 // Remove all existing non plupload items 86 target.contents().each(function(i, node) { 87 node = $(node); 88 89 if (!node.is('.plupload')) { 90 node.remove(); 91 } 92 }); 93 94 target.prepend( 95 '<a href="#" class="plupload_button plupload_add pi-btn" id="' + id + '_browse"><i class="far fa-save"></i> ' + _('Add Files') + '</a>' + 96 '<div class="plupload_wrapper plupload_scroll">' + 97 '<div id="' + id + '_container" class="plupload_container">' + 98 '<div class="plupload">' + 99 '<div class="plupload_header">' + 100 '<div class="plupload_header_content">' + 101 '<div class="plupload_header_title">' + _('Select files') + '</div>' + 102 '<div class="plupload_header_text">' + _('Please add files to the upload queue or select the Find Files button.') + '</div>' + 103 '</div>' + 104 '</div>' + 105 106 '<div class="plupload_content">' + 107 '<div class="plupload_filelist_header">' + 108 '<div class="plupload_file_name">' + _('Filename') + '</div>' + 109 '<div class="plupload_file_action"> </div>' + 110 '<div class="plupload_file_status"><span>' + _('Status') + '</span></div>' + 111 '<div class="plupload_file_size">' + _('Size') + '</div>' + 112 '<div class="plupload_clearer"> </div>' + 113 '</div>' + 114 115 '<ul id="' + id + '_filelist" class="plupload_filelist"></ul>' + 116 117 '<div class="plupload_filelist_footer">' + 118 '<div class="plupload_file_name">' + 119 '<div class="plupload_buttons">' + 120 '<a href="#" class="plupload_button plupload_start">' + _('Start Upload') + '</a>' + 121 '</div>' + 122 '<span class="plupload_upload_status"></span>' + 123 '</div>' + 124 '<div class="plupload_file_action"></div>' + 125 '<div class="plupload_file_status"><span class="plupload_total_status">0%</span></div>' + 126 '<div class="plupload_file_size"><span class="plupload_total_file_size">0 b</span></div>' + 127 '<div class="plupload_progress">' + 128 '<div class="plupload_progress_container">' + 129 '<div class="plupload_progress_bar"></div>' + 130 '</div>' + 131 '</div>' + 132 '<div class="plupload_clearer"> </div>' + 133 '</div>' + 134 '</div>' + 135 '</div>' + 136 '</div>' + 137 '<input type="hidden" id="' + id + '_count" name="' + id + '_count" value="
1370" />' + 138 '</div>' 139 ); 140 } 141 142 $.fn.pluploadQueue = function(settings) { 143 if (settings) { 144 this.each(function() { 145 var uploader, target, id, contents_bak; 146 147 target = $(this); 148 id = target.attr('id'); 149 150 if (!id) { 151 id = plupload.guid(); 152 target.attr('id', id); 153 } 154 155 contents_bak = target.html(); 156 renderUI(id, target); 157 158 settings = $.extend({ 159 dragdrop : true, 160 browse_button : id + '_browse', 161 container : id 162 }, settings); 163 164 // Enable drag/drop (see PostInit handler as well) 165 if (settings.dragdrop) { 166 settings.drop_element = id + '_filelist'; 167 } 168 169 uploader = new plupload.Uploader(settings); 170 171 uploaders[id] = uploader; 172 173 function handleStatus(file) { 174 var actionClass; 175 176 if (file.status == plupload.DONE) { 177 actionClass = 'plupload_done'; 178 } 179 180 if (file.status == plupload.FAILED) { 181 actionClass = 'plupload_failed'; 182 } 183 184 if (file.status == plupload.QUEUED) { 185 actionClass = 'plupload_delete'; 186 } 187 188 if (file.status == plupload.UPLOADING) { 189 actionClass = 'plupload_uploading'; 190 } 191 192 var icon = $('#' + file.id).attr('class', actionClass).find('a').css('display', 'block'); 193 if (file.hint) { 194 icon.attr('title', file.hint); 195 } 196 } 197 198 function updateTotalProgress() { 199 $('span.plupload_total_status', target).html(uploader.total.percent + '%'); 200 $('div.plupload_progress_bar', target).css('width', uploader.total.percent + '%'); 201 $('span.plupload_upload_status', target).html( 202 o.sprintf(_('Uploaded %d/%d files'), uploader.total.uploaded, uploader.files.length) 203 ); 204 } 205 206 function updateList() { 207 var fileList = $('ul.plupload_filelist', target).html(''), inputCount = 0, inputHTML; 208 209 $.each(uploader.files, function(i, file) { 210 inputHTML = ''; 211 212 if(typeof file.response != 'undefined') { 213 if(typeof file.response.error != 'undefined') { 214 alert(file.response.error.message); 215 return; 216 } 217 } 218 219 if (file.status == plupload.DONE ) { 220 if (file.target_name) { 221 inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_tmpname" value="' + plupload.xmlEncode(file.target_name) + '" />'; 222 } 223 224 inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_name" value="' + plupload.xmlEncode(file.name) + '" />'; 225 inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_status" value="' + (file.status == plupload.DONE ? 'done' : 'failed') + '" />'; 226 227 inputCount++; 228 229 $('#' + id + '_count').val(inputCount); 230 } 231 232 //icon = file.ext.substring(1); 233 sp = file.name.split('.') 234 icon = sp[sp.length-1].toLowerCase(); 235 filename=file.file_down_url ? '<article class="plupload_file_down" href="' +file.file_down_url+ '" url="' +file.file_url+ '">' + file.name + '</article>' : file.name; 236 237 fileList.append( 238 '<li id="' + file.id + '">' + 239 '<div class="plupload_file_name"><span><i class="pi-icon '+icon+'"></i>' +filename+ '</span></div>' + 240 ( file.type.indexOf('image') > -1 && typeof file.file_url != 'undefined' && settings.axis == 'xy' ? '<img src="' +file.file_url+ '" class="thumb" onload=this.style.display="block" />' : '' ) + 241 '<div class="plupload_file_action"><a href="#"></a></div>' + 242 '<div class="plupload_file_status">' + file.percent + '%</div>' + 243 '<div class="plupload_file_size">' + plupload.formatSize(file.size) + '</div>' + 244 '<div class="plupload_clearer"> </div>' + 245 inputHTML + 246 '</li>' 247 ); 248 249 if ( (file.status == plupload.DONE && file.response) || typeof file.uniquid != 'undefined' ) 250 { 251 252 253 $('#' + file.id).find('.plupload_file_name span').append('<a href="' +(typeof file.uniquid != 'undefined' ? file.uniquid : file.response.file.id)+ '" class="plupload_add_editor"></a>'); 254 $('#' + file.id).find('.plupload_file_name span').append('<a href="' +(typeof file.uniquid != 'undefined' ? file.uniquid : file.response.file.id)+ '" class="plupload_remove"></a>'); 255 256 if( typeof file.uniquid == 'undefined' && typeof plupload_stack[file.id] == 'undefined' ) { 257 plupload_stack[file.id] = true; 258 $('.plupload_add_editor', $('#' + file.id)).trigger('image.click'); 259 } 260 261 } 262 263 handleStatus(file); 264 265 $('#' + file.id + '.plupload_delete a').click(function(e) { 266 $('#' + file.id).remove(); 267 uploader.removeFile(file); 268 269 e.preventDefault(); 270 }); 271 }); 272 273 $('span.plupload_total_file_size', target).html(plupload.formatSize(uploader.total.size+uploader.total.plus_size)); 274 275 if (uploader.total.queued === 0) { 276 $('span.plupload_add_text', target).html(_('Add Files')); 277 } else { 278 $('span.plupload_add_text', target).html(o.sprintf(_('%d files queued'), uploader.total.queued)); 279 } 280 281 $('a.plupload_start', target).toggleClass('plupload_disabled', uploader.files.length == (uploader.total.uploaded + uploader.total.failed)); 282 283 // Scroll to end of file list 284 fileList[0].scrollTop = fileList[0].scrollHeight; 285 286 updateTotalProgress(); 287 288 // Re-add drag message if there is no files 289 if (!uploader.files.length && uploader.features.dragdrop && uploader.settings.dragdrop) { 290 $('#' + id + '_filelist').append('<li class="plupload_droptext">' + _("Drag files here.") + '</li>'); 291 } 292 } 293 294 function destroy() { 295 delete uploaders[id]; 296 uploader.destroy(); 297 target.html(contents_bak); 298 uploader = target = contents_bak = null; 299 } 300 301 uploader.updateList = function(){ 302 updateList(); 303 } 304 305 uploader.bind("UploadFile", function(up, file) { 306 $('#' + file.id).addClass('plupload_current_file'); 307 }); 308 309 uploader.bind('Init', function(up, res) { 310 // Enable rename support 311 if (!settings.unique_names && settings.rename) { 312 target.on('click', '#' + id + '_filelist div.plupload_file_name span', function(e) { 313 var targetSpan = $(e.target), file, parts, name, ext = ""; 314 315 // Get file name and split out name and extension
316 file = up.getFile(targetSpan.parents('li')[0].id); 317 name = file.name; 318 parts = /^(.+)(\.[^.]+)$/.exec(name); 319 if (parts) { 320 name = parts[1]; 321 ext = parts[2]; 322 } 323 324 // Display input element 325 targetSpan.hide().after('<input type="text" />'); 326 targetSpan.next().val(name).focus().blur(function() { 327 targetSpan.show().next().remove(); 328 }).keydown(function(e) { 329 var targetInput = $(this); 330 331 if (e.keyCode == 13) { 332 e.preventDefault(); 333 334 // Rename file and glue extension back on 335 file.name = targetInput.val() + ext; 336 targetSpan.html(file.name); 337 targetInput.blur(); 338 } 339 }); 340 }); 341 } 342 343 $('#' + id + '_container').attr('title', 'Using runtime: ' + res.runtime); 344 345 $('a.plupload_start', target).click(function(e) { 346 if (!$(this).hasClass('plupload_disabled')) { 347 uploader.start(); 348 } 349 350 e.preventDefault(); 351 }); 352 353 uploader.bind('FilesAdded', function(up) { 354 updateList(); 355 356 if(settings.max_file_count > 0 && (up.files.length > settings.now_file_count)) { 357 while(up.files.length > settings.now_file_count) { 358 if(up.files.length > settings.now_file_count) { 359 uploader.removeFile(up.files[settings.now_file_count]); 360 } 361 } 362 363 alert(o.sprintf(_("Upload element accepts only %d file(s) at a time. Extra files were stripped."), settings.max_file_count || 0)); 364 365 return false; 366 } 367 368 if( typeof settings.mime_types != 'undefined' ){ 369 var arr_ext = settings.mime_types.split(','); 370 var is_del = false; 371 372 for( key in up.files ){ 373 var ext_split = up.files[key].name.split('.'); 374 var ext = ext_split[ext_split.length-1].toLowerCase(); 375 /*if( $.inArray(ext, arr_ext) < 0 ){ 376 uploader.removeFile(up.files[key]); 377 is_del = true; 378 }*/ 379 } 380 381 if( is_del == true ){ 382 alert(o.sprintf(_("(%d) you can only upload files. Extra files were stripped."), settings.mime_types)); 383 } 384 } 385 386 387 $('.plupload_wrapper', target).slideDown(); 388 389 uploader.start(); 390 }); 391 392 $('a.plupload_stop', target).click(function(e) { 393 e.preventDefault(); 394 uploader.stop(); 395 }); 396 397 $('a.plupload_start', target).addClass('plupload_disabled'); 398 }); 399 400 uploader.bind("Error", function(up, err) { 401 var file = err.file, message; 402 403 if (file) { 404 message = err.message; 405 406 if (err.details) { 407 message += " (" + err.details + ")"; 408 } 409 410 if (err.code == plupload.FILE_SIZE_ERROR) { 411 alert(_("Error: File too large:") + " " + file.name); 412 } 413 414 if (err.code == plupload.FILE_EXTENSION_ERROR) { 415 alert(_("Error: Invalid file extension:") + " " + file.name); 416 } 417 418 file.hint = message; 419 $('#' + file.id).attr('class', 'plupload_failed').find('a').css('display', 'block').attr('title', message); 420 } 421 422 if (err.code === plupload.INIT_ERROR) { 423 setTimeout(function() { 424 destroy(); 425 }, 1); 426 } 427 }); 428 429 uploader.bind("PostInit", function(up) { 430 // features are populated only after input components are fully instantiated 431 if (up.settings.dragdrop && up.features.dragdrop) { 432 $('#' + id + '_filelist').append('<li class="plupload_droptext">' + _("Drag files here.") + '</li>'); 433 434 $(window).one 435 ( 436 'dragover', function(){ 437 $('.plupload_wrapper', target).slideDown(); 438 } 439 ); 440 }else{ 441 $('#' + id + '_filelist').append('<li class="plupload_droptext">' + _("Select the file button.") + '</li>'); 442 } 443 444 $('#' + id + '_filelist').bind('dragover', function() { 445 $(this).addClass('drag_over'); 446 }).bind('dragleave drop', function() { 447 $(this).removeClass('drag_over'); 448 }); 449 450 451 }); 452 453 uploader.init(); 454 455 456 uploader.bind('StateChanged', function() { 457 if (uploader.state === plupload.STARTED) { 458 $('li.plupload_delete a,div.plupload_buttons', target).hide(); 459 uploader.disableBrowse(true); 460 461 $('span.plupload_upload_status,div.plupload_progress,a.plupload_stop', target).css('display', 'block'); 462 $('span.plupload_upload_status', target).html('Uploaded ' + uploader.total.uploaded + '/' + uploader.files.length + ' files'); 463 464 if (settings.multiple_queues) { 465 $('span.plupload_total_status,span.plupload_total_file_size', target).show(); 466 } 467 } else { 468 updateList(); 469 $('a.plupload_stop,div.plupload_progress', target).hide(); 470 $('a.plupload_delete', target).css('display', 'block'); 471 472 if (settings.multiple_queues && uploader.total.uploaded + uploader.total.failed == uploader.files.length) { 473 $(".plupload_buttons,.plupload_upload_status", target).css("display", "inline"); 474 uploader.disableBrowse(false); 475 476 $(".plupload_start", target).addClass("plupload_disabled"); 477 //$('span.plupload_total_status,span.plupload_total_file_size', target).hide(); 478 } 479 } 480 }); 481 482 483 uploader.bind('FilesRemoved', function() { 484 // since the whole file list is redrawn for every change in the queue 485 // we need to scroll back to the file removal point to avoid annoying 486 // scrolling to the bottom bug (see #926) 487 var scrollTop = $('#' + id + '_filelist').scrollTop(); 488 updateList(); 489 $('#' + id + '_filelist').scrollTop(scrollTop); 490 }); 491 492 uploader.bind('FileUploaded', function(up, file, response) { 493 try { 494 response = jQuery.parseJSON(response.response); 495 496 file.file_url = response.file.file_url 497 file.file_down_url = response.file.file_down_url 498 499 if(response.error.code == '500') 500 { 501 alert(response.error.message); 502 file.status = plupload.FAILED; 503 } 504 } catch(e) { 505 } 506 507 file.response = response; 508 509 510 511 handleStatus(file); 512 }); 513 514 uploader.bind("UploadProgress", function(up, file) { 515 // Set file specific progress 516 $('#' + file.id + ' div.plupload_file_status', target).html(file.percent + '%'); 517 518 handleStatus(file); 519 updateTotalProgress(); 520 }); 521 522 // Call setup function 523 if (settings.setup) { 524 settings.setup(uploader); 525 } 526 }); 527 return this; 528 } else { 529 // Get uploader instance for specified element 530 return uploaders[$(this[0]).attr('id')]; 531 } 532 }; 533})(jQuery, mOxie);
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.