1(function ($) { 2 function _(str) { 3 return plupload.translate(str) || str; 4 } 5 6 /// <summary> 7 /// Configures a form. This widge sets up various features including 8 /// tool tips, validation, and file uploads. 9 /// </summary> 10 $.widget("ui.FormContent", 11 { 12 /// <summary> 13 /// Set of files to upload. 14 /// </summary> 15 _fileUploadsToProcess: undefined, 16 17 /// <summary> 18 /// FormContent widget options. 19 /// </summary> 20 options: 21 { 22 Disabled: false, 23 UseRecaptcha: false, 24 RecaptchaSubType: null, 25 RecaptchaSiteKey: null, 26 RecaptchaErrorV2HtmlId: null, 27 RecaptchaElementV2HtmlId: null, 28 RecaptchaInputV3HtmlId: null 29 }, 30 31 /// <summary> 32 /// Called when widget is destroyed. 33 /// </summary> 34 _destroy: function () { 35 return undefined; 36 }, 37 38 /// <summary> 39 /// Called on widget init. 40 /// </summary> 41 _init: function () { 42 return undefined; 43 }, 44 45 /// <summary> 46 /// Called to create this widget. 47 /// </summary> 48 _create: function () { 49 this.grecaptcha_widget_id = null; 50 51 const self = this; 52 const jElement = $(self.element); 53 54 // Create exactly one (1) wrapper function instance! 55 const debounceWrapper = debounceFunc(function (event) { 56 event.stopPropagation(); 57 event.preventDefault(); 58 event.stopImmediatePropagation(); 59 self._HandleFormSubmit(event); 60 return false; 61 }, 250); 62 63 // Wrapper calling the single debounce function instance. 64 function doubleWrapped(event) { 65 // Do this first! Immediately stop other submit handlers! 66 event.preventDefault(); 67 68 // call the debouncewrapper. 69 return debounceWrapper(event); 70 } 71 72 self.element[0].addEventListener("submit", doubleWrapped); 73 74 75 // TODO: Do we need a submit event handler on the form? 76 77 if (self.options.Disabled) { 78 jElement.find('input,select,button,textarea').off().prop('disabled', true); 79 return; 80 } 81 82 jElement.vpformchecker({ 83 manageFormFieldStyling: false 84 }); 85 86 jElement.vpformchecker('addOtherFunction', function () { 87 return self._additionalFormChecking; 88 }); 89 90 if (self.options.UseRecaptcha) { 91 self._waitForGrecaptcha(); 92 } 93 94 self._InitToolTips(); 95 self._InitFileUploaders(); 96 jElement.vpformchecker('initFormSetupFields', "(required)"); 97 98 99 }, 100 101 /// <summary> 102 /// Initializes tool tip help on the form. 103 /// </summary> 104 _InitToolTips: function () { 105 const self = this; 106 const jElement = $(self.element); 107 const lHelpTextMap = []; 108 109 jElement.find(".fbcms_form_helptext").each(function (_index, aElement) //ignore jslint 110 { 111 const jHelpTextDiv = $(aElement); 112 lHelpTextMap["field" + jHelpTextDiv.data("field_id")] = [jHelpTextDiv.data("title"), jHelpTextDiv.html()]; 113 }); 114 115 jElement.find('.fbcms_custom_form_help').FoxToolTip({ 116 getInfo: (topic_id) => lHelpTextMap ? lHelpTextMap[topic_id] : '' 117 }); 118 }, 119 120 /// <summary> 121 /// Called after a file is uploaded to the server. 122 /// </summary> 123 /// <param name="uploader">The uploader object doing the work.</param> 124 /// <param name="files">The set uploaded files.</param> 125 _UploadCompleteCallback: function (uploader, files) //ignore jslint 126 { 127 const self = this; 128 const jElement = $(self.element); 129 130 if (files !== null) { 131 for (let fileIndex = 0; fileIndex < files.length; fileIndex += 1) { 132 const fileNameId = 'UploadedFiles[' + files[fileIndex].id + '].FileName'; 133 const fileNameInput = $('<input>').attr({ 134 type: 'hidden', 135 id: fileNameId, 136 name: fileNameId, 137 value: files[fileIndex].name 138 }); 139 140 const targetNameId = 'UploadedFiles[' + files[fileIndex].id + '].TargetName'; 141 const targetNameInput = $('<input>').attr({ 142 type: 'hidden', 143 id: targetNameId, 144 name: targetNameId, 145 value: files[fileIndex].target_name 146 }); 147 148 const idId = 'UploadedFiles[' + files[fileIndex].id + '].Id'; 149 const idInput = $('<input>').attr({ 150 type: 'hidden', 151 id: idId, 152 name: idId, 153 value: files[fileIndex].id 154 }); 155 156 jElement.find("div.put_hidden_fields_here") 157 .append(fileNameInput) 158 .append(targetNameInput) 159 .append(idInput); 160 } 161 } 162 163 self._ProcessNextUploadOrSubmit(); 164 }, 165 166 /// <summary> 167 /// Custom initialization for an uploader specific to this widget. 168 /// </summary> 169 /// <param name="uploader">The uploader to modify.</param> 170 _CustomUploaderSetup: function (uploader) { 171 const self = this; 172 uploader.bind('UploadComplete', function (uploader, files) { 173 self._UploadCompleteCallback(uploader, files); 174 }); 175 }, 176 177 /// <summary> 178 /// Configures a single upload element. 179 /// </summary> 180 /// <param name="element">The upload element to prepare.</param> 181 _SetupUploadElement: function (element) { 182 const self = this; 183 const jElement = $(self.element); 184 const jUploadElement = $(element); 185 const maxFileUploads = jUploadElement.data("max-file-uploads"); 186 187 jUploadElement.FormContentUploader({ 188 max_file_count: maxFileUploads, 189 form: jElement, 190 filters: 191 { 192 mime_types: [ 193 {title: "Allowed Files", extensions: jUploadElement.data("allowed-file-extensions")}, 194 {title: "Zip files", extensions: "zip"} 195 ], 196 max_file_size: '250mb', 197 prevent_duplicates: false 198 }, 199 customSetup: function (uploader) {self._CustomUploaderSetup(uploader);} 200 }); 201 }, 202 203 /// <summary> 204 /// Create and intialize all uploaders. 205 /// </summary> 206 _InitFileUploaders: function () { 207 const self = this; 208 $(self.element).find(".file_upload").each(function () { 209 self._SetupUploadElement(this); 210 }); 211 }, 212 213 /// <summary> 214 /// Cycles thru all the upload fields on the form. Uploads for each upload field are processed. Once all 215 /// upload fields are processed the form is submitted. 216 /// </summary> 217 _ProcessNextUploadOrSubmit: function () { 218 const self = this; 219 220 if (self._fileUploadsToProcess !== undefined && self._fileUploadsToProcess.length > 0) { 221 for (let lUploader = self._fileUploadsToProcess.pop(); lUploader !== undefined; lUploader = self._fileUploadsToProcess.pop()) { 222 if ($(lUploader).FormContentUploader("start")) { 223 return; 224 } 225 } 226 } 227 228
229 const data = $(self.element).serialize(); 230 const formid = $(self.element).data("formid"); 231 232 $.ajax({ 233 url: `/Core/Forms/Submit/${formid}`, 234 type: 'post', 235 dataType: 'json', 236 data: data, 237 success: function (data) { 238 if (data.Success !== true) { 239 $(self.element).find("input.submit_button").removeAttr("disabled"); 240 $(self.element).find('.fbcms_custom_form_errormessage').html(data.Message); 241 } 242 else if (data.Reason === "redirect") { 243 document.location = data.Message; 244 } 245 else { 246 $(self.element).find('.formwrapper').hide(); 247 $(self.element).find('.messagewrapper').html(data.Message); 248 } 249 }, 250 error: function (jqXHR, textStatus, errorThrown) { 251 console.error(`Failed to submit: ${textStatus} ${errorThrown}`); 252 $(self.element).find("input.submit_button").removeAttr("disabled"); 253 $(self.element).find('.fbcms_custom_form_errormessage').html("Unable to submit the form at this time."); 254 } 255 }); 256 }, 257 258 _completeSubmit: function () { 259 const $element = $(this.element); 260 $element.find(".fbcms_custom_form_errormessage").html(""); 261 this._fileUploadsToProcess = $element.find(".file_upload").toArray(); 262 this._ProcessNextUploadOrSubmit(); 263 return; 264 }, 265 266 /// <summary> 267 /// Validates, prepares, and submits the form upon clicking the submit button. 268 /// </summary> 269 _HandleFormSubmit: function (e) { 270 const self = this; 271 const $element = $(this.element); 272 const $submitButton = $element.find("input.submit_button"); 273 274 e.preventDefault(); 275 276 if ($submitButton.attr('disabled')) { 277 return; 278 } 279 280 $submitButton.attr('disabled', true); 281 282 let formCheckOk = $element.vpformchecker('checkForm'); 283 284 $element.find(".file_upload").each(function (_index, element) { 285 const $myElement = $(element); 286 const lValidation = $myElement.data("validation-mode"); 287 288 if (lValidation === "required") { 289 let uploaderCheckOk = $myElement.FormContentUploader("haveFile"); 290 if (!uploaderCheckOk) { 291 formCheckOk = false; 292 $myElement.closest('.fbcms_custom_form_field').removeClass('field_correct').addClass('field_warning'); 293 $(".fbcms_custom_form_errormessage").append( 294 "<div>Please select a file for the `" 295 + $(element).data("validation-title") 296 + "` field.</div>" 297 ); 298 } 299 else { 300 $myElement.closest('.fbcms_custom_form_field').removeClass('field_warning').addClass('field_correct'); 301 } 302 } 303 }); 304 305 306 if (formCheckOk) { 307 if (!self.options.UseRecaptcha) { 308 self._completeSubmit(); 309 return; 310 } 311 else if (self.options.RecaptchaSubType === 'V3Score') { 312 grecaptcha.ready(function () { 313 grecaptcha.execute(self.options.RecaptchaSiteKey, {action: 'submit'}) 314 .then(function (token) { 315 $element.find(`#${self.options.RecaptchaInputV3HtmlId}`).val(token); 316 self._completeSubmit(); 317 }); 318 }); 319 return; 320 } 321 else if (self.options.RecaptchaSubType === 'V2Invisible') { 322 grecaptcha.ready(function () { 323 grecaptcha.execute(self.grecaptcha_widget_id); 324 $submitButton.removeAttr('disabled'); 325 return; 326 }); 327 } 328 else { 329 self._completeSubmit(); 330 return; 331 } 332 } 333 334 $submitButton.removeAttr('disabled'); 335 }, 336 _additionalFormChecking: function () { 337 let success; 338 if (!this.options.UseRecaptcha) { 339 success = true; 340 } 341 else if (this.options.RecaptchaSubType !== "V2Checkbox") { 342 success = true; 343 } 344 else if (grecaptcha.getResponse(this.grecaptcha_widget_id)) { 345 $(`#${this.options.RecaptchaErrorV2HtmlId}`).html(''); 346 success = true; 347 } 348 else { 349 $(`#${this.options.RecaptchaErrorV2HtmlId}`).html('Please check the reCAPTCHA.'); 350 success = false; 351 } 352 return success; 353 }, 354 _waitForGrecaptcha: function () { 355 const self = this; 356 if (typeof grecaptcha !== "undefined") { 357 if (self.options.RecaptchaSubType === "V2Checkbox") { 358 try { 359 grecaptcha.ready(function () { 360 try { 361 self.grecaptcha_widget_id = grecaptcha.render(self.options.RecaptchaElementV2HtmlId, {'sitekey': self.options.RecaptchaSiteKey}); 362 } 363 catch (renderError) { 364 console.error(`grecaptcha.render raised an error: ${renderError}`); 365 } 366 }); 367 } 368 catch (readyError) { 369 console.error(`grecaptcha.ready raised an error: ${readyError}`); 370 } 371 } 372 else if (self.options.RecaptchaSubType === "V2Invisible") { 373 try { 374 375 grecaptcha.ready(function () { 376 try { 377 self.grecaptcha_widget_id = grecaptcha.render( 378 self.options.RecaptchaElementV2HtmlId, 379 { 380 'sitekey': self.options.RecaptchaSiteKey, 381 'size': "invisible", 382 'badge': "inline", 383 'callback': function (token) { 384 $(self.element).find("input.submit_button").attr('disabled', 'true'); 385 $(self.element).find(`#${self.options.RecaptchaInputV3HtmlId}`).val(token); 386 self._completeSubmit(); 387 } 388 }); 389 } 390 catch (renderError) { 391 console.error(`grecaptcha.render raised an error: ${renderError}`); 392 } 393 }); 394 } 395 catch (readyError) { 396 console.error(`grecaptcha.ready raised an error: ${readyError}`); 397 } 398 } 399 } 400 else { 401 setTimeout(function () { 402 self._waitForGrecaptcha(); 403 }, 250); 404 } 405 } 406 }); 407 408 /// <summary> 409 /// Prepares an upload area on a form for processing uploads. 410 /// </summary> 411 $.widget("ui.FormContentUploader", 412 { 413 /// <summary> 414 /// The PLUpload object backing this upload field. 415 /// </summary> 416 _uploader: undefined, 417 /// <summary> 418 /// FormContent widget options. 419 /// </summary> 420 options: 421 { 422 runtimes: 'html5,html4', 423 unique_names: true, 424 multi_selection: false, 425 max_file_count: 1, 426 form: undefined, 427 chunk_size: '1mb', 428 url: '/Core/PLUpload', 429 filters: 430 { 431 mime_types: [ 432 {title: "Allowed Files", extensions: 'jpg,jpeg,png,gif,svg,pdf,webp,avif'}, 433 {title: "Zip files", extensions: "zip"} 434 ], 435 max_file_size: '250mb', 436 prevent_duplicates: false 437 }, 438 customSetup: function () { 439 return undefined; 440 }, 441 dragdrop: true, 442 container: undefined, 443 browse_button: undefined 444 }, 445 446 /// <summary> 447 /// Called when widget is destroyed. 448 /// </summary> 449 _destroy: function () { 450 return undefined; 451 }, 452 453 /// <summary> 454 /// Called on widget init. 455 /// </summary> 456 _init: function () { 457 return undefined; 458 }, 459 460 /// <summary> 461 /// Updates the overall progress displayed on the upload field. 462 /// </summary> 463 _updateTotalProgress: function () { 464 const self = this; 465 const jElement = $(self.element); 466 467 $('.plupload_total_status', jElement).html(self._uploader.total.percent + '%'); 468 $('.plupload_progress_bar', jElement).css('width', self._uploader.total.percent + '%'); 469 470 const html = _('Uploaded %d/%d files').replace(/%d\/%d/, self._uploader.total.uploaded + '/' + self._uploader.files.length); 471 $('.plupload_upload_status', jElement).html(html); 472 }, 473 474 /// <summary> 475 /// Updates a files status as displayed on the screen. 476 /// </summary> 477 /// <param name="file">The file that was updated.</param> 478 _updateFileStatus: function (file) { 479 const self = this; 480 const jElement = $(self.element); 481 482 let actionClass; 483 if (file.status === plupload.DONE) { 484 actionClass = 'plupload_done'; 485 } 486 else if (file.status === plupload.FAILED) { 487 actionClass = 'plupload_failed'; 488 } 489 else if (file.status === plupload.QUEUED) { 490 actionClass = 'plupload_delete'; 491 } 492 else if (file.status === plupload.UPLOADING) { 493 actionClass = 'plupload_uploading'; 494 } 495 else { 496 actionClass = null; 497 } 498 499 const jIcons = $('#' + file.id, jElement); 500 jIcons.removeClass('plupload_done'); 501 jIcons.removeClass('plupload_failed'); 502 jIcons.removeClass('plupload_delete'); 503 jIcons.removeClass('plupload_uploading'); 504 if (actionClass) { 505 jIcons.addClass(actionClass); 506 } 507 508 const jIconLinks = jIcons.find('a'); 509 jIconLinks.css('display', 'block'); 510 511 if (file.hint) { 512 jIconLinks.attr('title', file.hint); 513 } 514 }, 515 516 /// <summary>
517 /// Adds a newly queue file to the list of files displayed on the screen. 518 /// </summary> 519 /// <param name="index">Position of this file with the set of all queued files. (zero based)</param> 520 /// <param name="file">The new file.</param> 521 _addFileToFileListing: function (index, file) { 522 const self = this; 523 const jElement = $(self.element); 524 525 let inputHTML = ''; 526 if (file.status === plupload.DONE) { 527 if (file.target_name) { 528 inputHTML += '<input type="hidden" name="' 529 + self.options.container 530 + '_' 531 + index 532 + '_tmpname" value="' 533 + plupload.xmlEncode(file.target_name) + '" />'; 534 } 535 536 inputHTML += '<input type="hidden" name="' 537 + self.options.container + '_' 538 + index 539 + '_name" value="' 540 + plupload.xmlEncode(file.name) 541 + '" />'; 542 543 inputHTML += '<input type="hidden" name="' 544 + self.options.container 545 + '_' 546 + index 547 + '_status" value="' 548 + (file.status === plupload.DONE ? 'done' : 'failed') 549 + '" />'; 550 551 $('#' + self.options.container + '_count', jElement).val(index + 1); 552 } 553 554 $('.plupload_filelist', jElement).append( 555 '<div class="fbcms_table_row uploadfile_row" id="' + file.id + '">' 556 + '<span class="fbcms_table_cell plupload_file_name"><span>' + file.name + '</span></span>' 557 + '<span class="fbcms_table_cell text-right plupload_file_size">' + plupload.formatSize(file.size) 558 + '</span>' 559 + '<span class="fbcms_table_cell text-right plupload_file_status">' + file.percent + '%</span>' 560 + '<span class="fbcms_table_cell text-right plupload_file_action">' 561 + '<button type="button"><span class="screen-reader-text">Delete</span></button>' 562 + inputHTML 563 + '</span>' 564 + '</div>' 565 ); 566 567 self._updateFileStatus(file); 568 569 $('#' + file.id + '.plupload_delete button', jElement).on('click', function (e) { 570 e.preventDefault(); 571 572 let jRowDiv = $('#' + file.id, jElement); 573 let jPrevDiv = jRowDiv.prev(); 574 let jNextDiv = jRowDiv.next(); 575 let focusElementSelector = null; 576 577 if (jPrevDiv.length > 0) { 578 focusElementSelector = "#" + jPrevDiv.attr('id') + " button"; 579 } 580 else if (jNextDiv.length > 0) { 581 focusElementSelector = "#" + jNextDiv.attr('id') + " button"; 582 } 583 else { 584 focusElementSelector = '#' + self.options.container + '_upload_browse'; 585 } 586 587 jRowDiv.trigger('blur'); 588 jRowDiv.remove(); 589 self._uploader.removeFile(file); 590 $(focusElementSelector).focus(); 591 }); 592 593 }, 594 595 /// <summary> 596 /// Rebuilds the file list displayed on the screen. 597 /// </summary> 598 _updateFileListing: function () { 599 const self = this; 600 const jElement = $(self.element); 601 const jFileList = $('.plupload_filelist', jElement); 602 603 jFileList.html(''); 604 $.each(self._uploader.files, function (index, file) {self._addFileToFileListing(index, file);}); 605 606 $('.plupload_total_file_size', jElement).html(plupload.formatSize(self._uploader.total.size)); 607 $('.plupload_add_text', jElement).html("Select File"); 608 609 $('.plupload_start', jElement).toggleClass( 610 'disabled', 611 self._uploader.files.length === (self._uploader.total.uploaded + self._uploader.total.failed) 612 ); 613 614 const maxFileUploads = self._uploader.settings.max_file_count; 615 const currentUploads = self._uploader.files.length; 616 617 $('.file_upload_button', jElement).prop('disabled', maxFileUploads <= currentUploads); 618 619 if (maxFileUploads == 0) { 620 $('.plupload_maximum_count', jElement).text(``); 621 } 622 else { 623 $('.plupload_maximum_count', jElement).text(`${currentUploads} of ${maxFileUploads} selected`); 624 } 625 626 // Scroll to end of file list 627 jFileList[0].scrollTop = jFileList[0].scrollHeight; 628 629 self._updateTotalProgress(); 630 631 // Re-add drag message if there is no files 632 if (!self._uploader.files.length && self._uploader.features.dragdrop && self._uploader.settings.dragdrop) { 633 $('#' + self.options.container + '_filelist', jElement).append('<li class="plupload_droptext">' + _("Drag files here.") + '</li>'); 634 } 635 }, 636 637 /// <summary> 638 /// Highlights the file the is about to be uploaded. 639 /// </summary> 640 _highlightCurrentUploadFile: function (up, file) //ignore jslint 641 { 642 const self = this; 643 const jElement = $(self.element); 644 $('#' + file.id, jElement).addClass('plupload_current_file'); 645 }, 646 647 /// <summary> 648 /// Starts editing of a name. 649 /// </summary> 650 /// <param name="nameElement">Element containing the name to change.</param> 651 _startRenameFile: function (nameElement) { 652 const targetSpan = $(nameElement); 653 const self = this;
654 const file = self._uploader.getFile(targetSpan.parents('li')[0].id); 655 const parts = /^(.+)(\.[^.]+)$/.exec(file.name); 656 657 let ext; 658 let name; 659 if (parts) { 660 name = parts[1]; 661 ext = parts[2]; 662 } 663 else { 664 name = file.name; 665 ext = ""; 666 } 667 668 // Display input element 669 targetSpan.hide().after('<input type="text" />'); 670 targetSpan.next().val(name) 671 .focus() 672 .on('blur', function () { 673 targetSpan.show().next().remove(); 674 }) 675 .on('keydown', function (e) { 676 const targetInput = $(this); 677 678 if ($.inArray(e.keyCode, [13, 27]) !== -1) { 679 e.preventDefault(); 680 681 // Rename file and glue extension back on 682 if (e.keyCode === 13) { 683 file.name = targetInput.val() + ext; 684 targetSpan.html(file.name); 685 } 686 targetInput.trigger('blur'); 687 } 688 }); 689 }, 690 691 692 /// <summary> 693 /// Initializes the plupload uploader object. 694 /// </summary> 695 _initializeUploader: function () { 696 const self = this; 697 const jElement = $(self.element); 698 699 // Enable rename support 700 if (!self._uploader.settings.unique_names && self._uploader.settings.rename) { 701 jElement.on('click', `#${self.options.container}_filelist .plupload_file_name span`, function (e) { 702 self._startRenameFile(e.target); 703 }); 704 } 705 706 self._uploader.settings.browse_button = self.options.container + '_upload_browse'; 707 708 // Enable drag/drop. 709 if (self._uploader.features.dragdrop && self._uploader.settings.dragdrop) { 710 self._uploader.settings.drop_element = self.options.container + '_filelist'; 711 $('#' + self.options.container + '_filelist', jElement).append('<li class="plupload_droptext">' + _("Drag files here.") + '</li>'); 712 } 713 714 $('.plupload_start', jElement).on('click', function (e) { 715 e.preventDefault(); 716 if (!$(e.target).hasClass('disabled') && jElement.vpformchecker('checkForm')) { 717 self._uploader.start(); 718 } 719 }); 720 721 $('.plupload_stop', jElement).on('click', function (e) { 722 e.preventDefault(); 723 self._uploader.stop(); 724 }); 725 726 $('.plupload_start', jElement).addClass('disabled'); 727 }, 728 729 /// <summary> 730 /// Displays an error encountered by the uploader. 731 /// </summary> 732 /// <param name="up">Reference to the uploader.</param> 733 /// <param name="err">Object describing the error.</param> 734 _displayUploaderError: function (up, err) { 735 const self = this; 736 const jElement = $(self.element); 737 const file = err.file 738 739 if (file) { 740 let message = err.message; 741 742 if (err.details) { 743 message += " (" + err.details + ")"; 744 } 745 746 if (err.code === plupload.FILE_SIZE_ERROR) { 747 alert(_("Error: File too large: ") + file.name); 748 } 749 750 if (err.code === plupload.FILE_EXTENSION_ERROR) { 751 alert(_("Error: Invalid file extension: ") + file.name); 752 } 753 754 file.hint = message; 755 $('#' + file.id, jElement).attr('class', 'plupload_failed').find('a').css('display', 'block').attr('title', message); 756 } 757 }, 758 759 /// <summary> 760 /// Updates the display when the state of the uploader changes. 761 /// </summary> 762 _uploaderStateChanged: function (uploader) { 763 const self = this; 764 const jElement = $(self.element); 765 766 if (self._uploader.state === plupload.STARTED) { 767 $('.plupload_delete a,.plupload_buttons', jElement).hide(); 768 $('.plupload_upload_status,.plupload_progress,.plupload_stop', jElement).css('display', 'block'); 769 if (self._uploader.settings.multi_selection) { 770 $('.plupload_total_status,.plupload_total_file_size', jElement).show(); 771 } 772 } 773 else {
774 self._updateFileListing(); 775 $('.plupload_stop, .plupload_progress', jElement).hide(); 776 $('.plupload_delete', jElement).css('display', 'block'); 777 } 778 }, 779 780 /// <summary> 781 /// Updates the displayed status of a file that has just been uploaded. 782 /// </summary> 783 /// <param name="up">The uploader.</param> 784 /// <param name="file">The newly uploaded file.</param> 785 _fileUploaded: function (up, file) //ignore jslint 786 { 787 const self = this; 788 self._updateFileStatus(file); 789 }, 790 791 /// <summary> 792 /// Displays the program made in uploading a file. 793 /// </summary> 794 /// <param name="up">Reference to the uploader.</param> 795 /// <param name="file">The file being uploaded.</param> 796 _updateUploadProgress: function (up, file) //ignore jslint 797 { 798 const self = this; 799 const jElement = $(self.element); 800 801 // Set file specific progress 802 $('#' + file.id + ' .plupload_file_status', jElement).html(file.percent + '%'); 803 804 self._updateFileStatus(file); 805 self._updateTotalProgress(); 806 807 if (self._uploader.settings.multi_selection && self._uploader.total.uploaded + self._uploader.total.failed === self._uploader.files.length) { 808 $(".plupload_buttons,.plupload_upload_status", jElement).css("display", "inline"); 809 $(".plupload_start", jElement).addClass("disabled"); 810 $('.plupload_total_status,.plupload_total_file_size', jElement).hide(); 811 } 812 }, 813 814 /// <summary> 815 /// Called to create this widget. 816 /// </summary> 817 _create: function () { 818 const self = this; 819 const jElement = $(self.element); 820 821 if (self.options.container === undefined) { 822 self.options.container = jElement.attr('id'); 823 if (self.options.container === undefined) { 824 self.options.container = plupload.guid(); 825 jElement.attr('id', self.options.container); 826 } 827 } 828 829 self.options.browse_button = self.options.container + "_upload_browse"; 830 self._uploader = new plupload.Uploader(self.options); 831 832 self._uploader.bind("UploadFile", function (up, file) { 833 self._highlightCurrentUploadFile(up, file); 834 }); 835 self._uploader.bind('Init', function (up) { 836 self._initializeUploader(up); 837 }); 838 self._uploader.bind('PostInit', function ( /*uploader*/) { 839 const maxFileUploads = jElement.data("max-file-uploads"); 840 buttonLabel = (maxFileUploads === 1) ? "Select File" : "Add Files"; 841 $(self.element).find('input[type=file]').attr('aria-label', buttonLabel); 842 }); 843 self._uploader.bind("Error", function (up, err) { 844 self._displayUploaderError(up, err); 845 }); 846 self._uploader.init(); 847 self._uploader.bind('StateChanged', function (uploader) { 848 self._uploaderStateChanged(uploader); 849 }); 850 self._uploader.bind('QueueChanged', function (up, file) { 851 self._updateFileListing(up, file); 852 }); 853 self._uploader.bind('FileUploaded', function (up, file) { 854 self._fileUploaded(up, file); 855 }); 856 self._uploader.bind("UploadProgress", function (up, file) { 857 self._updateUploadProgress(up, file); 858 }); 859 860 self._uploader.bind("FilesAdded", function (uploader, files) { 861 const maxFileUploads = uploader.settings.max_file_count; 862 const currentUploads = uploader.files.length; 863 if (maxFileUploads < currentUploads) { 864 alert(`Only ${maxFileUploads} file uploads are allowed.`); 865 uploader.splice(maxFileUploads); 866 } 867 }); 868 869 self._uploader.refresh();
869 // Reposition Flash/Silverlight 870 871 // Call customSetup function 872 if (self.options.customSetup !== undefined && (typeof self.options.customSetup === 'function')) { 873 self.options.customSetup(self._uploader); 874 } 875 }, 876 877 start: function () { 878 let started = false; 879 if (this._uploader && this._uploader.files.length > 0) { 880 this._uploader.start(); 881 started = true; 882 } 883 return started; 884 }, 885 haveFile: function () { 886 return (this._uploader && this._uploader.files.length !== 0); 887 } 888 }); 889}(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.