1jQuery(document).ajaxError(function (e, xhr, settings) { 2 if (window._env == "web") { 3 //global login redirect 4 if (xhr.status == 401) { 5 //if a it's from exchange server, prevent redirection 6 if (xhr.url && xhr.url.indexOf("/api/v1/hostedstorage/") > -1) { 7 return; 8 } 9 if (xhr.getResponseHeader("x-auth-changed") == "true") { 10 if (xhr.authChanged) 11 return; 12 xhr.authChanged = true; 13 alertMessage("USER_AUTHENTICATION_CHANGED"); 14 } 15 else { 16 var logoutUrl = AppUrls.Logout + "?ClientId=" + $("#hdnClientId").val(); 17 if (xhr.responseJSON != null && xhr.responseJSON.errorCode != null) { 18 logoutUrl = logoutUrl + "&errorCode=" + xhr.responseJSON.errorCode; 19 } else { 20 logoutUrl = logoutUrl + "&errorCode=e2006"; 21 } 22 window.location.href = logoutUrl; 23 } 24 25 } 26 else if (xhr.status == 424) { 27 if (xhr.responseJSON != null && xhr.responseJSON.errorCode != null) { 28 if (xhr.responseJSON.errorCode == "LINKED_SERVER_CONNECTION_FAILURE") { 29 showEmptySearch(true); 30 } 31 } 32 } 33 else if (xhr.status == 409) { 34 if (xhr.responseJSON != null && xhr.responseJSON.errorCode != null) { 35 if (xhr.responseJSON.errorCode == "FOLDER_NOT_FOUND") { 36 notify("error", getMessage("ROOT_FOLDER_NOT_FOUND"), "#file-list", true); 37 } 38 } 39 } 40 else if (xhr.status == 404) { //Fixed dom-based vulnarabilities found in burp scan: Data is read from window.location.href and passed to window.location.href via the following statements: 41 if (settings.suppressNotFound) 42 return; 43 var url = new URL(xhr.url); 44 if (url.origin != window.location.origin) 45 return; 46 var siteurl = window.location.origin; 47 var lite = "/lite/"; 48 if (window.location.pathname.toLowerCase().indexOf(lite) == 0) { 49 siteurl = window.location.origin + lite; 50 } else { 51 siteurl = siteurl + "/"; 52 } 53 window.location.href = siteurl + "404"; 54 } 55 else if (xhr.status == 500) { 56 var err = getMessage("e1000"); 57 if (jQuery("#response").length == 0) { 58 fasTable.toast.show("Error", err); 59 } else { 60 notify("error", getMessage("e1000"), '#response', true); 61 } 62 } 63 } 64 else if (window._env == "guest") { 65 if (xhr.status == 401) { 66 window.location.reload(); 67 } 68 } 69 70}); 71 72jQuery.ajaxSetup({ 73 beforeSend: function (xhr, settings) { 74 if (settings.url.indexOf('api.autodesk.com') == -1) 75 xhr.setRequestHeader("x-uid", window._xuid); 76 } 77}); 78 79var ajax = function (obj) { 80 if (obj.method === "POST") { 81 //add token if not set 82 obj.headers = obj.headers || {}; 83 obj.headers["X-CSRF-TOKEN"] = obj.headers["X-CSRF-TOKEN"] || window._xsrf; 84 } 85 var override = jQuery.extend({ 86 beforeSend: function (request, settings) { 87 if (obj.headers && !isAws(obj.url)) { 88 for (var key in obj.headers) { 89 if (key.toLowerCase() == "host") { 90 delete obj.headers[key]; 91 continue; 92 } 93 request.setRequestHeader(key, obj.headers[key]); 94 } 95 } 96 97 request.setRequestHeader("x-uid", window._xuid); 98 request.url = settings.url; 99 }, 100 cache: false, 101 processData: obj.method !== "PUT" 102 }, obj); 103 var xhr = null; 104 var promise = new Promise(function (resolve, reject) { 105 override.success = function (data) { 106 resolve(data); 107 } 108 override.error = function (err) { 109 if (obj.notifyPanel && err.responseJSON && err.responseJSON.errorCode) { 110 notify("error", getMessage(err.responseJSON.errorCode, err.responseJSON.data), obj.notifyPanel); 111 } 112 reject(err); 113 } 114 xhr = jQuery.ajax(override); 115 });
116 promise.abort = function () { 117 promise.catch(function (ex) { 118 //do nothing 119 }); 120 xhr.abort(); 121 } 122 promise.xhr = xhr; 123 return promise; 124} 125jQuery.fn.serializeObject = function () { 126 var o = {}; 127 var a = this.serializeArray(); 128 $.each(a, function () { 129 if (o[this.name]) { 130 if (!o[this.name].push) { 131 o[this.name] = [o[this.name]]; 132 } 133 o[this.name].push(this.value || ''); 134 } else { 135 o[this.name] = this.value || ''; 136 } 137 }); 138 return o; 139}; 140 141var isFunction = function (variable) { 142 return variable && typeof (variable) == "function"; 143} 144var notify = function (type, msg, target, hideClose) { 145 var element = jQuery("<div role='alert' />"); 146 var alertType = "fade show alert alert-dismissible error-div-notify"; 147 element.addClass(alertType); 148 if (type == "error") { 149 element.addClass("alert-danger"); 150 element.append("<span class='fa fa-exclamation-circle text-danger me-2'></span>"); 151 } 152 else if (type == "success") { 153 element.addClass("alert-success"); 154 element.append("<span class='fa fa-check-circle me-2 text-success'></span>"); 155 } 156 else if (type == "info") { 157 element.addClass("alert-secondary"); 158 element.append("<span class='fa fa-info-circle me-2'></span>"); 159 } 160 else if (type == "warning") { 161 element.addClass("alert-warning"); 162 element.append("<span class='fa fa-exclamation-triangle me-2'></span>"); 163 } 164 element.append("<span>" + msg + "</span>"); 165 if (!hideClose) { 166 var close = jQuery( 167 '<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>'); 168 element.append(close); 169 } 170 171 if (target) { 172 jQuery(target).html(""); 173 jQuery(target).append(element); 174 } else { 175 jQuery("body").append(element); 176 element.css("top", 10); 177 element.fadeIn(); 178 } 179} 180var showFormLoader = function (formId, loaderSize, message) { 181 if (!formId.startsWith('#')) { 182 formId = '#' + formId; 183 } 184 var spinner = loaderSize == 'm' 185 ? '<span style="font-size:50px" class="fas fa-spinner fa-pulse"></span>' 186 : '<span class="fas fa-spinner fa-pulse"></span>'; 187 var msgHtml = message 188 ? '<div class="ajax-grayout-loader-message mt-2 px-3">' + $('<div/>').text(message).html() + '</div>' 189 : ''; 190 jQuery(formId).append('<div class="ajax-grayout-loader" style="flex-direction:column">' + spinner + msgHtml + '</div>'); 191} 192var setFormLoaderMessage = function (formId, message) { 193 if (!formId.startsWith('#')) { 194 formId = '#' + formId; 195 } 196 var $loader = jQuery(formId).find(".ajax-grayout-loader"); 197 if (!$loader.length) { 198 return; 199 } 200 var $msg = $loader.find('.ajax-grayout-loader-message'); 201 if (!$msg.length) { 202 $loader.append('<div class="ajax-grayout-loader-message mt-2 px-3"></div>'); 203 $msg = $loader.find('.ajax-grayout-loader-message'); 204 } 205 $msg.text(message || ''); 206} 207var hideFormLoader = function (formId) { 208 if (!formId.startsWith('#')) { 209 formId = '#' + formId; 210 } 211 jQuery(formId).find(".ajax-grayout-loader").remove(); 212} 213var markErrorField = function (element) { 214 let $element = element; 215 if (!(element instanceof jQuery)) { 216 $element = $(element); 217 } 218 $element.addClass('error-field'); 219 $element.focus(); 220} 221var initAjaxForm = function (formId, options) { 222 formId = "#" + formId; 223 var submitter = null; 224 options = jQuery.extend({}, 225 { 226 extraData: null, 227 expectsHtmlResponse: false, 228 onError: function () { }, 229 onSuccess: function () { } 230 }, 231 options); 232 jQuery(formId).submit(function (e) { 233 submitter = e.originalEvent ? e.originalEvent.submitter : null; 234 e.preventDefault(); 235 }) 236 .validate({ 237 invalidHandler: options.invalidHandler, 238 submitHandler: function (form) { 239 var extraData = options.extraData; 240 if (isFunction(options.extraData)) { 241 extraData = options.extraData(); 242 if (!extraData) { 243 if (options.onError) 244 options.onError(); 245 return; 246 } 247 } 248 //get form object 249 var object = jQuery(form).serializeObject(); 250 //add additional parameters 251 object = jQuery.extend(object, extraData); 252 if (options.beforeSubmit) { 253 if (!options.beforeSubmit(object)) 254 return; 255 } 256 var method = jQuery(form).attr("method") || "post"; 257 var action = jQuery(form).attr("action") || window.location.href; 258 259 var submitBtn = jQuery(form).find("button[type=submit]:focus"); 260 261 if (submitBtn) { 262 var formAction = submitBtn.attr('formAction'); 263 if (formAction) 264 action = formAction; 265 } 266 267 var enableControls = function () { 268 //remove loader 269 hideFormLoader(formId); 270 }; 271 272 var disableControls = function () { 273 //Create loader 274 showFormLoader(formId, options.loaderSize) 275 }; 276 277 jQuery(formId).find('[name]').removeClass('error-field'); 278 disableControls(); 279 var ajaxOptions = { 280 url: action, 281 data: object, 282 method: method 283 }; 284 if (options.notifyPanel) { 285 jQuery(options.notifyPanel).html(""); 286 } 287 ajax(ajaxOptions) 288 .then(function (response) { 289 enableControls(); 290 if (options.expectsHtmlResponse || !response.responseJSON || response.success) { 291 if (options.onSuccess) 292 options.onSuccess(response, submitter); 293 } else { 294 295 if (options.notifyPanel && response.errorCode) { 296 notify("error", getMessage(response.errorCode, response.data), options.notifyPanel); 297 } 298 299 if (options.onError) { 300 options.onError(response, submitter); 301 } 302 } 303 }) 304 .catch(function (response) { 305 if (response.responseJSON) 306 response = response.responseJSON; 307 enableControls(); 308 if (options.notifyPanel && response.errorCode) { 309 if (options.disableNotifyError && options.disableNotifyError.includes(response.errorCode)) { 310 //no notify // its us in folder properties confirmation window 311 } else { 312 notify("error", getMessage(response.errorCode, response.data), options.notifyPanel); 313 } 314 315 if (response.errorCodes) { 316 var fileds = Object.keys(response.errorCodes); 317 if (fileds.length > 0) { 318 var fieldName = fileds[0]; 319 fieldName = fieldName.charAt(0).toUpperCase() + fieldName.slice(1); 320 if (fieldName.includes('.')) { 321 let fieldId = fieldName.replace('.', '_'); 322 $fieldName = $(formId).find('#' + fieldId); 323 } else { 324 $fieldName = $(formId).find('[name=' + fieldName + ']'); 325 } 326 markErrorField($fieldName); 327 } 328 } 329 } 330 if (options.onError) 331 options.onError(response, submitter); 332 }); 333 }, 334 errorPlacement: options.errorPlacement 335 }); 336 337 //add step false for input time as it conflicts with jquery validation plugin 338 jQuery(formId + ' input[type="time"]').each(function () { jQuery(this).rules('add', { step: fal
338se }); }); 339} 340 341var isHosted = function (url) { 342 return url.indexOf("hostedstorage") != -1; 343} 344 345var isRelativeHosted = function (url) { 346 return url.startsWith("/"); 347} 348var isAws = function (url) { 349 return url.indexOf("amazonaws") != -1; 350} 351var isAzureFileShare = function (url) { 352 return url.indexOf("file.core.windows.net") != -1; 353} 354var isAzureBlob = function (url) { 355 return url.indexOf("blob.core.windows.net") != -1; 356} 357var getSignedUrlForFile = function (verb, key, contentType, withHeaders, keyIsId, overwrite) { 358 var obj = { 359 verb: verb, 360 key: key, 361 contentType: contentType, 362 withHeaders: withHeaders, 363 overwrite: overwrite 364 }; 365 if (keyIsId) 366 obj.id = key; 367 return ajax({ 368 url: AppUrls.GetProviderCorsUrlForFile, 369 method: "POST", 370 data: obj, 371 dataType: "json" 372 }); 373} 374 375var getSignedUrlForFolder = function (fileRequests, parentPath, data, options) { 376 options = options || {}; 377 if (typeof _uploadAction == 'undefined') 378 _uploadAction = 0; 379 data = jQuery.extend({ 380 files: fileRequests, 381 parentPath: parentPath, 382 uploadAction: _uploadAction 383 }, data); 384 let ajaxHandle = ajax({ 385 url: options.fetchUrl || AppUrls.GetProviderCorsUrlForFolder, 386 method: "POST", 387 data: data, 388 dataType: "json" 389 }); 390 return ajaxHandle; 391} 392var getSignedUrlForProfile = function (fileRequests, parentPath, uploadAction) { 393 $("#error").html(""); 394 return ajax({ 395 url: AppUrls.GetCorsUploadUrlForProfile, 396 method: "POST", 397 data: { 398 files: fileRequests, 399 parentPath: parentPath, 400 uploadAction: uploadAction 401 }, 402 dataType: "json" 403 }); 404} 405var getSignedUrlForContactImage = function (fileRequests, parentPath, uploadAction) { 406 $("#error").html(""); 407 return ajax({ 408 url: AppUrls.createGetImageUploadUrl, 409 method: "POST", 410 data: { 411 files: fileRequests, 412 parentPath: parentPath, 413 uploadAction: uploadAction 414 }, 415 dataType: "json" 416 }); 417} 418 419var createChunks = function (file, cSize) { 420 let startPointer = 0; 421 let endPointer = file.size; 422 let chunks = []; 423 while (startPointer < endPointer) { 424 let newStartPointer = startPointer + cSize; 425 let chunk = file.slice(startPointer, newStartPointer); 426 chunk.dirPath = file.dirPath; 427 chunks.push(chunk); 428 startPointer = newStartPointer; 429 } 430 return chunks; 431} 432 433var blobUpload = function (signedUrl, headers, blob, onProgress, onError) { 434 var htmlFile = blob; 435 if (!isAws(signedUrl) && !isAzureBlob(signedUrl)) { 436 var formData = new FormData(); 437 formData.append("file", htmlFile); 438 blob = formData; 439 } 440 return ajax({ 441 url: signedUrl, 442 method: isHosted(signedUrl) ? "POST" : "PUT", 443 data: blob, 444 headers: isAws(signedUrl) ? null : headers, 445 cache: false, 446 contentType: isAws(signedUrl) || isAzureBlob(signedUrl) ? "multipart/form-data" : false, 447 error: onError, 448 processData: !isHosted(signedUrl), 449 xhr: function () { 450 var started_at = new Date(); 451 var xhr = new window.XMLHttpRequest(); 452 xhr.upload.addEventListener("progress", function (evt) { 453 if (evt.lengthComputable) { 454 var loaded = evt.loaded; 455 var total = evt.total; 456 var percentComplete = ((loaded / total) * 100).toFixed(2); 457 var seconds_elapsed = (new Date().getTime() - started_at.getTime()) / 1000; 458 var bytes_per_second = seconds_elapsed ? loaded / seconds_elapsed : 0; 459 var Kbytes_per_second = bytes_per_second / 1024; 460 var remaining_bytes = total - loaded; 461 var seconds_remaining = seconds_elapsed ? remaining_bytes / bytes_per_second : 'calculating'; 462 463 if (onProgress) 464 onProgress(percentComplete, secondsToString(seconds_remaining), Kbytes_per_second, loaded, total); 465 } 466 }, false); 467 xhr.onreadystatechange = function (e) { 468 if (xhr.readyState === 4) { 469 if (xhr.status == 200) { 470 percentComplete = 100; 471 } 472 } 473 } 474 return xhr; 475 } 476 });
477} 478 479var awsUpload = function (signedUrl, headers, file, fileRequest, onProgress, uploadSessionInfo, extraData, checkinComment) { 480 var htmlFile = file; 481 var fileSize = (file ? file.size : 0) || 0; 482 if (!isRelativeHosted(signedUrl) && !isAws(signedUrl) && !isAzureBlob(signedUrl) && !isAzureFileShare(signedUrl)) { 483 var formData = new FormData(); 484 formData.append("file", htmlFile); 485 file = formData; 486 } 487 488 if(headers) 489 //delete the host header 490 delete headers['host']; 491 var percentComplete = 0; 492 return ajax({ 493 url: signedUrl, 494 method: isHosted(signedUrl) || isRelativeHosted(signedUrl) ? "POST" : "PUT", 495 data: file, 496 cache: false, 497 processData: isRelativeHosted(signedUrl), 498 headers: isAws(signedUrl) ? null : headers, 499 contentType: isAws(signedUrl) || isAzureBlob(signedUrl) ? "multipart/form-data" : (isRelativeHosted(signedUrl) ? "application/x-www-form-urlencoded" : false), 500 xhrFields: { 501 withCredentials: isHosted(signedUrl) 502 }, 503 crossDomain: isHosted(signedUrl), 504 xhr: function () { 505 var started_at = new Date(); 506 var xhr = new window.XMLHttpRequest(); 507 var seconds_elapsed, bytes_per_second, Kbytes_per_second, remaining_bytes, seconds_remaining; 508 xhr.upload.addEventListener("progress", function (evt) { 509 if (evt.lengthComputable) { 510 511 var total = evt.total; 512 var percent = (evt.loaded / total); 513 percentComplete = (percent * 100).toFixed(2); 514 let loaded = percent * fileSize; 515 seconds_elapsed = (new Date().getTime() - started_at.getTime()) / 1000; 516 bytes_per_second = seconds_elapsed ? loaded / seconds_elapsed : 0; 517 Kbytes_per_second = bytes_per_second / 1024; 518 remaining_bytes = total - loaded; 519 seconds_remaining = seconds_elapsed ? remaining_bytes / bytes_per_second : 'calculating'; 520 521 if (onProgress) 522 onProgress(percentComplete, secondsToString(seconds_remaining), Kbytes_per_second, loaded); 523 } 524 }, false); 525 //if (window._env == "guest") { 526 // xhr.onreadystatechange = function (e) { 527 // if (xhr.readyState === 4) { 528 // if (xhr.status === 200 || xhr.status === 201) { 529 // percentComplete = 100; 530 // insertUploadActivity(htmlFile, fileRequest, seconds_elapsed, uploadSessionInfo, null, null, extraData, checkinComment); 531 // } 532 // } 533 // } 534 //} 535 536 return xhr; 537 } 538 }); 539} 540 541var insertUploadActivity = function (file, fileRequest, secondsElapsed, uploadSessionInfo, type, chunkNum, extraData, checkinComment) { 542 var data = jQuery.extend({ 543 fileName: file != null ? file.name : null, 544 fileSize: file != null ? file.size : null, 545 timeTakenInSeconds: Math.round(secondsElapsed), 546 uploadPath: fileRequest != null ? fileRequest.key : null, 547 SessionInfo: uploadSessionInfo, 548 uploadActivityType: type, 549 failedAtChunk: chunkNum, 550 CheckInComments: checkinComment 551 }, extraData); 552 ajax({ 553 url: AppUrls.InsertUploadActivity, 554 method: "POST", 555 data: data 556 }); 557} 558var sendCheckInUploadMail = function (fileKeyStr, parentPath, checkinEmail, checkinComments, isSendEmail, uploadSessionInfo) { 559 ajax({ 560 url: AppUrls.SendCheckinUploadMail, 561 method: "POST", 562 data: { 563 keySsv: fileKeyStr, 564 parentPath: parentPath, 565 checkinEmailAddress: checkinEmail, 566 checkinComments: checkinComments, 567 isSendCheckinEmail: isSendEmail, 568 SessionInfo: 'WEB-' + uploadSessionInfo 569 } 570 }).then(function (response) { 571 var fileKeys = fileKeyStr.split("\n"); 572 for (let i = 0; i < fileKeys.length; i++) { 573 let fetchSourcekey = fasTable.getObjectByKey(fileKeys[i]); 574 if (fetchSourcekey && fetchSourcekey.fileFolderProperties) { 575 fetchSourcekey.fileFolderProperties.isFileCheckedOut = false; 576 fasTable.updateObjectRow(fetchSourcekey, true); 577 } 578 } 579 580 });
581} 582var uploadPostProcess = function (fileKeyStr, parentPath, uploadSessionInfo) { 583 if (!uploadSessionInfo.startsWith("WEB-")) { 584 uploadSessionInfo = 'WEB-' + uploadSessionInfo; 585 } 586 ajax({ 587 url: AppUrls.PostUploadProcess, 588 method: "POST", 589 data: { 590 keySsv: fileKeyStr, 591 parentPath: parentPath, 592 SessionInfo: uploadSessionInfo 593 } 594 }); 595} 596function secondsToString(seconds) { 597 if (seconds <= 1) 598 return "processing uploaded item"; 599 var numyears = Math.floor(seconds / 31536000); 600 var numdays = Math.floor((seconds % 31536000) / 86400); 601 var numhours = Math.floor(((seconds % 31536000) % 86400) / 3600); 602 var numminutes = Math.floor((((seconds % 31536000) % 86400) % 3600) / 60); 603 var numseconds = (((seconds % 31536000) % 86400) % 3600) % 60; 604 var str = ""; 605 if (numyears > 0) 606 str += Math.round(numyears) + " " + Humanize.pluralize(numyears, "year", "years") + " "; 607 if (numdays > 0) 608 str += Math.round(numdays) + " " + Humanize.pluralize(numdays, "day", "days") + " "; 609 if (numhours > 0) 610 str += Math.round(numhours) + " " + Humanize.pluralize(numhours, "hour", "hours") + " "; 611 if (numminutes > 0) 612 str += Math.round(numminutes) + " " + Humanize.pluralize(numminutes, "minute", "minutes") + " "; 613 if (numseconds > 0) 614 str += Math.round(numseconds) + " " + Humanize.pluralize(numseconds, "second", "seconds"); 615 return str + " left"; 616 617} 618 619var initDownloadProgress = function (stopAutoClose, timeout, floatingIndicatorOption) { 620 timeout = timeout || 30; 621 let timerId = null; 622 let m = showAsModal('', 623 { 624 body: jQuery("#downloadProgress").clone().html(), 625 hideclose: true, 626 hideok: true, 627 hideHeader: true, 628 aftershow: function () { 629 m.find("#loader").html(typeof htmlJs != 'undefined' ? htmlJs.getMiniLoader() : fasModel.getMiniLoader()); 630 } 631 }); 632 633 m.on("hide.bs.modal", function (e) { 634 var hideEnable = m.data('hideEnable'); 635 return hideEnable == true; 636 }); 637 638 m.enableHide = function () { 639 m.data('hideEnable', true); 640 }; 641 642 m.close = function (clearIntreval = true) { 643 m.enableHide(); 644 m.modal('hide'); 645 if (clearIntreval) { 646 clearTimeout(timerId); 647 if (m.floatingIndicator) 648 m.floatingIndicator.close(); 649 } 650 }; 651 652 if (!stopAutoClose) { 653 //hide after 10 seconds 654 timerId = setTimeout(function () { 655 if (m) { 656 m.close(false); 657 if (floatingIndicatorOption) { 658 m.floatingIndicator = createFloatingIndicator(floatingIndicatorOption); 659 } 660 } 661 }, 10000) 662 } 663 else { 664 timerId = setTimeout(function () { 665 if (m) { 666 m.close(false); 667 668 if (floatingIndicatorOption) { 669 m.floatingIndicator = createFloatingIndicator(floatingIndicatorOption); 670 } 671 } 672 }, timeout * 1000) 673 } 674 return m; 675} 676 677function createFloatingIndicator(options) { 678 if (!options) 679 options = {}; 680 681 let defaults = { 682 centerIcon: 'fa-download', 683 }; 684 let settings = $.extend({}, defaults, options); 685 686 let btn = createElement('div', { 687 className: 'bg-secondary text-white cursor-pointer position-fixed bottom-0 end-0 m-4 rounded-circle shadow d-flex align-items-center justify-content-center', 688 style: 'width:50px;height:50px;z-index:1050;' 689 }); 690 let loader = createElement('span', { 691 className: 'position-relative d-inline-flex align-items-center justify-content-center', 692 style: 'width:32px;height:32px;' 693 }); 694 let spinner = createElement('span', { 695 className: 'spinner-border', 696 style: 'width:32px;height:32px;' 697 }); 698 let downloadIcon = createElement('i', { 699 className: settings.centerIcon + ' fa position-absolute top-50 start-50 translate-middle', 700 style: 'font-size:0.75rem;' 701 });
702 loader.appendChild(spinner); 703 loader.appendChild(downloadIcon); 704 btn.appendChild(loader); 705 btn.addEventListener('mouseenter', function () { 706 downloadIcon.classList.replace(settings.centerIcon, 'fa-times'); 707 $(btn).tooltip({ title: 'Close' }); 708 }); 709 btn.addEventListener('mouseleave', function () { 710 downloadIcon.classList.replace('fa-times', settings.centerIcon); 711 }); 712 btn.addEventListener('click', function () { 713 if (downloadIcon.classList.contains('fa-times')) { 714 $(btn).tooltip('dispose'); 715 btn.close(); 716 } 717 }); 718 btn.close = function () { 719 dispatchCustomEvent('close', null, btn); 720 btn.remove(); 721 } 722 $('body').append(btn); 723 return btn; 724}
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.