1var BaseHelper = { 2 uuid: 0, 3 setIfNotNull: (item, field, value) => { 4 if (item == null || value == null || item[field] == null) { 5 return; 6 } 7 item[field] = value; 8 }, 9 10 isNullOrUndefined(value) { 11 return value === null || value === undefined; 12 }, 13 14 // Earth's radius in kilometers and miles 15 EARTH_RADIUS_KM: 6371, 16 EARTH_RADIUS_MI: 3959, 17 extractNumbers: (str) => { 18 let result = ''; 19 let hasDecimal = false; 20 21 for (let i = 0; i < str.length; i++) { 22 const char = str[i]; 23 24 if (char >= '0' && char <= '9') { 25 result += char; 26 } else if (char === '.' && !hasDecimal) { 27 result += char; 28 hasDecimal = true; 29 } 30 } 31 32 return result; 33 }, 34 calculateGeoDistance: function (point1, point2, radius) { 35 // Convert latitude and longitude from degrees to radians 36 var lat1 = point1.lat * Math.PI / 180; 37 var lat2 = point2.lat * Math.PI / 180; 38 var deltaLat = (point2.lat - point1.lat) * Math.PI / 180; 39 var deltaLng = (point2.lng - point1.lng) * Math.PI / 180; 40 41 // Apply the Haversine formula 42 var a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) + 43 Math.cos(lat1) * Math.cos(lat2) * 44 Math.sin(deltaLng / 2) * Math.sin(deltaLng / 2); 45 var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); 46 47 // Distance in the unit corresponding to the given radius 48 var distance = radius * c; 49 50 return distance; 51 }, 52 53 insertOrGetLookupArr: function (lookup, key) { 54 let arr = lookup[key]; 55 if (arr == null) { 56 arr = lookup[key] = []; 57 } 58 return arr; 59 }, 60 61 getTags: function (data) { 62 data.tag = BaseHelper.DeserializeDataTableToObjects(data.tagRaw); 63 let listingTagKeyValueList = data.tag; 64 let tagKeyList = data.tagKey; 65 let tagKeyValueList = data.tagKeyValue; 66 let tagValueList = data.tagValue; 67 68 let tagList = []; 69 let tagValueLookupTagGroup = {}; 70 let keywordLookupTagGroup = {} 71 let idLookupTagKey = {}; 72 let idLookupTagValue = {}; 73 let idLookupTagKeyValue = {}; 74 let idLookupTag = {}; 75 76 let listingLookupTag = {}; 77 let tagLookupListing = {}; 78 79 tagKeyList.forEach((tagKey) => { 80 idLookupTagKey[tagKey.TagKeyId] = tagKey; 81 }); 82 83 tagValueList.forEach((tagValue) => { 84 idLookupTagValue[tagValue.TagValueId] = tagValue; 85 }); 86 87 tagKeyValueList.forEach((tagKeyValue) => { 88 idLookupTagKeyValue[tagKeyValue.TagKeyValueId] = tagKeyValue; 89 }); 90 91 listingTagKeyValueList.forEach((item) => { 92 let listingId = item.ListingID; 93 let tagKeyValueId = item.TagKeyValueID; 94 let tag = idLookupTag[tagKeyValueId]; 95 if (tag == null) { 96 let tkv = idLookupTagKeyValue[tagKeyValueId]; 97 if (tkv != null) { 98 let tk = idLookupTagKey[tkv.TagKeyId]; 99 let tv = idLookupTagValue[tkv.TagValueId]; 100 if (tk != null && tv != null) { 101 tag = { 102 TagKeyValueID: tagKeyValueId, 103 TagKeyID: tk.TagKeyId, 104 TagValueID: tv.TagValueId, 105 TagKey: tk.Name, 106 TagValue: tv.Name, 107 Keyword: tv.Name 108 }; 109 idLookupTag[tagKeyValueId] = tag; 110 tagList.push(tag); 111 //-------------------------------------------------------------------------------- 112 let tagGroup = BaseHelper.insertOrGetLookupArr(tagValueLookupTagGroup, tv.Name); 113 tagGroup.push(tag); 114 tagGroup = BaseHelper.insertOrGetLookupArr(keywordLookupTagGroup, tv.Name); 115 tagGroup.push(tag); 116 117 //--------------------------------------------------------------------------------- 118 //handle features 119 let tvLower = tv.Name.toLowerCase(); 120 let noneMatch = tvLower.match("none"); 121 let tkLower = tk.Name.toLowerCase(); 122 let featureMatch = tkLower.match("features"); 123 if ( 124 noneMatch == null 125 && featureMatch != null 126 && featureMatch.index != null 127 && featureMatch.index > 0 128 ) { 129 let keyword = tk.Name.substr(0, featureMatch.index); 130 tagGroup = BaseHelper.insertOrGetLookupArr(keywordLookupTagGroup, keyword); 131 let featureTag = structuredClone(tag); 132 featureTag.Keyword = keyword 133 tagGroup.push(featureTag); 134 } 135 136 } 137 } 138 } 139 //------------------------------------------------------------------------ 140 listingLookupTag[listingId] = tag; 141 let listingList = tagLookupListing[tagKeyValueId]; 142 if (listingList == null) { 143 listingList = []; 144 tagLookupListing[tagKeyValueId] = listingList; 145 } 146 listingList.push(listingId); 147 }); 148 149 let result = { 150 tagList: tagList, 151 tagValueLookupTagGroup: tagValueLookupTagGroup, 152 idLookupTagKey: idLookupTagKey, 153 idLookupTagKeyValue: idLookupTagKeyValue, 154 idLookupTagValue: idLookupTagValue, 155 listingLookupTag: listingLookupTag, 156 tagLookupListing: tagLookupListing, 157 keywordLookupTagGroup: keywordLookupTagGroup 158 }; 159 return result; 160 161 }, 162 163
164 setBackgroundImageWithFallback: function (containerElement, mainImagePath, loadingImagePath, errorImagePath) { 165 // Set the loading image initially 166 containerElement.style.backgroundImage = 'url(' + loadingImagePath + ')'; 167 168 var img = new Image(); 169 170 img.onload = function () { 171 // On successful load, set the main image as the background 172 containerElement.style.backgroundImage = 'url(' + mainImagePath + '), url(' + loadingImagePath + ')'; 173 }; 174 175 img.onerror = function () { 176 // On error, set the error image as the background 177 containerElement.style.backgroundImage = 'url(' + errorImagePath + '), url(' + loadingImagePath + ')'; 178 }; 179 180 // Start loading the main image 181 img.src = mainImagePath; 182 }, 183 184 //takes in an array of coordinates, and outputs the average positions 185 calculateAverageGeoPosition: function (coords) { 186 let sumX = 0, sumY = 0, sumZ = 0; 187 188 coords.forEach(coord => { 189 // Convert latitude and longitude from degrees to radians 190 let lat = coord.lat * Math.PI / 180; 191 let lng = coord.lng * Math.PI / 180; 192 193 // Convert from spherical to Cartesian coordinates 194 sumX += Math.cos(lat) * Math.cos(lng); 195 sumY += Math.cos(lat) * Math.sin(lng); 196 sumZ += Math.sin(lat); 197 }); 198 199 // Compute average Cartesian coordinates 200 let avgX = sumX / coords.length; 201 let avgY = sumY / coords.length; 202 let avgZ = sumZ / coords.length; 203 204 // Convert back to spherical coordinates 205 let avgLng = Math.atan2(avgY, avgX) * 180 / Math.PI; 206 let avgHyp = Math.sqrt(avgX * avgX + avgY * avgY); 207 let avgLat = Math.atan2(avgZ, avgHyp) * 180 / Math.PI; 208 209 // Return the average position 210 return { lat: avgLat, lng: avgLng }; 211 }, 212 213 calculateMedianPosition: function (coords) { 214 let lats = coords.map(p => p.lat).sort((a, b) => a - b); 215 let lngs = coords.map(p => p.lng).sort((a, b) => a - b); 216 217 let medianLat = lats[Math.floor(lats.length / 2)]; 218 let medianLng = lngs[Math.floor(lngs.length / 2)]; 219 220 // If even number of elements, average the two middle values 221 if (lats.length % 2 === 0) { 222 medianLat = (medianLat + lats[Math.floor(lats.length / 2) - 1]) / 2; 223 medianLng = (medianLng + lngs[Math.floor(lngs.length / 2) - 1]) / 2; 224 } 225 226 return { lat: medianLat, lng: medianLng }; 227 }, 228 229 capitalizeFirstLetter: (str) => { 230 return str[0].toUpperCase() + str.substr(1, str.length - 1) 231 }, 232 233 displayAddress: (listing) => { 234 if (listing.IdxFeedProviderID == 6 || listing.IdxFeedProviderID == 11 || listing.IdxFeedTypeID == 10 || listing.IdxFeedTypeID == 215) { 235 if (listing.InternetAddressDisplay == 0) { 236 return false; 237 } 238 } 239 return true; 240 }, 241 displayMapLink: (listing) => { 242 if (listing.IdxFeedTypeID == 10) { 243 if (listing.MapLink == 0) { 244 return false; 245 } 246 } 247 return true; 248 }, 249 250 getHouseSize: (record) => { 251 let result = "--"; 252 if (record.IdxFeedID == 54) { 253 return result; 254 } 255 let houseSize = record.HouseSize; 256 if (houseSize != null) { 257 result = houseSize + " sq.ft."; 258 } 259 return result; 260 }, 261 262 toTitleCase: (str) => { 263 str = str.toLowerCase(); 264 return str.replace(/\b(\w)/g, (match, p1) => p1.toUpperCase()); 265 }, 266 267 getLotSize: (record) => { 268 let result = "--"; 269 let lotSize = record.LotSize 270 if (lotSize != null) { 271 let fLotSize = parseFloat(lotSize); 272 let acres = (fLotSize / 43560).toFixed(2); 273 if (acres < 0.25) { 274 result = fLotSize.toFixed(0) + " sq.ft."; 275 } 276 else { 277 result = acres + " acres"; 278 } 279 } 280 return result; 281 }, 282 283 getLoadingImg: (style) => { 284 let loadingGif = document.createElement("img"); 285 if (style != null) { 286 for (let key in style) { 287 loadingGif.setAttribute("style", style) 288 } 289 } 290 loadingGif.src = "/img/blue-wheel-loading.gif";
291 return loadingGif; 292 }, 293 294 yield: async (time = 0) => { 295 return new Promise((resolve, reject) => { 296 window.setTimeout(() => { 297 resolve(); 298 }, time) 299 }) 300 }, 301 //bootstrap table 302 BT: { 303 getRowFromElement: (bt, element) => { 304 let index = BaseHelper.BT.getRowIndexFromElement(element); 305 if (index != null) { 306 return bt.bootstrapTable("getData")[index]; 307 } 308 return null; 309 }, 310 getRowIndexFromElement: (element) => { 311 let row = BaseHelper.getParentWithNodeNameFromElement(element, "TR"); 312 if (row != null) { 313 let index = row.getAttribute("data-index"); 314 if (index != null) { 315 return parseInt(index); 316 } 317 } 318 return null; 319 }, 320 getFieldIndexFromElement: (element) => { 321 let row = BaseHelper.getParentWithNodeNameFromElement(element, "TR"); 322 let cell = BaseHelper.getParentWithNodeNameFromElement(element, "TD"); 323 for (let i = 0; i < row.children.length; i++) { 324 let child = row.children[i]; 325 if (child == cell) { 326 return i; 327 } 328 } 329 return null; 330 } 331 }, 332 333 //grabs first parent with given node name. 334 getParentWithNodeNameFromElement: (element, nodeName) => { 335 let current = element 336 do { 337 let currentNodeName = current.nodeName.toUpperCase() 338 if (currentNodeName == nodeName.toUpperCase()) { 339 return current; 340 } 341 current = current.parentElement; 342 } while (current != null); 343 return null; 344 }, 345 346 WidgetReadyWait: async (w) => { 347 return new Promise((resolve, reject) => { 348 w.onReady(() => { 349 resolve(w); 350 }) 351 }) 352 },
353 //WARNINING, THIS FUNCTION DOES NOT HANDLE CIRCUMSTANCES WHERE THE COORDINATES CROSS THE 0 DEGREE 354 isPolygonInsideRectangle: (rect, poly) => { 355 if (rect == null || rect.length != 5) { 356 return null; 357 } 358 if (poly == null) { 359 return null; 360 } 361 let minX = null; 362 let maxX = null; 363 let minY = null; 364 let maxY = null; 365 ipt = BaseHelper.getPointXY(rect[0]); 366 minX = ipt.x; 367 maxX = ipt.x; 368 minY = ipt.y; 369 maxY = ipt.y; 370 for (let i = 1; i < rect.length; i++) { 371 let pt = BaseHelper.getPointXY(rect[i]); 372 minX = Math.min(minX, pt.x); 373 maxX = Math.max(maxX, pt.x); 374 minY = Math.min(minY, pt.y); 375 maxY = Math.max(maxY, pt.y); 376 } 377 for (let i = 0; i < poly.length; i++) { 378 let pt = BaseHelper.getPointXY(poly[i]); 379 if ( 380 pt.x < minX || 381 pt.x > maxX || 382 pt.y < minY || 383 pt.y > maxY 384 ) { 385 return false 386 } 387 } 388 return true; 389 }, 390 getNextPoint: (boundary, currentIndex, direction) => { 391 let nextIndex = currentIndex + direction; 392 while (nextIndex < 0) { 393 nextIndex = boundary.length + nextIndex; 394 } 395 while (nextIndex >= boundary.length) { 396 nextIndex = nextIndex - boundary.length; 397 } 398 return { 399 raw: boundary[nextIndex], 400 point: BaseHelper.getPointXY(boundary[nextIndex]), 401 index: nextIndex 402 } 403 }, 404 getPointXY: (b) => { 405 try { 406 let parts = b.split(','); 407 return { x: parseFloat(parts[0]), y: parseFloat(parts[1]) }; 408 } 409 catch (ex) { 410 throw ex; 411 } 412 }, 413 isBoundaryIdentical: (b0, b1) => { 414 if (b0.length == 0 && b1.length == 0) { 415 return true; 416 } 417 if (b0.length != b1.length) { 418 return false; 419 } 420 let i0 = { 421 raw: b0[0], 422 point: BaseHelper.getPointXY(b0[0]), 423 index: 0 424 }; 425 let i1 = null; 426 for (let i = 0; i < b1.length; i++) { 427 let ipt = BaseHelper.getPointXY(b1[i]); 428 if (ipt.x == i0.point.x && ipt.y == i0.point.y) { 429 i1 = { 430 raw: b1[i], 431 point: ipt, 432 index: i 433 } 434 break; 435 } 436 } 437 if (i1 == null) { 438 return false; 439 } 440 let direction = 1; 441 let next0 = BaseHelper.getNextPoint(b0, i0.index, 1); 442 let next1 = BaseHelper.getNextPoint(b1, i1.index, 1); 443 if (next0.point.x == next1.point.x && next0.point.y == next1.point.y) { 444 direction = 1; 445 } 446 else { 447 direction = -1 448 } 449 next0 = i0; 450 next1 = i1; 451 for (let i = 0; i < b0.length; i++) { 452 next0 = BaseHelper.getNextPoint(b0, next0.index, 1); 453 next1 = BaseHelper.getNextPoint(b1, next1.index, direction); 454 if (next0.point.x != next1.point.x || next0.point.y != next1.point.y) { 455 return false; 456 } 457 } 458 return true; 459 }, 460 isPromise: (p) => { 461 if ( 462 p !== null && 463 typeof p === 'object' && 464 typeof p.then === 'function' && 465 typeof p.catch === 'function' 466 ) { 467 return true; 468 } 469 return false; 470 }, 471 maxDaysInMonth: { 472 1: 31, 473 2: 29, 474 3: 31, 475 4: 30, 476 5: 31, 477 6: 30, 478 7: 31, 479 8: 31,
480 9: 30, 481 10: 31, 482 11: 30, 483 12: 31, 484 }, 485 486 displayException: true, 487 488 isStringNullOrWhiteSpace: function (s) { 489 if (typeof s !== 'string') { 490 //s is not a string, null, or a whitespace, so it returns false 491 return false; 492 } else if (typeof s === 'undefined' || s === null || s.trim() === '') { 493 return true; 494 } else { 495 return false; 496 } 497 }, 498 499 isOverflown(element) { 500 return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth; 501 }, 502 503 getTextFromHtml: function (html) { 504 if (html == null) { 505 return ""; 506 } 507 let buffer = document.createElement("div"); 508 buffer.innerHTML = html; 509 let result = buffer.innerText; 510 return result; 511 }, 512 GetBytesFromBlob: async function (blob, includeLength = true) { 513 return new Promise((resolve, reject) => { 514 try { 515 let fileReader = new FileReader(); 516 fileReader.onload = function () { 517 var data = fileReader.result; 518 var result = new Uint8Array(data); 519 if (includeLength == true) { 520 let length = BaseHelper.GetBytesFromInt(result.length); 521 result = BaseHelper.MergeBytes(length, result); 522 } 523 resolve(result); 524 } 525 fileReader.readAsArrayBuffer(blob); 526 } 527 catch (e) { 528 reject(e); 529 } 530 }); 531 }, 532 533 GetBytesFromInt: function (num) { 534 /* 535 the bytes require an endian check on server to get correct number 536 if (BitConverter.IsLittleEndian) 537 { 538 Array.Reverse(bytes_DataLength); 539 } 540 */ 541 arr = new ArrayBuffer(4); // an Int32 takes 4 bytes 542 view = new DataView(arr); 543 view.setUint32(0, num, false); // byteOffset = 0; litteEndian = false 544 return new Uint8Array(arr); 545 }, 546 547 GetBytesFromText: function (text, includeLength = true) { 548 let utf8Encode = new TextEncoder(); 549 let result = utf8Encode.encode(text) 550 if (includeLength == true) { 551 let length = BaseHelper.GetBytesFromInt(result.length); 552 result = BaseHelper.MergeBytes(length, result); 553 } 554 return result; 555 }, 556 557 MergeBytes: function (a, b) { 558 let newLength = a.length + b.length; 559 let result = new Uint8Array(newLength); 560 for (let i = 0; i < a.length; i++) { 561 result[i] = a[i]; 562 } 563 for (let i = 0; i < b.length; i++) { 564 result[a.length + i] = b[i]; 565 } 566 return result; 567 }, 568 569 //requires importing of sweetalert2 library 570 //<link rel="stylesheet" href="/lib/sweetalert2/sweetalert2.min.css" /> 571 //<script src="/lib/sweetalert2/sweetalert2.all.min.js"></script> 572 showAlert: function (message, type, timer) { 573 if (type == null) { 574 type = "info"; 575 } 576 577 if (timer == null) { 578 timer = 5000; 579 } 580 581 Swal.fire( 582 { 583 position: 'top-end', 584 type: type, 585 title: message,
586 showConfirmButton: false, 587 timer: timer, 588 toast: true 589 }); 590 }, 591 592 //requires importing of sweetalert2 library 593 //<link rel="stylesheet" href="/lib/sweetalert2/sweetalert2.min.css" /> 594 //<script src="/lib/sweetalert2/sweetalert2.all.min.js"></script> 595 showAlert2: function (message, type, timer, position, showConfirmButton) { 596 message = "<div class='text-start p-3'> " + message + "</div>"; 597 if (type == null) { //warning, error, success, info 598 type = "info"; 599 } 600 601 if (timer == null) { 602 timer = 5000; 603 } 604 605 if (position == null) { 606 position = 'top-end'; //top, top-start, top-end, center, center-start, center-end, bottom, bottom-start, bottom-end 607 } 608 609 if (showConfirmButton == null) { 610 showConfirmButton = false; 611 } 612 613 let options = { 614 position: position, 615 type: type, 616 html: message, 617 showConfirmButton: showConfirmButton, 618 showCloseButton: false, 619 toast: true 620 } 621 if (timer != 0 && timer != null) { 622 options["timer"] = timer; 623 } 624 Swal.fire(options); 625 }, 626 627 //requires importing of sweetalert2 library 628 //<link rel="stylesheet" href="/lib/sweetalert2/sweetalert2.min.css" /> 629 //<script src="/lib/sweetalert2/sweetalert2.all.min.js"></script> 630 showAlert3: function (message, icon, timer, position, showConfirmButton) { 631 message = "<div class='text-start p-3'> " + message + "</div>"; 632 if (icon == null) { //warning, error, success, info, question 633 icon = "info"; 634 } 635 636 if (timer == null) { 637 timer = 5000; 638 } 639 640 if (position == null) { 641 position = 'top-end'; //top, top-start, top-end, center, center-start, center-end, bottom, bottom-start, bottom-end 642 } 643 644 if (showConfirmButton == null) { 645 showConfirmButton = false; 646 } 647 648 let options = { 649 position: position, 650 icon: icon, 651 html: message, 652 showConfirmButton: showConfirmButton, 653 showCloseButton: false, 654 toast: true 655 } 656 if (timer != 0 && timer != null) { 657 options["timer"] = timer; 658 } 659 Swal.fire(options); 660 }, 661 662 showAlertPopup: function (messageType, element, title, message, placement, timer, showCloseButton) { 663 //alert(element); 664 $(element).popover("dispose"); 665 666 if (messageType == null) { 667 messageType = "info"; 668 } 669 670 if (timer == null) { 671 timer = 5000; 672 } 673 674 if (placement == null) { 675 placement = "top"; 676 } 677 678 let titleStyle = ""; 679 let contentStyle = ""; 680 681 switch (messageType) { 682 case "error": 683 titleStyle = "<div class='col text-white bg-danger text-center fw-bold fs-5 p-1 m-0'>" + title + "</div>"; 684 contentStyle = "<div class='col pt-1 pb-3 fs-6'>" + message + "</div>"; 685 if (showCloseButton) { 686 contentStyle += "<div class='col text-center mt-2'><a href='#' class='btn btn-sm btn-danger btn-rounded close'>Close</a></div>"; 687 } 688 break; 689 case "success": 690 titleStyle = "<div class='col text-white bg-success text-center fw-bold fs-5 p-1 m-0'>" + title + "</div>"; 691 contentStyle = "<div class='col pt-1 pb-3 fs-6'>" + message + "</div>"; 692 if (showCloseButton) { 693 contentStyle += "<div class='col text-center mt-2'><a href='#' class='btn btn-sm btn-secondary btn-rounded close'>Close</a></div>"; 694 } 695 break; 696 case "info": 697 titleStyle = "<div class='col text-center fw-bold fs-5 p-1 m-0'>" + title + "</div>"; 698 contentStyle = "<div class='col pt-1 pb-3 fs-6'>" + message + "</div>"; 699 if (showCloseButton) { 700 contentStyle += "<div class='col text-center mt-2'><a href='#' class='btn btn-sm btn-secondary btn-rounded close'>Close</a></div>"; 701 } 702 break; 703 case "tooltip": 704 titleStyle = "<div class='col text-white bg-success text-center fw-bold fs-5 p-1 m-0'>" + title + "</div>"; 705 contentStyle = "<div class='col pt-1 pb-3 fs-6'>" + message + "</div>"; 706 break; 707 default: 708 titleStyle = "<div class='col text-white bg-secondary text-center fw-bold fs-5 p-1 m-0'>" + title + "</div>"; 709 contentStyle = "<div class='col pt-1 pb-3 fs-6'>" + message + "</div>"; 710 break; 711 } 712 713 $(element).popover({ 714 placement: placement, 715 trigger: "focus", 716 html: true, 717 title: titleStyle, 718 content: contentStyle, 719 animation: true 720 }); 721 $(element).popover("show"); 722 setTimeout(function () { 723 $(element).popover('hide'); 724 }, timer); 725 }, 726 727 SwapElements: (parent, item1, item2) => { 728 let iIndex1 = null; 729 let iIndex2 = null; 730 if (item1 == null || item2 == null || item1 == item2) { 731 return; 732 } 733 let children = parent.children; 734 for (let i = 0; i < children.length; i++) { 735 if (children[i] == item1) { 736 iIndex1 = i; 737 } 738 if (children[i] == item2) { 739 iIndex2 = i; 740 } 741 } 742 if (iIndex1 == null || iIndex2 == null) { 743 return; 744 } 745 746 let i1 = Math.min(iIndex1, iIndex2); 747 let i2 = Math.max(iIndex1, iIndex2); 748 let one = children[i1]; 749 let two = children[i2]; 750 751 let next = null;
752 if (i2 + 1 < children.length) { 753 next = children[i2 + 1]; 754 } 755 parent.insertBefore(two, one); 756 if (next == null) { 757 parent.append(one) 758 } 759 else { 760 parent.insertBefore(one, next); 761 } 762 }, 763 764 containsClass: function (elem, name) { 765 for (let i = 0; i < elem.classList.length; i++) { 766 if (elem.classList[i] == name) { 767 return true; 768 } 769 } 770 return false; 771 }, 772 773 nodeListToArr: function (nodeList) { 774 if (BaseHelper.isNullOrUndefined(nodeList)) { 775 return null; 776 } 777 let result = []; 778 nodeList.forEach((n) => { 779 result.push(n); 780 }); 781 return result; 782 }, 783 784 showLoading: function (message) { 785 Swal.fire({ 786 title: message, 787 onBeforeOpen: function () { 788 Swal.showLoading() 789 }, 790 onAfterClose: function () { 791 Swal.hideLoading() 792 },
793 showConfirmButton: false, 794 showCloseButton: false, 795 showCancelButton: false 796 }) 797 }, 798 799 hideLoading: function () { 800 Swal.close(); 801 }, 802 803 getUniquifiedElementFromId: function (element, IdLookupUniqueId, id) { 804 let uidList = IdLookupUniqueId[id]; 805 if (uidList == null || uidList.length == null || uidList.length == 0) { 806 return null; 807 } 808 let uid = uidList[0]; 809 return element.querySelector("#" + uid); 810 }, 811 getUniquifiedElementsFromId: function (element, IdLookupUniqueId, id) { 812 let uidList = IdLookupUniqueId[id]; 813 if (uidList == null || uidList.length == null || uidList.length == 0) { 814 return null; 815 } 816 let result = []; 817 uidList.forEach((uid) => { 818 let e = element.querySelector("#" + uid); 819 if (e != null) { 820 result.push(e); 821 } 822 }); 823 return result; 824 }, 825 getAllElements: function (element) { 826 let result = []; 827 result.push(element); 828 let children = element.children; 829 for (child of children) { 830 let grandChildren = this.getAllElements(child); 831 for (grandChild of grandChildren) { 832 result.push(grandChild); 833 } 834 }; 835 return result; 836 }, 837 838 pushQueue: function (queue, value) { 839 queue.push(value); 840 }, 841 842 createRequestQueue: function () { 843 let result = { 844 queue: null, 845 }; 846 result.pop = () => { 847 let value = null; 848 let queue = result.queue; 849 if (queue != null && queue.length > 0) { 850 value = queue.splice(0, 1)[0]; 851 } 852 return value; 853 }; 854 result.push = (value) => { 855 let queue = result.queue; 856 if (queue == null) { 857 queue = []; 858 } 859 queue.push(value); 860 }; 861 return result; 862 }, 863 864 clearRequestQueue: function (requestQueue) { 865 if (requestQueue.queue != null) { 866 requestQueue.queue = []; 867 } 868 }, 869 870 createRequest: function (callback, type = null, url = null, data = null) { 871 return { 872 type: type, 873 url: url, 874 data: data, 875 callback: callback 876 } 877 }, 878 879 //if type, url, data is null then it just runs the callback. 880 handleRequest: async function (requestQueue, request) { 881 if (requestQueue.queue == null) { 882 requestQueue.queue = []; 883 let currentRequest = request; 884 while (currentRequest != null) { 885 try { 886 //if one of the request is invalid, dont prevent the rest of the requests from running. 887 let url = currentRequest.url; 888 let type = currentRequest.type; 889 if (type != null) { 890 type.toLowerCase(); 891 } 892 let cb = currentRequest.callback; 893 let data = currentRequest.data; 894 let jsonResult = null; 895 if (type == "get") { 896 jsonResult = await BaseHelper.MakeAJAXGetRequest(url, data); 897 } 898 else if (type == "post") { 899 jsonResult = await BaseHelper.MakeAJAXPostJSONRequest(url, data); 900 } 901 else { 902 jsonResult = null; 903 } 904 if (cb != null) { 905 cb(jsonResult); 906 } 907 } 908 catch (e) { 909 //display the exception to debug. 910 console.log(e); 911 } 912 currentRequest = requestQueue.pop(); 913 } 914 requestQueue.queue = null; 915 return true; 916 } 917 else { 918 requestQueue.push(request); 919 return false 920 } 921 }, 922 defaultImageInputText: "Choose file", 923 updateBrowseImage: function (files, imageText) { 924 let path = BaseHelper.defaultImageInputText; 925 if (files != null && files.length > 0) { 926 path = files[0].name; 927 } 928 imageText.innerText = path; 929 }, 930 931 blurActive: function () { 932 let activeElement = window.document.activeElement; 933 if (activeElement != null) { 934 activeElement.blur(); 935 } 936 }, 937 938 onImageChange: function (files, image) { 939 if (files && files.length > 0) { 940 let file = files[0]; 941 let reader = new FileReader(); 942 reader.onload = async (e) => { 943 image.src = reader.result; 944 image.style.display = "inline-block"; 945 //this.drawUrl(canvas, reader.result); 946 };
947 reader.readAsDataURL(file); 948 } 949 else { 950 image.style.display = "none"; 951 } 952 }, 953 954 UniquifyBootstrapNavs: function (element) { 955 let navItems = element.querySelectorAll("a.nav-item"); 956 let IdLookupUniqueId = {}; 957 navItems.forEach((nItem, index) => { 958 if (nItem.getAttribute("data-uniquified") == 1) { 959 return; 960 } 961 let uuid = BaseHelper.getUuid(); 962 let ac = nItem.getAttribute("aria-controls") + uuid; 963 let href = nItem.getAttribute("href"); 964 965 let tPane = element.querySelector(href); 966 let current_tpId = tPane.getAttribute("id"); 967 let current_nItemId = nItem.getAttribute("id"); 968 969 let tpId = current_tpId + uuid; 970 let nItemId = tpId + "Nav"; 971 972 tPane.setAttribute("id", tpId); 973 nItem.setAttribute("id", nItemId); 974 nItem.setAttribute("href", "#" + tpId); 975 976 977 tPane.setAttribute("aria-labelledby", ac + "-tab"); 978 tPane.setAttribute("data-uniquified", 1); 979 nItem.setAttribute("data-uniquified", 1); 980 981 tpIdList = IdLookupUniqueId[current_tpId]; 982 if (tpIdList == null) { 983 tpIdList = []; 984 IdLookupUniqueId[current_tpId] = tpIdList 985 } 986 tpIdList.push(tpId) 987 988 nItemIdList = IdLookupUniqueId[current_nItemId]; 989 if (nItemIdList == null) { 990 nItemIdList = []; 991 IdLookupUniqueId[current_nItemId] = nItemIdList 992 } 993 nItemIdList.push(nItemId); 994 }); 995 return IdLookupUniqueId; 996 }, 997 //{one} = headingOne 998 //{two} = collapseOne 999 //{three} = #{two} 1000 //{four} = accordionExample 1001 //{five} = #{four} 1002 //<div class="accordion" id="{four}"> 1003 // <div class="accordion-item"> 1004 // <h2 class="accordion-header" id="{one}"> 1005 // <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="{three}" aria-expanded="true" aria-controls="{two}"> 1006 // Background Image 1007 // </button> 1008 // </h2> 1009 // <div id="{two}" class="accordion-collapse collapse show" aria-labelledby="{one}" data-bs-parent="{five}"> 1010 // <div class="accordion-body"> 1011 // </div> 1012 // </div> 1013 // </div > 1014 //</div> 1015 UniquifyBootstrapAccordion: function (element) { 1016 let aElementList = element.querySelectorAll(".accordion"); 1017 let IdLookupUniqueID = {}; 1018 aElementList.forEach((aElement) => { 1019 let oFour = BaseHelper.tryGetAttribute(aElement, "id"); 1020 let four = oFour + BaseHelper.getUuid(); 1021 let five = "#" + four; 1022 BaseHelper.trySetAttribute(aElement, "id", four); 1023 let accordionItemList = aElement.querySelectorAll(".accordion-item"); 1024 IdLookupUniqueID[oFour] = four; 1025 accordionItemList.forEach((aItem) => { 1026 let aHeader = aItem.querySelector(".accordion-header"); 1027 let aButton = aHeader.querySelector(".accordion-button"); 1028 let aCollapse = aItem.querySelector(".accordion-collapse"); 1029 1030 let oOne = BaseHelper.tryGetAttribute(aHeader, "id"); 1031 let oTwo = BaseHelper.tryGetAttribute(aCollapse, "id"); 1032 1033 let one = oOne + BaseHelper.getUuid(); 1034 let two = oTwo + BaseHelper.getUuid(); 1035 let three = "#" + two; 1036 1037 BaseHelper.trySetAttribute(aHeader, "id", one); 1038 BaseHelper.trySetAttribute(aCollapse, "id", two); 1039 BaseHelper.trySetAttribute(aCollapse, "aria-labelledby", one); 1040 BaseHelper.trySetAttribute(aButton, "aria-controls", two); 1041 BaseHelper.trySetAttribute(aButton, "data-bs-target", three); 1042 BaseHelper.trySetAttribute(aCollapse, "data-bs-parent", five); 1043 IdLookupUniqueID[oOne] = one; 1044 IdLookupUniqueID[oTwo] = two; 1045 }) 1046 }) 1047 return IdLookupUniqueID; 1048 }, 1049 trySetAttribute: (element, name, value) => { 1050 if (element == null || name == null || value == null) { 1051 return; 1052 } 1053 element.setAttribute(name, value); 1054 }, 1055 tryGetAttribute: (element, name) => { 1056 if (element == null || name == null) { 1057 return null; 1058 } 1059 return element.getAttribute(name); 1060 }, 1061 //one = umnEdit-tab 1062 //two = {one}-pane = umnEdit-tab-pane 1063 //three = #{two} = #umnEdit-tab-pane 1064 //tab1 = umnTab 1065 //tab2 = {tab1}Content = umnTabContent 1066 //<div class="UserManagerNav"> 1067 // <ul class="nav nav-tabs" id="umnTab" role="tablist"> 1068 // <li class="nav-item" role="presentation"> 1069 // <button class="nav-link active" id="{one}" data-bs-toggle="tab" data-bs-target="#{two}" type="button" role="tab" aria-controls="{two}" aria-selected="true">Edit</button> 1070 // </li> 1071 // </ul> 1072 // <div class="tab-content" id="umnTabContent"> 1073 // <div class="tab-pane fade show active" id="{two}" role="tabpanel" aria-labelledby="{one}" tabindex="0">Edit</div> 1074 // </div> 1075 //</div> 1076 UniquifyBootstrap5Navs: function (element) { 1077 let tabs = element.querySelector(".nav.nav-tabs"); 1078 let tabContent = element.querySelector(".tab-content"); 1079 1080 let tab1 = tabs.getAttribute("id") + BaseHelper.getUuid(); 1081 let tab2 = tab1 + "Content"; 1082 1083 let oTab1 = tabs.getAttribute("id"); 1084 tabs.setAttribute("id", tab1); 1085 tabs.setAttribute("data-uniquified", 1); 1086 1087 let oTab2 = tabContent.getAttribute("id"); 1088 tabContent.setAttribute("id", tab2); 1089 tabContent.setAttribute("data-uniquified", 1); 1090 let navLinks = element.querySelectorAll(".nav-item .nav-link"); 1091 1092 let IdLookupUniqueId = {}; 1093 IdLookupUniqueId[oTab1] = tab1; 1094 IdLookupUniqueId[oTab2] = tab2; 1095 1096 navLinks.forEach((nLink, index) => { 1097 let uuid = BaseHelper.getUuid(); 1098 let paneTarget = nLink.getAttribute("data-bs-target"); 1099 let one = nLink.getAttribute("id") + uuid; 1100 let two = one + "-pane"; 1101 let three = "#" + two; 1102 1103 let oOne = nLink.getAttribute("id"); 1104 nLink.setAttribute("id", one); 1105 nLink.setAttribute("data-uniquified", 1); 1106 nLink.setAttribute("data-bs-target", three); 1107 nLink.setAttribute("aria-controls", two); 1108 let tPane = tabContent.querySelector(paneTarget); 1109 1110 let oTwo = tPane.getAttribute("id"); 1111 tPane.setAttribute("id", two); 1112 tPane.setAttribute("data-uniquified", 1); 1113 tPane.setAttribute("aria-labelledby", one); 1114 1115 IdLookupUniqueId[oOne] = one; 1116 IdLookupUniqueId[oTwo] = two; 1117 }); 1118 return IdLookupUniqueId; 1119 }, 1120 1121 1122 getBootstrapRowIndex: function (element) { 1123 let currentElement = element; 1124 while (currentElement != null) { 1125 let tag = currentElement.tagName; 1126 let dIndex = currentElement.getAttribute("data-index"); 1127 if (tag.toUpperCase() == "TR" && dIndex != null) { 1128 return dIndex; 1129 } 1130 currentElement = currentElement.parentElement; 1131 } 1132 return null; 1133 }, 1134 1135 getBootstrapRowFromElement: function (bt, element) { 1136 let rowIndex = BaseHelper.getBootstrapRowIndex(element); 1137 if (rowIndex != null) { 1138 return bt.bootstrapTable("getData")[rowIndex]; 1139 } 1140 return null; 1141 }, 1142 1143 //makes the ids under the element unique and returns a way to lookup the unique ids. 1144 //the unique ids are in a list in case the id was not actually unique 1145 UniquifyIds: function (element) { 1146 let IdLookupUniqueId = {} 1147 let allElements = this.getAllElements(element);
1148 allElements.forEach(e => { 1149 let id = e.getAttribute("id"); 1150 let uniquified = e.getAttribute("data-uniquified"); 1151 if (uniquified) { 1152 return; 1153 } 1154 if (id != null) { 1155 let uuid = this.getUuid() 1156 let uniqueId = id + "-" + uuid; 1157 let uidList = IdLookupUniqueId[id]; 1158 if (uidList == null) { 1159 uidList = []; 1160 IdLookupUniqueId[id] = uidList; 1161 } 1162 e.setAttribute("id", uniqueId); 1163 e.setAttribute("data-uniquified", true); 1164 uidList.push(uniqueId); 1165 } 1166 }) 1167 return IdLookupUniqueId; 1168 }, 1169 1170 //usage: BaseHelper.dollarFormatter.format({amount}); 1171 dollarFormatter: new Intl.NumberFormat('en-US', { 1172 style: 'currency', 1173 currency: 'USD', 1174 minimumFractionDigits: 0 1175 1176 // These options are needed to round to whole numbers if that's what you want. 1177 //minimumFractionDigits: 0, // (this suffices for whole numbers, but will print 2500.10 as $2,500.1) 1178 //maximumFractionDigits: 0, // (causes 2500.99 to be printed as $2,501) 1179 }), 1180 1181 //takes in date from the database and output the locale date. 1182 //returns null if its unparsable 1183 dbDateToLocale: function (value) { 1184 if (value == null || value.trim() == "") { 1185 return null; 1186 } 1187 let dt = new Date(value); 1188 if (isNaN(dt)) { 1189 return null; 1190 } 1191 return dt.toLocaleDateString(); 1192 }, 1193 1194 getUuid: function () { 1195 return this.uuid++; 1196 }, 1197 1198 getSubscriberName: function (fullName, firstName, lastName) { 1199 if (fullName == null) { 1200 return firstName + " " + lastName 1201 } 1202 else { 1203 return fullName 1204 } 1205 }, 1206 1207 GenerateGlobalFunction: function (f) { 1208 let functionName = "BaseHelperGeneratedGlobalFunction" + this.getUuid(); 1209 window[functionName] = f; 1210 return functionName; 1211 }, 1212 EncodeObjectToHtmlData: function (data) { 1213 if (data == null) { 1214 return null; 1215 } 1216 else { 1217 urlData = ""; 1218 for (let key in data) { 1219 let value = data[key]; 1220 urlData += key + "=" + encodeURIComponent(value) + "&"; 1221 } 1222 return urlData.substr(0, urlData.length - 1); 1223 } 1224 }, 1225 1226 ExportTable: function (table, name, type) { 1227 let wb = XLSX.utils.table_to_book(table, { sheet: name }); 1228 XLSX.writeFile(wb, name + "." + type); 1229 }, 1230 1231 ExportArray: function (arr, name, type) { 1232 let wb = XLSX.utils.book_new(); 1233 let sheet = XLSX.utils.json_to_sheet(arr); 1234 XLSX.utils.book_append_sheet(wb, sheet, name) 1235 XLSX.writeFile(wb, name + "." + type); 1236 }, 1237 1238 MakeAJAXGetRequest: async function (url, data = null, onProgress = null, handleException = true) { 1239 let urlData = this.EncodeObjectToHtmlData(data); 1240 let query = url; 1241 if (urlData != null) { 1242 query += "?" + urlData; 1243 } 1244 return new Promise((resolve, reject) => { 1245 let xhttp = new XMLHttpRequest(); 1246 xhttp.onload = function () { 1247 if (handleException) { 1248 BaseHelper.HandleException(this.responseText); 1249 } 1250 resolve(this.responseText); 1251 } 1252 xhttp.onerror = function () { 1253 reject("ajax failed!"); 1254 }; 1255 if (onProgress != null) { 1256 xhttp.onprogress = onProgress; 1257 } 1258 xhttp.open("GET", query); 1259 xhttp.send(); 1260 }) 1261 }, 1262 1263 GetFormData: function (data) { 1264 let result = new FormData(); 1265 for (let key in data) { 1266 if (data[key] instanceof Blob) { 1267 result.append(key, data[key], data[key].name) 1268 } 1269 else { 1270 result.append(key, data[key]) 1271 } 1272 1273 } 1274 return result; 1275 }, 1276 1277 HandleException: function (response) {
1278 if (!BaseHelper.displayException) { 1279 return false; 1280 } 1281 try { 1282 let rsp = JSON.parse(response); 1283 if (rsp.Type != null) { 1284 if (rsp.Type == "AuthenticationFailedException") { 1285 window.location = "/login"; 1286 return true; 1287 } 1288 else if (rsp.Type == "Exception") { 1289 alert(rsp.Message); 1290 return true; 1291 } 1292 } 1293 } 1294 catch (e) { 1295 //do nothing 1296 } 1297 return false; 1298 }, 1299 //Converts data to json and sends it to server. 1300 //obtain parameters data on the server by reading from the form request "HttpContext.Request.Form[{ParameterName}]" or by adding [FromForm] attribute; 1301 MakeAJAXPostFormRequest: async function (url, data = null, onProgress = null, handleException = true) { 1302 return new Promise((resolve, reject) => { 1303 let xhttp = new XMLHttpRequest(); 1304 xhttp.onload = function () { 1305 if (handleException) { 1306 BaseHelper.HandleException(this.responseText); 1307 } 1308 resolve(this.responseText); 1309 } 1310 xhttp.onerror = function () { 1311 reject("ajax failed!"); 1312 }; 1313 if (onProgress != null) { 1314 xhttp.onprogress = onProgress; 1315 }; 1316 xhttp.open("post", url); 1317 xhttp.send(this.EncodeObjectToHtmlData(data)); 1318 }) 1319 }, 1320 1321 MakeAJAXPostFormDataRequest: async function (url, data, onProgress = null, handleException = true) { 1322 return new Promise((resolve, reject) => { 1323 let fData = BaseHelper.GetFormData(data); 1324 let xhttp = new XMLHttpRequest(); 1325 xhttp.onload = function () { 1326 if (handleException) { 1327 BaseHelper.HandleException(this.responseText); 1328 } 1329 resolve(this.responseText); 1330 } 1331 xhttp.onerror = function () { 1332 reject("ajax failed!"); 1333 }; 1334 if (onProgress != null) { 1335 //xhttp.onprogress = onProgress; 1336 xhttp.upload.onprogress = onProgress; 1337 }; 1338 xhttp.open("post", url); 1339 xhttp.send(fData); 1340 }) 1341 }, 1342 1343 MakeAJAXPostBinaryRequest: async function (url, bytes, onProgress = null, handleException = true) { 1344 return new Promise((resolve, reject) => { 1345 let xhttp = new XMLHttpRequest(); 1346 xhttp.onload = function () { 1347 if (handleException) { 1348 BaseHelper.HandleException(this.responseText); 1349 } 1350 resolve(this.responseText); 1351 } 1352 xhttp.onerror = function () { 1353 reject("ajax failed!"); 1354 }; 1355 if (onProgress != null) { 1356 xhttp.onprogress = onProgress; 1357 }; 1358 xhttp.open("post", url); 1359 xhttp.setRequestHeader("Content-Type", "application/octet-stream"); 1360 xhttp.send(bytes); 1361 }) 1362 }, 1363 1364 1365 DeserializeDataTableToObjects: (dt) => { 1366 try { 1367 const dataArray = dt; 1368 1369 // Extract the column names from the first row 1370 const columnNames = dataArray[0]; 1371 1372 // Convert the rest of the rows into an array of objects 1373 const objectsArray = dataArray.slice(1).map(row => { 1374 const obj = {}; 1375 columnNames.forEach((columnName, index) => { 1376 obj[columnName] = row[index]; 1377 }); 1378 return obj; 1379 }); 1380 1381 return objectsArray; 1382 } catch (error) { 1383 console.error('Error parsing JSON:', error); 1384 return null; // or handle the error as needed 1385 } 1386 }, 1387 1388 //Converts data to json and sends it to server. 1389 //obtain parameters data on the server by reading from the context request body "(new StreamReader(HttpContext.Request.Body)).ReadToEnd()" and parsing the result as JSON; 1390 MakeAJAXPostJSONRequest: async function (url, data = null, handleException = true) { 1391 return new Promise((resolve, reject) => { 1392 let xhttp = new XMLHttpRequest(); 1393 xhttp.onload = function () { 1394 if (handleException) { 1395 BaseHelper.HandleException(this.responseText); 1396 } 1397 resolve(this.responseText); 1398 } 1399 xhttp.onerror = function () { 1400 reject("ajax failed!"); 1401 }; 1402 xhttp.open("post", url); 1403 xhttp.setRequestHeader("Content-type", "application/json"); 1404 xhttp.send(JSON.stringify(data)); 1405 }) 1406 }, 1407 1408 MergeObjects: function (a, b) { 1409 let result = {}; 1410 for (key in a) { 1411 result[key] = a[key]; 1412 }; 1413 for (key in b) { 1414 result[key] = b[key]; 1415 }; 1416 return result; 1417 }, 1418 1419 MergeArrays: function (a, b) { 1420 let result = [] 1421 a.forEach((e) => { 1422 result.push(e); 1423 }) 1424 b.forEach((e) => { 1425 result.push(e); 1426 }) 1427 return result; 1428 }, 1429 1430 MergeIntoObject: function (obj, a) { 1431 if (a == null) { 1432 return obj; 1433 } 1434 for (key in a) { 1435 obj[key] = a[key]; 1436 }; 1437 return obj; 1438 }, 1439 1440 asyncWait:async function(t){ 1441 return new Promise((resolve)=>{ 1442 setTimeout(()=>{ 1443 resolve(true); 1444 }, t) 1445 }); 1446 }, 1447 1448 CopyToClipboard: function (element) { 1449 if (element == null) { 1450 return false 1451 } 1452 element.select(); 1453 if (!document.execCommand("copy")){ 1454 return false;
1455 } 1456 return true; 1457 }, 1458 1459 GetHousePhotoUrl: function (id = null) {s 1460 let url = "/content/housephoto"; 1461 if (id != null) { 1462 url += "?housephotoid=" + id; 1463 } 1464 return url; 1465 }, 1466 1467 CreateDialog: function (dialogClassName, title, width, height, animationTimer = 250, options = {}) { 1468 let baseOptions = { 1469 title: title, 1470 width: width, 1471 height: height, 1472 autoOpen: false 1473 } 1474 if (animationTimer != 0 && options.show == null && options.hide == null) { 1475 options.show = { 1476 effect: "blind", 1477 duration: animationTimer 1478 }; 1479 options.hide = { 1480 effect: "blind", 1481 duration: animationTimer 1482 }; 1483 } 1484 let resultOptions = this.MergeObjects(baseOptions, options); 1485 1486 let dialogElement = document.createElement("div"); 1487 dialogElement.classList.add(dialogClassName); 1488 document.body.appendChild(dialogElement); 1489 let dialog = { 1490 element: $(dialogElement).dialog(resultOptions), 1491 cleanup: function () { 1492 $(dialogElement).dialog("destroy"); 1493 dialogElement.remove(); 1494 } 1495 }; 1496 return dialog; 1497 }, 1498 1499 getWindowSides: function () { 1500 let top = window.scrollY; 1501 let bottom = top + window.innerHeight; 1502 let left = window.scrollX; 1503 let right = left + window.innerWidth 1504 1505 return { 1506 top: top, 1507 bottom: bottom, 1508 left: left, 1509 right: right 1510 } 1511 }, 1512 1513 getBoundSides: function (clientRect) { 1514 let top = clientRect.y + window.scrollY; 1515 let bottom = top + clientRect.height; 1516 let left = clientRect.x + window.scrollX; 1517 let right = left + clientRect.width; 1518 return { 1519 top: top, 1520 bottom: bottom, 1521 left: left, 1522 right: right 1523 } 1524 }, 1525 1526 isScrolledIntoView: function (container, elem) { 1527 let docViewBounds = container.getBoundingClientRect(); 1528 let elemBounds = elem.getBoundingClientRect(); 1529 if (docViewBounds.width == 0 || docViewBounds.height == 0) { 1530 return false; 1531 } 1532 if (elemBounds.width == 0 || elemBounds.height == 0) { 1533 return false; 1534 } 1535 let containerSides = BaseHelper.getBoundSides(docViewBounds); 1536 let elemSides = BaseHelper.getBoundSides(elemBounds); 1537 return BaseHelper.isScrolledIntoViewSides(containerSides, elemSides); 1538 }, 1539 1540 isScrolledIntoViewSides: function (containerSides, elemSides) { 1541 if (containerSides.left == containerSides.right || containerSides.top == containerSides.bottom) { 1542 return false; 1543 } 1544 if (elemSides.left == elemSides.right || elemSides.top == elemSides.bottom) { 1545 return false; 1546 } 1547 return ((elemSides.bottom >= containerSides.top) && (elemSides.top <= containerSides.bottom)); 1548 }, 1549 1550 //------------------------------------------------------------------------------------------------------ 1551 //image helpers 1552 1553 //set img width/height based on parent node 1554 //parent node must be visible. 1555 calculateFillType: function (containerWidth, containerHeight, imgWidth, imgHeight) { 1556 let containerRatio = containerWidth / containerHeight; 1557 let imgRatio = imgWidth / imgHeight; 1558 1559 if (imgRatio < containerRatio) { 1560 return "tall"; 1561 } else { 1562 return "wide"; 1563 } 1564 }, 1565 1566 getImageFillType: function (container, img) { 1567 let containerWidth = container.clientWidth; 1568 let containerHeight = container.clientHeight; 1569 let imgWidth = img.width; 1570 let imgHeight = img.height; 1571 1572 return BaseHelper.calculateFillType(containerWidth, containerHeight, imgWidth, imgHeight); 1573 }, 1574 1575 setImgWidthHeight: function (img, width, height) { 1576 let nw = img.naturalWidth; 1577 let nh = img.naturalHeight; 1578 let ratio = nw / nh; 1579 if (ratio >= 1) { 1580 img.style.width = width + "px"; 1581 img.style.height = "auto"; 1582 } 1583 else { 1584 img.style.width = "auto"; 1585 img.style.height = height + "px"; 1586 } 1587 }, 1588 //------------------------------------------------------------------------------------------------------ 1589 1590 HasParent: function (parent, element) { 1591 let currentElement = element; 1592 while (currentElement != null) { 1593 if (currentElement == parent) { 1594 return true; 1595 } 1596 currentElement = currentElement.parentElement; 1597 } 1598 return false;
1599 }, 1600 1601 post: async function (url, request) { 1602 return new Promise((resolve) => { 1603 $.post("/api/Listing/GetSearchAreaCount", request).done(function (data) { 1604 resolve(data); 1605 }); 1606 }); 1607 }, 1608 1609 getValueFromBoolean: function (b) { 1610 if (b === 0 || b === 1) { 1611 return b; 1612 } 1613 if (b == true) { 1614 return 1; 1615 } 1616 else if (b == false) { 1617 return 0; 1618 } 1619 else if (typeof b === 'string') { 1620 bVal = b.trim().toUpperCase(); 1621 if ( 1622 bVal == "TRUE" || 1623 bVal == "Y" || 1624 bVal == "YES" 1625 ) { 1626 return 1; 1627 } 1628 else if ( 1629 bVal == "FALSE" || 1630 bVal == "N" || 1631 bVal == "NO" 1632 ) { 1633 return 0; 1634 } 1635 } 1636 return null; 1637 }, 1638 1639 /* buttons contains an array of text which is displayed on the buttons 1640 * ["button0", "button1", "button2"] 1641 * the buttons array that is returned should return the buttons in the same order that was listed in the array 1642 */ 1643 1644 getRange: function (min, max, symbol, after =false) { 1645 let formatNumber = num => num != null ? Number(num).toLocaleString() : null; 1646 if (symbol == null) { 1647 if (min != null && max == null) { 1648 return formatNumber(min) + "+"; 1649 } else if (min != null && max != null) { 1650 return formatNumber(min) + " - " + formatNumber(max); 1651 } else if (min == null && max != null) { 1652 return '<' + formatNumber(max); 1653 } else { 1654 return null; 1655 } 1656 } 1657 else { 1658 if (after) { 1659 if (min != null && max == null) { 1660 return formatNumber(min) + symbol + "+"; 1661 } else if (min != null && max != null) { 1662 return formatNumber(min) + symbol + " - " + formatNumber(max) + symbol; 1663 } else if (min == null && max != null) { 1664 return '<' + formatNumber(max) + symbol; 1665 } else { 1666 return null; 1667 } 1668 } 1669 else { 1670 if (min != null && max == null) { 1671 return symbol + formatNumber(min) + "+"; 1672 } else if (min != null && max != null) { 1673 return symbol + formatNumber(min) + " - " + symbol + formatNumber(max); 1674 } else if (min == null && max != null) { 1675 return `< ${symbol}` + formatNumber(max); 1676 } else { 1677 return null; 1678 } 1679 } 1680 } 1681 1682 }, 1683 1684 ExtractDomain: function extractDomain(input) { 1685 if (typeof input !== 'string') return null; 1686 input = input.trim(); 1687 if (!input) return null; 1688 1689 let url; 1690 try { 1691 // If the string doesn't start with a protocol, prepend "http://" 1692 if (!/^https?:\/\//i.test(input)) { 1693 url = new URL('http://' + input); 1694 } else { 1695 url = new URL(input); 1696 } 1697 } catch (e) { 1698 // If URL construction fails, it's not a valid domain/URL. 1699 return null; 1700 } 1701 1702 // Extract the hostname (e.g., "www.test.com" or "test.com") 1703 const hostname = url.hostname; 1704 // Split the hostname by the dot. 1705 const parts = hostname.split('.'); 1706 // If there aren't at least two parts, it's not a valid domain. 1707 if (parts.length < 2) return null; 1708 1709 // Return the second-to-last part, which should be the domain name. 1710 return parts[parts.length - 2]; 1711 }, 1712 1713 CreateModal: async function (modalClassName, title, maxWidth = null, buttons = null) { 1714 let modalElement = document.createElement("div"); 1715 let modalMarkup = await this.MakeAJAXGetRequest("/Template/Modal"); 1716 modalElement.classList.add(modalClassName); 1717 modalElement.innerHTML = modalMarkup; 1718 1719 let modal = modalElement.querySelector(".modal"); 1720 let modalDialog = modalElement.querySelector(".modal-dialog"); 1721 let meHeader = modalElement.querySelector(".modal .modal-header"); 1722 let meTitle = modalElement.querySelector(".modal .modal-header .modal-title"); 1723 let meBody = modalElement.querySelector(".modal .modal-body"); 1724 let meFooter = modalElement.querySelector(".modal-footer"); 1725 meTitle.innerHTML = title; 1726 if (maxWidth != null) { 1727 modalDialog.style.maxWidth = maxWidth; 1728 } 1729 1730 let result = { 1731 element: modalElement, 1732 modal: modal, 1733 title: meTitle, 1734 body: meBody, 1735 footer: meFooter, 1736 dialog: modalDialog, 1737 cleanup: () => { 1738 modalElement.remove(); 1739 } 1740 }; 1741 1742 if (title == null) { 1743 meHeader.parentElement.removeChild(meHeader); 1744 } 1745 else { 1746 result.header = meHeader; 1747 result.title = meTitle; 1748 } 1749 let btnList = null; 1750 if ( 1751 buttons != null && 1752 buttons.length != null && 1753 buttons.length > 0 1754 ) { 1755 btnList = [] 1756 meFooter.innerHTML = ""; 1757 buttons.forEach((text) => { 1758 let btn = document.createElement("button"); 1759 btn.classList.add("btn"); 1760 btn.classList.add("btn-info"); 1761 btn.innerText = text; 1762 meFooter.appendChild(btn); 1763 btnList.push(btn); 1764 }); 1765 result.buttons = btnList; 1766 } 1767 document.body.appendChild(modalElement); 1768 return Promise.resolve(result); 1769 }, 1770 1771 ToggleScroll: function (scroll) { 1772 if (scroll == true) { 1773 document.body.style.height = null; 1774 document.body.style.overflow = null; 1775 } 1776 else { 1777 document.body.style.height = "100%"; 1778 document.body.style.overflow = "hidden"; 1779 } 1780 } 1781};
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.