1Widgets.ListingSearch = function (options = null) { 2 let rawData = null; 3 this.className = "defaultListingSearchContainer"; 4 this.currentDisplay = null; 5 this.currentScrollId = null; 6 Widgets.BaseWidget.call(this, "/Widgets/ListingSearch/ListingSearch", this.className); 7 8 //custom overriding options 9 BaseHelper.MergeIntoObject(this, options); 10 11 this._setup = function () { 12 Widgets.BaseWidget.prototype._setup.call(this); 13 this.isRefreshing = false; 14 this.pBar = new PaginationBar(0, 3); 15 this.pBar.init(); 16 this.defaultImageUrl = "/img/no-housephoto.jpg" 17 this.fetchCount = 50; 18 this.pendingRawDataList = []; 19 20 this.dataTask = null; 21 this.currentUuid = null; 22 23 this.currentData = null; 24 this.prevListingRequest = { 25 request: null, 26 response:null 27 } 28 this.prevMapRequest = { 29 requst: null, 30 response:null 31 } 32 this.onPaginationChange = null; 33 }; 34 35 this.getLoadData = async function () { 36 let result = Widgets.BaseWidget.prototype.getLoadData.call(this); 37 38 let json_response = await BaseHelper.MakeAJAXGetRequest("/api/Website/IsListHubSite"); 39 let response = JSON.parse(json_response); 40 this.IsListHub = response["IsListHub"]; 41 //console.log("this.IsListHub", this.IsListHub); 42 43 this.ListingSearchItemMarkup = await BaseHelper.MakeAJAXGetRequest("/Widgets/ListingSearch/ListingSearchItem"); 44 this.ListingSearchFillerItemMarkup = await BaseHelper.MakeAJAXGetRequest("/Widgets/ListingSearch/ListingSearchFillerItem"); 45 return result; 46 }; 47 48 this.getRawData = async () => { 49 return new Promise((resolve, reject) => { 50 if (this.rawData != null) { 51 resolve(this.rawData); 52 } 53 if (this.isRefreshing) { 54 this.pendingRawDataList.push((rawData) => { 55 resolve(rawData); 56 }); 57 } 58 else { 59 resolve(this.rawData); 60 } 61 }); 62 }; 63 64 // Returns a populated div. 65 this.GetPopulatedCard = function (data, heartKey) { 66 let div = document.createElement("div"); 67 68 div.innerHTML = this.ListingSearchItemMarkup; 69 70 this.populateSearchListingItem(div, data, true, heartKey); 71 72 div.firstChild.attributes["data-listingid"].value = data.ListingID; 73 74 return div.firstChild; 75 }; 76 77 //returns a card to use as a filler while loading. 78 this.GetFillerCard = function () { 79 let div = document.createElement("div"); 80 div.innerHTML = this.ListingSearchFillerItemMarkup; 81 return div.firstChild; 82 } 83 84 this.setFilters = (filterArr) => { 85 if (this.currentData == null) { 86 this.currentData = this.getDefaultData(); 87 } 88 this.currentData.page = 0; 89 this.currentData.data = null; 90 let sortFilter = null; 91 for (let i = 0; i < filterArr.length; i++) { 92 let f = filterArr[i]; 93 if (f.name == "SortResult") { 94 sortFilter = f; 95 break; 96 } 97 } 98 if (sortFilter == null) { 99 this.currentData.orderBy = "ListingDate"; 100 this.currentData.orderSort = "DESC"; 101 } 102 else { 103 let sfValue = sortFilter.value; 104 if (sfValue == "lowest") { 105 this.currentData.orderBy = "ListPrice"; 106 this.currentData.orderSort = "ASC"; 107 } 108 else if (sfValue == "highest") { 109 this.currentData.orderBy = "ListPrice"; 110 this.currentData.orderSort = "DESC"; 111 } 112 else if (sfValue == "lotsize") { 113 this.currentData.orderBy = "LotSize"; 114 this.currentData.orderSort = "DESC"; 115 } 116 else if (sfValue == "openhouse") { 117 this.currentData.orderBy = "OpenHouseUpcomingStartDate"; 118 this.currentData.orderSort = "ASC"; 119 } 120 else { 121 this.currentData.orderBy = "ListingDate"; 122 this.currentData.orderSort = "DESC"; 123 } 124 } 125 this.currentData.filterArr = filterArr;
126 }; 127 128 this.setMapRequest = (request) => { 129 if (this.currentData == null) { 130 this.currentData = this.getDefaultData(); 131 } 132 this.currentData.page = 0; 133 this.currentData.data = null; 134 this.currentData.mapRequest = request; 135 }; 136 137 138 this.getDefaultData = () => { 139 let data = { 140 filterArr: null, 141 page: 0, 142 fetch: this.fetchCount, 143 orderBy: "ListingDate", 144 orderSort: "DESC", 145 isMap: false, 146 data: null 147 } 148 return data; 149 }; 150 151 this.getMaxPage = (maxPage) => { 152 return maxPage; 153 }; 154 155 this.populateGrid = (listings) => { 156 this.clearGrid(); 157 if (this.currentData == null || listings == null) { 158 return; 159 } 160 this.currentData.data = listings; 161 let pData = listings.PaginatedData; 162 let currentPage = pData.offset / pData.fetch; 163 this.pBar.currentPage = currentPage; 164 let maxPage = this.getMaxPage(pData.maxPages); 165 this.pBar.setMaxPage(maxPage); 166 this.pBar.refresh(); 167 this.currentPropTypeList = this.getCurrentPropTypeList(); 168 if (BaseHelper.isNullOrUndefined(this.ListingIDLookupHeart)) { 169 this.ListingIDLookupHeart = {}; 170 } 171 else { 172 for (let key in this.ListingIDLookupHeart) { 173 delete this.ListingIDLookupHeart[key]["ListingSearch"]; 174 } 175 } 176 if (pData != null && pData.data != null) { 177 pData.data.forEach((record) => { 178 let div = this.GetPopulatedCard(record, "ListingSearch"); 179 this.ListingSearchItemContainer.appendChild(div); 180 181 //remove the background src before appending to element and add the unveil src to element 182 let imgTop = div.querySelector(".card-img-top"); 183 let src = imgTop.getAttribute("image-src"); 184 //imgTop.setAttribute("data-src", src); 185 //imgTop.setAttribute("data-lazyload", false); 186 //imgTop.removeAttribute("style"); 187 188 imgTop.setAttribute("style", "background-image:url('" + src + "'),url('/img/no-housephoto.jpg');"); 189 }); 190 } 191 192 window.addEventListener("scroll", () => { 193 this.onScroll(); 194 }); 195 }; 196 197 this.onScroll = () => { 198 let scrollId = this.currentScrollId = BaseHelper.getUuid(); 199 //console.log("scroll"); 200 //window.setTimeout(() => { 201 // if (this.currentScrollId == scrollId) { 202 // let imgList = this.ListingSearchItemContainer.querySelectorAll(".card-img-top[data-lazyload=false]"); 203 // for (let i = 0; i < imgList.length; i++) { 204 // let img = imgList[i]; 205 // let windowSides = BaseHelper.getWindowSides() 206 // let boundSides = BaseHelper.getBoundSides(img.getBoundingClientRect()) 207 // if (BaseHelper.isScrolledIntoViewSides(windowSides, boundSides)) { 208 // let src = img.getAttribute("image-src"); 209 // img.setAttribute("style", "background-image:url('" + src + "'),url('/img/no-housephoto.jpg');"); 210 // img.setAttribute("data-lazyload", true); 211 // } 212 // } 213 // } 214 //}, 200); 215 }; 216 217 218 219 //this.clearSavedListings = () => { 220 // if ( 221 // this.currentData == null || 222 // this.currentData.data == null || 223 // this.currentData.data.PaginatedData == null || 224 // this.currentData.data.PaginatedData.data == null) { 225 // return; 226 // } 227 // let data = this.currentData.data.PaginatedData.data; 228 // data.forEach((d) => { 229 // d.SiteUserSavedListingStatusTblID = null; 230 // }) 231 // this.populateGrid(this.currentData.data); 232 //}; 233 234 this.getValueOrEmpty = (str) => { 235 if (str == null) { 236 return ""; 237 } 238 else { 239 return str; 240 } 241 }; 242 243 244 this.getUrlAddress = (record) => {
245 if (!BaseHelper.displayAddress(record)) { 246 return ""; 247 } 248 let streetNumber = record["StreetNumber"]; 249 let streetName = record["StreetName"]; 250 let unitNumber = record["UnitNumber"]; 251 let city = record["City"]; 252 let state = record["State"]; 253 let zip = record["Zip"]; 254 let fullAddress = this.getValueOrEmpty(streetNumber) + " " + this.getValueOrEmpty(streetName) + " " + this.getValueOrEmpty(unitNumber) + " " + this.getValueOrEmpty(city) + " " + this.getValueOrEmpty(state) + " " + this.getValueOrEmpty(zip); 255 // Remove special characters, but keep letters, numbers, and spaces 256 fullAddress = fullAddress.replaceAll(/[^A-Za-z0-9\s]/g, ""); 257 //replace multiple spaces with single space 258 fullAddress = fullAddress.replaceAll(/\s+/g, ' '); 259 // Trim leading/trailing spaces before converting spaces to underscores 260 fullAddress = fullAddress.trim(); 261 262 // Replace spaces with underscores 263 fullAddress = fullAddress.replaceAll(/\s/g, "_"); 264 265 return fullAddress; 266 }; 267 268 this.getCurrentPropTypeList = () => { 269 if (this.currentData == null || this.currentData.filterArr == null || this.currentData.filterArr.length == null) { 270 return null; 271 } 272 let filterArr = this.currentData.filterArr; 273 for (let i = 0; i < filterArr.length; i++) { 274 f = filterArr[i]; 275 if (f.name == "PropTypeList") { 276 return f.value; 277 } 278 } 279 return null; 280 }; 281 282 this.isNewlyListed = function (record) { 283 if (record == null || record.ListingDate == null) { 284 return false; 285 } 286 let dtListing = new Date(record.ListingDate); 287 if (isNaN(dtListing)) { 288 return false; 289 } 290 let now = new Date(); 291 let dayDiff = (now - dtListing) / (1000 * 3600 * 24); 292 if (dayDiff <= 7) { 293 return true; 294 } 295 return false; 296 }; 297 298 299 this.isNewConstruction = function (record) { 300 if (record == null || record.PropType8 == null) { 301 return false; 302 } 303 if (record.PropType8 == 1) { 304 return true; 305 } 306 return false; 307 }; 308 309 this.isComingSoon = function (record) { 310 if (record == null || record.ListingStatusTblID == null) { 311 return false; 312 } 313 if (record.ListingStatusTblID == 4) { 314 return true; 315 } 316 return false; 317 }; 318 319 320 this.getOpenHouseDate = function (record) { 321 if (record == null) { 322 return null; 323 } 324 let tzOffset = parseInt(record.TimeZone); 325 let timezone = null; 326 let dtOpenHouse = new Date(record.OpenHouseUpcomingStartDate); 327 if (isNaN(dtOpenHouse) || dtOpenHouse.getFullYear() == 5000) { 328 return null; 329 } 330 331 if (record.LocalOpenHouseUpcomingStartDate != null && record.DayLightSaving != null && !isNaN(tzOffset)) { 332 if (tzOffset == 6) { 333 timezone = "Central"; 334 } 335 else if (tzOffset == 7) { 336 timezone = "Mountain"; 337 } 338 else if (tzOffset == 8) { 339 timezone = "Pacific"; 340 } 341 else if (tzOffset == 9) { 342 timezone = "Alaskan"; 343 } 344 dtOpenHouse = new Date(record.OpenHouseUpcomingStartDate); 345 } 346 347 return { 348 dtOpenHouse: dtOpenHouse, 349 timezone: timezone 350 } 351 }; 352 353 this.SetSavedListing = async function (ListingID, save) { 354 let data = { 355 ListingID: ListingID, 356 Save: save == true ? 1 : 0 357 }; 358 let json_response = await BaseHelper.MakeAJAXPostJSONRequest("/api/SiteUser/SetSiteUserListing", data, false); 359 let response = JSON.parse(json_response); 360 //console.log(response); 361 if (response.Status == 1) { 362 let hItemObj = this.ListingIDLookupHeart[ListingID]; 363 if (hItemObj != null) { 364 for (let key in hItemObj) { 365 heartItem = hItemObj[key]; 366 if (save == true) { 367 this.ToggleHeart(heartItem, true); 368 } 369 else { 370 this.ToggleHeart(heartItem, false); 371 } 372 } 373 } 374 } 375 else { 376 this.PendingSavedListingID = ListingID; 377 } 378 if (this.onSavedListingComplete != null) { 379 this.onSavedListingComplete(this, response); 380 } 381 }; 382 383 this.onSavedListingComplete = null; 384 385 this.clearHearts = function () { 386 for (let key in this.ListingIDLookupHeart) { 387 let hItemObj = this.ListingIDLookupHeart[key]; 388 if (hItemObj != null) { 389 for (let hiKey in hItemObj) { 390 hItem = hItemObj[hiKey]; 391 this.ToggleHeart(hItem, false); 392 } 393 } 394 } 395 }; 396 397 this.populateHearts = function (data) { 398 this.clearHearts(); 399 if (data != null && data.length > 0) { 400 data.forEach((savedListing) => { 401 let hItemObj = this.ListingIDLookupHeart[savedListing.ListingID]; 402 if (hItemObj != null) { 403 for (let key in hItemObj) { 404 heart = hItemObj[key]; 405 this.ToggleHeart(heart, true); 406 } 407 } 408 }) 409 } 410 }; 411 412 this.ToggleHeart = function (heartItem, saved) { 413 let heartPath = heartItem.path; 414 heartItem.heart.setAttribute("data-saved", saved == true ? 1 : 0); 415 if (saved) { 416 heartPath.setAttribute("stroke", "#FFF") 417 heartPath.setAttribute("fill-opacity", 1) 418 heartPath.setAttribute("fill", "#F00") 419 } 420 else { 421 heartPath.setAttribute("stroke", "#FFF") 422 heartPath.setAttribute("fill-opacity", 0.2) 423 heartPath.setAttribute("fill", "#000") 424 } 425 }; 426 427 this.getListingName = (data) => { 428 if (data.IdxFeedTypeID == 10) { 429 return data.MlsStatus; 430 } 431 //return data.ListingStatus; 432 if (data.IdxFeedTypeID == 215) { 433 return data.ListingStatus; 434 } 435 let result = data.ListingStatusName; 436 if (data.ListingStatusCategoryTypeTblID == 2) { 437 if (data.ListingStatusCategoryFullName != null) { 438 result = data.ListingStatusCategoryFullName; 439 } 440 } 441 return result; 442 }; 443 444 this.getListingColor = (data) => { 445 let result = data.ListingStatusCategoryColor; 446 if (data.ListingStatusTblID == 4 || result == null) { 447 result = data.ListingStatusColor; 448 } 449 return result; 450 }; 451 452 // Populates a ListingSearchItem with listing data. 453 this.populateSearchListingItem = (siContainer, record, canOpenInNewWindow, heartKey) => { 454 try { 455 let box = siContainer.querySelector("a.box"); 456 box.href = "/prop-details/" + record.ListingID + "/" + this.getUrlAddress(record); 457 //box.setAttribute("class", "img"); 458 if (canOpenInNewWindow != undefined && canOpenInNewWindow == true) { 459 box.setAttribute("target", "_blank"); 460 } 461 462 let spanSearchResultPrice = siContainer.querySelector(".search-result-price"); 463 let spanSearchResultAddress = siContainer.querySelector(".srAddress"); 464 let liSearchResultBedrooms = siContainer.querySelector(".search-result-bedrooms"); 465 let liSearchResultBathrooms = siContainer.querySelector(".search-result-bathrooms"); 466 let liSearchResultSqft = siContainer.querySelector(".search-result-sqft"); 467 let liSearchResultAcres = siContainer.querySelector(".search-result-lot"); 468 let spanSearchResultCityStateZip = siContainer.querySelector(".srCity"); 469 let spanSearchResultPropType = siContainer.querySelector(".search-result-proptype"); 470 let propSaleStatus = siContainer.querySelector(".propSaleStatus"); 471 let propSaleStatusText = siContainer.querySelector(".propSaleStatus span"); 472 let spanNewlyListed = siContainer.querySelector("span.NewlyListed"); 473 let spanComingSoon = siContainer.querySelector("span.ComingSoon"); 474 let spanNewConstruction = siContainer.querySelector("span.NewConstruction"); 475 let spanOpenHouseDate = siContainer.querySelector("span.OpenHouseDate"); 476 let spanOpenHouseDateText = siContainer.querySelector("span.OpenHouseDate span"); 477 let divCardImageTop = siContainer.querySelector("div.card-img-top"); 478 let heartContainer = siContainer.querySelector(".heart-container"); 479 let svgHeart = siContainer.querySelector(".heart-container .svgHeart"); 480 let svgHeartPath = siContainer.querySelector(".heart-container .svgHeart path"); 481 let divOfficeName = siContainer.querySelector(".card-body .officeName"); 482 if (record["IdxFeedTypeID"] == 71 || record["IdxFeedTypeID"] == 72) { 483 let officeName = record["OfficeName"]; 484 if (officeName != null) { 485 officeName = officeName.toUpperCase(); 486 } 487 divOfficeName.innerText = officeName; 488 } 489 490 let heartItem = { 491 "record": record, 492 "heartContainer": heartContainer, 493 "heart": svgHeart, 494 "path": svgHeartPath 495 }; 496 497 if (this.ListingIDLookupHeart != null) {
498 if (this.ListingIDLookupHeart[record.ListingID] == null) { 499 this.ListingIDLookupHeart[record.ListingID] = {}; 500 } 501 this.ListingIDLookupHeart[record.ListingID][heartKey] = heartItem; 502 if (record.SiteUserSavedListingStatusTblID == 1) { 503 this.ToggleHeart(heartItem, true); 504 } 505 else { 506 this.ToggleHeart(heartItem, false); 507 } 508 } 509 510 heartContainer.addEventListener("click", (e) => { 511 let saved = heartItem.heart.getAttribute("data-saved"); 512 if (saved == 1) { 513 saved = false; 514 this.SetSavedListing(record.ListingID, false) 515 } 516 else { 517 saved = true; 518 this.SetSavedListing(record.ListingID, true) 519 } 520 }); 521 522 let imgfeedLogo = siContainer.querySelector(".feedLogo"); 523 if (this.isComingSoon(record)) { 524 spanComingSoon.style.display = "inline-block"; 525 } 526 else if (this.isNewlyListed(record)) { 527 spanNewlyListed.style.display = "inline-block"; 528 } 529 else if (this.isNewConstruction(record)) { 530 spanNewConstruction.style.display = "inline-block"; 531 } 532 533 let openHouseDate = this.getOpenHouseDate(record); 534 if (openHouseDate != null && openHouseDate.dtOpenHouse != null) { 535 spanOpenHouseDate.style.display = "inline-block"; 536 let dtOh = openHouseDate.dtOpenHouse; 537 spanOpenHouseDateText.innerText = (dtOh.getMonth() + 1) + "/" + dtOh.getDate() 538 } 539 let streetAddress = ""; 540 if (BaseHelper.displayAddress(record)) { 541 let addressParts = []; 542 addressParts.push(record["StreetNumber"]); 543 addressParts.push(record["StreetDirPrefix"]); 544 545 let streetName = record["StreetName"]; 546 let streetSuffix = record["StreetSuffix"]; 547 548 addressParts.push(streetName); 549 if (streetName == null) { 550 addressParts.push(streetSuffix); 551 } 552 else if ( 553 streetSuffix 554 && !streetName.toUpperCase().endsWith(streetSuffix.toUpperCase()) 555 ) { 556 addressParts.push(streetSuffix); 557 } 558 addressParts.push(record["StreetDirSuffix"]); 559 addressParts.push(record["UnitNumber"]); 560 let filteredAddress = addressParts.filter(part => part); 561 streetAddress = BaseHelper.toTitleCase(filteredAddress.join(" ")); 562 if (record["StreetNumber"] == null && record["StreetName"] == null && record["AddressLine"] != null) { 563 streetAddress = BaseHelper.toTitleCase(record["AddressLine"].split(',')[0]); 564 } 565 } 566 let listPrice = "" 567 if (record.ListingStatusTblID == 8 && (record.ClosePrice == null || record.State == "TX")) { 568 listPrice = "$Unknown" 569 } 570 else { 571 listPrice = record.SortPrice == null ? "" : BaseHelper.dollarFormatter.format(record.SortPrice); 572 } 573 let houseSize = "--"; 574 let lotSize = "--"; 575 houseSize = BaseHelper.getHouseSize(record); 576 lotSize = BaseHelper.getLotSize(record); 577 let CityStateZip = BaseHelper.toTitleCase(this.getValueOrEmpty(record.City)) + ", " + this.getValueOrEmpty(record.State) + ", " + BaseHelper.toTitleCase(this.getValueOrEmpty(record.Zip)); 578 let bedroomCount = "--"; 579 if (record.BedroomCount != null && record.BedroomCount != 0) { 580 bedroomCount = record.BedroomCount 581 } 582 let bathroomCount = "--"; 583 if (record.BathroomCount != null && record.BathroomCount != 0) { 584 bathroomCount = record.BathroomCount 585 } 586 let housePhotoUrl; 587 if (canOpenInNewWindow) { 588 housePhotoUrl = "/api/listing/" + record.ListingID + "/mainphoto"; 589 } 590 else { 591 housePhotoUrl = this.getHousePhotoUrl(record); 592 }
593 BaseHelper.setBackgroundImageWithFallback(divCardImageTop, housePhotoUrl,"/images/photos-coming-soon.svg", "/img/no-housephoto.jpg"); 594 //divCardImageTop.style = "background-image: url('" + housePhotoUrl + "'), url('/img/no-housephoto.jpg');"; 595 divCardImageTop.setAttribute("image-src", housePhotoUrl); 596 divCardImageTop.setAttribute("role", "img"); 597 divCardImageTop.setAttribute("aria-label", "Photo for " + streetAddress + ", " + CityStateZip); 598 spanSearchResultPrice.innerText = listPrice 599 spanSearchResultAddress.innerText = streetAddress.trim(); 600 601 liSearchResultBedrooms.prepend(bedroomCount + " "); 602 liSearchResultBathrooms.prepend(bathroomCount + " "); 603 liSearchResultSqft.innerText = houseSize; 604 liSearchResultAcres.innerText = lotSize; 605 spanSearchResultCityStateZip.innerText = CityStateZip; 606 spanSearchResultPropType.innerText = this.getValueOrEmpty(record.PropertyTypeName); 607 let color = this.getListingColor(record); 608 let name = this.getListingName(record); 609 propSaleStatus.style.color = this.getValueOrEmpty(color); 610 propSaleStatusText.innerText = this.getValueOrEmpty(name); 611 612 if (record["IdxFeedLogoImagePath"] == null) { 613 imgfeedLogo.style.display = "none"; 614 } 615 else { 616 imgfeedLogo.src = record["IdxFeedLogoImagePath"]; 617 imgfeedLogo.style.display = "block"; 618 imgfeedLogo.setAttribute("alt", record.ListingMlsName); 619 } 620 } 621 catch (e) { 622 console.log(e); 623 } 624 }; 625 626 this.getHousePhotoUrl = (record) => { 627 let providerID = record.IdxFeedProviderID; 628 629 //trestle 630 if (providerID != 1 && providerID != 4) { 631 let result = record.ListingMediaPreferredUrl; 632 633 if (result == null) { 634 result = record.ListingMediaFirstUrl; 635 } 636 637 if (result == null) { 638 return this.defaultImageUrl 639 } 640 641 return result; 642 } 643 644 //mlsgrid 645 let url = record.FirstPhotoURL; 646 let key = record.FirstMediaKey; 647 let type = record.FirstMediaType; 648 let origin = record.OriginatingSystemName 649 if (this.currentData == null || this.currentData.data == null || this.currentData.data.AzureStorageBaseUrl == null || providerID == null || BaseHelper.isStringNullOrWhiteSpace(url) || BaseHelper.isStringNullOrWhiteSpace(key)) { 650 return this.defaultImageUrl; 651 } 652 653 let base = this.currentData.data.AzureStorageBaseUrl + "/images/"; 654 655 if (providerID == 1) { 656 let provider = null; 657 provider = "MlsGrid/"; 658 let parts = url.split('/'); 659 let fileName = parts[parts.length - 1]; 660 let result = base + provider + key + "-" + fileName; 661 return result; 662 } 663 else if (providerID == 4) { 664 let provider = null; 665 provider = "MetroList2022/"; 666 let result = base + provider + origin.replaceAll(' ', '_') + "-" + record.ListingKey + "-" + key 667 return result; 668 } 669 else { 670 return this.defaultImageUrl 671 } 672 }; 673 674 this.clearGrid = (listings) => { 675 this.ListingSearchItemContainer.innerHTML = ""; 676 }; 677 this.findListings = async (request) => { 678 let response = await BaseHelper.MakeAJAXPostJSONRequest("/api/Listing/FindListings", request); 679 return response; 680 }; 681 //------------------------------------------------------------------------------------------------- 682 this.getListingRequest = (filterArr, page, fetch, orderBy, orderSort, count) => { 683 let data = 684 { 685 filterArr: filterArr, 686 page: page, 687 fetch: fetch, 688 orderBy: orderBy, 689 orderSort: orderSort, 690 count: count 691 }; 692 if (data.filterArr == null) { 693 data.filterArr = this.currentData.filterArr;
694 } 695 return JSON.parse(JSON.stringify(data)); 696 }; 697 698 this.makeListingRequest = () => { 699 let page = this.pBar.currentPage 700 let data = this.currentData; 701 let count = -1; 702 if (this.currentData.data != null && this.currentData.data.PaginatedData != null) { 703 count = this.currentData.data.PaginatedData.count 704 } 705 let request = this.getListingRequest(data.filterArr, page, data.fetch, data.orderBy, data.orderSort, count); 706 return request; 707 } 708 709 this.findListings = async (request) => { 710 let response = await BaseHelper.MakeAJAXPostJSONRequest("/api/Listing/FindListings", request); 711 return response; 712 }; 713 714 this.getListingData = async (request) => { 715 if (this.currentData == null || this.currentData.filterArr == null) { 716 return; 717 } 718 let response = await this.findListings(request); 719 if (this.IsListHub) { 720 let listHubResponse = JSON.parse(response); 721 let listingKeyObj = []; 722 listHubResponse.PaginatedData.data.forEach((d) => { 723 let item = { 724 lkey: d.ListingKey 725 } 726 listingKeyObj.push(item); //switched from key to lkey 01-23-2025 727 }) 728 lh('submit', 'SEARCH_DISPLAY', listingKeyObj); 729 } 730 return { 731 request: request, 732 response: response 733 }; 734 }; 735 //------------------------------------------------------------------------------------------------- 736 this.getAreaRequest = (mapRequest, page) => { 737 let request = JSON.parse(JSON.stringify(mapRequest)); 738 request.page = page; 739 return request; 740 }; 741 742 this.makeAreaRequest = () => { 743 return this.getAreaRequest(this.currentData.mapRequest, this.pBar.currentPage); 744 } 745 746 this.getArea = async (request) => { 747 let cpyRequest = JSON.parse(JSON.stringify(request)); 748 if (cpyRequest.filters != null) { 749 cpyRequest.filters = JSON.stringify(request.filters); 750 } 751 let response = await $.post("/api/Listing/listingSearcharea", cpyRequest); 752 return response; 753 }; 754 755 this.getMapData = async (request) => { 756 if (this.currentData == null || this.currentData.mapRequest == null) { 757 return; 758 } 759 let response = await this.getArea(request); 760 if (this.IsListHub) { 761 let listHubResponse = JSON.parse(response); 762 let listingKeyObj = []; 763 listHubResponse.PaginatedData.data.forEach((d) => { 764 let item = { 765 lkey: d.ListingKey 766 } 767 listingKeyObj.push(item); //switched from key to lkey 01-23-2025 768 }) 769 lh('submit', 'SEARCH_DISPLAY', listingKeyObj); 770 } 771 return { 772 request: request, 773 response: response 774 }; 775 }; 776 //-------------------------------------------------------------------------------------------- 777 this.getKeywordData = async () => { 778 if (this.currentData == null || this.currentData.filterArr == null) { 779 return; 780 } 781 let data = this.currentData;
782 let response = await this.getSearchKeywords(data.filterArr); 783 return response; 784 }; 785 786 this.isNewRequest = async () => { 787 if (this.currentData?.mapRequest != null) { 788 result = await this.getMapData(); 789 } 790 else if (this.currentData?.filterArr != null) { 791 result = await this.getListingData(); 792 } 793 return true; 794 }; 795 796 this.getData = async (request) => { 797 let result = null; 798 799 if (this.currentData?.mapRequest != null) { 800 result = await this.getMapData(request); 801 } 802 else if (this.currentData?.filterArr != null) { 803 result = await this.getListingData(request); 804 } 805 return result; 806 }; 807 808 this.getRequest = () => { 809 let result = null; 810 if (this.currentData?.mapRequest != null) { 811 result = this.makeAreaRequest(); 812 } 813 else if (this.currentData?.filterArr != null) { 814 result = this.makeListingRequest(); 815 } 816 return result; 817 }; 818 819 this.hasRequestChanged = async () => { 820 let result = null; 821 if (this.currentData?.mapRequest != null) { 822 result = await this.getMapData(this.pBar.currentPage); 823 } 824 else if (this.currentData?.filterArr != null) { 825 result = await this.getListingData(this.pBar.currentPage); 826 } 827 return result; 828 }; 829 830 this.refresh = async () => { 831 if (this.currentData == null) { 832 return null; 833 } 834 this.isRefreshing = true; 835 //give the latest call of refresh a unique id 836 let uuid = this.currentUuid = BaseHelper.getUuid() 837 //----------------------------------------------------------------- 838 //store the request, if it was previously retrieved, then just reuse it. 839 let request = this.getRequest(); 840 if (this.prevRequest != null && JSON.stringify(this.prevRequest) == JSON.stringify(request)) { 841 return { 842 type: "current", 843 data: this.rawData 844 }; 845 } 846 //----------------------------------------------------------------- 847 this.ToggleLoading(true); //display loading circle 848 let dataTask = this.dataTask = this.getData(request); //get the needed to refresh the display 849 let result = await this.dataTask; //wait for the data to come in. 850 851 while (this.dataTask != dataTask) { 852 //if refresh called again before the data was retrieved, await the latest task 853 dataTask = this.dataTask; 854 result = await dataTask; 855 } 856 857 //check if the current instance is the latest refresh call. 858 //if it wasnt, just return the data without refreshing the page. 859 if (this.currentUuid != uuid) { 860 return { 861 type: "copy", 862 data: this.rawData 863 }; 864 } 865 866 //if current instance is the latest refresh call, refresh the page. 867 //only need to refresh the page once with the latest data. 868 let response = result.response; 869 this.rawData = JSON.parse(response); 870 this.isRefreshing = false; 871 this.ToggleLoading(false); 872 //----------------------------------------------------------------- 873 this.populateGrid(this.rawData); 874 this.prevRequest = request; 875 this.pendingRawDataList.forEach((pendingRawData) => { 876 pendingRawData(this.rawData); 877 }); 878 this.pendingRawDataList = []; 879 if (this.onRefreshComplete != null) { 880 this.onRefreshComplete(this); 881 } 882 this.onScroll(); 883 return { 884 type: "latest", 885 data: this.rawData 886 }; 887 }; 888 889 this.onRefreshComplete = null; 890 891 this.getSearchKeywords = async (filterArr) => { 892 let data = 893 { 894 filterArr: filterArr, 895 }; 896 897 if (data.filterArr == null) { 898 data.filterArr = this.currentData.filterArr; 899 } 900 901 let result = await BaseHelper.MakeAJAXPostJSONRequest("/api/Listing/GetSearchKeywords", data); 902 903 return result; 904 }; 905 906 907 908 this.onTemplateLoad = function () { 909 this.ListingSearchItemContainer = this.element.querySelector(".ListingSearchItemContainer") 910 this.ListingSearchPagination = this.element.querySelector(".ListingSearchPagination"); 911 //------------------------------------------------------------------------- 912 //Update loading screen 913 this.fillerContainer = document.createElement("div"); 914 this.ListingSearchFillerContainer = document.createElement("div"); 915 916 this.fillerContainer.setAttribute("class", "container"); 917 this.ListingSearchFillerContainer.setAttribute("class", "ListingSearchFillerContainer row row-cols-1 row-cols-sm-2 row-cols-lg-3 g-3"); 918 919 this.fillerContainer.appendChild(this.ListingSearchFillerContainer); 920 921 this.div_loading.innerHTML = ""; 922 this.div_loading.appendChild(this.fillerContainer); 923 //------------------------------------------------------------------------- 924 this.ListingSearchPagination.appendChild(this.pBar.element); 925 926 for (let i = 0; i < 20; i++) { 927 let div = this.GetFillerCard(); 928 this.ListingSearchFillerContainer.appendChild(div); 929 } 930 this.pBar.onChange = (e) => { 931 if (this.currentData != null) { 932 //refresh and display new page if the current page is different than the page in pBar 933 if (this.currentData.page != this.pBar.currentPage) { 934 this.currentData.page = this.pBar.currentPage; 935 this.refresh(); 936 } 937 } 938 } 939 //this.btnPrevPage.addEventListener("click", this.onPrevPage); 940 //this.btnNextPage.addEventListener("click", this.onNextPage); 941 }; 942 943 944 this.changePage = (diff) => { 945 if (this.currentData == null) { 946 return 947 } 948 this.setPage(this.currentData.page + 1); 949 }; 950 951 this.setPage = (page) => { 952 this.currentData.page = page; 953 if (this.currentData == null || this.currentData.data == null || this.currentData.data.PaginatedData == null) { 954 return 955 } 956 let pData = this.currentData.data.PaginatedData; 957 if (this.currentData.page < 0) { 958 this.currentData.page = 0; 959 } 960 if (this.currentData.page >= pData.maxPages) { 961 this.currentData.page = pData.maxPages - 1; 962 } 963 }; 964} 965Widgets.ListingSearch.prototype = new Widgets.ListingSearch();
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.