1/** 2 * @file control.js 3 * @description Half-map and listing UI interactions and layout toggles for the WPresidence theme, including half-map behaviors. 4 */ 5/*global $,Modernizr, jQuery, ajaxcalls_vars,wpestate_custom_search_start_filtering_ajax,imagesLoaded,wpestate_restart_js_after_ajax, panorama,wpestate_toggleStreetView,wpestate_start_filtering_ajax,map,google,wpestate_new_open_close_map,document,initialGeop,placeCircle,wpestate_custom_search_start_filtering_ajax,first_time_wpestate_show_inpage_ajax_half,wpestate_show_pins, wpestate_load_stats,wpestate_enable_half_map_pin_action,wpestate_change_map_type,wpestate_load_stats_tabs,control_vars,mapfunctions_vars, wpestate_map_shortcode_function,grecaptcha,window*/ 6var width,height; 7width = jQuery(window).width(); 8height = jQuery(window).height(); 9var scroll_trigger = 0; 10var scroll_modal_save,scroll_modal; 11var modal_url = window.location.href; 12var modal_title = document.getElementsByTagName("title")[0]; 13var slider_counter = 0; 14 15 16 17jQuery(window).bind("load", function() { 18 wpestate_lazy_load_carousel_property_unit(); 19}); 20 21 22if(document.getElementById("search_wrapper")){ 23 var searchbar = document.getElementById("search_wrapper"); 24 var sticky_search = searchbar.offsetTop; 25} 26 27 28 29var switch_logo; 30switch_logo = jQuery('.header_wrapper_inside').attr('data-sticky-logo'); 31 32if(jQuery('.header5_top_row').length > 0){ 33 switch_logo = jQuery('.header5_top_row').attr('data-sticky-logo'); 34} 35if(wpestate_isRetinaDisplay()){ 36 switch_logo=wpestate_get_custom_retina_pin(switch_logo); 37 38} 39 40 41var switch_logo_original = jQuery('.header_wrapper_inside').attr('data-logo'); 42if(jQuery('.header5_top_row').length > 0){ 43 switch_logo_original = jQuery('.header5_top_row').attr('data-logo'); 44} 45 46if(wpestate_isRetinaDisplay()){ 47 switch_logo_original=wpestate_get_custom_retina_pin(switch_logo_original); 48} 49 50function wpestate_get_custom_retina_pin(custom_img){ 51 "use strict"; 52 53 if(typeof(custom_img) === "undefined"){ 54 return; 55 } 56 var custom_img_retina; 57 custom_img_retina=custom_img.replace(".png","_2x.png"); 58 59 jQuery.get(custom_img_retina) 60 .done(function() { 61 custom_img = custom_img_retina; 62 }).fail(function() { 63 }); 64 return custom_img; 65} 66 67 68 69 70jQuery(window).scroll(function () { 71 "use strict"; 72 var scroll =scroll_modal= jQuery(window).scrollTop(); 73 74 if(control_vars.stiky_search==='yes'){ 75 wpestate_adv_search_sticky(scroll); 76 }else{ 77 wpestate_header_sticky(scroll); 78 } 79 80 81 if (scroll >= control_vars.scroll_trigger) { 82 jQuery('.contact-box').addClass('islive'); 83 jQuery('.backtop').addClass('islive'); 84 }else{ 85 jQuery('.contact-box ').removeClass('islive'); 86 jQuery('.backtop').removeClass('islive'); 87 jQuery('.contactformwrapper').addClass('hidden'); 88 } 89 jQuery('.contact_close_button').on( 'click', function(event) { 90 event.preventDefault(); 91 jQuery('.contactformwrapper').addClass('hidden'); 92 }); 93 94}); 95 96 97 98 99 100 101var sticky_search_local = document.getElementById("search_wrapper") ? document.getElementById("search_wrapper").offsetTop : 0; 102var search_height = jQuery('#search_wrapper').height(); 103 104 105 106/* 107* When we advanced search sticky 108* 109* 110*/ 111// Global variable to store the scroll position at which the searchbar 112// should be considered as "exiting" the viewport 113var searchbarExitingThreshold; 114 115/** 116 * Calculates the threshold at which the searchbar is considered to be exiting the viewport. 117 * This function should be called on page load and window resize to ensure accuracy. 118 */ 119function calculateSearchbarThreshold() { 120 "use strict"; 121 var searchbar = jQuery('.search_wrapper_sticky_search'); 122 if (searchbar.length > 0) { 123 // Get the initial top position of the searchbar 124 var searchbarInitialPosition = searchbar.offset().top; 125 // Get the height of the searchbar 126 var searchbarHeight = searchbar.outerHeight(); 127 // Calculate the threshold by adding the initial position and height 128 searchbarExitingThreshold = searchbarInitialPosition + searchbarHeight; 129 130 } 131} 132 133/** 134 * Main function to handle the sticky behavior of the advanced search bar. 135 * This function is called on scroll events. 136 * 137 * @param {number} scroll - The current scroll position of the window. 138 */ 139function wpestate_adv_search_sticky(scroll) { 140 "use strict"; 141 142 // Early return if the search wrapper doesn't exist 143 if (!document.getElementById("search_wrapper")) { 144 return; 145 } 146 // Early return for mobile devices (screens smaller than 1024px) 147 if (screen.width < 1024) { 148 return; 149 } 150 151 var searchbar = jQuery('.search_wrapper_sticky_search.with_search_form_float'); 152 // Early return if the searchbar doesn't exist 153 if (searchbar.length === 0) { 154 return; 155 } 156 157 if (scroll >= searchbarExitingThreshold) { 158 // The searchbar is exiting or has exited the screen 159 if (!searchbar.hasClass('sticky_adv_anime')) { 160 // Add the class only if it's not already present 161 searchbar.addClass('sticky_adv_anime'); 162 163 } 164 } else { 165 // The searchbar is visible on the screen 166 if (searchbar.hasClass('sticky_adv_anime')) { 167 // Remove the class only if it's present 168 searchbar.removeClass('sticky_adv_anime'); 169 170 } 171 } 172} 173 174 175 176 177 178 179 180 181 182function wpestate_header_sticky(scroll){ 183 184 "use strict"; 185 186 var sticky_class="master_header_sticky"; 187 var control_vars_scroll_trigger=parseInt(control_vars.scroll_trigger); 188
189 if(control_vars.content_type!='' && control_vars.content_type!=='tabs' && jQuery('.wpestate_top_property_navigation_link').length!==0){ 190 sticky_class=sticky_class+" "+"sticky_property_menu" 191 } 192 193 194 if(jQuery('.admin-bar').length>0){ 195 control_vars_scroll_trigger=control_vars_scroll_trigger+32; 196 } 197 198 if (scroll >= control_vars_scroll_trigger) { 199 if (!Modernizr.mq('only all and (max-width: 1023px)')) { 200 201 jQuery(".master_header").addClass(sticky_class); 202 jQuery('.logo').addClass('miclogo'); 203 if( switch_logo!=='' ){ 204 jQuery('#logo_image').attr('src',switch_logo); 205 } 206 207 if( !jQuery(".header_wrapper").hasClass('header_type4') ){ 208 jQuery(".header_wrapper").addClass("navbar-fixed-top"); 209 210 } 211 212 jQuery('#user_menu_open').hide(); 213 jQuery('.navicon-button').removeClass('opensvg'); 214 jQuery('#wpestate_header_shoping_cart').hide(); 215 216 jQuery('.wpestate_top_property_navigation').addClass('sticky_property_menu_visible'); 217 218 } 219 220 } else { 221 jQuery(".master_header").removeClass(sticky_class); 222 jQuery(".header_wrapper").removeClass("navbar-fixed-top"); 223 224 225 226 jQuery('#user_menu_open').hide(); 227 jQuery('#wpestate_header_shoping_cart').hide(); 228 jQuery('.logo').removeClass('miclogo'); 229 230 jQuery('.wpestate_top_property_navigation').removeClass('sticky_property_menu_visible'); 231 232 233 if( switch_logo!=='' ){ 234 235 jQuery('#logo_image').attr('src',switch_logo_original); 236 } 237 } 238} 239 240 241 242function wpestate_isRetinaDisplay() { 243 "use strict"; 244 if (window.matchMedia) { 245 var mq = window.matchMedia("only screen and (min--moz-device-pixel-ratio: 1.3), only screen and (-o-min-device-pixel-ratio: 2.6/2), only screen and (-webkit-min-device-pixel-ratio: 1.3), only screen and (min-device-pixel-ratio: 1.3), only screen and (min-resolution: 1.3dppx)"); 246 return (mq && mq.matches || (window.devicePixelRatio > 1)); 247 } 248} 249 250 251/** 252 * Property Navigation Scroll Handler 253 * 254 * Manages smooth scrolling to property sections and highlights 255 * active navigation items based on scroll position. 256 * 257 * Dependencies: 258 * - jQuery 259 * - .wpestate_top_property_navigation element with anchor links 260 * - .property-panel elements with matching IDs 261 */ 262 263function wpestate_property_sticky() { 264 'use strict'; 265 266 const SCROLL_OFFSET = 80; 267 const SCROLL_DURATION = 500; 268 const $navigation = jQuery('.wpestate_top_property_navigation a'); 269 270 // Handle navigation click events 271 $navigation.on('click', function(event) { 272 event.preventDefault(); 273 274 // Get target section 275 const targetId = jQuery(this).attr('href'); 276 const $targetElement = jQuery(targetId); 277 278 // Update active state 279 $navigation.removeClass('item_active'); 280 jQuery(this).addClass('item_active'); 281 282 // Smooth scroll to target 283 jQuery('html, body').animate({ 284 scrollTop: $targetElement.offset().top - SCROLL_OFFSET 285 }, SCROLL_DURATION); 286 }); 287 288 // Handle scroll events 289 jQuery(window).on('scroll', function() { 290 const scrollTop = jQuery(window).scrollTop() + SCROLL_OFFSET; 291 let currentSection = null; 292 293 // Find the current section 294 jQuery('.property-panel').each(function() { 295 const sectionTop = jQuery(this).offset().top; 296 const sectionBottom = sectionTop + jQuery(this).outerHeight(); 297 298 if (scrollTop >= sectionTop && scrollTop < sectionBottom) { 299 currentSection = this.id; 300 return false; // Break the loop when found 301 } 302 }); 303 304 // Update active state only if a section is found 305 $navigation.removeClass('item_active'); 306 jQuery('.wpestate_top_property_navigation a').removeClass('item_active'); 307 308 if (currentSection) { 309 $navigation.filter(`[href="#${currentSection}"]`).addClass('item_active'); 310 311 } 312 }); 313} 314 315 316jQuery(window).resize(function() { 317 "use strict"; 318 if(jQuery(window).width() != width ){ 319 jQuery('#mobile_menu').hide('10'); 320 } 321 wpestate_adjustMegaMenuPosition(); 322 wpestate_studioMegaMenuInit(); 323 wpestate_half_map_responsive(); 324 wpestat_resize_wpestate_property_slider_v2(); 325 326}); 327 328function wpestate_half_map_responsive(){ 329 if (Modernizr.mq('only screen and (min-width: 640px)') && Modernizr.mq('only screen and (max-width: 1025px)')) { 330 var half_map_header = jQuery('.master_header ').height(); 331 } 332 333} 334 335/** 336 * Manages half-map controls, toggling between split and list-only layouts without 337 * mutating column classes until the user interacts with the controls. 338 */ 339function wpestate_half_map_controls(){ 340 341 // Cache DOM elements used by the half-map controls to avoid repeated lookups. 342 const halfMapListButton = jQuery('#wperesidence_half_map_list_view'); 343 const halfMapMapButton = jQuery('#wperesidence_half_map_view'); 344 const halfMapSidebar = jQuery('#google_map_prop_list_sidebar'); 345 const halfMapWrapper = jQuery('#google_map_prop_list_wrapper'); 346 const listingAjaxContainer = jQuery('#listing_ajax_container'); 347 const filterWrapper = jQuery('.wpresidence_half_map_filter_wrapper'); 348 const defaultHalfMapView = (filterWrapper.data('half-map-default-view') || 'grid').toString().toLowerCase();
349 let currentHalfMapMode = defaultHalfMapView === 'list' ? 'list' : 'map'; 350 351 // Guard for missing elements before binding handlers. 352 if (halfMapListButton.length && halfMapMapButton.length && halfMapSidebar.length && halfMapWrapper.length) { 353 /** 354 * Extracts the column class for the requested breakpoint. 355 * @param {jQuery} element - Element with Bootstrap grid classes. 356 * @param {string} breakpoint - Breakpoint suffix (sm|md|lg). 357 * @returns {string} The matching column class or an empty string. 358 */ 359 const getHalfMapColClass = function(element, breakpoint) { 360 const currentClasses = element.attr('class') || ''; 361 const matchedClass = currentClasses.match(new RegExp(`col-${breakpoint}-\\d+`)); 362 363 return matchedClass ? matchedClass[0] : ''; 364 }; 365 366 /** 367 * Replaces a specific breakpoint column class while keeping other classes intact. 368 * @param {jQuery} element - Element to update. 369 * @param {string}
369 breakpoint - Breakpoint suffix (sm|md|lg). 370 * @param {string} targetClass - Column class to apply (e.g., col-md-3). 371 */ 372 const setHalfMapColClass = function(element, breakpoint, targetClass) { 373 const currentClasses = element.attr('class') || ''; 374 const classesForBreakpoint = currentClasses.match(new RegExp(`col-${breakpoint}-\\d+`, 'g')); 375 376 // Remove only the breakpoint-specific classes so other styling remains untouched. 377 if (classesForBreakpoint) { 378 element.removeClass(classesForBreakpoint.join(' ')); 379 } 380 381 // Apply the requested column class when provided. 382 if (targetClass) { 383 element.addClass(targetClass); 384 } 385 }; 386 387 /** 388 * Returns the wrappers targeted for half map layout updates. 389 * @returns {jQuery} Listing wrappers inside the AJAX container. 390 */ 391 const getHalfMapListingWrappers = function(){ 392 return listingAjaxContainer.find('.listing_wrapper'); 393 }; 394 395 /** 396 * Persists the starting column classes and data-org values for each listing wrapper. 397 */ 398 const storeOriginalListingColumns = function() { 399 if (!listingAjaxContainer.length) { 400 return; 401 } 402 403 getHalfMapListingWrappers().each(function(){ 404 const wrapper = jQuery(this); 405 406 if (!wrapper.data('half-map-original-md-class')) { 407 wrapper.data('half-map-original-md-class', wrapper.attr('data-half-map-original-md-class') || getHalfMapColClass(wrapper, 'md')); 408 } 409 410 if (!wrapper.data('half-map-original-lg-class')) { 411 wrapper.data('half-map-original-lg-class', wrapper.attr('data-half-map-original-lg-class') || getHalfMapColClass(wrapper, 'lg')); 412 } 413 414 if (!wrapper.data('half-map-original-sm-class')) { 415 wrapper.data('half-map-original-sm-class', wrapper.attr('data-half-map-original-sm-class') || getHalfMapColClass(wrapper, 'sm')); 416 } 417 418 if (!wrapper.data('half-map-original-org')) { 419 wrapper.data('half-map-original-org', wrapper.attr('data-half-map-original-org') || wrapper.attr('data-org') || ''); 420 } 421 }); 422 }; 423 424 /** 425 * Extracts the numeric column size from a Bootstrap class. 426 * @param {string} columnClass - Bootstrap column class (e.g. col-md-6). 427 * @param {string} fallback - Value used when no match is found. 428 * @returns {string} Column size number as a string. 429 */ 430 const deriveOrgFromClass = function(columnClass, fallback) { 431 const match = (columnClass || '').match(/col-[a-z]+-(\d+)/); 432 return match ? match[1] : fallback; 433 }; 434 435 /** 436 * Transforms the theme setting column size for the list-only half-map layout. 437 * @param {string} originalOrg - Column size read from theme settings. 438 * @returns {string} Remapped column size. 439 */ 440 const transformOrgForListMode = function(originalOrg) { 441 switch (originalOrg) { 442 case '6': 443 return '3'; 444 case '4': 445 case '3': 446 return '2'; 447 case '12': 448 return '12'; 449 default: 450 return originalOrg; 451 } 452 }; 453 454 /** 455 * Restores the column size when leaving the compressed list-mode mapping. 456 * 457 * @param {string} currentOrg - Column size currently applied to the card. 458 * @returns {string} Column size adjusted back toward the grid defaults. 459 */ 460 const getGridOrgFromSettings = function() { 461 let listingsPerRow = parseInt(control_vars.listings_per_row, 10); 462 463 if (filterWrapper.length && halfMapWrapper.length && halfMapSidebar.length) { 464 listingsPerRow = listingsPerRow - 1; 465 } 466 467 switch (listingsPerRow) { 468 case 2: 469 return '6'; 470 case 3: 471 return '4'; 472 case 4: 473 return '3'; 474 default: 475 return ''; 476 } 477 }; 478 479 const revertOrgFromListMode = function(currentOrg) { 480 const settingsOrg = getGridOrgFromSettings(); 481 482 switch (currentOrg) { 483 case '3': 484 return settingsOrg || '6'; 485 case '2': 486 return settingsOrg || '4'; 487 case '12': 488 // When listings start in a single-column layout, restore the grid using the theme setting. 489 return settingsOrg || '6'; 490 default: 491 return currentOrg; 492 } 493 }; 494 495 /** 496 * Applies the grid layout based on the current half-map mode (map or list). 497 * When returning from list-only mode, previously shrunk columns are expanded 498 * back to their original theme-configured sizes. 499 */ 500 const applyHalfMapGridColumns = function() { 501 if (!listingAjaxContainer.length) { 502 return; 503 } 504 505 storeOriginalListingColumns(); 506 507 getHalfMapListingWrappers().each(function(){ 508 const wrapper = jQuery(this); 509 const originalMdClass = wrapper.data('half-map-original-md-class') || wrapper.attr('data-half-map-original-md-class') || ''; 510 const originalLgClass = wrapper.data('half-map-original-lg-class') || wrapper.attr('data-half-map-original-lg-class') || ''; 511 const originalSmClass = wrapper.data('half-map-original-sm-class') || wrapper.attr('data-half-map-original-sm-class') || ''; 512 const originalOrg = wrapper.data('half-map-original-org') || wrapper.attr('data-half-map-original-org') || deriveOrgFromClass(originalMdClass, '') || wrapper.attr('data-org') || ''; 513 514 const settingsOrg = getGridOrgFromSettings(); 515 let restoredOrg = originalOrg ? originalOrg.toString() : settingsOrg || '6'; 516 517 if ((originalMdClass === 'col-md-12' && originalLgClass === 'col-lg-12') && settingsOrg) { 518 restoredOrg = settingsOrg; 519 } 520 // When list mode shrunk the columns (e.g., 6 -> 3), expand them back before 521 // rebuilding the grid view. If no original is present, the reverse mapping 522 // still ensures a sensible fallback size. 523 const normalizedOrg = currentHalfMapMode === 'map' ? revertOrgFromListMode(restoredOrg) : restoredOrg; 524 525 let targetOrg = normalizedOrg || '6'; 526 const derivedMdOrg = deriveOrgFromClass(originalMdClass, targetOrg); 527 const derivedLgOrg = deriveOrgFromClass(originalLgClass, targetOrg); 528 const derivedSmOrg = deriveOrgFromClass(originalSmClass, targetOrg); 529 530 let targetMdClass = originalMdClass || `col-md-${targetOrg}`; 531 let targetLgClass = originalLgClass || `col-lg-${targetOrg}`; 532 let targetSmClass = originalSmClass || `col-sm-${targetOrg}`; 533 534 if (derivedMdOrg !== targetOrg) { 535 targetMdClass = `col-md-${targetOrg}`; 536 } 537 538 if (derivedLgOrg !== targetOrg) { 539 targetLgClass = `col-lg-${targetOrg}`; 540 } 541 542 if (derivedSmOrg !== targetOrg) { 543 targetSmClass = `col-sm-${targetOrg}`; 544 } 545 546 if (currentHalfMapMode === 'list') { 547 targetOrg = transformOrgForListMode(targetOrg.toString()); 548 targetMdClass = `col-md-${targetOrg}`; 549 targetLgClass = `col-lg-${targetOrg}`; 550 targetSmClass = `col-sm-${targetOrg}`; 551 } 552 553 setHalfMapColClass(wrapper, 'md', targetMdClass); 554 setHalfMapColClass(wrapper, 'lg', targetLgClass); 555 setHalfMapColClass(wrapper, 'sm', targetSmClass); 556 wrapper.attr('data-org', targetOrg); 557 }); 558 }; 559 560 /** 561 * Forces a single-column layout for list view while keeping data-org in sync. 562 */ 563 const applyHalfMapListColumns = function() { 564 if (!listingAjaxContainer.length) { 565 return; 566 } 567 568 // Persist the starting grid classes before forcing the list layout so we can 569 // rebuild the correct column sizes when switching back to grid view. 570 storeOriginalListingColumns(); 571 572 getHalfMapListingWrappers().each(function(){ 573 const wrapper = jQuery(this); 574 setHalfMapColClass(wrapper, 'md', 'col-md-12'); 575 setHalfMapColClass(wrapper, 'lg', 'col-lg-12'); 576 setHalfMapColClass(wrapper, 'sm', 'col-sm-12'); 577 wrapper.attr('data-org', '12'); 578 }); 579 }; 580 581 /** 582 * Synchronizes the grid/list layout with the currently selected view control. 583 */ 584 const applyCurrentGridListLayout = function() { 585 if (jQuery('#list_view').hasClass('icon_selected')) { 586 applyHalfMapListColumns(); 587 } else { 588 applyHalfMapGridColumns(); 589 } 590 }; 591 592 /**
593 * Displays the split view and applies the appropriate grid/list sizing. 594 * @param {string} [selectedControl='map'] - Which control should be marked selected. 595 */ 596 const setHalfMapSplitView = function(selectedControl = 'map') { 597 currentHalfMapMode = 'map'; 598 halfMapWrapper.show().removeClass('col-md-12').addClass('col-md-6'); 599 halfMapSidebar.show().removeClass('col-md-12').addClass('col-md-6'); 600 applyCurrentGridListLayout(); 601 /** 602 * Forces the Google/Leaflet map canvas to recalculate dimensions after the 603 * hidden container becomes visible again. 604 */ 605 const refreshHalfMapCanvas = function() { 606 // Abort when the global map reference is not available yet. 607 if (typeof map === 'undefined') { 608 return; 609 } 610 611 // Trigger the appropriate resize hook for the active map library. 612 if (typeof wp_estate_kind_of_map !== 'undefined' && wp_estate_kind_of_map === 1 && typeof google !== 'undefined' && google.maps) { 613 google.maps.event.trigger(map, 'resize'); 614 615 // Re-fit map bounds when available to avoid empty canvases after resizing. 616 if (typeof bounds_list !== 'undefined') { 617 map.fitBounds(bounds_list); 618 } 619 } else if (typeof map.invalidateSize === 'function') { 620 map.invalidateSize(); 621 622 // Leaflet also benefits from an explicit fit once the DOM size is updated. 623 if (typeof bounds_list !== 'undefined') { 624 map.fitBounds(bounds_list); 625 } 626 } 627 }; 628 629 // Ensure the map is redrawn now that the wrapper has a non-zero width. 630 refreshHalfMapCanvas(); 631 632 if (selectedControl === 'map') { 633 halfMapMapButton.addClass('half_map_selected'); 634 halfMapListButton.removeClass('half_map_selected'); 635 } else { 636 halfMapListButton.addClass('half_map_selected'); 637 halfMapMapButton.removeClass('half_map_selected'); 638 } 639 }; 640 641 /** 642 * Expands the listings sidebar to full width and remaps columns for list mode. 643 */ 644 const setHalfMapListOnlyView = function() { 645 currentHalfMapMode = 'list'; 646 halfMapListButton.addClass('half_map_selected'); 647 halfMapMapButton.removeClass('half_map_selected'); 648 halfMapSidebar.show().removeClass('col-md-6').addClass('col-md-12'); 649 halfMapWrapper.hide(); 650 applyCurrentGridListLayout(); 651 }; 652 653 // Bind click handlers to toggle between map and list layouts. 654 halfMapMapButton.on('click', function(){ 655 setHalfMapSplitView('map'); 656 }); 657 658 halfMapListButton.on('click', function(){ 659 setHalfMapListOnlyView(); 660 }); 661 662 // Make current layout helpers available for the grid/list controls. 663 window.wpestateHalfMapState = { 664 applyGridLayout: applyHalfMapGridColumns, 665 applyListLayout: applyHalfMapListColumns, 666 applyCurrentLayout: applyCurrentGridListLayout, 667 getMode: function(){ 668 return currentHalfMapMode; 669 } 670 }; 671 } 672 673 jQuery('.half_mobile_toggle_listings').on('click',function(){ 674 675 jQuery('.half_map_controllers_wrapper div').removeClass('half_control_visible'); 676 jQuery(this).addClass('half_control_visible'); 677 jQuery('#google_map_prop_list_wrapper').removeAttr('style'); 678 jQuery('#google_map_prop_list_sidebar').show(); 679 jQuery('.half_mobile_hide').hide(); 680 jQuery('#colophon').show(); 681 wpestate_adjust_sticky_footer(); 682 }); 683 684 685 jQuery('.half_mobile_toggle_map').on('click',function(){ 686 687 jQuery('.half_map_controllers_wrapper div').removeClass('half_control_visible'); 688 jQuery(this).addClass('half_control_visible'); 689 jQuery('#google_map_prop_list_sidebar').hide(); 690 jQuery('#google_map_prop_list_wrapper').css('height','100%'); 691 jQuery('#google_map_prop_list_wrapper').css('position','relative'); 692 jQuery('#googleMap').css('min-height','100vh'); 693 694 // Hide footer 695 jQuery('#colophon').hide(); 696 jQuery('.wpresidence_main_wrapper_class').css('margin-bottom','0px'); 697 698 699 jQuery('.half_mobile_hide').show(); 700
701 wpresidence_map_general_fit_to_bounds(1); 702 if(wp_estate_kind_of_map===1){ 703 704 }else if(wp_estate_kind_of_map===2){ 705 map.invalidateSize(); 706 map.fitBounds(bounds_list); 707 } 708 }); 709} 710 711 712 713 714 715Number.prototype.format = function(n, x) { 716 var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\.' : '$') + ')'; 717 return this.toFixed(Math.max(0, ~~n)).replace(new RegExp(re, 'g'), '$&'+control_vars.price_separator); 718}; 719 720function wpestate_element_hide(item){ 721 "use strict"; 722 jQuery(document).on( 'click', function(event) { 723 if (!jQuery(item).is(event.target) && jQuery(item).has(event.target).length === 0 ){ 724 jQuery('#results').fadeOut(); 725 726 } 727 }); 728} 729wpestate_element_hide('.search_wrapper'); 730 731function wpestate_lazy_load_carousel_property_unit(){ 732 "use strict"; 733 734 jQuery('.property_unit_carousel img').each(function(event){ 735 var new_source=''; 736 new_source=jQuery(this).attr('data-lazy-load-src'); 737 if(typeof (new_source)!=='undefined' && new_source!==''){ 738 739 jQuery(this).attr('src',new_source); 740 } 741 }); 742} 743 //recaptha 744 745 746function wpestate_card_unit_contact_actions(){ 747 748 749 jQuery('.wpestate_property_card_contact_wrapper_phone').on('click',function(event){ 750 event.stopPropagation(); 751 752 var prop_id = jQuery(this).attr('data-item-id'); 753 var parent = jQuery(this).parent().parent(); 754 755 parent.find('.wpestate_card_unit_call_'+prop_id).appendTo("body"); 756 jQuery('body> .wpestate_card_unit_call_'+prop_id).first().modal("show"); 757 }); 758 759 jQuery('.wpestate_property_card_contact_wrapper_email').on('click',function(event){ 760 event.stopPropagation(); 761 var prop_id = jQuery(this).attr('data-item-id'); 762 var parent = jQuery(this).parent().parent(); 763 parent.find('.wpestate_card_unit_email_'+prop_id).appendTo("body"); 764 jQuery('body> .wpestate_card_unit_email_'+prop_id).first().modal("show"); 765 }); 766 767 jQuery('.wpestate_property_card_contact_wrapper_whatsupp').on('click',function(event){ 768 event.stopPropagation(); 769 770 }); 771 772} 773 774 775 776 777 778 779wpestate_advnced_filters_bars(); 780 781function wpresidence_advanced_searc_6_actions(){ 782 ////////// adv serach 6 783 jQuery('.adv6_tab_head,.elementor_search_tab_head').on( 'click', function(event) { 784 785 786 787 var tab_controls; 788 var parent=jQuery(this).parent().parent(); 789 parent.find('.adv_search_tab_item').removeClass('active'); 790 jQuery(this).parent().addClass('active'); 791 792 793 tab_controls = jQuery(this).attr('aria-controls'); 794 jQuery('.adv6_price_low').removeClass('price_active'); 795 jQuery('.adv6_price_max').removeClass('price_active'); 796 797 jQuery('#'+tab_controls).find('.adv6_price_low').addClass('price_active'); 798 jQuery('#'+tab_controls).find('.adv6_price_max').addClass('price_active'); 799 800 }); 801 802} 803 804 805 806/** 807 * Trigger Login Modal Open Action 808 * 809 * This function sets up an event listener for the login trigger modal button. 810 * When clicked, it calls the function to open the login modal. 811 * 812 * @since 1.0.0 813 * 814 * @requires jQuery 815 * @requires wpestate_trigger_login_modal_open 816 * 817 * @return {void} 818 */ 819function wpestate_trigger_login_modal_open_action() { 820 jQuery('#login_trigger_modal').on('click', function(event) { 821 wpestate_trigger_login_modal_open(2); 822 }); 823} 824 825/** 826 * Open Login Modal 827 * 828 * This function handles the opening of the login modal. It's used in various scenarios 829 * such as saving to favorites, saving a search, or adding a property when login is required. 830 * The function behaves differently based on the screen size (desktop vs mobile). 831 * 832 * @since 1.0.0 833 * 834 * @requires jQuery 835 * @requires Modernizr 836 * 837 * @return {void} 838 */ 839function wpestate_trigger_login_modal_open(stayOnPage) { 840 // Check if the screen width is greater than 768px (non-mobile devices) 841 // stayOnPage is a flag that indicates if the page should be reloaded after login 1-yes, 0-no will reload page from theme option , 2 - no will reload current page 842 if(!wpestate_isMobileOrTablet()){ 843 // Desktop behavior 844 var login_modal = jQuery('#modal_login_wrapper'); 845 846 // Show the login modal 847 login_modal.show(); 848 // Set focus to the first focusable element in the modal 849 login_modal.find('[autofocus]').focus(); 850 851 // Set the loginpop value to 1 (indicating a popup login) 852 login_modal.find('.loginpop').val(stayOnPage); 853 } else { 854 // Mobile behavior 855 // Trigger the mobile user menu 856 jQuery('.mobile-trigger-user').trigger('click'); 857 858 // Set the loginpop value to 1 in the mobile wrapper 859 jQuery('.mobilewrapper-user .loginpop').val(stayOnPage); 860 } 861} 862 863 864function wpestate_bootstrap53_dropdown(){ 865 jQuery('.wpresidence_dropdown .dropdown-menu li').on('click', function() { 866 // Get the selected value and label 867 var selectedValue = jQuery(this).data('value'); 868 var selectedLabel = jQuery(this).text(); 869 870 // Get the term ID from the clicked item (taxonomy items carry data-term-id) 871 var selectedTermId = jQuery(this).data('term-id') || ''; 872 873 var $wrapper = jQuery(this).closest('.wpresidence_dropdown'); 874 875 // Update the button text 876 $wrapper.find('.dropdown-toggle').text(selectedLabel); 877 878 // Update the hidden input value 879 $wrapper.find('input[type="hidden"]').val(selectedValue); 880 881 // Propagate the selected term ID to button, hidden input, and dropdown list 882 $wrapper.find('.dropdown-toggle, input[type="hidden"], .dropdown-menu').attr('data-term-id-selected', selectedTermId); 883 884 // Optionally close the dropdown after selection 885 jQuery(this).closest('.dropdown').removeClass('show'); 886 jQuery(this).closest('.dropdown').find('.dropdown-menu').removeClass('show'); 887 }); 888} 889 890 891 892jQuery(document).ready(function () { 893 "use strict"; 894 895 wpestate_bootstrap53_dropdown(); 896 wpestate_initializeTooltips_bootstrap53(); 897 898 // Calculate the initial threshold for advanced search sticky 899 calculateSearchbarThreshold(); 900 // Get the initial scroll position 901 var initialScroll = jQuery(window).scrollTop(); 902 // Call the function to set the correct initial state for advanced search sticky 903 wpestate_adv_search_sticky(initialScroll); 904 905 // trigger login modal open 906 wpestate_trigger_login_modal_open_action(); 907 908 909 jQuery('#login_user_wd').focus({ preventScroll: true }); 910 911 if(jQuery('.wpestate_anime').length>0 ){ 912 jQuery('.wpestate_anime').each( function(){ 913 var element_id = jQuery(this).attr('id'); 914 wpestate_property_list_sh('#'+element_id+' .wpestate_item_list_sh', '#'+element_id+' .control_tax_sh'); 915 }); 916 917 } 918 wpestate_change_currency_dropdown_action(); 919 wpestate_adjustMegaMenuPosition(); 920 wpestate_studioMegaMenuInit(); 921 wpestate_reposion_dropdowns(); 922 wpestate_beds_baths_component(); 923 wpestate_price_component_item(); 924 wpestate_price_component_item_v3(); 925 926 wpestate_blog_list_widget(); 927 wpestate_get_location(); 928 wpestate_grid_list_controls(); 929 930 wpestate_slider_box(); 931 wpestate_enable_share_unit(); 932 wpestate_control_media_buttons(); 933 wpestate_card_unit_contact_actions(); 934 wpestate_morgate_widget_action(); 935 wpestate_zillow_widget_action(); 936 wpestate_save_search_actions(); 937 wpestate_delete_save_search_actions(); 938 wpestate_overview_map(); 939 wpestate_extended_search_function(); 940 wpresidence_advanced_searc_6_actions(); 941 wpestate_show_hide_search_form_hidden_fields(); 942 wpestate_adjust_sticky_footer(); 943 wpestate_map_types_control(); 944 945
946 //////////////////////////////////////////////////////////////////////////////////////////// 947 ///city-area-selection 948 /////////////////////////////////////////////////////////////////////////////////////////// 949 950 wpestate_filter_city_area('filter_city','filter_area'); 951 wpestate_filter_city_area('sidebar-adv-search-city','sidebar-adv-search-area'); 952 wpestate_filter_city_area('adv-search-city','adv-search-area'); 953 wpestate_filter_city_area('half-adv-search-city','half-adv-search-area'); 954 wpestate_filter_city_area('shortcode-adv-search-city','shortcode-adv-search-area'); 955 wpestate_filter_city_area('mobile-adv-search-city','mobile-adv-search-area'); 956 wpestate_filter_city_area('property_city_submit', 'property_area_submit'); 957 wpestate_filter_city_area('a_filter_cities', 'a_filter_areas'); 958 wpestate_filter_city_area('property_city', 'property_area'); 959 960 //////////////////////////////////////////////////////////////////////////////////////////// 961 //county-city-selection 962 /////////////////////////////////////////////////////////////////////////////////////////// 963 wpestate_filter_county_city( 'filter_county', 'filter_city' ); 964 wpestate_filter_county_city( 'sidebar-adv-search-countystate', 'sidebar-adv-search-city' ); 965 wpestate_filter_county_city( 'adv-search-countystate', 'adv-search-city' ); 966 wpestate_filter_county_city( 'half-adv-search-countystate', 'half-adv-search-city' ); 967 wpestate_filter_county_city( 'shortcode-adv-search-countystate', 'shortcode-adv-search-city' ); 968 wpestate_filter_county_city( 'mobile-adv-search-countystate', 'mobile-adv-search-city' ); 969 wpestate_filter_county_city( 'a_filter_county', 'a_filter_cities' ); 970 wpestate_filter_county_city( 'county-state', 'property_city' ); 971 972 973 974 if(jQuery('.googleMap_shortcode_class').length>0 ){ 975 if( jQuery(".single-estate_property").length==0 ){ 976 wpestate_map_shortcode_function(); 977 }else{ 978 if( jQuery("#googleMap").length==0 && jQuery("#googleMapSlider").length==0 ){ 979 } 980 } 981 } 982 983 984 jQuery('body').on('click', '.add_custom_parameter', function(){ 985 const cloned = ` 986 <div class="cliche_row row"> 987 <div class="col-md-5"> 988 <label for="agent_custom_label">${control_vars.agent_field_name}</label> 989 <input type="text" class="form-control agent_custom_label" value="" name="agent_custom_label[]"> 990 </div> 991 <div class="col-md-5"> 992 <label for="agent_custom_value">${control_vars.agent_field_value}</label> 993 <input type="text" class="form-control agent_custom_value" value="" name="agent_custom_value[]"> 994 </div> 995 <div class="col-md-2"> 996 <button type="button" class="wpresidence_button remove_parameter_button">${control_vars.remove}</button> 997 </div> 998 </div> 999 `; 1000 1001 jQuery('input', cloned).val(''); 1002 jQuery('.wpresidence_button.add_custom_parameter').before( cloned ); 1003 }); 1004 1005 1006 1007 1008 jQuery('body').on('click', '.remove_parameter_button', function(){ 1009 var pnt = jQuery(this).parents( '.cliche_row' ); 1010 pnt.fadeOut(500, function(){ 1011 pnt.replaceWith(''); 1012 }); 1013 }); 1014 1015 1016 jQuery('.buy_package_sh a').on( 'click', function(event) { 1017 if (parseInt(ajaxcalls_vars.userid, 10) === 0 ) { 1018 event.preventDefault(); 1019 jQuery('#modal_login_wrapper').show(); 1020 jQuery('#modal_login_wrapper').find('[autofocus]').focus(); 1021 jQuery('.loginpop').val('1'); 1022 } 1023 }); 1024 1025 if (typeof wpestate_enable_half_map_pin_action == 'function'){ 1026 wpestate_enable_half_map_pin_action(); 1027 } 1028 1029 1030 1031 var screen_width,screen_height,map_tab; 1032 if (jQuery.datepicker && jQuery.datepicker.regional && jQuery.datepicker.regional[control_vars.datepick_lang]) { 1033 jQuery.datepicker.setDefaults( jQuery.datepicker.regional[control_vars.datepick_lang] ); 1034 } 1035 1036 1037 1038 estate_splash_slider(); 1039 1040 1041 var new_height; 1042 if (jQuery(".full_screen_yes").length) { 1043 1044 if( jQuery('.header_transparent').length > 0){ 1045 new_height = jQuery( window ).height(); 1046 }else{ 1047 new_height = jQuery( window ).height() - jQuery('.master_header').height(); 1048 } 1049
1050 if( jQuery('.with_search_on_start').length>0 ){ 1051 new_height=new_height- jQuery('.search_wrapper.with_search_on_start ').height(); 1052 } 1053 1054 jQuery('.wpestate_header_image,.wpestate_header_video,.theme_slider_wrapper,.theme_slider_classic,.theme_slider_wrapper .item_type2 ').css('height',new_height); 1055 } 1056 1057 1058 1059 1060 1061 1062 jQuery('.wp-block-residence-gutenberg-block-testimonial-slider').each(function(){ 1063 1064 if( jQuery(this).find('.type_class_3 ').length>0 ){ 1065 jQuery(this).addClass('container_type_3'); 1066 } 1067 1068 }) 1069 1070 1071 1072 1073 1074 1075 jQuery('#preview_view_all').on( 'click', function(event) { 1076 1077 if( (mapfunctions_vars.adv_search_type==='6' || mapfunctions_vars.adv_search_type==='7' || mapfunctions_vars.adv_search_type==='8' || mapfunctions_vars.adv_search_type==='9' ) ){ 1078 1079 jQuery('.search_wrapper .tab-pane.active .wpresidence_button').trigger('click'); 1080 }else{ 1081 jQuery('.search_wrapper .wpresidence_button').trigger('click'); 1082 } 1083 }); 1084 1085 1086 jQuery('.theme_slider_2 .prop_new_details ').on( 'click', function(event) { 1087 1088 var new_link; 1089 new_link = jQuery(this).attr('data-href'); 1090 window.open (new_link,'_self',false); 1091 }); 1092 1093 jQuery('.theme_slider_classic').on( 'click', function(event) { 1094 1095 if (event.target == this) { 1096 var new_link; 1097 new_link = jQuery(this).attr('data-href'); 1098 window.open (new_link,'_self',false); 1099 } 1100 }); 1101 1102 setTimeout(function() { wpresidence_list_view_arrange(); }, 300); 1103 1104 ////////// map shortcode 1105 map_tab=0; 1106 jQuery('#propmaptrigger').on( 'click', function(event) { 1107 if(map_tab===0){ 1108 1109 wpestate_map_shortcode_function(); 1110 map_tab=1; 1111 1112 } 1113 }); 1114 1115 1116 setTimeout(function(){ 1117 jQuery('.theme_slider_2 .theme_slider_2_contact_agent').fadeIn(); 1118 }, 700); 1119 1120 1121 //////////////////////////// 1122 // taxonomy slick slider 1123 //////////////////////////// 1124 wpestate_half_map_responsive(); 1125 wpestate_half_map_controls(); 1126 1127 jQuery('.show_stats').on( 'click', function(event) { 1128 event.preventDefault(); 1129 var parent,listing_id; 1130 parent = jQuery(this).parent().parent().parent(); 1131 listing_id = jQuery(this).attr('data-listingid'); 1132 //jQuery('.statistics_wrapper').slideUp(); 1133 1134 if( parent.find('.statistics_wrapper').hasClass('is_slide') ){ 1135 parent.find('.statistics_wrapper').slideUp().removeClass('is_slide'); 1136 }else{ 1137 parent.find('.statistics_wrapper').slideDown().addClass('is_slide'); 1138 wpestate_load_stats(listing_id); 1139 } 1140 1141 1142 1143 1144 }); 1145 1146 jQuery('.tabs_stats,#1462452319500-8587db8d-e959,#1462968563400-b8613baa-7092').on( 'click', function(event) { 1147 var parent,listing_id; 1148 listing_id = jQuery(this).attr('data-listingid'); 1149 if(typeof(listing_id)==='undefined'){ 1150 listing_id = jQuery('.estate_property_first_row').attr('data-prp-listingid'); 1151 } 1152 1153 1154 wpestate_load_stats_tabs(listing_id); 1155 }); 1156 1157 1158 1159 //////////////////////////////////////////////////////////////////////////// 1160 //new retina script 1161 //////////////////////////////////////////////////////////////////////////// 1162 1163 jQuery('.retina_ready').dense({ 1164 'ping' : true, 1165 'dimension' : 'preserve' 1166 }); 1167 var image_unnit = jQuery('<div data-1x="'+control_vars.path+'/css/css-images/unit.png" data-2x="'+control_vars.path+'/css/css-images/unit_2x.png" />').dense('getImageAttribute'); 1168 var image_unnit = jQuery('<div data-1x="'+control_vars.path+'/css/css-images/unitshare.png" data-2x="'+control_vars.path+'/css/css-images/unitshare_2x.png" />').dense('getImageAttribute'); 1169 1170 //////////////////////////////////////////////////////////////////////////// 1171 //invoice filters 1172 //////////////////////////////////////////////////////////////////////////// 1173 1174 1175 jQuery(function() { 1176 jQuery("#invoice_start_date,#invoice_end_date").datepicker({ 1177 dateFormat : "yy-mm-dd", 1178 }).datepicker('widget').wrap('<div class="ll-skin-melon"/>'); 1179 }); 1180 1181
1182 //////////////////////////////////////////////////////////////////////////// 1183 //new mobile menu 1.10 1184 //////////////////////////////////////////////////////////////////////////// 1185 1186 jQuery('.all-elements').animate({ 1187 minHeight: 100+'%' 1188 }); 1189 1190 jQuery('.header-tip').addClass('hide-header-tip'); 1191 1192 wpestate_mobile_menu_slideout(); 1193 wpestate_mobile_menu_open_submenu(); 1194 wpestate_elementor_mobile_menu_trigger_open(); 1195 1196 1197 1198 1199 1200 1201 1202 //////////////////////////////////////////////////////////////////////////// 1203 // easure unit cookige 1204 //////////////////////////////////////////////////////////////////////////// 1205 1206 jQuery('.list_sidebar_measure_unit li').on( 'click', function(event) { 1207 var ajaxurl,value, pick; 1208 value = jQuery(this).attr('data-value'); 1209 1210 var parent_pointer = jQuery(this).parents('.dropdown '); 1211 pick = jQuery(this).text(); 1212 jQuery('.sidebar_filter_menu', parent_pointer).text(pick).append('<span class="caret caret_sidebar"></span>'); 1213 var nonce = jQuery('#wpestate_change_measure').val(); 1214 ajaxurl = ajaxcalls_vars.admin_url + 'admin-ajax.php'; 1215 jQuery.ajax({ 1216 type: 'POST', 1217 url: ajaxurl, 1218 data: { 1219 'action' : 'wpestate_set_cookie_measure_unit', 1220 'value' : value, 1221 'security' : nonce 1222 }, 1223 success: function (data) { 1224 1225 location.reload(); 1226 }, 1227 error: function (errorThrown) {} 1228 });//end ajax 1229 1230 }); 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 //////////////////////////////////////////////////////////////////////////// 1242 /// slider price 1243 //////////////////////////////////////////////////////////////////////////// 1244 1245 var price_low_val= parseInt( jQuery('#price_low').val() ); 1246 var price_max_val= parseInt( jQuery('#price_max').val() ); 1247 var my_custom_curr_symbol = decodeURI ( wpestate_getCookie('my_custom_curr_symbol') ); 1248 var my_custom_curr_coef = parseFloat( wpestate_getCookie('my_custom_curr_coef')); 1249 var my_custom_curr_pos = parseFloat( wpestate_getCookie('my_custom_curr_pos')); 1250 var my_custom_curr_cur_post= wpestate_getCookie('my_custom_curr_cur_post'); 1251 1252 1253 wpestate_enable_slider('slider_price', 'price_low', 'price_max', 'amount', my_custom_curr_pos, my_custom_curr_symbol, my_custom_curr_cur_post,my_custom_curr_coef); 1254 jQuery( "#slider_price" ).slider({ 1255 stop: function( event, ui ) { 1256 if (typeof (wpestate_show_pins) !== "undefined") { 1257 first_time_wpestate_show_inpage_ajax_half=1; 1258 1259 wpestate_show_pins(); 1260 } 1261 } 1262 }); 1263 wpestate_enable_slider('slider_price_sh', 'price_low_sh', 'price_max_sh', 'amount_sh', my_custom_curr_pos, my_custom_curr_symbol, my_custom_curr_cur_post,my_custom_curr_coef); 1264 wpestate_enable_slider('slider_price_widget', 'price_low_widget', 'price_max_widget', 'amount_wd', my_custom_curr_pos, my_custom_curr_symbol, my_custom_curr_cur_post,my_custom_curr_coef); 1265 wpestate_enable_slider('slider_price_mobile', 'price_low_mobile', 'price_max_mobile', 'amount_mobile', my_custom_curr_pos, my_custom_curr_symbol, my_custom_curr_cur_post,my_custom_curr_coef); 1266 1267 1268 wpestate_enable_slider_elementor(); 1269 1270 if(control_vars.adv6_taxonomy_term!==''){ 1271 control_vars.adv6_taxonomy_term.forEach(wpestate_advtabs_function); 1272 } 1273 1274 1275 1276 1277 1278 //////////////////////////////////////////////////////////////////////////// 1279 1280 1281 1282 1283 1284 jQuery('#estate-carousel .slider-content h3 a,#estate-carousel .slider-content .read_more ').on( 'click', function(event) { 1285 var new_link; 1286 new_link = jQuery(this).attr('href'); 1287 window.open (new_link,'_self',false); 1288 }); 1289 1290 1291 1292 1293 1294 1295 //////////////////////////////////////////////////////////////////////////////////////////// 1296 ///mobile 1297 /////////////////////////////////////////////////////////////////////////////////////////// 1298 1299 1300 jQuery('#adv-search-header-mobile').on( 'click', function(event) { 1301 jQuery('#adv-search-mobile').fadeToggle('300'); 1302 1303 }); 1304 1305
1306 //////////////////////////////////////////////////////////////////////////////////////////// 1307 ///navigational links 1308 /////////////////////////////////////////////////////////////////////////////////////////// 1309 1310 jQuery('.nav-prev,.nav-next ').on( 'click', function(event) { 1311 event.preventDefault(); 1312 var link = jQuery(this).find('a').attr('href'); 1313 window.open (link,'_self',false); 1314 }); 1315 1316 //////////////////////////////////////////////////////////////////////////////////////////// 1317 /// featured agent 1318 /////////////////////////////////////////////////////////////////////////////////////////// 1319 1320 1321 jQuery('.featured_agent_details_wrapper, .agent-listing-img-wrapper').on( 'click', function(event) { 1322 var newl= jQuery( this ).attr('data-link'); 1323 window.open (newl,'_self',false); 1324 }); 1325 1326 jQuery('.see_my_list_featured').on( 'click', function(event) { 1327 event.stopPropagation(); 1328 }); 1329 1330 //////////////////////////////////////////////////////////////////////////////////////////// 1331 /// featuerd property 1332 /////////////////////////////////////////////////////////////////////////////////////////// 1333 1334 jQuery('.featured_cover').on( 'click', function(event) { 1335 var newl= jQuery( this ).attr('data-link'); 1336 window.open (newl,'_self',false); 1337 }); 1338 1339 1340 jQuery( '.agent_face' ) 1341 .on('mouseenter', function(){ jQuery(this).find('.agent_face_details').fadeIn('500'); }) 1342 .on('mouseleave', function(){ jQuery(this).find('.agent_face_details').fadeOut('500'); }); 1343 1344 1345 //////////////////////////////////////////////////////////////////////////////////////////// 1346 /// listings unit navigation 1347 /////////////////////////////////////////////////////////////////////////////////////////// 1348 jQuery('.places_cover,.agent_unit, .blog_unit , .featured_widget_image,.blog3v .property_listing_blog,.featured_img_type2').on( 'click', function(event) { 1349 // Skip card-level navigation when clicking on links or buttons inside the card 1350 // This prevents the card click from overriding WhatsApp, phone, and other action links 1351 var clickedEl = jQuery(event.target).closest('a, button'); 1352 if (clickedEl.length && clickedEl.closest(this).length) { 1353 return; 1354 } 1355 1356 // Skip card-level navigation for Type 5 agent cards (horizontal layout) 1357 // Type 5 has its own explicit action buttons; only image and name link should navigate 1358 if (jQuery(this).hasClass('agent_unit_type_5')) { 1359 return; 1360 } 1361 1362 var link; 1363 link = jQuery(this).attr('data-link'); 1364 1365 window.open(link, '_self'); 1366 }); 1367 1368 1369 1370 jQuery('.property_listing').on( 'click', function(event) { 1371 1372 if ( 1373 event.target.classList.contains('demo-icon') || 1374 event.target.classList.contains('carousel-control-next-icon') || 1375 event.target.classList.contains('carousel-control-prev-icon') 1376 ){ 1377 1378 return; 1379 } 1380 1381 if(control_vars.property_modal === '1' && !Modernizr.mq('only all and (max-width: 1024px)') ){ 1382 event.preventDefault(); 1383 event.stopPropagation(); 1384 scroll_modal_save=scroll_modal; 1385 1386 var listing_id = jQuery(this).parent().attr('data-listid'); 1387 var main_img_url= jQuery(this).parent().attr('data-main-modal'); 1388 var main_title = jQuery(this).parent().attr('data-modal-title'); 1389 var link = jQuery(this).parent().attr('data-modal-link'); 1390 wpestate_enable_property_modal(listing_id,main_img_url,main_title,link); 1391 }else{ 1392 1393 if(control_vars.new_page_link==='_blank' && !jQuery(this).hasClass('places_listing')){ 1394 return; 1395 } 1396 var link; 1397 link = jQuery(this).attr('data-link'); 1398 1399 window.open(link, '_self'); 1400 } 1401 }); 1402 1403 1404 1405 1406 1407 1408 jQuery('.share_unit').on( 'click', function(event) { 1409 event.stopPropagation(); 1410 }); 1411 1412 jQuery('.related_blog_unit_image').on( 'click', function(event) { 1413 var link; 1414 link = jQuery(this).attr('data-related-link'); 1415 window.open(link, '_self'); 1416 }); 1417
1418 //////////////////////////////////////////////////////////////////////////////////////////// 1419 /// user menu 1420 /////////////////////////////////////////////////////////////////////////////////////////// 1421 1422 wpestate_open_menu(); 1423 1424 jQuery('#wpresidence_elementor_register').on( 'click', function(event) { 1425 1426 event.preventDefault(); 1427 jQuery('.login-links').show(); 1428 1429 jQuery('#modal_login_wrapper').show(); 1430 event.preventDefault(); 1431 jQuery('#login-div_topbar,#widget_register_topbar,#login-div-title-topbar,#forgot-div-title-topbar,#forgot-pass-div').hide(); 1432 jQuery('#register-div-topbar,#register-div-title-topbar,#widget_login_topbar,#forgot_pass_topbar').show().find('[autofocus]').focus(); 1433 1434 jQuery('#modal_login_wrapper').find('[autofocus]').focus(); 1435 }); 1436 1437 jQuery('#wpresidence_elementor_login').on( 'click', function(event) { 1438 1439 event.preventDefault(); 1440 jQuery('.login-links').show(); 1441 jQuery('#modal_login_wrapper').show(); 1442 jQuery('#login-div_topbar,#widget_register_topbar,#login-div-title-topbar,#forgot_pass_topbar').show().find('[autofocus]').focus(); 1443 jQuery('#register-div-topbar,#register-div-title-topbar,#widget_login_topbar,#forgot-div-title-topbar,#forgot-pass-div').hide(); 1444 1445 1446 jQuery('#modal_login_wrapper').find('[autofocus]').focus(); 1447 }); 1448 1449 1450 1451 1452 jQuery('#user_menu_u.user_not_loged .submit_action').on( 'click', function(event) { 1453 jQuery('.login-links').show(); 1454 jQuery('#modal_login_wrapper').show(); 1455 jQuery('#modal_login_wrapper').find('[autofocus]').focus(); 1456 }); 1457 1458 1459 1460 jQuery('#property_details_modal_close').on('click',function(event){ 1461 jQuery('.website-wrapper').removeAttr('style'); 1462 window.scrollTo(0, parseInt(scroll_modal_save) ); 1463 jQuery('#property_details_modal_wrapper').hide(); 1464 window.history.pushState("", modal_title,modal_url); 1465 }); 1466 1467 jQuery('#shopping-cart').on('click',function (event) { 1468 1469 jQuery('#user_menu_open').removeClass('iosfixed').fadeOut(400); 1470 if (jQuery('#wpestate_header_shoping_cart').is(":visible")) { 1471 jQuery('#wpestate_header_shoping_cart').fadeOut(400); 1472 } else { 1473 jQuery('#wpestate_header_shoping_cart').fadeIn(400); 1474 } 1475 event.stopPropagation(); 1476 }); 1477 1478 1479 jQuery(document).on( 'click', function(event) { 1480 1481 var clicka = event.target.id; 1482 var clicka2 = jQuery(event.target).attr('share_unit'); 1483 jQuery('#wpestate_header_shoping_cart').fadeOut(400); 1484 if ( !jQuery('#'+clicka).parents('.topmenux').length) { 1485 jQuery('#user_menu_open').removeClass('iosfixed').hide(400); 1486 jQuery('.navicon-button').removeClass('opensvg'); 1487 jQuery('#user_menu_u .navicon-button').removeClass('open'); 1488 } 1489 1490 jQuery('.share_unit').hide(); 1491 1492 1493 if (event.target.id == "header_type3_wrapper" || jQuery(event.target).parents("#header_type3_wrapper").size()) { 1494 1495 } else { 1496 var css_right = parseFloat( jQuery('.header_type3_menu_sidebar').css('right') ); 1497 var css_left = parseFloat( jQuery('.header_type3_menu_sidebar').css('left') ); 1498 if(css_right===0 || css_left===0 ){ 1499 jQuery('.header_type3_menu_sidebar.header_left.sidebaropen').css("right","-300px"); 1500 jQuery('.header_type3_menu_sidebar.header_right.sidebaropen').css("left","-300px"); 1501 jQuery('.container.main_wrapper.has_header_type3').css("padding","0px"); 1502 jQuery('.elementor-section.elementor-top-section ').css("padding-right","0px"); 1503 jQuery('.elementor-section.elementor-top-section ').css("padding-left","0px"); 1504 jQuery('.master_header').removeAttr('style'); 1505 1506 } 1507 } 1508 }); 1509 1510 1511 jQuery('#header_type3_trigger').on( 'click', function(event) { 1512 1513 event.preventDefault(); 1514 if ( !jQuery('.container').hasClass('is_boxed') ){ 1515 if( jQuery('.header_type3_menu_sidebar').hasClass('header_left') ){ 1516 jQuery(".header_type3_menu_sidebar").css("right","0px"); 1517 jQuery(".container.main_wrapper ").css("padding-right","300px"); 1518 jQuery('.elementor-section.elementor-top-section ').css("padding-right","300px"); 1519 jQuery(".master_header").css("right","150px"); 1520 }else{ 1521 jQuery(".header_type3_menu_sidebar").css("left","0px"); 1522 jQuery(".container.main_wrapper ").css("padding-left","300px"); 1523 jQuery('.elementor-section.elementor-top-section ').css("padding-left","300px"); 1524 jQuery(".master_header").css("left","150px"); 1525 1526 } 1527 jQuery(".header_type3_menu_sidebar").addClass("sidebaropen"); 1528 }else{ 1529 if( jQuery('.header_type3_menu_sidebar').hasClass('header_left') ){ 1530 jQuery(".header_type3_menu_sidebar").css("right","0px"); 1531 1532 }else{ 1533 jQuery(".header_type3_menu_sidebar").css("left","0px"); 1534 1535 } 1536 jQuery(".header_type3_menu_sidebar").addClass("sidebaropen"); 1537 } 1538 }); 1539 1540
1541 //////////////////////////////////////////////////////////////////////////////////////////// 1542 /// new controls for upload pictures 1543 /////////////////////////////////////////////////////////////////////////////////////////// 1544 1545 jQuery('#imagelist i.fa-trash-alt').on( 'click', function(event) { 1546 var curent=''; 1547 jQuery(this).parent().remove(); 1548 1549 jQuery('#imagelist .uploaded_images').each(function(){ 1550 curent=curent+','+jQuery(this).attr('data-imageid'); 1551 }); 1552 jQuery('#attachid').val(curent); 1553 1554 }); 1555 1556 jQuery('#imagelist img').dblclick(function(){ 1557 1558 jQuery('#imagelist .uploaded_images .thumber').each(function(){ 1559 jQuery(this).remove(); 1560 }); 1561 1562 jQuery(this).parent().append('<i class="fa thumber fa-star"></i>'); 1563 jQuery('#attachthumb').val( jQuery(this).parent().attr('data-imageid') ); 1564 }); 1565 1566 1567 1568 1569 1570 jQuery('#switch').on( 'click', function(event) { 1571 jQuery('.main_wrapper').toggleClass('wide'); 1572 }); 1573 1574 1575 jQuery('#accordion_prop_addr, #accordion_prop_details, #accordion_prop_features').on('shown.bs.collapse', function () { 1576 jQuery(this).find('h4').removeClass('carusel_closed'); 1577 }); 1578 1579 jQuery('#accordion_prop_addr, #accordion_prop_details, #accordion_prop_features').on('hidden.bs.collapse', function () { 1580 jQuery(this).find('h4').addClass('carusel_closed'); 1581 }); 1582 1583 /////////////////////////////////////////////////////////////////////////////////////////// 1584 //////// advanced search filters 1585 //////////////////////////////////////////////////////////////////////////////////////////// 1586 1587 var elems = ['.directory_sidebar','.search_wrapper' , 1588 '#advanced_search_shortcode', '#advanced_search_shortcode_2', '.adv-search-mobile','.advanced_search_sidebar']; 1589 1590 jQuery.each( elems, function( i, elem ) { 1591 1592 jQuery(elem+' li').on( 'click', function(event) { 1593 event.preventDefault(); 1594 var pick, value, parent,parent_replace; 1595 parent_replace='.filter_menu_trigger'; 1596 if(elem === '.advanced_search_sidebar' ){ 1597 parent_replace='.sidebar_filter_menu'; 1598 } 1599 1600 pick = jQuery(this).text(); 1601 value = jQuery(this).attr('data-value'); 1602 1603 // agents search patch 1604 //if( jQuery(this).parents('.advanced_search_sidebar').hasClass('ag_ag_dev_search_widget') ){ 1605 if( jQuery(this).parent().hasClass('aag_picker') ){ 1606 jQuery('.ag_ag_dev_search_selector').hide(); 1607 jQuery('.selector_for_'+value).fadeIn(); 1608 } 1609 1610 1611 parent = jQuery(this).parent().parent(); 1612 if(elem === '.directory_sidebar' ){ 1613 parent.find(parent_replace).text(pick).attr('data-value',value); 1614 }else{ 1615 parent.find(parent_replace).text(pick).attr('data-value',value); 1616 } 1617 parent.find('input').val(value); 1618 }); 1619 }); 1620 1621 1622 1623 1624 jQuery('.search_wrapper li, .extended_search_check_wrapper input[type="checkbox"]').on( 'click', function(event) { 1625 1626 if(jQuery(this).hasClass('wpestate_prevent_ajax')){ 1627 return; 1628 } 1629 1630 // Skip generic map-pin refresh for half-map order dropdown items. 1631 // Those items already trigger listing refresh through their dedicated handler. 1632 if (jQuery(this).closest('.wpresidence_property_list_half_map_core .wpresidence_wrap_a_filter_order').length > 0) { 1633 return; 1634 } 1635 1636 if (typeof (wpestate_show_pins) !== "undefined") { 1637 first_time_wpestate_show_inpage_ajax_half=1; 1638 1639 wpestate_show_pins(); 1640 } 1641 }); 1642 1643 1644 1645 1646 1647 var typingTimer; //timer identifier 1648 var doneTypingInterval = 1500; //time in ms, 5 second for example 1649 var jQueryinput = jQuery('#adv_location,.search_wrapper input[type=text]'); 1650 1651 jQueryinput.on('keyup', function (event) { 1652 if(jQuery(this).attr('id')=='geolocation_search' || jQuery(this).attr('id')=='geolocation_search2') { 1653 return; 1654 } 1655 if (event.keyCode === 13) { 1656 first_time_wpestate_show_inpage_ajax_half=1; 1657 wpestate_show_pins(); 1658 } 1659 }); 1660 1661 //on keydown, clear the countdown 1662 jQueryinput.on('keydown', function () { 1663 clearTimeout(typingTimer); 1664 }); 1665 1666 1667
1668 /////////////////////////////////////////////////////////////////////////////////////////// 1669 //////// advanced search filters 1670 //////////////////////////////////////////////////////////////////////////////////////////// 1671 1672 jQuery('#openmap').on( 'click', function(event) { 1673 1674 if( jQuery(this).find('i').hasClass('fa-angle-down') ){ 1675 jQuery(this).empty().append('<i class="fas fa-angle-up"></i>'+control_vars.close_map); 1676 1677 if (control_vars.show_adv_search_map_close === 'no') { 1678 jQuery('.search_wrapper').addClass('adv1_close'); 1679 wpestate_adv_search_click(); 1680 } 1681 1682 }else{ 1683 jQuery(this).empty().append('<i class="fas fa-angle-down"></i>'+control_vars.open_map); 1684 1685 } 1686 wpestate_new_open_close_map(2); 1687 1688 }); 1689 1690 1691 /////////////////////////////////////////////////////////////////////////////////////////// 1692 //////// full screen map 1693 //////////////////////////////////////////////////////////////////////////////////////////// 1694 var wrap_h; 1695 var map_h; 1696 1697 jQuery('#gmap-full').on( 'click', function(event) { 1698 1699 1700 if( jQuery('#gmap_wrapper').hasClass('fullmap') ){ 1701 jQuery('#google_map_prop_list_wrapper').removeClass('fullhalf'); 1702 1703 jQuery('#gmap_wrapper').removeClass('fullmap').css('height',wrap_h+'px'); 1704 jQuery('#googleMap').removeClass('fullmap').css('height',map_h+'px'); 1705 jQuery('.master_header ').removeClass('header_full_map'); 1706 jQuery('#search_wrapper').removeClass('fullscreen_search'); 1707 jQuery('#search_wrapper').removeClass('fullscreen_search_open'); 1708 1709 if( !jQuery('#google_map_prop_list_wrapper').length ){ 1710 jQuery('.content_wrapper').show(); 1711 } 1712 jQuery('body,html').animate({ 1713 scrollTop: 0 1714 }, "slow"); 1715 jQuery('#openmap').show(); 1716 jQuery(this).empty().append('<i class="fas fa-arrows-alt"></i>'+control_vars.fullscreen).removeClass('spanselected'); 1717 1718 jQuery('#google_map_prop_list_wrapper').removeClass('fullscreen'); 1719 jQuery('#google_map_prop_list_sidebar').removeClass('fullscreen'); 1720 1721 1722 }else{ 1723 jQuery('#gmap_wrapper,#googleMap').css('height','100%').addClass('fullmap'); 1724 1725 jQuery('#google_map_prop_list_wrapper').addClass('fullscreen'); 1726 jQuery('#google_map_prop_list_sidebar').addClass('fullscreen'); 1727 1728 1729 1730 1731 jQuery('#google_map_prop_list_wrapper').addClass('fullhalf'); 1732 1733 1734 wrap_h=jQuery('#gmap_wrapper').outerHeight(); 1735 map_h=jQuery('#googleMap').outerHeight(); 1736 1737 jQuery('.master_header ').addClass('header_full_map'); 1738 1739 1740 jQuery('#search_wrapper').addClass('fullscreen_search'); 1741 1742 if( !jQuery('#google_map_prop_list_wrapper').length ){ 1743 jQuery('.content_wrapper').hide(); 1744 } 1745 1746 jQuery('#openmap').hide(); 1747 jQuery(this).empty().append('<i class="fas fa-square"></i>'+control_vars.default).addClass('spanselected'); 1748 1749 } 1750 wpresidence_map_resise(); 1751 1752 1753 1754 }); 1755 1756 1757 jQuery('#street-view').on( 'click', function(event) { 1758 wpestate_toggleStreetView(); 1759 }); 1760 1761 1762 1763 1764 1765 /////////////////////////////////////////////////////////////////////////////////////////// 1766 /////// caption-wrapper 1767 /////////////////////////////////////////////////////////////////////////////////////////// 1768 1769 jQuery('.caption-wrapper').on( 'click', function(event) { 1770 jQuery(this).toggleClass('closed'); 1771 jQuery('.carusel-back').toggleClass('rowclosed'); 1772 jQuery('.wpestate_horizontal_slider_wrapper .carousel-indicators').toggleClass('rowclosed'); 1773 }); 1774 1775 jQuery('.carousel-round-indicators li').on( 'click', function(event) { 1776 jQuery('.carousel-round-indicators li').removeClass('active'); 1777 jQuery(this).addClass('active'); 1778 }); 1779 1780 jQuery('.videoitem iframe').on( 'click', function(event) { 1781 jQuery('.estate_video_control').remove(); 1782 });
1783 /////////////////////////////////////////////////////////////////////////////////////// 1784 ////// Advanced search 1785 ///////////////////////////////////////////////////////////////////////////////////////// 1786 1787 wpestate_adv_search_click(); 1788 1789 1790 jQuery('.custom_details_container .send_email_agent').on( 'click', function(event) { 1791 event.preventDefault(); 1792 1793 jQuery('body,html').animate({ 1794 scrollTop: ( jQuery("#show_contact").offset().top-100) 1795 }, "slow"); 1796 1797 }); 1798 1799 /////////////////////////////////////////////////////////////////////////////////////////// 1800 /////// back to top 1801 /////////////////////////////////////////////////////////////////////////////////////////// 1802 1803 1804 jQuery('.backtop').on( 'click', function(event) { 1805 event.preventDefault(); 1806 1807 jQuery('body,html').animate({ 1808 scrollTop: 0 1809 }, "slow"); 1810 1811 }); 1812 1813 /////////////////////////////////////////////////////////////////////////////////////////// 1814 /////// footer contact 1815 /////////////////////////////////////////////////////////////////////////////////////////// 1816 1817 jQuery('.contact-box ').on( 'click', function(event) { 1818 event.preventDefault(); 1819 jQuery('.contactformwrapper').toggleClass('hidden'); 1820 wpestate_contact_footer_starter(); 1821 }); 1822 1823 1824 1825 1826 1827 /////////////////////////////////////////////////////////////////////////////////////////// 1828 /////// Search widget 1829 /////////////////////////////////////////////////////////////////////////////////////////// 1830 jQuery('#searchform input').focus(function(){ 1831 jQuery(this).val(''); 1832 }).blur(function(){ 1833 1834 }); 1835 1836 1837 1838 //////////////////////////////////////////////////////////////////////////////////////////// 1839 /// adding total for featured listings 1840 /////////////////////////////////////////////////////////////////////////////////////////// 1841 jQuery('.extra_featured').on('change', function(){ 1842 var parent= jQuery(this).parent().parent(); 1843 var price_regular = parseFloat( parent.find('.submit-price-no').text(),10 ); 1844 var price_featured = parseFloat( parent.find('.submit-price-featured').text(),10 ); 1845 var total= price_regular+price_featured; 1846 1847 if( jQuery(this).is(':checked') ){ 1848 parent.find('.submit-price-total').text(total); 1849 parent.find('.stripe_form_featured').show(); 1850 parent.find('.stripe_form_simple').hide(); 1851 }else{ 1852 //substract from total 1853 parent.find('.submit-price-total').text(price_regular); 1854 parent.find('.stripe_form_featured').hide(); 1855 parent.find('.stripe_form_simple').show(); 1856 } 1857 }); 1858 1859 1860 1861 ///////////////////////////////////////////////////////////////////////////////////////// 1862 /////// grid to list view 1863 /////////////////////////////////////////////////////////////////////////////////////////// 1864 1865 1866 jQuery('.col-md-12.listing_wrapper .property_unit_custom_element.image').each(function(){ 1867 jQuery(this).parent().addClass('wrap_custom_image'); 1868 }); 1869 1870 1871 1872 1873 1874 1875 /////////////////////////////////////////////////////////////////////////////////////////// 1876 /////// compare action 1877 /////////////////////////////////////////////////////////////////////////////////////////// 1878 var already_in=[]; 1879 jQuery('#compare_close').on( 'click', function(event) { 1880 jQuery('.prop-compare').animate({ 1881 right: "-240px" 1882 }); 1883 }); 1884 1885 jQuery('.compare-action').on( 'click', function(e) { 1886 1887 e.preventDefault(); 1888 e.stopPropagation(); 1889 jQuery('.prop-compare').animate({ 1890 right: "0px" 1891 }); 1892 1893 var post_id = jQuery(this).attr('data-pid'); 1894 for(var i = 0; i < already_in.length; i++) { 1895 if(already_in[i] === post_id) { 1896 return; 1897 } 1898 } 1899 1900 already_in.push(post_id); 1901 1902 1903 var post_image = jQuery(this).attr('data-pimage'); 1904 1905 var to_add = '<div class="items_compare" style="display:none;"><img src="' + post_image + '" class="img-responsive"><input type="hidden" value="' + post_id + '" name="selected_id[]" /></div>'; 1906 jQuery('div.items_compare:first-child').css('background', 'red');
1907 if (parseInt(jQuery('.items_compare').length,10) > 3) { 1908 jQuery('.items_compare:first').remove(); 1909 } 1910 jQuery('#submit_compare').before(to_add); 1911 1912 jQuery('#submit_compare').on( 'click', function(event) { 1913 jQuery('#form_compare').trigger('submit'); 1914 }); 1915 1916 jQuery('.items_compare').fadeIn(500); 1917 }); 1918 1919 jQuery('#submit_compare').on( 'click', function(event) { 1920 jQuery('#form_compare').trigger('submit'); 1921 }); 1922 1923 1924 1925 ///////////////////////////////////////////////////////////////////////////////////////// 1926 ////// form upload 1927 ///////////////////////////////////////////////////////////////////////////////////////// 1928 1929 jQuery('#form_submit_2,#form_submit_1 ').on( 'click', function(event) { 1930 var loading_modal; 1931 window.scrollTo(0, 0); 1932 loading_modal='<div class="modal fade" id="loadingmodal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"><div class="modal-dialog"><div class="modal-content"><div class="modal-body listing-submit"><span>'+control_vars.addprop+'</div></div></div></div></div>'; 1933 1934 jQuery('body').append(loading_modal); 1935 jQuery('#loadingmodal').modal(); 1936 }); 1937 1938 1939 jQuery('#add-new-image').on( 'click', function(event) { 1940 jQuery('<p><label for="file">New Image:</label><input type="file" name="upload_attachment[]" id="file_featured"></p> ').appendTo('#files_area'); 1941 }); 1942 1943 1944 1945 jQuery('.delete_image').on( 'click', function(event) { 1946 var image_id=jQuery(this).attr('data-imageid'); 1947 1948 var curent=jQuery('#images_todelete').val(); 1949 if(curent===''){ 1950 curent=image_id; 1951 }else{ 1952 curent=curent+','+image_id; 1953 } 1954 1955 jQuery('#images_todelete').val(curent) ; 1956 jQuery(this).parent().remove(); 1957 }); 1958 1959 ///////////////////////////////////////////////////////////////////////////////////////// 1960 ////// mouse over map tooltip 1961 ///////////////////////////////////////////////////////////////////////////////////////// 1962 1963 jQuery('#googleMap').on('mousemove', function(e){ 1964 jQuery('.tooltip').css({'top':e.pageY,'left':e.pageX, 'z-index':'1'}); 1965 }); 1966 1967 setTimeout(function(){ jQuery('.tooltip').fadeOut("fast");},10000); 1968}); 1969 1970///////////////////////////////////////////////////// 1971////////////////// END ready 1972 1973 1974/** 1975 * Initializes Bootstrap tooltips for all elements with the 'data-bs-toggle="tooltip"' attribute. 1976 * This function selects all elements that should have tooltips and applies the Bootstrap tooltip 1977 * functionality to each of them. It should be called after the DOM is fully loaded to ensure all 1978 * elements are accessible. 1979 */ 1980function wpestate_initializeTooltips_bootstrap53() { 1981 // Select all elements with the 'data-bs-toggle="tooltip"' attribute 1982 var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')); 1983 1984 // Initialize a Bootstrap tooltip for each selected element 1985 var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) { 1986 return new bootstrap.Tooltip(tooltipTriggerEl); 1987 }); 1988} 1989 1990 1991 1992/* 1993* control google map types 1994* 1995*/ 1996 1997function wpestate_map_types_control(){ 1998 1999 2000 jQuery('#map-view').on( 'click', function(event) { 2001 jQuery('.wpresidence_map_styles_wrapper').toggle(); 2002 }); 2003 2004 jQuery('.map-type').on( 'click', function(event) { 2005 var map_type; 2006 jQuery('.wpresidence_map_styles_wrapper').hide(); 2007 map_type=jQuery(this).attr('id'); 2008 wpestate_change_map_type(map_type); 2009 2010 }); 2011 2012 2013 2014} 2015 2016 2017/* 2018* adjust sticky footer 2019* 2020*/ 2021 2022 2023 2024function wpestate_adjust_sticky_footer(){ 2025 if(control_vars.sticky_footer==='yes'){ 2026 var footer_height=jQuery('#colophon').height(); 2027 jQuery('.wpresidence_main_wrapper_class:not(.has_header_type4)').css('margin-bottom', footer_height); 2028 jQuery('.wpresidence_wrapper_for_header_4_colum').css('padding-bottom',footer_height); 2029 } 2030 2031} 2032 2033 2034/* 2035*multiple currency set coookie 2036* 2037*/ 2038 2039 2040function wpestate_change_currency_dropdown_action(){ 2041 2042 jQuery('.list_sidebar_currency li').on( 'click', function(event) { 2043 2044 var ajaxurl,data,pos,symbol,coef,curpos, pick; 2045 2046 data=jQuery(this).attr('data-value'); 2047 pos=jQuery(this).attr('data-pos'); 2048 symbol=jQuery(this).attr('data-symbol'); 2049 coef=jQuery(this).attr('data-coef'); 2050 curpos=jQuery(this).attr('data-curpos'); 2051 2052 var parent_pointer = jQuery(this).parents('.dropdown '); 2053 2054 ajaxurl = ajaxcalls_vars.admin_url + 'admin-ajax.php'; 2055 var nonce = jQuery('#wpestate_change_currency').val(); 2056 jQuery.ajax({ 2057 type: 'POST', 2058 url: ajaxurl, 2059 data: { 2060 'action' : 'wpestate_set_cookie_multiple_curr', 2061 'curr' : data, 2062 'pos' : pos,
2063 'symbol' : symbol, 2064 'coef' : coef, 2065 'curpos' : curpos, 2066 'security' : nonce 2067 }, 2068 success: function (data) { 2069 2070 location.reload(); 2071 }, 2072 error: function (errorThrown) {} 2073 });//end ajax 2074 2075 }); 2076 2077} 2078 2079/* 2080* 2081* 2082* 2083*/ 2084 2085 2086 2087 2088function wpestate_adjustMegaMenuPosition() { 2089 jQuery(".wpestate_mega_menu2_wrapper").each(function() { 2090 var $megaMenu = jQuery(this); 2091 2092 // Skip Studio mega panels â CSS handles their positioning (Task 430) 2093 if ($megaMenu.closest('li').find('.megamenu-studio-panel').length) { 2094 return true; // continue to next iteration 2095 } 2096 2097 var parentOffset = $megaMenu.closest("li").offset().left; 2098 var viewportWidth = jQuery(window).width(); 2099 $megaMenu.css({ 2100 2101 left: -parentOffset + "px", 2102 width: viewportWidth + "px", 2103 "max-width": viewportWidth + "px", 2104 }); 2105 }); 2106} 2107 2108 2109/** 2110 * Studio Mega Menu â mobile toggle, keyboard accessibility (Task 430) 2111 * Handles mobile expand/collapse and Escape key close for Studio mega panels. 2112 * Desktop show/hide is handled via CSS :hover. 2113 */ 2114function wpestate_studioMegaMenuInit() { 2115 // Mobile toggle: inject toggle buttons before each .megamenu-studio-panel 2116 if (jQuery(window).width() <= 768) { 2117 jQuery('.megamenu-studio-panel').each(function() { 2118 var $panel = jQuery(this); 2119 // Only inject toggle once 2120 if (!$panel.prev('.megamenu-studio-toggle').length) { 2121 var $toggle = jQuery('<button>') 2122 .addClass('megamenu-studio-toggle') 2123 .attr('aria-expanded', 'false') 2124 .attr('aria-label', 'Toggle mega menu') 2125 .text('Mega Menu'); 2126 $panel.before($toggle); 2127 } 2128 }); 2129 } 2130 2131 // Mobile toggle click handler 2132 jQuery(document).on('click', '.megamenu-studio-toggle', function(e) { 2133 e.preventDefault(); 2134 e.stopPropagation(); 2135 var $toggle = jQuery(this); 2136 var $panel = $toggle.next('.megamenu-studio-panel'); 2137 var isOpen = $panel.hasClass('is-open'); 2138
2139 // Close all other open panels first 2140 jQuery('.megamenu-studio-panel.is-open').removeClass('is-open'); 2141 jQuery('.megamenu-studio-toggle[aria-expanded="true"]').attr('aria-expanded', 'false'); 2142 2143 // Toggle this panel 2144 if (!isOpen) { 2145 $panel.addClass('is-open'); 2146 $toggle.attr('aria-expanded', 'true'); 2147 } 2148 }); 2149 2150 // Keyboard: Escape closes any open mega panel 2151 jQuery(document).on('keydown', function(e) { 2152 if (e.key === 'Escape' || e.keyCode === 27) { 2153 var $openPanels = jQuery('.megamenu-studio-panel.is-open'); 2154 if ($openPanels.length) { 2155 $openPanels.removeClass('is-open'); 2156 jQuery('.megamenu-studio-toggle[aria-expanded="true"]') 2157 .attr('aria-expanded', 'false') 2158 .focus(); // Return focus to the toggle button 2159 } 2160 } 2161 }); 2162} 2163 2164 2165/** 2166 * WpEstate Advanced Filters Multi-Select 2167 * Handles the chained filtering between County/State -> City -> Area dropdowns 2168 * Uses Bootstrap Select plugin for enhanced multi-select functionality 2169 * 2170 * HTML Structure Expected: 2171 * - Multi-select dropdowns with class 'wpestatemultiselectselectpicker' 2172 * - Options with data-taxonomy (county / state, cities, areas) 2173 * - Options with data-parent-value matching parent selection values 2174 * 2175 * @since 5.0.5 2176 */ 2177/** 2178 * WpEstate Advanced Filters Multi-Select 2179 * Handles the chained filtering between County/State -> City -> Area dropdowns 2180 */ 2181function wpestate_advnced_filters_bars() { 2182 /** 2183 * Step 1: Keep `data-term-id-selected` in sync with current multi-select state. 2184 * This supports both selection and deselection, including the "none selected" case. 2185 * 2186 * @param {jQuery} element Multi-select element enhanced by bootstrap-select. 2187 */ 2188 function updateSelectedTermIdsMetadata(element) { 2189 var selectedTermIds = element.find('option:selected').map(function() { 2190 var termId = jQuery(this).attr('data-term-id'); 2191 if (typeof termId === 'undefined' || termId === null) { 2192 return ''; 2193 } 2194 return String(termId).trim(); 2195 }).get(); 2196 2197 // Step 2: Remove empty values and duplicates. 2198 selectedTermIds = selectedTermIds.filter(function(value, index, array) { 2199 return value !== '' && array.indexOf(value) === index; 2200 }); 2201 2202 // Step 3: Store a stable comma-separated value on select and generated UI nodes. 2203 var selectedTermIdsValue = selectedTermIds.join(','); 2204 element.attr('data-term-id-selected', selectedTermIdsValue); 2205 element.closest('.bootstrap-select').find('.dropdown-toggle, .dropdown-menu').attr('data-term-id-selected', selectedTermIdsValue); 2206 } 2207 2208 function initializeSelectPicker(element) { 2209 element.selectpicker({ 2210 styleBase: 'wpestate-multiselect-custom-style', 2211 size: 7 2212 }).on('changed.bs.select', function(e, clickedIndex, isSelected, previousValue) { 2213 // Step 4: Update metadata right after each user change. 2214 updateSelectedTermIdsMetadata(jQuery(this)); 2215 2216 2217 var elememtParent = jQuery(this).closest('.tab-pane.active'); 2218 if (elememtParent.length == 0) { 2219 elememtParent = jQuery(this).parents().eq(2); 2220 } 2221 2222 var elementId = jQuery(this).attr('id'); 2223 2224 const county_relations = { 2225 'county-state': 'property_city', 2226 'sidebar-county-state': 'sidebar-property_city', 2227 'shortcode-county-state': 'shortcode-property_city', 2228 'mobile-county-state': 'mobile-property_city' 2229 }; 2230 2231 const city_relations = { 2232 'property_city': 'property_area', 2233 'sidebar-property_city': 'sidebar-property_area', 2234 'shortcode-property_city': 'shortcode-property_area', 2235 'mobile-property_city': 'mobile-property_area' 2236 }; 2237 2238 var selectedOption = jQuery(this).find('option').eq(clickedIndex); 2239 var attributeTaxonomy = selectedOption.attr('data-taxonomy'); 2240 var selectedOptions = jQuery(this).find('option:selected'); 2241 2242 if (attributeTaxonomy === 'cities' || attributeTaxonomy === 'county / state') { 2243 triggerChangeOn = county_relations[elementId]; 2244 if (attributeTaxonomy === 'cities') { 2245 triggerChangeOn = city_relations[elementId]; 2246 } 2247 2248 var selectedValues = jQuery(this).find('option:selected').map(function() { 2249 return jQuery(this).val(); 2250 }).get(); 2251 2252 var elementCousin = elememtParent.find('#' + triggerChangeOn); 2253 elementCousin.find('option').each(function() { 2254 var optionValue = jQuery(this).data('parent-value'); 2255 if (selectedValues.length === 0 || selectedValues.indexOf(optionValue) !== -1) { 2256 jQuery(this).show(); 2257 } else { 2258 jQuery(this).hide(); 2259 } 2260 }); 2261 2262 // Destroy and reinitialize with all event handlers 2263 elementCousin.selectpicker('destroy'); 2264 initializeSelectPicker(elementCousin); 2265 } 2266 2267 first_time_wpestate_show_inpage_ajax_half = 1; 2268 wpestate_show_pins(); 2269 2270 }).on('shown.bs.select', function(e) { 2271 var thisButton = jQuery(this); 2272 2273 var windowWidth = jQuery(window).width(); 2274 var buttonOffset = thisButton.offset(); 2275 var buttonWidth = thisButton.outerWidth(); 2276 var $dropdownMenu = jQuery(this).parent().find('.dropdown-menu.open'); 2277 2278 var distanceFromLeft = buttonOffset.left; 2279 var distanceFromRight = windowWidth - (buttonOffset.left + buttonWidth); 2280 2281 if (distanceFromLeft <= 150) { 2282 $dropdownMenu.css('left', 0); 2283 $dropdownMenu.css('right', 'auto'); 2284 } else if (distanceFromRight <= 150) { 2285 $dropdownMenu.css('left', 'auto'); 2286 $dropdownMenu.css('right', 0); 2287 } 2288 }); 2289 2290 // Step 5: Ensure metadata is correct on initial render too. 2291 updateSelectedTermIdsMetadata(element); 2292 } 2293 2294 // Initialize all selectpickers 2295 jQuery('.wpestatemultiselectselectpicker').each(function() { 2296 initializeSelectPicker(jQuery(this)); 2297 }); 2298} 2299 2300 2301 2302 2303/**
2304 * Function to show/hide hidden fields in the WP Estate search form. 2305 * This function handles both floating and non-floating search forms, 2306 * providing smooth animations for expanding and collapsing advanced search options. 2307 */ 2308function wpestate_show_hide_search_form_hidden_fields(){ 2309 // Variable to store the original top position of the search wrapper 2310 var handler_top; 2311 2312 // Attach click event handler to the advanced search toggle button 2313 jQuery('.adv_handler').on('click', function(event) { 2314 // Prevent the default action of the click event 2315 event.preventDefault(); 2316 2317 // Select the hidden fields container 2318 var check_row = jQuery('.adv_search_hidden_fields'); 2319 2320 // Check if the search form is floating 2321 if (jQuery('#search_wrapper').hasClass('with_search_form_float')) { 2322 // Handle floating search form 2323 if (!jQuery('#search_wrapper').hasClass('openmore')) { 2324 // If the form is not expanded, prepare to open it 2325 2326 // Temporarily set display to flex and hide to measure accurate height 2327 // This is necessary because flex display can affect the element's dimensions 2328 check_row.css({'display': 'flex', 'visibility': 'hidden'}); 2329 var height = check_row.outerHeight(); 2330 // Reset to original state before animation 2331 check_row.css({'visibility': '', 'display': 'none'}); 2332 2333 // Get the current top position of the search wrapper 2334 handler_top = parseInt(jQuery('#search_wrapper').css('top')); 2335 // Calculate the new top position 2336 2337 2338 2339 // Slide down hidden fields and set to flex display after animation 2340 // This ensures smooth animation while achieving the desired flex layout 2341 check_row.slideDown({ 2342 duration: 200, 2343 queue: false, 2344 complete: function() { 2345 jQuery(this).css('display', 'flex'); 2346 } 2347 }); 2348 2349 // Mark the search wrapper as expanded 2350 jQuery('#search_wrapper').addClass('openmore'); 2351 } else { 2352 // If the form is already expanded, close it 2353 2354 // Animate the search wrapper back to its original position 2355 jQuery('#search_wrapper').animate({ 2356 'top': handler_top 2357 }, { duration: 200, queue: false }); 2358 2359 // Slide up the hidden fields 2360 check_row.slideUp({ duration: 200, queue: false }); 2361 // Remove the expanded state class 2362 jQuery('#search_wrapper').removeClass('openmore'); 2363 } 2364 } else { 2365 // Handle non-floating search form 2366 if (check_row.css('display') === 'none') { 2367 // If hidden fields are not visible, show them 2368 // Set display to flex, hide it, then slide down for smooth animation 2369 check_row.css('display', 'flex').hide().slideDown(200); 2370 } else { 2371 // If hidden fields are visible, hide them 2372 check_row.slideUp(200); 2373 } 2374 } 2375 }); 2376} 2377 2378 2379 2380 2381/** 2382 * Function to control "more options" in search form 2383 * 2384 * This function sets up event handlers for expanding and collapsing 2385 * additional search options in real estate search form. 2386 * 2387 * 2388 */ 2389function wpestate_extended_search_function(){ 2390 // Event handler for expanding the search options 2391 jQuery('.residence_adv_extended_options_text').on('click', function(event) { 2392 var parent_wrapper = jQuery(this).parent(); 2393 2394 // Hide the "More options" text 2395 jQuery(this).hide(); 2396 2397 // Find and show the extended search options 2398 var check_row = parent_wrapper.find('.extended_search_check_wrapper'); 2399 check_row.slideDown({ duration: 200, queue: false }); 2400 2401 // Show the close button 2402 parent_wrapper.find('.adv_extended_close_button').show(); 2403 }); 2404 2405 // Event handler for collapsing the search options 2406 jQuery('.adv_extended_close_button').on('click', function(event) { 2407 var parent_wrapper = jQuery(this).parent().parent(); 2408 2409 // Hide the close button 2410 jQuery(this).hide(); 2411 2412 // Show the "More options" text 2413 parent_wrapper.find('.residence_adv_extended_options_text').show(); 2414 2415 // Hide the extended search options 2416 parent_wrapper.find('.extended_search_check_wrapper').slideUp({ duration: 200, queue: false }); 2417 }); 2418} 2419 2420 2421 2422/* 2423 * wp_estate_baths_component_item 2424 * 2425 * This function sets up the behavior for a beds and baths selection component 2426 * in a real estate WordPress theme or plugin. 2427 */ 2428function wpestate_beds_baths_component() { 2429 2430 /** 2431 * Handles the click event on beds or baths items 2432 * @param {string} itemClass - The class of the clicked item 2433 * @param {string} inputClass - The class of the input to update 2434 */
2435 function handleItemClick(itemClass, inputClass) { 2436 var selected_item = jQuery(this); 2437 var parent = selected_item.parent(); 2438 var component = selected_item.closest('.wpestate-beds-baths-popoup-component'); 2439 // Remove selected class from all items and add it to the clicked item 2440 parent.find(itemClass).removeClass('wp_estate_component_item_selected'); 2441 selected_item.addClass('wp_estate_component_item_selected'); 2442 // Update the hidden input value 2443 var selected_value = selected_item.attr('data-value'); 2444 jQuery(inputClass).val(selected_value); 2445 update_label(component); 2446 } 2447 2448 /** 2449 * Updates the label of the component with the selected beds and baths 2450 * @param {jQuery} component - The component to update 2451 */ 2452 function update_label(component){ 2453 var selected_beds = component.find('.wp_estate_beds_component_item.wp_estate_component_item_selected').length > 0 ? component.find('.wp_estate_beds_component_item.wp_estate_component_item_selected').attr('data-value') : '0'; 2454 var selected_baths = component.find('.wp_estate_baths_component_item.wp_estate_component_item_selected').length > 0 ? component.find('.wp_estate_baths_component_item.wp_estate_component_item_selected').attr('data-value') : '0'; 2455 var update_label=parseFloat(selected_beds)+'+ '+control_vars.bd+'/'+parseFloat(selected_baths)+'+ '+control_vars.ba; 2456 component.find('.dropdown-toggle').text(update_label); 2457 } 2458 2459 // Attach event handlers 2460 // Handler for bed selection 2461 jQuery('.wp_estate_beds_component_item').on('click', function(event) { 2462 event.stopPropagation(); 2463 handleItemClick.call(this, '.wp_estate_beds_component_item', '.wpresidence-componentsbeds'); 2464 }); 2465 2466 // Handler for bath selection 2467 jQuery('.wp_estate_baths_component_item').on('click', function(event) { 2468 event.stopPropagation(); 2469 handleItemClick.call(this, '.wp_estate_baths_component_item', '.wpresidence-componentsbaths'); 2470 }); 2471 2472 // Handler for resetting the selection 2473 jQuery('.wpestate-beds-baths-popoup-reset').on('click', function(event) { 2474 event.stopPropagation(); 2475 var parent = jQuery(this).closest('.wpestate-beds-baths-popoup-wrapper'); 2476 // Remove selected class from all items 2477 parent.find('.wp_estate_baths_component_item').removeClass('wp_estate_component_item_selected'); 2478 parent.find('.wp_estate_beds_component_item').removeClass('wp_estate_component_item_selected'); 2479 // Clear input values 2480 parent.find('.wpresidence-componentsbeds, .wpresidence-componentsbaths').val(''); 2481 // Reset the label 2482 var component = jQuery(this).closest('.wpestate-beds-baths-popoup-component'); 2483 var update_value=jQuery(this).attr('data-default-value')+'<span class="caret caret_filter "></span>'; 2484 component.find('.dropdown-toggle').html(update_value); 2485 }); 2486 2487 // Handler for completing the selection 2488 jQuery('.wpestate-beds-baths-popoup-done').on('click', function() { 2489 first_time_wpestate_show_inpage_ajax_half=1; 2490 wpestate_show_pins(); 2491 }); 2492 2493} 2494 2495 2496/* 2497 * wp_estate_price_component_item 2498 * 2499 * This function sets up the behavior for a price range selection component 2500 * in a real estate WordPress theme or plugin. 2501 */ 2502function wpestate_price_component_item(){ 2503 2504 // Prevent click event propagation on the price popup wrapper 2505 jQuery('.wpestate-price-popoup-wrapper').on('click', function(event) { 2506 event.stopPropagation(); 2507 }); 2508 2509 // Clear input value on focus for price range inputs 2510 jQuery('.component_adv_search_elementor_price_low,.component_adv_search_elementor_price_max').on('focus',function(){ 2511 jQuery(this).val(''); 2512 }) 2513 2514 // Ensure only numeric input for price range fields 2515 jQuery('.component_adv_search_elementor_price_low,.component_adv_search_elementor_price_max').on('input', function() { 2516 // Replace non-digit characters with an empty string 2517 jQuery(this).val(jQuery(this).val().replace(/\D/g, '')); 2518 }); 2519 2520 // Update slider when price input changes 2521 jQuery('.component_adv_search_elementor_price_low,.component_adv_search_elementor_price_max').on('change',function(event) { 2522 var inputValue = jQuery(this).val(); 2523 var parent = jQuery(this).closest('.wpestate-price-popoup-wrapper'); 2524 var numericValue = parseFloat(inputValue) 2525 var slider = parent.find('.ui-slider') 2526 2527 // Update slider based on which input changed (low or max) 2528 if( jQuery(this).hasClass('component_adv_search_elementor_price_low') ){ 2529 slider.slider('values', 0, numericValue); 2530 slider.slider("option", "slide").call(slider, null, { values: [numericValue, slider.slider("values")[1]] }); 2531 }else{ 2532 slider.slider('values', 1, numericValue); 2533 slider.slider("option", "slide").call(slider, null, { values: [slider.slider("values")[0], numericValue] }); 2534 } 2535 }); 2536 2537 // Reset price component to default values 2538 jQuery('.wpestate-price-component-popoup-reset').on('click',function(event){ 2539 event.stopPropagation(); 2540 var parent = jQuery(this).closest('.wpestate-price-popoup-wrapper'); 2541 var low_value_label = parent.find('.wpestate-price-popoup-field-low').attr('data-value'); 2542 var max_value_label = parent.find('.wpestate-price-popoup-field-max').attr('data-value'); 2543 2544 // Reset values based on the type of price input present 2545 if(parent.find('.adv_search_elementor_price_low').length>0 ){ 2546 var low_value = parent.find('.adv_search_elementor_price_low').attr('data-value'); 2547 var max_value = parent.find('.adv_search_elementor_price_max').attr('data-value'); 2548 parent.find('.adv_search_elementor_price_low').val(low_value); 2549 parent.find('.adv_search_elementor_price_max').val(max_value); 2550 }else{ 2551 if( parent.find('.adv6_price_low').length > 0 ){ 2552 var low_value = parent.find('.adv6_price_low').attr('data-value'); 2553 var max_value = parent.find('.adv6_price_max').attr('data-value'); 2554 parent.find('.adv6_price_low').val(low_value); 2555 parent.find('.adv6_price_max').val(max_value); 2556 }else{ 2557 var low_value = parent.find('.single_price_low').attr('data-value'); 2558 var max_value = parent.find('.single_price_max').attr('data-value'); 2559 parent.find('.adv6_price_low').val(low_value); 2560 parent.find('.adv6_price_max').val(max_value); 2561 } 2562 } 2563 2564 // Reset dropdown button text 2565 var button_item = parent.parent().find('.dropdown-toggle'); 2566 button_item.html( button_item.attr('data-default-value')+' <sp
2566an class="caret caret_filter "></span>' ) ; 2567 2568 // Reset price range fields 2569 parent.find('.wpestate-price-popoup-field-low').val(low_value_label); 2570 parent.find('.wpestate-price-popoup-field-max').val(max_value_label); 2571 2572 // Reset slider label and values 2573 var slider_label = parent.find('.wpresidence_slider_price').attr('data-default'); 2574 parent.find('.wpresidence_slider_price').text(slider_label); 2575 var slider = parent.find('.ui-slider') 2576 slider.slider('values', 0, parseFloat(low_value)); // sets first handle (e.g., min value) 2577 slider.slider('values', 1, parseFloat(max_value)); 2578 }) 2579 2580 // Handle 'Done' button click 2581 jQuery('.wpestate-price-component-popoup-done').on('click',function(event){ 2582 var parent_wrapper = jQuery('body'); 2583 var fake_click_item = parent_wrapper.parent(); 2584 fake_click_item.trigger('click'); 2585 wpestate_show_pins(); 2586 }) 2587} 2588 2589 2590 2591/* 2592* 2593* format a price 2594* 2595*/ 2596function wpestate_format_a_price(priceValue){ 2597 thousandSeparator = control_vars.price_separator; 2598 decimalPoints = control_vars.decimal_poins; 2599 decimalSeparator = control_vars.decimal_poins_separator; 2600 2601 if (!isNaN(priceValue)) { 2602 priceValue= parseFloat(priceValue); 2603 var formattedPrice = priceValue.toFixed(decimalPoints).replace(/\d(?=(\d{3})+\.)/g, '$&' + thousandSeparator); 2604 formattedPrice = formattedPrice.replace('.', decimalSeparator); 2605 var formattedPriceWithCurrency= wpestate_return_price_with_multi_currency(formattedPrice); 2606 return formattedPriceWithCurrency; 2607 } 2608 2609 2610} 2611 2612 2613/* 2614* 2615* add currency to a price 2616* 2617*/ 2618 2619function wpestate_return_price_with_multi_currency(theValue){ 2620 var return_string=''; 2621 var my_custom_curr_symbol = decodeURI ( wpestate_getCookie('my_custom_curr_symbol') ); 2622 var my_custom_curr_coef = parseFloat( wpestate_getCookie('my_custom_curr_coef')); 2623 var my_custom_curr_pos = parseFloat( wpestate_getCookie('my_custom_curr_pos')); 2624 var my_custom_curr_cur_post= wpestate_getCookie('my_custom_curr_cur_post'); 2625 2626 2627 2628 if (!isNaN(my_custom_curr_pos) && my_custom_curr_pos !== -1) { 2629 if (my_custom_curr_cur_post === 'before') { 2630 return_string= wpestate_replace_plus( decodeURIComponent ( my_custom_curr_symbol ) ) + " " + theValue; 2631 } else { 2632 return_string=theValue + " " + wpestate_replace_plus( decodeURIComponent ( my_custom_curr_symbol ) ) ; 2633 } 2634 } else { 2635 2636 if (control_vars.where_curency === 'before') { 2637 return_string= wpestate_replace_plus( decodeURIComponent ( control_vars.curency ) ) + " " + theValue; 2638 } else { 2639 return_string=theValue + " " + wpestate_replace_plus( decodeURIComponent ( control_vars.curency ) ) ; 2640 } 2641 } 2642 2643 return return_string; 2644 2645 2646 2647} 2648/* 2649* 2650* wp estate price component_item v3 2651* 2652*/ 2653function wpestate_price_component_item_v3(){ 2654 jQuery('.wpestate-price-popoup-wrapper_v3').on('click', function(event) { 2655 2656 event.stopPropagation(); 2657 jQuery(this).find('.dropdown-menu').hide(); 2658 }); 2659 2660 2661 jQuery('.wpestate_child_dropdown_item').on("click", function(e) { 2662 jQuery(this).parent().find('.dropdown-menu').toggle(); 2663 e.stopPropagation(); 2664 }); 2665 2666 2667 jQuery('.wpestate-price-component-popoup-reset_v3').on('click',function(event){ 2668 event.stopPropagation(); 2669 var parent = jQuery(this).closest('.wpestate-price-popoup-wrapper_v3'); 2670 2671 parent.find('.wpestate-price-component-select').each(function() { 2672 jQuery(this).val(jQuery(this).find('option:first').val()); 2673 }); 2674 2675 var component = parent.closest('.wpestate-beds-baths-popoup-component'); 2676 var update_value=jQuery(this).attr('data-default-value')+'<span class="caret caret_filter"></span>'; 2677 2678 var item_update_value = jQuery(this).attr('data-default-value2')+'<span class="caret caret_filter"></span>'; 2679 component.find('.dropdown-toggle').html(update_value); 2680 component.find('.wpestate_child_dropdown_item').html(item_update_value); 2681 component.find('.wpresidence-component3_input_class').val(''); 2682 component.find('.price_label_component').val(''); 2683 2684 }) 2685 2686 jQuery('.wpestate-price-component-popoup-done_v3').on('click',function(event){ 2687 var parent_wrapper = jQuery('body'); 2688 var fake_click_item= parent_wrapper.parent(); 2689 fake_click_item.trigger('click'); 2690 first_time_wpestate_show_inpage_ajax_half=1; 2691 wpestate_show_pins(); 2692 }) 2693 2694 2695 2696 jQuery('.wpresidence_half_search_type_2 .wpresidence_button ,.wpresidence_note_half_search .wpresidence_button').on('click',function(event){ 2697 event.preventDefault(); 2698 first_time_wpestate_show_inpage_ajax_half=1; 2699 wpestate_show_pins(); 2700 }); 2701 2702 2703 jQuery('.wpestate-price-popoup-wrapper_v3 li').on("click", function(e){ 2704 2705 var parent = jQuery(this).closest('.wpestate-price-popoup-wrapper_v3'); 2706 var component = parent.closest('.wpestate-beds-baths-popoup-component'); 2707 var parent_ul = jQuery(this).parent(); 2708 var selected_value = jQuery(this).attr('data-value'); 2709 2710 if(parent_ul.hasClass('wpresidence-component3-min-price_class')){ 2711 var selectedmin =selected_value; 2712 var selectedmax = parent.find('.wpresidence-component3-max-price_input_class').val(); 2713 }else{ 2714 var selectedmin = parent.find('.wpresidence-component3-min-price_input_class').val(); 2715 var selectedmax = selected_value 2716 } 2717 2718 2719 var update_value=wpestate_return_price_with_multi_currency(selectedmin)+" - "+wpestate_return_price_with_multi_currency(selectedmax); 2720 component.find('.wpestate-beds-baths-popoup-component-toggle').html(update_value); 2721 component.find('.price_label_component').val(update_value); 2722 parent_ul.hide(); 2723 }); 2724 2725} 2726 2727 2728 2729 2730/* 2731* 2732*wpestate-price-popoup-wrapper_v3 2733*/ 2734function wpestate_reposion_dropdowns(){ 2735 jQuery('.wpestate-multiselect-custom-style').on('click', function() { 2736 2737 var $popupWrapper = jQuery(this);
2738 var $searchWrapper = $popupWrapper.closest('.search_wrapper'); // Get the closest parent with the class '.search_wrapper' 2739 2740 if($searchWrapper.length===0){ 2741 return; 2742 } 2743 2744 var $dropdownMenu = jQuery(this).next('.wpestate-price-popoup-wrapper_v3'); 2745 2746 if($dropdownMenu.length==0){ 2747 var $dropdownMenu = jQuery(this).next('.wpestate-beds-baths-popoup-wrapper'); 2748 } 2749 if($dropdownMenu.length==0){ 2750 var $dropdownMenu = jQuery(this).next('.wpestate-price-popoup-wrapper'); 2751 } 2752 2753 var popupOffset = $popupWrapper.offset(); 2754 var searchOffset = $searchWrapper.offset(); 2755 2756 // Calculate the distances 2757 var distanceToLeft = popupOffset.left - searchOffset.left; 2758 var distanceToRight = (searchOffset.left + $searchWrapper.outerWidth()) - (popupOffset.left + $popupWrapper.outerWidth()); 2759 2760 if (distanceToLeft <= 150) { 2761 // Close to the left edge 2762 $dropdownMenu.css('left', 0); 2763 $dropdownMenu.css('right', 'auto'); 2764 2765 } else if (distanceToRight <= 150) { 2766 // Close to the right edge 2767 $dropdownMenu.css('left', 'auto'); 2768 $dropdownMenu.css('right', 0); 2769 2770 } 2771 2772 2773 2774 2775 }); 2776} 2777 2778 2779/** 2780* Initializes Slick Slider for Estate Place Cards 2781* @param {Object} jQuery - Requires jQuery 2782* @requires slick-carousel 2783* @description Sets up responsive sliders for real estate location/place displays with optional autoplay 2784* Data attributes required: 2785* - data-items-per-row: Number of slides to show 2786* - data-auto: Autoplay speed in ms (0 to disable) 2787* Global required: 2788* - control_vars.is_rtl: RTL language setting ('1' or '0') 2789*/ 2790 2791function wpestate_enable_slick_places() { 2792 jQuery('.estate_places_slider').not('.slick-initialized').each(function() { 2793 let items = jQuery(this).attr('data-items-per-row'), 2794 auto = parseInt(jQuery(this).attr('data-auto')), 2795 isRTL = control_vars.is_rtl === '1'; 2796 2797 const config = { 2798 infinite: true, 2799 slidesToShow: items, 2800 slidesToScroll: 1, 2801 dots: false, 2802 rtl: isRTL, 2803 responsive: [ 2804 { 2805 breakpoint: 1025, 2806 settings: { 2807 slidesToShow: 2, 2808 slidesToScroll: 1 2809 } 2810 }, 2811 { 2812 breakpoint: 525, 2813 settings: { 2814 slidesToShow: 1, 2815 slidesToScroll: 1 2816 } 2817 } 2818 ] 2819 }; 2820 2821 if (auto) { 2822 config.autoplay = true; 2823 config.autoplaySpeed = auto; 2824 } 2825 2826 jQuery(this).slick(config); 2827 }); 2828 } 2829 2830 2831/* 2832* 2833* 2834*/ 2835 2836function wpestate_enble_slick_slider_list(){ 2837 jQuery('.shortcode_slider_list').each(function() { 2838 const $slider = jQuery(this); 2839 const items = $slider.attr('data-items-per-row'); 2840 const auto = parseInt($slider.attr('data-auto')); 2841 const isRTL = control_vars.is_rtl === '1'; 2842 2843 const slickConfig = { 2844 infinite: true, 2845 slidesToShow: items, 2846 slidesToScroll: 1, 2847 dots: true, 2848 rtl: isRTL, 2849 autoplay: auto !== 0, 2850 autoplaySpeed: auto, 2851 responsive: [ 2852 { 2853 breakpoint: 1025, 2854 settings: { 2855 slidesToShow: 2, 2856 slidesToScroll: 1 2857 } 2858 }, 2859 { 2860 breakpoint: 550, 2861 settings: { 2862 slidesToShow: 1, 2863 slidesToScroll: 1 2864 } 2865 } 2866 ] 2867 }; 2868 2869 // Initialize slick with settings 2870 $slider.not('.slick-initialized').slick(slickConfig); 2871 }); 2872} 2873 2874/** 2875 * Initialize and configure Slick slider for theme and property image sliders 2876 * Handles both RTL and LTR layouts with responsive design and mobile optimization 2877 * 2878 * @param {number|string} items_received - Number of slides to show on desktop view (defaults to 3 if invalid) 2879 * 2880 * Configuration: 2881 * - Supports auto-play and manual navigation modes 2882 * - Responsive breakpoints at 1025px (2 slides) and 576px (1 slide) 2883 * - RTL support with mobile positioning fixes 2884 * - Custom navigation arrows with Bootstrap carousel styling 2885 * - Adaptive height on mobile devices 2886 * 2887 * HTML Requirements: 2888 * - Target elements: .theme_slider_2 or .property_multi_image_slider 2889 * - data-auto attribute for autoplay speed (0 for manual navigation) 2890 * 2891 * Dependencies: 2892 * - jQuery 2893 * - Slick Slider 2894 * - control_vars.is_rtl global variable ('1' for RTL, '0' for LTR) 2895 * 2896 * @return {void} 2897 */ 2898function wpestate_enable_slick_theme_slider(items_received) { 2899 var items = 3; 2900 if (parseInt(items_received) !== '') { 2901 items = parseInt(items_received); 2902 } 2903 2904 jQuery('.theme_slider_2,.property_multi_image_slider').each(function() {
2905 var auto = parseInt(jQuery(this).attr('data-auto')); 2906 var isRTL = control_vars.is_rtl === '1'; 2907 2908 // Common settings for both auto and non-auto 2909 var commonSettings = { 2910 infinite: true, 2911 slidesToShow: items, 2912 slidesToScroll: 1, 2913 dots: auto === 0 ? false : true, 2914 rtl: isRTL, 2915 prevArrow: '<button class="carousel-control-prev wpresidence-carousel-control" type="button" data-bs-target="#wpresidence-blog-post-carousel-bootstrap" data-bs-slide="prev"><span class="carousel-control-prev-icon" aria-hidden="true"></span><span class="visually-hidden">Previous</span></button>', 2916 nextArrow: '<button class="carousel-control-next wpresidence-carousel-control" type="button" data-bs-target="#wpresidence-blog-post-carousel-bootstrap" data-bs-slide="next"><span class="carousel-control-next-icon" aria-hidden="true"></span><span class="visually-hidden">Next</span></button>', 2917 responsive: [ 2918 { 2919 breakpoint: 1025, 2920 settings: { 2921 slidesToShow: 2, 2922 slidesToScroll: 1 2923 } 2924 }, 2925 { 2926 breakpoint: 576, 2927 settings: { 2928 slidesToShow: 1, 2929 slidesToScroll: 1, 2930 adaptiveHeight: true 2931 } 2932 } 2933 ], 2934 init: function(slick) { 2935 if (isRTL) { 2936 // Fix for initial RTL positioning 2937 setTimeout(function() { 2938 var $track = jQuery(slick.$slideTrack); 2939 var width = $track.width(); 2940 var slideWidth = jQuery(window).width(); 2941 2942 if (window.innerWidth <= 576) { 2943 $track.css({ 2944 'transform': 'translate3d(0, 0, 0)', 2945 'width': 'auto' 2946 }); 2947 } 2948 }, 100); 2949 } 2950 } 2951 }; 2952 2953 // Add auto-specific settings 2954 if (auto !== 0) { 2955 commonSettings.autoplay = true; 2956 commonSettings.autoplaySpeed = auto; 2957 } 2958 2959 // Initialize slick if not already initialized 2960 if (!jQuery(this).hasClass('slick-initialized')) { 2961 jQuery(this).slick(commonSettings); 2962 } 2963 2964 // Handle window resize 2965 jQuery(window).on('resize', function() { 2966 if (isRTL && window.innerWidth <= 576) { 2967 jQuery('.slick-track').css({ 2968 'transform': 'translate3d(0, 0, 0)', 2969 'width': 'auto' 2970 }); 2971 } 2972 }); 2973 }); 2974} 2975 2976 2977/* 2978* 2979* 2980*/ 2981function wpestate_enable_slick_testimonial(){ 2982 jQuery('.testimonial-slider-container').each(function(){ 2983 2984 2985 var items = parseInt( jQuery(this).attr('data-visible-items')); 2986 var auto = parseInt( jQuery(this).attr('data-auto') ); 2987 2988 if (auto === 0 ){ 2989 2990 jQuery(this).not('.slick-initialized').slick({ 2991 infinite: true, 2992 slidesToShow: items, 2993 slidesToScroll: 1, 2994 dots: true, 2995 2996 responsive: [ 2997 { 2998 breakpoint:1025, 2999 settings: { 3000 slidesToShow: 1, 3001 slidesToScroll: 1 3002 } 3003 }, 3004 { 3005 breakpoint: 480, 3006 settings: { 3007 slidesToShow: 1, 3008 slidesToScroll: 1 3009 } 3010 } 3011 ] 3012 }); 3013 if(control_vars.is_rtl==='1'){ 3014 jQuery(this).slick('slickSetOption','rtl',true,true); 3015 } 3016 }else{ 3017 3018 jQuery(this).not('.slick-initialized').slick({ 3019 infinite: true, 3020 slidesToShow: items, 3021 slidesToScroll: 1, 3022 dots: true, 3023 autoplay: true, 3024 autoplaySpeed: auto, 3025 3026 responsive: [ 3027 { 3028 breakpoint:1025, 3029 settings: { 3030 slidesToShow: 1, 3031 slidesToScroll: 1 3032 } 3033 }, 3034 { 3035 breakpoint: 480, 3036 settings: { 3037 slidesToShow: 1, 3038 slidesToScroll: 1 3039 } 3040 } 3041 ] 3042 }); 3043 if(control_vars.is_rtl==='1'){ 3044 jQuery(this).slick('slickSetOption','rtl',true,true); 3045 } 3046 } 3047 }); 3048} 3049 3050/* 3051* 3052* 3053*/ 3054function wpestate_grid_list_controls(){ 3055 3056 jQuery('#list_view').unbind('click'); 3057 jQuery('#list_view').on( 'click', function(event) { 3058 jQuery(this).toggleClass('icon_selected'); 3059 jQuery('#listing_ajax_container').addClass('ajax12'); 3060 jQuery('#grid_view').toggleClass('icon_selected'); 3061 3062 3063 if (window.wpestateHalfMapState) { 3064 window.wpestateHalfMapState.applyListLayout(); 3065 } else { 3066 jQuery('#listing_ajax_container .listing_wrapper,.wpestate_filter_list_properties_wrapper .listing_wrapper').hide().removeClass('col-md-4').removeClass('col-md-6').removeClass('col-md-3').addClass('col-md-12 col-lg-12').fadeIn(400) ; 3067 } 3068 3069 jQuery('.the_grid_view').fadeOut(10,function() { 3070 jQuery('.the_list_view:not(.half_map_list_view)').fadeIn(300); 3071 }); 3072 3073 // custom unit code 3074 jQuery('#listing_ajax_container .col-md-12.listing_wrapper .property_unit_custom_element.image').each(function(){ 3075 jQuery(this).parent().addClass('wrap_custom_image'); 3076 }); 3077 3078 jQuery('.col-md-12.listing_wrapper .property_unit_custom_element.image').each(function(){ 3079 jQuery(this).parent().addClass('wrap_custom_image'); 3080 }); 3081 3082 wpresidence_list_view_arrange(); 3083 }); 3084 3085 3086 3087 jQuery('#grid_view').unbind('click'); 3088 jQuery('#grid_view').on( 'click', function(event) { 3089 var class_type; 3090 3091 class_type = jQuery('#listing_ajax_container .listing_wrapper').first().attr('data-org'); 3092 if( jQuery('.wpestate_filter_list_properties_wrapper').length >0 ){ 3093 class_type = jQuery('.wpestate_filter_list_properties_wrapper .listing_wrapper').first().attr('data-org'); 3094 } 3095 3096 jQuery(this).toggleClass('icon_selected'); 3097 jQuery('#listing_ajax_container').removeClass('ajax12'); 3098 jQuery('#list_view').toggleClass('icon_selected'); 3099 3100 if (window.wpestateHalfMapState) { 3101 window.wpestateHalfMapState.applyGridLayout(); 3102 } else { 3103 jQuery('#listing_ajax_container .listing_wrapper,.wpestate_filter_list_properties_wrapper .listing_wrapper ').hide().removeClass('col-lg-12').removeClass('col-md-12').addClass('col-lg-'+class_type).fadeIn(400); 3104 } 3105 3106 jQuery('#listing_ajax_container .the_list_view,.wpestate_filter_list_properties_wrapper .the_list_view').fadeOut(10,function(){ 3107 jQuery('.the_grid_view').fadeIn(300); 3108 }); 3109 3110 jQuery('#listing_ajax_container .wrap_custom_image').each(function(){ 3111 jQuery(this).removeClass('wrap_custom_image'); 3112 jQuery('.property_listing_custom_design').css('padding-left','0px'); 3113 }); 3114 3115 }); 3116 3117 3118 3119} 3120 3121 3122/* 3123* 3124* 3125*/ 3126function wpresidence_list_view_arrange(){ 3127 var wrap_image = parseInt( jQuery('.wrap_custom_image').width()); 3128 3129 if(wrap_image!=0){ 3130 jQuery('.col-md-12>.property_listing_custom_design').css('padding-left',wrap_image); 3131 } 3132} 3133 3134 3135 3136/** 3137 * Handles the dynamic filtering between city and area dropdowns in property listings. 3138 * When a city is selected, it filters the available areas to show only those belonging 3139 * to the selected city. The function works with multiple instances of city-area filter 3140 * pairs on the same page. 3141 * 3142 * @param {string} selected_city - ID of the city dropdown button (without '#') 3143 * @param {string} selected_area - ID of the area dropdown button (without '#') 3144 * 3145 * HTML Structure Expected: 3146 * <button id="[selected_city]"> 3147 * <ul class="dropdown-menu"> 3148 * <li data-value2="city-value" data-value="city-value">City Name</li> 3149 * </ul> 3150 * <button id="[selected_area]"> 3151 * <ul class="dropdown-menu"> 3152 * <li data-parentcity="city-value" data-value="area-value">Area Name</li> 3153 * </ul> 3154 */ 3155function wpestate_filter_city_area(selected_city, selected_area) { 3156 // The advanced search type 6 form (and a few other layouts) renders ONE form per 3157 // tab using the same hardcoded button/UL ids. jQuery '#id' returns only the first 3158 // match, so a non-delegated handler bound to '#selected_city ul li' would only 3159 // catch clicks inside the first tab. Use document-level delegation and scope every 3160 // DOM lookup to the closest .dropdown / form so each tab works in isolation. 3161 // 3162 // We also accept either the BUTTON id or the UL id as input â older call sites 3163 // pass UL ids (e.g. 'sidebar-adv-search-city'), newer ones pass button ids 3164 // (e.g. 'property_city'). Both selectors below match in either case. 3165 3166 3167 // ---- City <li> click: update city button + filter & reset area in same form ---- 3168 jQuery(document).on('click', 3169 '#' + selected_city + ' > li, #' + selected_city + ' ~ .dropdown-menu > li', 3170 function(event) { 3171 event.preventDefault(); 3172 3173 var $li = jQuery(this); 3174 var value_city = String($li.attr('data-value2')).toLowerCase(); 3175 var $wrapper = $li.closest('.dropdown'); 3176 var $form = $li.closest('form'); 3177 3178 3179 // Update the city button (scoped to THIS dropdown wrapper, not by global id). 3180 var $cityBtn = $wrapper.find('.dropdown-toggle, [data-bs-toggle="dropdown"], [data-toggle="dropdown"]').first(); 3181 3182 $cityBtn.text($li.text()).attr('data-value', value_city); 3183 3184 // Sync the hidden input (so the form submits the chosen city). 3185 var $cityHidden = $wrapper.find('input[type="hidden"][name="property_city"]'); 3186 3187 $cityHidden.val(value_city === 'all' ? '' : value_city); 3188 3189 // Locate the matching area dropdown inside the SAME form.
3190 // Half-map layout 1 has its <form> tag commented out, so $form is empty. 3191 // Walk to the nearest stable container that holds all sibling dropdowns 3192 // before falling back to $wrapper.parent() (which is just the dropdown's 3193 // own column and won't see siblings). .tab-pane scopes to the active 3194 // tab in adv6 (ids repeat across tabs) so it must precede the outer 3195 // wrappers that contain every tab. 3196 var $areaCtx = $form.length 3197 ? $form 3198 : $li.closest('.tab-pane, .adv-search-1, .search_wrapper, .wpresidence_note_half_search'); 3199 if (!$areaCtx.length) { $areaCtx = $wrapper.parent(); } 3200 var $areaWrap = $areaCtx.find('#' + selected_area).closest('.dropdown'); 3201 var areaResolveStep = 'id-as-button'; 3202 if ($areaWrap.length === 0) { 3203 $areaWrap = $areaCtx.find('[id="' + selected_area + '"]').closest('.dropdown'); 3204 areaResolveStep = 'attr-id'; 3205 } 3206 if ($areaWrap.length === 0) { 3207 $areaWrap = $areaCtx.find('.areas .dropdown, .col-md-3.areas .dropdown').first(); 3208 areaResolveStep = 'class-fallback'; 3209 } 3210 3211 3212 // Filter area options by parent city. 3213 var shown = 0, hidden = 0; 3214 $areaWrap.find('.dropdown-menu > li').each(function() { 3215 var is_city = String(jQuery(this).attr('data-parentcity')).toLowerCase().replace(' ', '-'); 3216 if (is_city === value_city || value_city === 'all') { 3217 jQuery(this).show(); 3218 shown++; 3219 } else { 3220 jQuery(this).hide(); 3221 hidden++; 3222 } 3223 }); 3224 3225 3226 // Reset the area button + hidden input in this form. 3227 var $areaBtn = $areaWrap.find('.dropdown-toggle, [data-bs-toggle="dropdown"], [data-toggle="dropdown"]').first(); 3228 3229 $areaBtn 3230 .text(control_vars.areas) 3231 .attr('data-value', 'all'); 3232 var $areaHidden = $areaCtx.find('input[type="hidden"][name="property_area"]'); 3233 3234 $areaHidden.val(''); 3235 console.groupEnd(); 3236 }); 3237 3238 // ---- Area <li> click: just update the area button label/value in its wrapper ---- 3239 jQuery(document).on('click', 3240 '#' + selected_area + ' > li, #' + selected_area + ' ~ .dropdown-menu > li', 3241 function(event) { 3242 event.preventDefault(); 3243 3244 var $li = jQuery(this); 3245 var $wrapper = $li.closest('.dropdown'); 3246 var areaValue = $li.attr('data-value'); 3247 3248 3249 3250 var $areaBtn = $wrapper.find('.dropdown-toggle, [data-bs-toggle="dropdown"], [data-toggle="dropdown"]').first(); 3251 3252 $areaBtn 3253 .text($li.text()) 3254 .attr('data-value', areaValue); 3255 $wrapper.find('input[type="hidden"][name="property_area"]').val(areaValue === 'all' ? '' : areaValue); 3256 console.groupEnd(); 3257 }); 3258} 3259 3260 3261/** 3262 * Handles the dynamic filtering between county and city dropdowns in property listings. 3263 * When a county is selected, it filters the available cities to show only those belonging 3264 * to the selected county. The function works with multiple instances of county-city filter 3265 * pairs on the same page. 3266 * 3267 * @param {string} selected_county - ID of the county dropdown button (without '#') 3268 * @param {string} selected_city - ID of the city dropdown button (without '#') 3269 * 3270 * HTML Structure Expected: 3271 * <button id="[selected_county]"> 3272 * <ul class="dropdown-menu"> 3273 * <li data-value2="county-value" data-value="county-value">County Name</li> 3274 * </ul> 3275 * <button id="[selected_city]"> 3276 * <ul class="dropdown-menu"> 3277 * <li data-parentcounty="county-value" data-value="city-value">City Name</li> 3278 * </ul> 3279 */ 3280function wpestate_filter_county_city(selected_county, selected_city) { 3281 // See wpestate_filter_city_area() above for the rationale: tabbed forms repeat 3282 // the same hardcoded ids per tab, so we delegate from document and resolve every 3283 // related element via .closest('.dropdown') / .closest('form'). 3284 3285 3286 // ---- County <li> click: update county button + filter & reset city in same form ---- 3287 jQuery(document).on('click', 3288 '#' + selected_county + ' > li, #' + selected_county + ' ~ .dropdown-menu > li', 3289 function(event) { 3290 event.preventDefault(); 3291 3292 var $li = jQuery(this); 3293 var value_county = String($li.attr('data-value2')).toLowerCase(); 3294 var $wrapper = $li.closest('.dropdown'); 3295 var $form = $li.closest('form'); 3296 3297 3298 // Update the county/state button (scoped to THIS dropdown). 3299 var $countyBtn = $wrapper.find('.dropdown-toggle, [data-bs-toggle="dropdown"], [data-toggle="dropdown"]').first(); 3300 3301 $countyBtn.text($li.text()).attr('data-value', value_county); 3302 3303 // Sync the hidden input. 3304 var $countyHidden = $wrapper.find('input[type="hidden"][name="property_county_state"]'); 3305 3306 $countyHidden.val(value_county === 'all' ? '' : value_county); 3307 3308 // Locate the matching city dropdown inside the SAME form.
3309 // Half-map layout 1 has its <form> tag commented out, so $form is empty. 3310 // Walk to the nearest stable container that holds all sibling dropdowns 3311 // before falling back to $wrapper.parent() (which is just the dropdown's 3312 // own column and won't see siblings). .tab-pane scopes to the active 3313 // tab in adv6 (ids repeat across tabs) so it must precede the outer 3314 // wrappers that contain every tab. 3315 var $cityCtx = $form.length 3316 ? $form 3317 : $li.closest('.tab-pane, .adv-search-1, .search_wrapper, .wpresidence_note_half_search'); 3318 if (!$cityCtx.length) { $cityCtx = $wrapper.parent(); } 3319 var $cityWrap = $cityCtx.find('#' + selected_city).closest('.dropdown'); 3320 var cityResolveStep = 'id-as-button'; 3321 if ($cityWrap.length === 0) { 3322 $cityWrap = $cityCtx.find('[id="' + selected_city + '"]').closest('.dropdown'); 3323 cityResolveStep = 'attr-id'; 3324 } 3325 if ($cityWrap.length === 0) { 3326 $cityWrap = $cityCtx.find('.cities .dropdown, .col-md-3.cities .dropdown').first(); 3327 cityResolveStep = 'class-fallback'; 3328 } 3329 3330 // Filter city options by parent county. 3331 var shown = 0, hidden = 0; 3332 $cityWrap.find('.dropdown-menu > li').each(function() { 3333 var is_county = String(jQuery(this).attr('data-parentcounty')).toLowerCase().replace(' ', '-'); 3334 if (is_county === value_county || value_county === 'all') { 3335 jQuery(this).show(); 3336 shown++; 3337 } else { 3338 jQuery(this).hide(); 3339 hidden++; 3340 } 3341 }); 3342 3343 // Reset the city button + hidden input in this form. Cascade-reset the 3344 // area too â when state changes, both city AND area must clear. 3345 var $cityBtn = $cityWrap.find('.dropdown-toggle, [data-bs-toggle="dropdown"], [data-toggle="dropdown"]').first(); 3346 3347 $cityBtn 3348 .text(control_vars.cities) 3349 .attr('data-value', 'all'); 3350 var $cityHidden = $cityCtx.find('input[type="hidden"][name="property_city"]'); 3351 3352 $cityHidden.val(''); 3353 3354 // Cascade reset for area (find any area dropdown in the same form). 3355 var $areaWrap = $cityCtx.find('[id="property_area"], [id="adv-search-area"], .areas .dropdown').closest('.dropdown').first(); 3356 3357 if ($areaWrap.length) { 3358 $areaWrap.find('.dropdown-toggle, [data-bs-toggle="dropdown"], [data-toggle="dropdown"]').first() 3359 .text(control_vars.areas) 3360 .attr('data-value', 'all'); 3361 // Show all area items again â the user may pick any city next. 3362 $areaWrap.find('.dropdown-menu > li').show(); 3363 } 3364 $cityCtx.find('input[type="hidden"][name="property_area"]').val(''); 3365 console.groupEnd(); 3366 }); 3367 3368 // ---- City <li> click: update the city button label/value in its wrapper ---- 3369 jQuery(document).on('click', 3370 '#' + selected_city + ' > li, #' + selected_city + ' ~ .dropdown-menu > li', 3371 function(event) { 3372 event.preventDefault(); 3373 3374 var $li = jQuery(this); 3375 var $wrapper = $li.closest('.dropdown'); 3376 var cityValue = $li.attr('data-value'); 3377 3378 3379 3380 var $cityBtn = $wrapper.find('.dropdown-toggle, [data-bs-toggle="dropdown"], [data-toggle="dropdown"]').first(); 3381 3382 $cityBtn 3383 .text($li.text()) 3384 .attr('data-value', cityValue); 3385 $wrapper.find('input[type="hidden"][name="property_city"]').val(cityValue === 'all' ? '' : cityValue); 3386 console.groupEnd(); 3387 }); 3388} 3389 3390 3391 3392 3393/* 3394* 3395* 3396*/ 3397function wpestate_raisePower(x, y) { 3398 "use strict"; 3399 return Math.pow(x, y); 3400} 3401 3402/* 3403* 3404* 3405*/ 3406function wpestate_adv_search_click(){ 3407 "use strict";
3408 jQuery('.with_search_form_float .adv-search-header-1,.with_search_form_float #adv-search-header-3').on( 'click', function(event) { 3409 if ( jQuery('#search_wrapper').hasClass('float_search_closed') ){ 3410 jQuery('#search_wrapper').removeClass('float_search_closed'); 3411 }else{ 3412 jQuery('#search_wrapper').addClass('float_search_closed'); 3413 } 3414 3415 }); 3416 3417} 3418 3419 3420/* 3421*Contact footer 3422* 3423*/ 3424function wpestate_contact_footer_starter(){ 3425 "use strict"; 3426 jQuery('#btn-cont-submit').on( 'click', function(event) { 3427 3428 var contact_name, contact_email, contact_phone, contact_coment, agent_email, property_id, nonce, ajaxurl; 3429 contact_name = jQuery('#foot_contact_name').val(); 3430 contact_email = jQuery('#foot_contact_email').val(); 3431 contact_phone = jQuery('#foot_contact_phone').val(); 3432 contact_coment = jQuery('#foot_contact_content').val(); 3433 var foot_contact_intent = jQuery('#foot_contact_intent input[name="contact_intent"]').val() || ''; 3434 nonce = jQuery('#agent_property_ajax_nonce').val(); 3435 ajaxurl = ajaxcalls_vars.admin_url + 'admin-ajax.php'; 3436 var parent = jQuery(this).parent().parent(); 3437 3438 3439 if(ajaxcalls_vars.use_gdpr==='yes'){ 3440 if (!parent.find('.wpestate_agree_gdpr').is(':checked')) { 3441 jQuery('#footer_alert-agent-contact').empty().append(ajaxcalls_vars.gdpr_terms); 3442 return; 3443 } 3444 } 3445 3446 jQuery('#footer_alert-agent-contact').empty().append(ajaxcalls_vars.sending); 3447 3448 3449 3450 jQuery.ajax({ 3451 type: 'POST', 3452 dataType: 'json', 3453 url: ajaxurl, 3454 data: { 3455 'action' : 'wpestate_ajax_agent_contact_form', 3456 'name' : contact_name, 3457 'email' : contact_email, 3458 'phone' : contact_phone, 3459 'contact_intent' : foot_contact_intent, 3460 'comment' : contact_coment, 3461 'is_footer' : 'yes', 3462 'nonce' : nonce 3463 }, 3464 success: function (data) { 3465 3466 if (data.sent) { 3467 jQuery('#foot_contact_name').val(''); 3468 jQuery('#foot_contact_email').val(''); 3469 jQuery('#foot_contact_phone').val(''); 3470 jQuery('#foot_contact_content').val(''); 3471 jQuery('#foot_contact_intent input[name="contact_intent"]').val(''); 3472 jQuery('#foot_contact_intent .dropdown-toggle').text(jQuery('#foot_contact_intent').data('placeholder') || ''); 3473 jQuery('#footer_alert-agent-contact').empty().addClass('wpestate-agent-contact-sent').append(data.response); 3474 }else{ 3475 jQuery('#footer_alert-agent-contact').empty().removeClass('wpestate-agent-contact-sent').append(data.response); 3476 } 3477 3478 3479 }, 3480 error: function (errorThrown) { 3481 3482 } 3483 }); 3484 3485 3486 jQuery.ajax({ 3487 type: 'POST', 3488 dataType: 'json', 3489 url: ajaxurl, 3490 data: { 3491 'action' : 'wpestate_ajax_agent_contact_form_forcrm', 3492 'name' : contact_name, 3493 'email' : contact_email, 3494 'phone' : contact_phone, 3495 'comment' : contact_coment, 3496 'nonce' : nonce 3497 }, 3498 success: function (data) { 3499 3500 3501 }, 3502 error: function (errorThrown) { 3503 3504 } 3505 }); 3506 3507 3508 }); 3509} 3510 3511 3512/* 3513* 3514* 3515*/ 3516function estate_splash_slider(){ 3517 3518 3519} 3520 3521 3522/* 3523* 3524* 3525*/ 3526function wpestat_resize_wpestate_property_slider_v2(){ 3527 if(control_vars.is_rtl==='1'){ 3528 3529 } 3530 var width = 1090; 3531 var window = jQuery( document ).width(); 3532 3533 var toadd=width+(window-width)/2; 3534 3535 if(toadd>1090){ 3536 jQuery('.property_slider_carousel_elementor_v2').css('width',toadd+'px'); 3537 }else{ 3538 jQuery('.property_slider_carousel_elementor_v2').css('width','100%'); 3539 } 3540} 3541 3542 3543/* 3544* 3545* 3546*/ 3547function wpestate_hotspots_click(){ 3548 jQuery('.wpestate_hotspot_icon_wrapper').on('click',function(){ 3549 jQuery('.wpestate_hotspot_tooltip').hide(); 3550 jQuery(this).parent().find('.wpestate_hotspot_tooltip').show(); 3551 }); 3552 3553} 3554 3555 3556/* 3557* 3558* 3559*/ 3560function wpestate_hotspots_hover(){ 3561 jQuery(".wpestate_hotspot_icon_wrapper").on('mouseenter', function () { 3562 jQuery(this).parent().find('.wpestate_hotspot_tooltip').show(); 3563 }).on('mouseleave', function () { 3564 jQuery(this).parent().find('.wpestate_hotspot_tooltip').hide(); 3565 }); 3566 3567 3568} 3569 3570/** 3571 * Initialize testimonial slider with RTL support 3572 * @param {string} slider_id - The ID of the slider element 3573 */ 3574function wpestate_testimonial_slider(slider_id){ 3575 3576 let rtl_value = false;
3577 if(control_vars.is_rtl==='1'){ 3578 rtl_value=true; 3579 } 3580 jQuery('#'+slider_id).owlCarousel({ 3581 loop:true, 3582 margin:0, 3583 nav:true, 3584 items:1, 3585 dots:true, 3586 mouseDrag:true, 3587 video:true, 3588 autoHeight: true, 3589 stagePadding:0, 3590 URLhashListener:false, 3591 rtl:rtl_value, 3592 navText: [ 3593 // Swap arrows for RTL 3594 rtl_value ? 3595 '<i class="fas fa-arrow-right"></i>' : 3596 '<i class="fas fa-arrow-left"></i>', 3597 rtl_value ? 3598 '<i class="fas fa-arrow-left"></i>' : 3599 '<i class="fas fa-arrow-right"></i>' 3600 ], 3601 }); 3602 3603} 3604 3605/* 3606* 3607* 3608*/ 3609function wpestate_property_slider_v2(slider_id, items) { 3610 wpestat_resize_wpestate_property_slider_v2(); 3611 3612 // Initialize RTL value checking both data attribute and control_vars 3613 let rtl_value = false; 3614 const $slider = jQuery('#' + slider_id); 3615 3616 // Check both data-rtl and control_vars.is_rtl 3617 if ($slider.attr('data-rtl') === 'yes' || control_vars.is_rtl === '1') { 3618 rtl_value = true; 3619 $slider.addClass('owl-rtl'); 3620 } 3621 3622 const is_loop = true; 3623 3624 $slider.owlCarousel({ 3625 loop: is_loop, 3626 margin: 0, 3627 nav: true, 3628 items: 6, 3629 dots: false, 3630 mouseDrag: true, 3631 video: true, 3632 autoHeight: true, 3633 autoWidth: true, 3634 stagePadding: 0, 3635 URLhashListener: false, 3636 rtl: rtl_value, 3637 navText: [ 3638 // Swap arrows for RTL 3639 rtl_value ? 3640 '<i class="fas fa-arrow-right"></i>' : 3641 '<i class="fas fa-arrow-left"></i>', 3642 rtl_value ? 3643 '<i class="fas fa-arrow-left"></i>' : 3644 '<i class="fas fa-arrow-right"></i>' 3645 ], 3646 onInitialized: function() { 3647 // Force RTL stage direction 3648 if (rtl_value) { 3649 const stage = $slider.find('.owl-stage'); 3650 stage.css('transform-origin', 'center center'); 3651 // Force correct direction on first load 3652 setTimeout(() => { 3653 $slider.trigger('refresh.owl.carousel'); 3654 }, 10); 3655 } 3656 } 3657 }); 3658} 3659 3660 3661/* 3662* 3663* 3664*/ 3665function wpestate_property_slider_v3(slider_id, items) { 3666 // Initialize RTL value checking both data attribute and control_vars 3667 let rtl_value = false; 3668 const $slider = jQuery('#' + slider_id); 3669 3670 // Check both data-rtl and control_vars.is_rtl 3671 if ($slider.attr('data-rtl') === 'yes' || control_vars.is_rtl === '1') { 3672 rtl_value = true; 3673 $slider.addClass('owl-rtl'); 3674 } 3675 3676 $slider.owlCarousel({ 3677 loop: true, 3678 margin: 0, 3679 nav: true, 3680 items: 1, 3681 dots: true, 3682 mouseDrag: true, 3683 video: true, 3684 autoHeight: true, 3685 stagePadding: 0, 3686 URLhashListener: false, 3687 rtl: rtl_value, 3688 navText: [ 3689 // Swap arrows for RTL 3690 rtl_value ? 3691 '<i class="fas fa-arrow-right"></i>' : 3692 '<i class="fas fa-arrow-left"></i>', 3693 rtl_value ? 3694 '<i class="fas fa-arrow-left"></i>' : 3695 '<i class="fas fa-arrow-right"></i>' 3696 ], 3697 onInitialized: function() { 3698 if (rtl_value) { 3699 const stage = $slider.find('.owl-stage'); 3700 stage.css('transform-origin', 'center center'); 3701 // Force correct direction on first load 3702 setTimeout(() => { 3703 $slider.trigger('refresh.owl.carousel'); 3704 }, 10); 3705 } 3706 } 3707 }); 3708} 3709 3710 3711/** 3712 * Initialize Property Slider V4 with Owl Carousel 3713 * Single-item carousel with stagePadding for partial side-card visibility (~20% peek) 3714 * 3715 * @param {string} slider_id - DOM ID of the slider container 3716 * @param {number} items - Number of items in the slider 3717 * @param {string} arrow_position - 'above' or 'below' 3718 * @param {number} listing_spacing - Space between listings in px (default 20) 3719 */ 3720function wpestate_property_slider_v4(slider_id, items, arrow_position, listing_spacing) { 3721 // Initialize RTL value 3722 let rtl_value = false;
3723 const $slider = jQuery('#' + slider_id); 3724 const spacing = listing_spacing || 20; 3725 3726 // Check RTL from data attribute and control_vars 3727 if ($slider.attr('data-rtl') === 'yes' || control_vars.is_rtl === '1') { 3728 rtl_value = true; 3729 $slider.addClass('owl-rtl'); 3730 } 3731 3732 // External nav container for arrows (left-aligned in controls row) 3733 var navContainer = '#' + slider_id + '_nav'; 3734 3735 // Initialize Owl Carousel with stagePadding for side peek, no dots 3736 $slider.owlCarousel({ 3737 loop: true, 3738 margin: spacing, 3739 nav: true, 3740 items: 1, 3741 dots: false, 3742 mouseDrag: true, 3743 autoHeight: false, 3744 stagePadding: 100, 3745 navContainer: navContainer, 3746 rtl: rtl_value, 3747 navText: [ 3748 rtl_value ? 3749 '<i class="fas fa-arrow-right"></i>' : 3750 '<i class="fas fa-arrow-left"></i>', 3751 rtl_value ? 3752 '<i class="fas fa-arrow-left"></i>' : 3753 '<i class="fas fa-arrow-right"></i>' 3754 ], 3755 responsive: { 3756 0: { stagePadding: 30, margin: Math.min(spacing, 10) }, 3757 768: { stagePadding: 60 }, 3758 1200: { stagePadding: 100 } 3759 }, 3760 onInitialized: function() { 3761 if (rtl_value) { 3762 const stage = $slider.find('.owl-stage'); 3763 stage.css('transform-origin', 'center center'); 3764 setTimeout(() => { 3765 $slider.trigger('refresh.owl.carousel'); 3766 }, 10); 3767 } 3768 } 3769 }); 3770} 3771 3772 3773jQuery(window).on('hashchange', function(event) { 3774 event.preventDefault(); 3775 history.pushState("", document.title, window.location.pathname + window.location.search); // Clear the hash 3776}); 3777 3778 3779 3780/** 3781* Initialize and configure the WpResidence property slider carousel 3782* 3783* This function sets up the Owl Carousel for property images with navigation controls, 3784* RTL support, and indicator synchronization. It handles both horizontal and vertical 3785* carousel layouts, updates active indicators, and manages indicator sliding. 3786* 3787* Dependencies: 3788* - jQuery 3789* - Owl Carousel 2 3790* - control_vars.is_rtl global variable 3791* 3792* @since 4.9.0 3793* @requires jQuery 3794* @requires owl.carousel.js 3795* 3796* Event handlers: 3797* - Click on indicator slides to specific image 3798* - Carousel translation updates active indicators 3799* - Manages indicator positioning for overflow 3800* 3801* Related functions: 3802* - wpestate_show_capture_vertical2() 3803* - wpestate_show_capture2() 3804* 3805* Global variables used: 3806* - control_vars.is_rtl 3807* 3808* @return {void} 3809*/ 3810function wpestate_property_slider() { 3811 let is_rtl = false; 3812 if (control_vars.is_rtl === '1') { 3813 is_rtl = true; 3814 } 3815 3816 var owl_slider_property = jQuery("#property_slider_carousel").owlCarousel({ 3817 loop: true, 3818 margin: 0, 3819 nav: true, 3820 items: 1, 3821 dots: false, 3822 mouseDrag: true, 3823 video: true, 3824 autoHeight: true, 3825 rtl: is_rtl, 3826 navText: [ 3827 '<button class="carousel-control-prev wpresidence-carousel-control " type="button" data-slide="prev"><span class="carousel-control-prev-icon" aria-hidden="true"></span><span class="visually-hidden">Previous</span></button>', 3828 '<button class="carousel-control-next wpresidence-carousel-control " type="button" data-slide="next"><span class="carousel-control-next-icon" aria-hidden="true"></span><span class="visually-hidden">Previous</span></button>' 3829 ], 3830 URLhashListener: false, 3831 }); 3832 3833 var hash; 3834 var number; 3835 3836 jQuery('li[data-slide-to]').on('click', function(event) { 3837 event.preventDefault(); 3838 var slideTo = parseInt(jQuery(this).data('slide-to')); 3839 owl_slider_property.trigger('to.owl.carousel', [slideTo, 300, true]); 3840 }); 3841 3842 owl_slider_property.on('translated.owl.carousel', function(event) { 3843 number = jQuery(".carousel-inner .owl-item.active .item").attr('data-number'); 3844 3845 // Remove active class from all indicators 3846 jQuery('.carousel-round-indicators a').removeClass('active'); 3847 jQuery('.carousel-indicators a').removeClass('active'); 3848 jQuery('.carousel-indicators-classic li').removeClass('active'); 3849 jQuery('.carousel-indicators-vertical li').removeClass('active'); 3850 jQuery('.carousel-indicators li').removeClass('active'); 3851 3852 // Add active class to current indicator 3853 const activeIndex = parseInt(number) - 1; 3854 3855 if (jQuery(this).hasClass('carouselvertical')) { 3856 // Handle vertical indicators 3857 const $activeIndicator = jQuery('.carousel-indicators-vertical li[data-sli
3857de-to="' + activeIndex + '"]').addClass('active'); 3858 const $container = jQuery('.carousel-indicators-vertical'); 3859 3860 if ($activeIndicator.length && $container.length) { 3861 const containerHeight = $container.height(); 3862 const indicatorOffset = $activeIndicator.position()?.top || 0; 3863 const scrollAmount = Math.max(0, indicatorOffset - (containerHeight / 2) + 45); 3864 3865 $container.css('transform', `translateY(-${scrollAmount}px)`); 3866 } 3867 } else { 3868 // Handle horizontal indicators 3869 let $activeIndicator = jQuery('.carousel-indicators li[data-slide-to="' + activeIndex + '"]').addClass('active'); 3870 let $container = jQuery('.wpestate_property_carousel.carouselhorizontal .carousel-indicators'); 3871 3872 if(jQuery('.wpestate_classic_slider_wrapper').length>0){ 3873 $activeIndicator = jQuery('.carousel-indicators li[data-slide-to="' + activeIndex + '"]').addClass('active'); 3874 $container = jQuery('.wpestate_classic_slider_wrapper .carousel-indicators'); 3875 } 3876 3877 3878 if ($activeIndicator.length && $container.length) { 3879 const containerWidth = $container.width(); 3880 const indicatorOffset = $activeIndicator.position()?.left || 0; 3881 const scrollAmount = Math.max(0, indicatorOffset - 100); // 100px buffer from left 3882 $container.css('transform', `translateX(-${scrollAmount}px)`); 3883 } 3884 } 3885 3886 3887 }); 3888} 3889 3890 3891 3892 3893/* 3894* 3895* 3896*/ 3897function wpestate_property_slider_2(){ 3898 var autoplayvalue=false; 3899 var autoplayTimeoutvalue= parseInt( jQuery(".theme_slider_3").attr('data-auto'),10); 3900 3901 if(autoplayTimeoutvalue>0){ 3902 autoplayvalue=true; 3903 } 3904 let is_rtl=false; 3905 if(control_vars.is_rtl==='1'){ 3906 is_rtl=true; 3907 } 3908 3909 var owl = jQuery(".property_slider2_wrapper").owlCarousel({ 3910 loop:true, 3911 margin:0, 3912 nav:true, 3913 items:1, 3914 dots:false, 3915 rtl:is_rtl, 3916 autoplay:autoplayvalue, 3917 autoplayTimeout:autoplayTimeoutvalue, 3918 navText : [ "<div class='nextright'><span class='carousel-control-prev-icon' aria-hidden='true'></div>", 3919 "<div class='nextleft'><span class='carousel-control-next-icon' aria-hidden='true'></div>"], 3920 URLhashListener:true, 3921 3922 }); 3923 3924 var hash; 3925 owl.on('translated.owl.carousel', function(event) { 3926 3927 hash = jQuery(".property_slider2_wrapper .owl-item.active .item").attr('data-hash'); 3928 3929 jQuery('.property_slider2_wrapper-indicators a').removeClass('active'); 3930 jQuery('a[href="#'+hash+'"]').addClass('active'); 3931 }); 3932 3933 3934} 3935 3936/* 3937* 3938* 3939*/ 3940function wpestate_theme_slider_3(){ 3941 var autoplayvalue=false; 3942 var autoplayTimeoutvalue= parseInt( jQuery(".theme_slider_3").attr('data-auto'),10); 3943 3944 if(autoplayTimeoutvalue>0){ 3945 autoplayvalue=true; 3946 } 3947 let is_rtl=false; 3948 if(control_vars.is_rtl==='1'){ 3949 is_rtl=true; 3950 } 3951 3952 var owl = jQuery(".theme_slider_3").owlCarousel({ 3953 loop:true, 3954 margin:0, 3955 nav:true, 3956 items:1, 3957 dots:false, 3958 rtl:is_rtl, 3959 autoplay:autoplayvalue, 3960 autoplayTimeout:autoplayTimeoutvalue, 3961 navText : [ 3962 '<svg xmlns="http://www.w3.org/2000/svg" width="32.414" height="20.828" viewBox="0 0 32.414 20.828"><g id="Group_30" data-name="Group 30" transform="translate(-1845.086 -1586.086)"><line id="Line_2" data-name="Line 2" x1="30" transform="translate(1846.5 1596.5)" fill="none" stroke="#fff" stroke-linecap="round" stroke-width="2"></line><line id="Line_3" data-name="Line 3" x1="9" y2="9" transform="translate(1846.5 1587.5)" fill="none" stroke="#fff" stroke-linecap="round" stroke-width="2"></line><line id="Line_4" data-name="Line 4" x1="9" y1="9" transform="translate(1846.5 1596.5)" fill="none" stroke="#fff" stroke-linecap="round" stroke-width="2"></line></g></svg>', 3963 '<svg xmlns="http://www.w3.org/2000/svg" width="32.414" height="20.828" viewBox="0 0 32.414 20.828"><g id="Symbol_1_1" data-name="Symbol 1 â 1" transform="translate(-1847.5 -1589.086)"><line id="Line_5" data-name="Line 2" x2="30" transform="translate(1848.5 1599.5)" fill="none" stroke="#fff" stroke-linecap="round" stroke-width="2"></line><line id="Line_6" data-name="Line 3" x2="9" y2="9" transform="translate(1869.5 1590.5)" fill="none" stroke="#fff" stroke-linecap="round" stroke-width="2"></line><line id="Line_7" data-name="Line 4" y1="9" x2="9" transform="translate(1869.5 1599.5)" fill="none" stroke="#fff" stroke-linecap="round" stroke-width="2"></line></g></svg>', 3964 ], 3965 URLhashListener:true, 3966 3967 }); 3968 3969 var hash; 3970 owl.on('translated.owl.carousel', function(event) { 3971 3972 hash = jQuery(".theme_slider_3 .owl-item.active .item").attr('data-hash'); 3973 3974 jQuery('.theme_slider_3_carousel-indicators a').removeClass('active'); 3975 jQuery('a[href="#'+hash+'"]').addClass('active'); 3976 }); 3977 3978 3979} 3980 3981 3982/* 3983* 3984* 3985*/ 3986function estate_sidebar_slider_carousel(){ 3987 "use strict"; 3988 let is_rtl=false; 3989 if(control_vars.is_rtl==='1'){ 3990 is_rtl=true; 3991 } 3992 3993 // Check if owlCarousel is available 3994 if (typeof jQuery.fn.owlCarousel === 'function') { 3995 jQuery(".owl-featured-slider").owlCarousel({ 3996 loop:true, 3997 margin:0, 3998 nav:true, 3999 items:1, 4000 dots:false, 4001 rtl:is_rtl, 4002 navText : [ 4003 '<button class="carousel-control-prev wpresidence-carousel-control " type="button" data-sli
4003de="prev"><span class="carousel-control-prev-icon" aria-hidden="true"></span><span class="visually-hidden">Previous</span></button>', 4004 '<button class="carousel-control-next wpresidence-carousel-control " type="button" data-slide="next"><span class="carousel-control-next-icon" aria-hidden="true"></span><span class="visually-hidden">Next</span></button>' 4005 ], 4006 }); 4007 }else { 4008 console.warn("owlCarousel function not found."); 4009 } 4010 4011} 4012 4013 4014 4015/* 4016* 4017* 4018*/ 4019function estate_start_lightbox_modal(){ 4020 "use strict"; 4021 var jump_slide; 4022 4023 var owl = jQuery("#owl-demo-modal"); 4024 owl.trigger("destroy.owl.carousel"); 4025 4026 owl.owlCarousel({ 4027 loop:true, 4028 margin:0, 4029 nav:true, 4030 items:1, 4031 dots:false, 4032 startPosition:1, 4033 navText : [ 4034 '<button class="carousel-control-prev wpresidence-carousel-control " type="button" data-slide="prev"><span class="carousel-control-prev-icon" aria-hidden="true"></span><span class="visually-hidden">Previous</span></button>', 4035 '<button class="carousel-control-next wpresidence-carousel-control " type="button" data-slide="next"><span class="carousel-control-next-icon" aria-hidden="true"></span><span class="visually-hidden">Previous</span></button>' 4036 ], 4037 }); 4038 4039 4040 jQuery('.lightbox_trigger').on( 'click', function(event) { 4041 4042 4043 4044 event.preventDefault(); 4045 jump_slide=parseInt( jQuery(this).attr('data-slider-no') ); 4046 var carousel = jQuery("#owl-demo-modal"); 4047 carousel.owlCarousel(); 4048 carousel.trigger("refresh.owl.carousel"); 4049 4050 carousel.trigger("to.owl.carousel", [jump_slide, 1, true]); 4051 jQuery('.lightbox_property_wrapper').show(); 4052 4053 }); 4054 4055 jQuery('.lighbox-image-close').on( 'click', function(event) { 4056 event.preventDefault(); 4057 jQuery('.lightbox_property_wrapper').hide(); 4058 }); 4059} 4060 4061 4062 4063 4064/** 4065 * WPResidence Blog List Widget AJAX Handler 4066 * 4067 * Handles AJAX loading of additional blog posts for the blog list widget. 4068 * 4069 * @package WPResidence 4070 * @subpackage Widgets 4071 * @since 1.0.0 4072 */ 4073function wpestate_blog_list_widget() { 4074 "use strict"; 4075 4076 var ajaxurl = ajaxcalls_vars.wpestate_ajax; 4077 4078 jQuery('.blog_list_loader').on('click', function (event) { 4079 var $button = jQuery(this); 4080 var $container = $button.parent().parent(); 4081 var $loader = $container.find('.wpestate_listing_sh_loader'); 4082 var $grid = $container.find('.items_shortcode_wrapper_grid'); 4083 4084 var page = parseInt($container.attr('data-page'), 10) + 1; 4085 $container.attr('data-page', page); 4086 4087 4088 4089 //$loader.show(); 4090 if ($container.find('.items_shortcode_wrapper_grid').length>0 ){ 4091 wpestate_createSkeletons($container.find('.items_shortcode_wrapper_grid'),true); 4092 }else{ 4093 wpestate_createSkeletons($container.find('.blog25_shortcode_wrapper'),true); 4094 } 4095 4096 jQuery.ajax({ 4097 type: 'POST', 4098 dataType: 'json', 4099 url: ajaxurl, 4100 data: { 4101 action: 'wpestate_load_blog_list_widget_wrapper', 4102 control_terms_id: $container.attr('data-category_ids'), 4103 number: $container.attr('data-number'), 4104 page: page, 4105 rownumber: $container.attr('data-row-number'), 4106 card_version: $container.attr('data-card-version'), 4107 sort_by: $container.attr('data-sort-by'), 4108 display_grid: $container.attr('data-display-grid') 4109 }, 4110 success: function (data) { 4111 4112 4113 if (data.success) { 4114 if ($grid.length) { 4115 if (data.results === 0) { 4116 // $loader.before(data.html).hide(); 4117 $button.hide(); 4118 } else { 4119 //$grid.append(data.html); 4120 wpestate_replaceSkeletons($container.find('.items_shortcode_wrapper_grid'), data.html,true) 4121 } 4122 } else { 4123 // $loader.before(data.html).hide(); 4124 wpestate_replaceSkeletons($container.find('.blog25_shortcode_wrapper'), data.html,true) 4125 if (data.results === 0) { 4126 $button.hide(); 4127 } 4128 } 4129 } else { 4130 $button.hide(); 4131 } 4132 $loader.hide(); 4133 }, 4134 error: function (xhr, status, error) { 4135 console.error('AJAX request failed:', error); 4136 $loader.hide(); 4137 } 4138 }); 4139 }); 4140} 4141 4142 4143 4144/**
4145 * Load next shortcode listings page via AJAX. 4146 * 4147 * Reads active filter ids from the shortcode container, normalizes taxonomy 4148 * payload values into arrays, requests the next page, and replaces loading 4149 * skeletons with rendered cards from the server response. 4150 * 4151 * @param {string} ajax_loader Selector for the load-more trigger. 4152 * @param {string} ajax_filters Reserved argument kept for compatibility. 4153 * @returns {void} 4154 */ 4155 4156/** 4157 * Normalize comma-separated taxonomy ids into an array. 4158 * 4159 * @param {string|number|null|undefined} rawValue Raw attribute value. 4160 * @returns {Array<string>} Clean taxonomy ids list. 4161 */ 4162function wpestate_normalize_taxonomy_values(rawValue) { 4163 "use strict"; 4164 4165 // Step 1: Return an empty list when the source value is missing. 4166 if (!rawValue || rawValue === '') { 4167 return []; 4168 } 4169 4170 // Step 2: Split by comma, trim values, and remove empty/all placeholders. 4171 return rawValue.toString().split(',').map(function(item){ 4172 return item.trim(); 4173 }).filter(function(item){ 4174 return item !== '' && item !== 'all'; 4175 }); 4176} 4177 4178/** 4179 * Load next shortcode listings page via AJAX. 4180 * 4181 * Reads active filter ids from the shortcode container, normalizes taxonomy 4182 * payload values into arrays, requests the next page, and replaces loading 4183 * skeletons with rendered cards from the server response. 4184 * 4185 * @param {string} ajax_loader Selector for the load-more trigger. 4186 * @param {string} ajax_filters Reserved argument kept for compatibility. 4187 * @returns {void} 4188 */ 4189function wpestate_property_list_sh(ajax_loader,ajax_filters){ 4190 "use strict"; 4191 4192 var ajaxurl = ajaxcalls_vars.wpestate_ajax; 4193 jQuery(ajax_loader).click( function(event) { 4194 // Step 1: Read pagination and filter values from the shortcode wrapper. 4195 4196 var container = jQuery(this).parent().parent(); 4197 var type = container.attr('data-type'); 4198 var category_ids = container.attr('data-category_ids'); 4199 var action_ids = container.attr('data-action_ids'); 4200 var city_ids = container.attr('data-city_ids'); 4201 var area_ids = container.attr('data-area_ids'); 4202 var state_ids = container.attr('data-state_ids'); 4203 var status = container.attr('data-status_ids'); 4204 var features = container.attr('data-features_ids'); 4205 var selected_category_ids = container.attr('data-selected-category_ids'); 4206 var selected_action_ids = container.attr('data-selected-action_ids'); 4207 var selected_city_ids = container.attr('data-selected-city_ids'); 4208 var selected_area_ids = container.attr('data-selected-area_ids'); 4209 var selected_state_ids = container.attr('data-selected-state_ids'); 4210 var selected_status_ids = container.attr('data-selected-status_ids'); 4211 var selected_features_ids = container.attr('data-selected-features_ids'); 4212 var number = container.attr('data-number'); 4213 var align = container.attr('data-align'); 4214 var show_featured_only = container.attr('data-show_featured_only'); 4215 var random_pick = container.attr('data-random_pick'); 4216 var featured_first = container.attr('data-featured_first'); 4217 var page = container.attr('data-page'); 4218 var align = container.attr('data-align'); 4219 var row_number = container.attr('data-row-number'); 4220 var card_version = container.attr('data-card-version'); 4221 var sort_by = container.attr('data-sort-by'); 4222 var display_grid = container.attr('data-display-grid'); 4223 var agentid = container.attr('data-agent-id'); 4224 var property_category = []; 4225 var property_action_category= []; 4226 var property_city = []; 4227 var property_area = []; 4228 var property_county_state = []; 4229 var property_status = []; 4230 var property_features = []; 4231 4232 var topbar_select_model = container.attr('data-topbar_select_model'); 4233 4234 4235 // Step 2: Increment current page for the next AJAX request. 4236 page=parseInt(page); 4237 page=page+1; 4238 container.attr('data-page',page); 4239 //container.find('.wpestate_listing_sh_loader').show(); 4240 4241 4242 4243 // Step 3: Show loading skeletons for the current card layout. 4244 if (container.find('.items_shortcode_wrapper_grid').length>0 ){ 4245 wpestate_createSkeletons(container.find('.items_shortcode_wrapper_grid'),true); 4246 }else{ 4247 wpestate_createSkeletons(container.find('.items_shortcode_wrapper'),true); 4248 } 4249 4250 page=parseInt(page); 4251 4252 // Step 4: Remove stale no-results notice on first page reload. 4253 if(page===1){ 4254 container.find('.no_results').remove(); 4255 } 4256 4257 4258 // Step 5: Normalize comma-separated taxonomy ids to array payload values. 4259 var nonce = jQuery('#wpestate_ajax_filtering').val(); 4260 property_category = wpestate_normalize_taxonomy_values(category_ids); 4261 property_action_category = wpestate_normalize_taxonomy_values(action_ids); 4262 property_city = wpestate_normalize_taxonomy_values(city_ids); 4263 property_area = wpestate_normalize_taxonomy_values(area_ids); 4264 property_county_state = wpestate_normalize_taxonomy_values(state_ids); 4265 property_status = wpestate_normalize_taxonomy_values(status); 4266 property_features = wpestate_normalize_taxonomy_values(features); 4267 4268 // Step 5.1: Merge immutable shortcode filters with the current top-bar selections. 4269 property_category = property_category.concat( 4270 wpestate_normalize_taxonomy_values(selected_category_ids).filter(function(item){ 4271 return property_category.indexOf(item) === -1; 4272 }) 4273 ); 4274 property_action_category = property_action_category.concat( 4275 wpestate_normalize_taxonomy_values(selected_action_ids).filter(function(item){ 4276 return property_action_category.indexOf(item) === -1; 4277 }) 4278 ); 4279 property_city = property_city.concat( 4280 wpestate_normalize_taxonomy_values(selected_city_ids).filter(function(item){ 4281 return property_city.indexOf(item) === -1; 4282 }) 4283 ); 4284 property_area = property_area.concat(
4285 wpestate_normalize_taxonomy_values(selected_area_ids).filter(function(item){ 4286 return property_area.indexOf(item) === -1; 4287 }) 4288 ); 4289 property_county_state = property_county_state.concat( 4290 wpestate_normalize_taxonomy_values(selected_state_ids).filter(function(item){ 4291 return property_county_state.indexOf(item) === -1; 4292 }) 4293 ); 4294 property_status = property_status.concat( 4295 wpestate_normalize_taxonomy_values(selected_status_ids).filter(function(item){ 4296 return property_status.indexOf(item) === -1; 4297 }) 4298 ); 4299 property_features = property_features.concat( 4300 wpestate_normalize_taxonomy_values(selected_features_ids).filter(function(item){ 4301 return property_features.indexOf(item) === -1; 4302 }) 4303 ); 4304 4305 // Step 6: Request next results page and taxonomy filters from backend. 4306 jQuery.ajax({ 4307 type: 'POST', 4308 dataType: 'json', 4309 url: ajaxurl, 4310 data: { 4311 'action' : 'wpestate_load_recent_items_sh', 4312 'type' : type, 4313 'property_category' : property_category, 4314 'property_action_category': property_action_category, 4315 'property_city' : property_city, 4316 'property_area' : property_area, 4317 'property_county_state' : property_county_state, 4318 'property_status' : property_status, 4319 'property_features' : property_features, 4320 'number' : number, 4321 'align' : align, 4322 'show_featured_only' : show_featured_only, 4323 'random_pick' : random_pick, 4324 'featured_first' : featured_first, 4325 'page' : page, 4326 'row_number' : row_number, 4327 'card_version' : card_version, 4328 'sort_by' : sort_by, 4329 'display_grid' : display_grid, 4330 'agentid' : agentid, 4331 'security' : nonce 4332 }, 4333 4334 4335 success: function (data) { 4336 // Step 7: Replace skeletons with cards, or hide controls on empty response. 4337 if (data.success == true && data.html !== '') { 4338 4339 //container.find('.wpestate_listing_sh_loader').hide(); 4340 4341 // Replace skeleton placeholders with real cards sequentially 4342 if (data.no_results === true) { 4343 // Remove skeletons and show no results message 4344 container.find('.skeleton-placeholder').remove(); 4345 container.find('.wpresidence_button').after(data.html).hide(); 4346 } else { 4347 // Replace skeletons one by one with smooth animation 4348 4349 4350 if (container.find('.items_shortcode_wrapper_grid').length>0 ){ 4351 4352 wpestate_replaceSkeletons(container.find('.items_shortcode_wrapper_grid'), data.html,true); 4353 }else{ 4354 wpestate_replaceSkeletons(container.find('.items_shortcode_wrapper'), data.html,true); 4355 } 4356 } 4357 4358 // Restart JavaScript functionality after AJAX load 4359 // wpestate_restart_js_after_ajax(); 4360 4361 // Handle custom image wrapping 4362 jQuery('.col-md-12.listing_wrapper .property_unit_custom_element.image').each(function(){ 4363 jQuery(this).parent().addClass('wrap_custom_image'); 4364 }); 4365 var wrap_image = parseInt( jQuery('.wrap_custom_image').width()); 4366 4367 if(wrap_image!=0){ 4368 jQuery('.col-md-12>.property_listing_custom_design').css('padding-left',wrap_image); 4369 } 4370 4371 } else { 4372 // Remove skeletons and hide load more button on failure 4373 container.find('.skeleton-placeholder').remove(); 4374 jQuery(ajax_loader).hide(); 4375 } 4376 }, 4377 error: function (errorThrown) { 4378 // Remove skeletons on error too 4379 container.find('.skeleton-placeholder').remove(); 4380 } 4381 });//end ajax 4382 4383 4384 }); 4385 4386 4387 jQuery(ajax_filters).on( 'click', function(event) { 4388 4389 var container = jQuery(this).parent().parent(); 4390 var taxid = jQuery(this).attr('data-taxid'); 4391 var taxonomy = jQuery(this).attr('data-taxonomy'); 4392 var topbar_select_model = container.attr('data-topbar_select_model'); 4393 4394 4395 4396 4397 if(topbar_select_model=='single'){ 4398 jQuery(this).parent().find('.control_tax_sh').removeClass('tax_active'); 4399 jQuery(this).addClass('tax_active'); 4400 }else{ 4401 jQuery(this).toggleClass('tax_active'); 4402 } 4403 4404 4405 4406 if(topbar_select_model=='single'){ 4407 // Step 2.1: Clear only the runtime top-bar selection layer. 4408 container.attr('data-selected-category_ids',''); 4409 container.attr('data-selected-action_ids',''); 4410 container.attr('data-selected-city_ids',''); 4411 container.attr('data-selected-area_ids',''); 4412 container.attr('data-selected-state_ids',''); 4413 container.attr('data-selected-status_ids',''); 4414 container.attr('data-selected-features_ids',''); 4415 } 4416 4417 4418 jQuery(this).parent().parent().find('.wpestate_item_list_sh').show(); 4419 4420 switch(taxonomy) { 4421 case 'property_category': 4422 4423 var selected_category_ids = container.attr('data-selected-category_ids'); 4424 selected_category_ids = wpestate_replace_tax_id(jQuery(this),selected_category_ids,taxid); 4425 4426 4427 if(topbar_select_model=='single'){ 4428 container.attr('data-selected-category_ids',taxid); 4429 }else{ 4430 container.attr('data-selected-category_ids',selected_category_ids); 4431 } 4432 4433 4434 4435 break; 4436 case 'property_action_category': 4437 4438 var selected_action_ids = container.attr('data-selected-action_ids'); 4439 selected_action_ids = wpestate_replace_tax_id(jQuery(this),selected_action_ids,taxid); 4440 4441 4442 if(topbar_select_model=='single'){ 4443 container.attr('data-selected-action_ids',taxid); 4444 }else{ 4445 container.attr('data-selected-action_ids',selected_action_ids); 4446 } 4447 4448 4449 4450 break; 4451 case 'property_city': 4452 4453 var selected_city_ids = container.attr('data-selected-city_ids'); 4454 selected_city_ids = wpestate_replace_tax_id(jQuery(this),selected_city_ids,taxid); 4455 4456 if(topbar_select_model=='single'){ 4457 container.attr('data-selected-city_ids',taxid); 4458 }else{ 4459 container.attr('data-selected-city_ids',selected_city_ids); 4460 } 4461 4462 break; 4463 case 'property_area': 4464
4465 var selected_area_ids = container.attr('data-selected-area_ids'); 4466 selected_area_ids = wpestate_replace_tax_id(jQuery(this),selected_area_ids,taxid); 4467 4468 if(topbar_select_model=='single'){ 4469 container.attr('data-selected-area_ids',taxid); 4470 }else{ 4471 container.attr('data-selected-area_ids',selected_area_ids); 4472 } 4473 4474 break; 4475 case 'property_county_state': 4476 4477 4478 var selected_state_ids = container.attr('data-selected-state_ids'); 4479 selected_state_ids = wpestate_replace_tax_id(jQuery(this),selected_state_ids,taxid); 4480 4481 if(topbar_select_model=='single'){ 4482 container.attr('data-selected-state_ids',taxid); 4483 }else{ 4484 container.attr('data-selected-state_ids',selected_state_ids); 4485 } 4486 4487 break; 4488 4489 case 'property_status': 4490 var selected_status_ids = container.attr('data-selected-status_ids'); 4491 selected_status_ids = wpestate_replace_tax_id(jQuery(this),selected_status_ids,taxid); 4492 4493 if(topbar_select_model=='single'){ 4494 container.attr('data-selected-status_ids',taxid); 4495 }else{ 4496 container.attr('data-selected-status_ids',selected_status_ids); 4497 } 4498 4499 break; 4500 case 'property_features': 4501 var selected_features_ids = container.attr('data-selected-features_ids'); 4502 selected_features_ids = wpestate_replace_tax_id(jQuery(this),selected_features_ids,taxid); 4503 4504 if(topbar_select_model=='single'){ 4505 container.attr('data-selected-features_ids',taxid); 4506 }else{ 4507 container.attr('data-selected-features_ids',selected_features_ids); 4508 } 4509 4510 break; 4511 4512 4513 } 4514 container.attr('data-page',0); 4515 4516 4517 4518 //container.find('.items_shortcode_wrapper_grid').empty(); 4519 //container.find('.listing_wrapper').remove(); 4520 4521 // Poll to check if skeletons exist, then remove original cards 4522 var pollCount = 0; 4523 var pollInterval = setInterval(function() { 4524 if (container.find('.skeleton-placeholder').length > 0 || pollCount > 10) { 4525 clearInterval(pollInterval); 4526 // Now safe to remove original cards 4527 // container.find('.items_shortcode_wrapper_grid').empty(); 4528 4529 4530 container.find('.shortcode_wrapper_grid_item').has('.listing_wrapper:not(.skeleton-placeholder)').remove(); 4531 container.find('.listing_wrapper:not(.skeleton-placeholder)').remove(); 4532 4533 4534 4535 container.find('.shortcode_wrapper_grid_item').each(function(){ 4536 var item = jQuery(this); 4537 4538 4539 if(item.children('.listing_wrapper').length > 0){ 4540 // console.log('keep it'); 4541 } else { 4542 //console.log('should not keep'); 4543 } 4544 }); 4545 container.find('.shortcode_wrapper_grid_item:empty').remove(); 4546 container.find('.shortcode_wrapper_grid_item').each(function(){ 4547 if(jQuery(this).is(':empty')){ 4548 jQuery(this).remove(); 4549 } 4550 }); 4551 } 4552 pollCount++; 4553 }, 150); // Check every 50ms 4554 4555 4556 4557 4558 4559 container.find('.wpestate_item_list_sh').trigger('click'); 4560 4561 }); 4562 4563 4564 function wpestate_replace_tax_id(acesta,tax_ids,taxid){ 4565 4566 4567 // Step 1: Add ids for active terms and remove ids for inactive terms. 4568 if(acesta.hasClass('tax_active')){ 4569 if ( tax_ids.indexOf(taxid + ",") === -1){ 4570 tax_ids=tax_ids+taxid+","; 4571 } 4572 }else{ 4573 var to_replace=taxid+","; 4574 tax_ids=tax_ids.replace(to_replace , ""); 4575 } 4576 return tax_ids; 4577 4578 } 4579 4580} 4581 4582 4583 4584/** 4585 * WpEstate Open Menu Function 4586 * 4587 * This function sets up event listeners for the header phone and user menu elements. 4588 * It handles the toggling of the user menu and shopping cart visibility. 4589 * 4590 * @since 1.0.0 4591 * 4592 * @requires jQuery 4593 * 4594 * @return {void} 4595 * 4596 * @example 4597 * // Call this function after the DOM is ready 4598 * jQuery(document).ready(function($) { 4599 * wpestate_open_menu(); 4600 * }); 4601 */ 4602function wpestate_open_menu() { 4603 "use strict"; 4604 4605 // Prevent click event propagation on header phone 4606 jQuery('.header_phone').on('click', function(event) { 4607 event.stopPropagation(); 4608 }); 4609 4610 // Handle click event on logged-in user menu 4611 jQuery('#user_menu_u.user_loged').on('click', function(event) { 4612 // Hide shopping cart 4613 jQuery('#wpestate_header_shoping_cart').fadeOut(400); 4614 4615 // Toggle user menu visibility 4616 if (jQuery('#user_menu_open').is(":visible")) { 4617 // If menu is visible, hide it and remove 'opensvg' class 4618 jQuery('#user_menu_open').removeClass('iosfixed').fadeOut(400); 4619 jQuery('.navicon-button').removeClass('opensvg'); 4620 } else { 4621 // If menu is hidden, show it and add 'opensvg' class 4622 jQuery('#user_menu_open').fadeIn(400); 4623 jQuery('.navicon-button').addClass('opensvg'); 4624 } 4625 4626 // Prevent event from bubbling up to parent elements 4627 event.stopPropagation(); 4628 }); 4629} 4630 4631/** 4632 * Check if the current device is mobile or tablet 4633 * 4634 * This function uses Bootstrap 5.3's breakpoint checking to determine 4635 * if the current device is considered mobile or tablet. 4636 * 4637 * @returns {boolean} True if the device is mobile or tablet, false otherwise 4638 */ 4639function wpestate_isMobileOrTablet() { 4640 // Check if the window width is less than the 'xl' breakpoint 4641 return window.innerWidth < 1200; // Bootstrap's 'xl' breakpoint is 1200px 4642} 4643 4644 4645/* 4646* 4647* 4648*/ 4649function wpestate_contact_us_shortcode(){ 4650 "use strict"; 4651 jQuery('#btn-cont-submit_sh').on( 'click', function(event) {
4652 var parent,contact_name, contact_email, contact_phone, contact_coment, agent_email, property_id, nonce, ajaxurl; 4653 contact_name = jQuery('#foot_contact_name_sh').val(); 4654 contact_email = jQuery('#foot_contact_email_sh').val(); 4655 contact_phone = jQuery('#foot_contact_phone_sh').val(); 4656 contact_coment = jQuery('#foot_contact_content_sh').val(); 4657 nonce = jQuery('#agent_property_ajax_nonce').val(); 4658 ajaxurl = ajaxcalls_vars.admin_url + 'admin-ajax.php'; 4659 parent = jQuery(this).parent().parent(); 4660 4661 if(ajaxcalls_vars.use_gdpr==='yes'){ 4662 if (!parent.find('.wpestate_agree_gdpr').is(':checked')) { 4663 jQuery('#footer_alert-agent-contact_sh').empty().removeClass('wpestate-agent-contact-sent').append(ajaxcalls_vars.gdpr_terms); 4664 return; 4665 } 4666 } 4667 4668 jQuery('#footer_alert-agent-contact_sh').empty().append(ajaxcalls_vars.sending); 4669 4670 jQuery.ajax({ 4671 type: 'POST', 4672 dataType: 'json', 4673 url: ajaxurl, 4674 data: { 4675 'action' : 'wpestate_ajax_agent_contact_form', 4676 'name' : contact_name, 4677 'email' : contact_email, 4678 'phone' : contact_phone, 4679 'comment' : contact_coment, 4680 'nonce' : nonce 4681 }, 4682 success: function (data) { 4683 4684 if (data.sent) { 4685 jQuery('#foot_contact_name_sh').val(''); 4686 jQuery('#foot_contact_email_sh').val(''); 4687 jQuery('#foot_contact_phone_sh').val(''); 4688 jQuery('#foot_contact_content_sh').val(''); 4689 jQuery('#footer_alert-agent-contact_sh').empty().addClass('wpestate-agent-contact-sent').append(data.response); 4690 }else{ 4691 jQuery('#footer_alert-agent-contact_sh').empty().removeClass('wpestate-agent-contact-sent').append(data.response); 4692 } 4693 4694 }, 4695 error: function (errorThrown) { 4696 4697 } 4698 }); 4699 }); 4700 4701} 4702 4703 4704 4705 4706 4707 4708 4709/* 4710* 4711* a 4712*/ 4713function wpestate_enable_property_modal(listing_id,main_img_url,main_title,link){ 4714 "use strict"; 4715 4716 if (Modernizr.mq('only all and (max-width: 1024px)')) { 4717 return; 4718 } 4719 4720 4721 4722 jQuery('.website-wrapper').css('position','fixed'); 4723 jQuery('#property_modal_images').empty(); 4724 var ajaxurl = ajaxcalls_vars.wpestate_ajax; 4725 var window_height =jQuery( window ).height(); 4726 4727 jQuery("#property_modal_images") .css('height', window_height+'px'); 4728 window_height=window_height-183; 4729 jQuery("#property_modal_content").css('height', window_height+'px'); 4730 4731 jQuery('#modal_property_agent').empty(); 4732 jQuery('.modal_content_block').empty(); 4733 jQuery('#property_modal_content .modal_property_description').empty(); 4734 jQuery('#property_modal_content .modal_property_adress').empty(); 4735 jQuery('#property_modal_content .modal_property_details').empty(); 4736 jQuery('#property_modal_content .modal_property_features').empty(); 4737 jQuery('#property_modal_content .modal_property_video').empty(); 4738 jQuery('#property_modal_content .modal_property_video_tour').empty(); 4739 jQuery('#property_modal_content .modal_property_walkscore').empty(); 4740 jQuery('#property_modal_content .modal_property_floor_plans').empty(); 4741 jQuery('#modal_property_mortgage').empty(); 4742 jQuery('#modal_property_maps').empty(); 4743 jQuery('#property_details_modal_wrapper').show(); 4744 4745 //prepopoluate 4746 var to_apped ='<img src="'+main_img_url+'" data-slider-no="1" class="img-responsive lightbox_trigger" alt="image">'; 4747 4748 jQuery('#property_modal_images').append(to_apped); 4749 jQuery('#property_modal_header .modal_property_title').html(main_title); 4750 jQuery('#owl-demo-modal').empty(); 4751 4752 4753 wpestate_propery_preview_prepopulate(); 4754 4755 4756 jQuery.ajax({ 4757 type: 'POST', 4758 url: ajaxurl, 4759 dataType: 'json', 4760 data: { 4761 'action' : 'wpestate_property_modal_listing_details', 4762 'postid' : listing_id, 4763 'security' : control_vars.wpestate_property_modal_nonce, // INPUT-11 4764 }, 4765 success: function (data) { 4766 4767 if(data.response===true){ 4768 4769
4770 data.images.forEach(wpestate_populate_modal_images); 4771 jQuery('.property_placeholder').remove(); 4772 data.full_images.forEach(wpestate_populate_modal_images_full); 4773 wpestate_populate_content(data); 4774 4775 } 4776 }, 4777 error: function (errorThrown) { 4778 4779 } 4780 });//end ajax 4781 4782 /// 4783 /// aysn request no 2 4784 //////////////////////////////////////////////////////////////////////////// 4785 jQuery.ajax({ 4786 type: 'POST', 4787 url: ajaxurl, 4788 dataType: 'json', 4789 data: { 4790 'action' : 'wpestate_property_modal_listing_details_second', 4791 'postid' : listing_id, 4792 'security' : control_vars.wpestate_property_modal_nonce, // INPUT-11 4793 }, 4794 success: function (data) { 4795 4796 if(data.response===true){ 4797 4798 jQuery('#property_modal_content .modal_property_yelp').empty().append(data.yelp); 4799 // jQuery('#property_modal_content .modal_property_walkscore').empty().append(data.walkscore); 4800 jQuery('#property_modal_content .modal_property_floor_plans').empty().append(data.floor_plans); 4801 jQuery('#modal_property_mortgage').empty().append(data.mortgage); 4802 jQuery('#modal_property_maps').empty().append(data.map); 4803 4804 4805 //floor plans 4806 wpestate_enable_floor_plans(); 4807 estate_start_lightbox_floorplans(); 4808 4809 //mortgage 4810 wpestate_show_morg_pie(); 4811 4812 // map 4813 4814 wpestate_map_shortcode_function(); 4815 4816 } 4817 }, 4818 error: function (errorThrown) { 4819 4820 } 4821 });//end ajax 4822} 4823 4824 4825/** 4826 * Populate the property quick-view modal with the AJAX payload. 4827 * 4828 * Called by the property modal AJAX success handler. Expects `data` to be a 4829 * JSON object produced by the server-side property modal endpoint containing: 4830 * - favorite, share â server-rendered HTML fragments (top bar) 4831 * - link â permalink URL (validated here to http/https) 4832 * - title â plain-text property title 4833 * - price, beds_section, 4834 * addr_section â server-rendered HTML spans 4835 * - agent_section, content, 4836 * address, details, features, 4837 * video, video_tour â server-rendered HTML blocks 4838 * 4839 * Security note (XSS-3, 2026-04-13): the title/link pair is built via 4840 * jQuery DOM construction so `data.title` is HTML-escaped via .text() and 4841 * `data.link` is whitelisted to http(s). The remaining `.html(data.*)` calls 4842 * consume server-rendered markup wrappers â server-side escaping of those 4843 * fields is the guarantee that keeps them safe and must be preserved. 4844 * 4845 * @param {Object} data Response payload from the modal AJAX endpoint. 4846 */ 4847function wpestate_populate_content(data){ 4848 // Top bar fragments (favorite button + share widget) are server-rendered 4849 jQuery('#property_modal_top_bar').empty(); 4850 jQuery('#property_modal_top_bar').append(data.favorite); 4851 jQuery('#property_modal_top_bar').append(data.share); 4852 4853 // Title anchor â safe construction. 4854 // 1. Coerce link to string and fall back to '#' unless it starts with 4855 // http:// or https:// (blocks javascript:, data: and other schemes). 4856 // 2. Build the <a> via jQuery({attrs}).text() so the title cannot render 4857 // as HTML even if it contains angle brackets or quotes. 4858 var modalLink = String(data.link || ''); 4859 if (!/^https?:\/\//i.test(modalLink)) { modalLink = '#'; } 4860 var $modalAnchor = jQuery('<a/>', { href: modalLink, target: '_blank' }).text(String(data.title || '')); 4861 jQuery('#property_modal_header .modal_property_title').empty().append($modalAnchor); 4862 jQuery('#property_modal_header .modal_property_price').html(data.price); 4863 jQuery('#property_modal_header .modal_property_bed').html(data.beds_section); 4864 jQuery('#property_modal_header .modal_property_addr').html(data.addr_section); 4865 4866 4867 jQuery('#modal_property_agent').empty().append(data.agent_section); 4868 jQuery('#property_modal_content .modal_property_description').empty().append(data.content); 4869 jQuery('#property_modal_content .modal_property_adress').empty().append(data.address); 4870 jQuery('#property_modal_content .modal_property_details').empty().append(data.details); 4871 jQuery('#property_modal_content .modal_property_features').empty().append(data.features); 4872 jQuery('#property_modal_content .modal_property_video').empty().append(data.video); 4873 jQuery('#property_modal_content .modal_property_video_tour').empty().append(data.video_tour); 4874 4875 //contact
4876 wpestate_agent_contact_modals(); 4877 //img 4878 estate_start_lightbox_modal(); 4879 4880 // video 4881 if (jQuery(".venobox").length > 0){ 4882 jQuery('.venobox').venobox(); 4883 } 4884 4885 //favorite 4886 wpestate_add_to_favorites(); 4887 4888 //print 4889 wpestate_print_property_page(); 4890 4891} 4892 4893/* 4894* 4895* 4896*/ 4897function wpestate_populate_modal_images(value,index){ 4898 4899 if( jQuery('.property_placeholder').length>0 ){ 4900 var placeholder= jQuery('.property_placeholder:first'); 4901 placeholder.attr('src',value).removeClass('property_placeholder'); 4902 }else{ 4903 var to_apped='<img src="'+value+'" data-slider-no="'+index+'" class="img-responsive lightbox_trigger" alt="image">'; 4904 4905 jQuery('#property_modal_images').append(to_apped); 4906 } 4907 4908 4909} 4910 4911/* 4912* 4913* 4914*/ 4915function wpestate_populate_modal_images_full(value,index){ 4916 // var to_append2='<div class="item"><img src="'+value+'"></div>'; 4917 var to_append2='<div class="owl_holder" style="background-image:url('+value+')"></div>'; 4918 jQuery('#owl-demo-modal').append(to_append2); 4919} 4920 4921 4922/* 4923* 4924* 4925*/ 4926function wpestate_propery_preview_prepopulate(){ 4927 4928 path_image=control_vars.path+'/img/placeholder1.png'; 4929 for (i = 0; i <14; i++) { 4930 var to_apped='<img src="'+path_image+'" class="img-responsive lightbox_trigger property_placeholder" data-slider-no="'+(i+1)+'" alt="image">'; 4931 jQuery('#property_modal_images').append(to_apped); 4932 } 4933} 4934 4935/* 4936* 4937* 4938*/ 4939
4940function wpestate_agent_contact_modals(){ 4941 wpestate_agent_submit_email(); 4942 4943 wpestate_enable_schedule_contact(); 4944 4945 jQuery( "#modal_contact_agent").unbind( "click" ); 4946 jQuery('#modal_contact_agent').on('click',function(event){ 4947 jQuery('.schedule_wrapper').hide(); 4948 jQuery('#property_modal_content .agent_contanct_form').slideDown(); 4949 4950 jQuery('#property_modal_content').animate({ 4951 scrollTop: 0 4952 }, 4953 "slow" 4954 ); 4955 }); 4956 4957 4958 4959} 4960 4961/* 4962* 4963* 4964*/ 4965 4966function wpestate_get_location(){ 4967 4968 if(control_vars.location_animation==='no'){ 4969 return; 4970 } 4971 if( jQuery('.heading_over_image').length===0){ 4972 return; 4973 } 4974 4975 jQuery.get("https://ipapi.co/json", function(place) { 4976 var city = place.city; 4977 4978 if(city == null || parseInt( jQuery('.home').length)===0 ){ 4979 //do nothing 4980 }else{ 4981 var heading = control_vars.location_animation_text; 4982 4983 heading = heading.replace("%city%", city); 4984 4985 jQuery('.home .heading_over_image,.home .heading_over_video').slideUp("300",function(){ 4986 jQuery('.home .heading_over_image,.home .heading_over_video').text(heading); 4987 jQuery('.home .heading_over_image,.home .heading_over_video').slideDown(); 4988 }); 4989 4990 } 4991 }, "json"); 4992} 4993 4994/** 4995 * WpEstate Sliding Box Interaction 4996 * 4997 * This function sets up the interactive behavior for the sliding box elements 4998 * in the WpResidence theme. It handles the mouseover event to activate and 4999 * deactivate sliding boxes. 5000 * 5001 * @since 1.0.0 5002 * 5003 * @requires jQuery 5004 */ 5005function wpestate_slider_box() { 5006 5007 // Attach a mouseover event handler to all elements with class 'wpestate_sliding_box' 5008 jQuery(".wpestate_sliding_box").mouseover(function() { 5009 // 'this' refers to the current element being hovered over 5010 var selected_item = jQuery(this); 5011 5012 // Find the parent container of the current sliding box 5013 var item_parent = selected_item.parent(); 5014 5015 // Remove 'active-element' class from all sliding boxes within the same parent 5016 item_parent.find('.wpestate_sliding_box').removeClass('active-element'); 5017 5018 // Add 'active-element' class to the currently hovered sliding box 5019 selected_item.addClass('active-element'); 5020 }); 5021} 5022 5023 5024 5025/* 5026*Mobile Menu Slide out 5027* 5028*/ 5029function wpestate_mobile_menu_slideout(){ 5030 var vc_size; 5031 var var_parents=new Array(); 5032 var var_parents_back=new Array(); 5033 5034 5035 5036 5037 if(jQuery('.mobile-trigger-user').length>0){ 5038 var slideout_user_menu = new Slideout({ 5039 'panel': document.getElementById('all_wrapper'), 5040 'menu': document.getElementById('mobilewrapperuser'), 5041 'padding': -256, 5042 'tolerance': 70 5043 }); 5044 5045 slideout_user_menu.disableTouch(); 5046 5047 // Toggle button 5048 document.querySelector('.mobile-trigger-user').addEventListener('click', function() { 5049 slideout_user_menu.toggle(); 5050 // jQuery('#mobilewrapperuser').show(); 5051 if(jQuery('#mobilewrapperuser').is(':visible') ){ 5052 jQuery('#mobilewrapperuser').hide(); 5053 }else{ 5054 jQuery('#mobilewrapperuser').show(); 5055 } 5056 5057 }); 5058 5059 jQuery('.mobilemenu-close-user').on( 'click', function(event) { 5060 slideout_user_menu.toggle(); 5061 setTimeout(function() { 5062 jQuery('#mobilewrapperuser').hide(); 5063 }, 200); 5064 5065 }); 5066 5067 } 5068 5069 5070 5071 5072 if(jQuery('.mobile-trigger').length>0){ 5073 5074 var slideout_link_menu = new Slideout({ 5075 'panel': document.getElementById('all_wrapper'), 5076 'menu': document.getElementById('mobilewrapper_links'), 5077 'padding': 256, 5078 'tolerance': 70, 5079 'side': 'left', 5080 'easing': 'cubic-bezier(.32,2,.55,.27)' 5081 }); 5082 slideout_link_menu.disableTouch(); 5083 document.querySelector('.mobile-trigger').addEventListener('click', function() {
5084 slideout_link_menu.toggle(); 5085 5086 if(jQuery('#mobilewrapper_links').is(':visible') ){ 5087 jQuery('#mobilewrapper_links').hide(); 5088 }else{ 5089 jQuery('#mobilewrapper_links').show(); 5090 } 5091 }); 5092 5093 jQuery('.mobilemenu-close').on( 'click', function(event) { 5094 slideout_link_menu.toggle(); 5095 setTimeout(function() { 5096 jQuery('#mobilewrapper_links').hide(); 5097 }, 200); 5098 }); 5099 } 5100 5101} 5102 5103/* 5104* Mobile Menu open submenu 5105*/ 5106 5107function wpestate_mobile_menu_open_submenu(){ 5108 jQuery('.mobilex-menu li').on( 'click', function(event) { 5109 event.stopPropagation(); 5110 5111 // Prevent navigation for items with a Studio mega menu panel 5112 if ( jQuery(this).children('.megamenu-studio-mobile').length > 0 ) { 5113 event.preventDefault(); 5114 } 5115 5116 var selected; 5117 selected = jQuery(this).find('.sub-menu:first'); 5118 selected.slideToggle(); 5119 }); 5120 5121} 5122 5123 5124 5125/* 5126* Mobile Menu Elementor open/close 5127*/ 5128 5129function wpestate_elementor_mobile_menu_trigger_open(){ 5130 jQuery('.wpestate_mobile_menu_trigger').on('click', function(event) { 5131 jQuery(this).hide(); 5132 const parent = jQuery(this).parent(); 5133 const openButton=parent.find('.wpestate_mobile_menu_trigger_close'); 5134 var menu = parent.find('.mobilex-menu'); 5135 5136 5137 jQuery('.wpestate_mobile_menu_trigger_close').show(); 5138 // Show the menu first to measure it correctly 5139 menu.css('display', 'block'); 5140 5141 var containerRect = openButton[0].getBoundingClientRect(); 5142 5143 var margin = 0; // Margin from the viewport edges 5144 5145 // Calculate the left position of the child 5146 var childLeft = -containerRect.left +margin; 5147 5148 // Apply the calculated positions 5149 // menu.css('left', childLeft + 'px'); 5150 menu.css('width', 'calc(100vw - ' + (margin * 2) + 'px)'); 5151 5152 5153 }); 5154 5155 jQuery('.wpestate_mobile_menu_trigger_close').on('click',function(event){ 5156 jQuery(this).hide(); 5157 const parent=jQuery(this).parent(); 5158 var menu = parent.find('.mobilex-menu'); 5159 menu.css('transform', ''); 5160 jQuery('.wpestate_mobile_menu_trigger').show(); 5161 parent.find('.mobilex-menu').hide(); 5162 }); 5163 5164} 5165 5166 5167/* 5168* Control media buttons 5169*/ 5170 5171function wpestate_control_media_buttons(){ 5172 var curentID; 5173 5174 jQuery('.wpestate_control_media_button').on('click',function(){ 5175 jQuery('.wpestate_control_media_button').removeClass('slideron'); 5176 jQuery(this).addClass('slideron'); 5177 jQuery('.wpestate_property_media_section_wrapper .status-wrapper').hide(); 5178 5179 jQuery('.wpestate_property_slider_thing').hide(); 5180 var div_to_show=jQuery(this).attr('data-show'); 5181 5182 jQuery('.'+div_to_show).show(); 5183 if(div_to_show=='wpestate_property_carousel'){ 5184 jQuery('.wpestate_property_media_section_wrapper .status-wrapper').show(); 5185 } 5186 5187 if(div_to_show=='google_map_slider_wrapper'){ 5188 wpestate_control_media_emable_map(); 5189 } 5190 5191 if(jQuery(this).attr('id')=='slider_enable_street'){ 5192 wpestate_control_media_emable_street_view(); 5193 } 5194 5195 5196 }); 5197} 5198 5199 5200 5201/* 5202* 5203* Enable Street Map 5204* 5205*/ 5206 5207 5208function wpestate_control_media_emable_street_view(){ 5209 var cur_lat, cur_long, myLatLng; 5210 5211 cur_lat = jQuery('#googleMapSlider').attr('data-cur_lat'); 5212 cur_long = jQuery('#googleMapSlider').attr('data-cur_long'); 5213 myLatLng = new google.maps.LatLng(cur_lat,cur_long); 5214 5215 jQuery('#gmapzoomplus.smallslidecontrol,#gmapzoomminus.smallslidecontrol,.google_map_poi_marker ').hide(); 5216 5217 panorama.setPosition(myLatLng); 5218 panorama.setVisible(true); 5219} 5220 5221/* 5222* 5223* Enable Map for Slider 5224* 5225*/ 5226 5227function wpestate_control_media_emable_map(){ 5228 jQuery('#googleMapSlider').show(); 5229 jQuery('#gmapzoomplus.smallslidecontrol,#gmapzoomminus.smallslidecontrol,.google_map_poi_marker ').show(); 5230 5231 if(wp_estate_kind_of_map===1){ 5232 google.maps.event.trigger(map, "resize"); 5233 }else{ 5234 setTimeout(function(){ map.invalidateSize(); }, 600); 5235 } 5236 5237 cur_lat = jQuery('#googleMapSlider').attr('data-cur_lat'); 5238 cur_long = jQuery('#googleMapSlider').attr('data-cur_long'); 5239 5240 if(wp_estate_kind_of_map===1){ 5241 map.setOptions({draggable: true}); 5242 myLatLng = new google.maps.LatLng(cur_lat,cur_long); 5243 map.setCenter(myLatLng); 5244 map.panBy(10,-100); 5245 panorama.setVisible(false); 5246 } 5247 5248} 5249/* 5250* 5251* Get Cookie 5252* 5253*/ 5254function wpestate_getCookie(cname) { 5255 var name = cname + "="; 5256 var ca = document.cookie.split(';'); 5257 for(var i=0; i<ca.length; i++) { 5258 var c = ca[i]; 5259 while (c.charAt(0)==' ') c = c.substring(1); 5260 if (c.indexOf(name) == 0) return c.substring(name.length,c.length); 5261 } 5262 return ""; 5263 } 5264 5265 5266 /* 5267* 5268* eanble advanced tab functions 5269* 5270*/ 5271 5272function wpestate_advtabs_function(item){ 5273 5274 var all_sliders = ['mainform','sidebar','shortcode','mobile','half']; 5275 var min_tab_slider= control_vars.adv6_min_price[slider_counter]; 5276 var max_tab_slider= control_vars.adv6_max_price[slider_counter]; 5277 5278 slider_counter++; 5279 for (var i = 0, length = all_sliders.length; i < length; i++) { 5280 wpestate_enable_slider_tab_for_all(all_sliders[i],item,min_tab_slider,max_tab_slider); 5281 } 5282} 5283 5284 5285/* 5286* 5287* eanble advanced tab functions 5288* 5289*/ 5290 5291 5292function wpestate_enable_slider_tab_for_all(position,item,min_tab_slider,max_tab_slider){ 5293 5294 var slider_id = 'slider_price_'+item+'_'+position ; 5295 var price_min = 'price_low_'+item; 5296 var price_max = 'price_max_'+item; 5297 var ammount = 'amount_'+item+'_'+position; 5298 5299 5300 var my_custom_curr_symbol = decodeURI ( wpestate_getCookie('my_custom_curr_symbol') ); 5301 var my_custom_curr_coef = parseFloat( wpestate_getCookie('my_custom_curr_coef')); 5302 var my_custom_curr_pos = parseFloat( wpestate_getCookie('my_custom_curr_pos')); 5303 var my_custom_curr_cur_post= wpestate_getCookie('my_custom_curr_cur_post'); 5304 5305// wpestate_enable_slider(slider_id, price_min, price_max, ammount, my_custom_curr_pos, my_custom_curr_symbol, my_custom_curr_cur_post, my_custom_curr_coef) ; 5306 wpestate_enable_slider_tab(min_tab_slider,max_tab_slider,'slider_price_'+item+'_'+position, 'price_low_'+item, 'price_max_'+item, 'amount_'+item+'_'+position, my_custom_curr_pos, my_custom_curr_symbol, my_custom_curr_cur_post,my_custom_curr_coef,control_vars.adv6_min_price[slider_counter],control_vars.adv6_max_price[slider_counter]); 5307 5308 jQuery( '#slider_price_'+item +'_'+position).slider({ 5309 stop: function( event, ui ) { 5310 if (typeof (wpestate_show_pins) !== "undefined") { 5311 first_time_wpestate_show_inpage_ajax_half=1; 5312 5313 wpestate_show_pins(); 5314 } 5315 } 5316 }); 5317} 5318 5319 5320/* 5321* 5322* eanble slider tab 5323*/ 5324function wpestate_enable_slider_tab(slider_min,slider_max,slider_name, price_low, price_max, amount, my_custom_curr_pos, my_custom_curr_symbol, my_custom_curr_cur_post, my_custom_curr_coef) { 5325 5326 "use strict"; 5327 var price_low_val, price_max_val, temp_min, temp_max;
5328 price_low_val = parseInt(jQuery('#'+price_low).val(), 10); 5329 price_max_val = parseInt(jQuery('#'+price_max).val(), 10); 5330 5331 5332 slider_min = parseInt(slider_min,10); 5333 slider_max = parseInt(slider_max,10); 5334 5335 if (!isNaN(my_custom_curr_pos) && my_custom_curr_pos !== -1) { 5336 slider_min =slider_min *my_custom_curr_coef; 5337 slider_max =slider_max *my_custom_curr_coef; 5338 } 5339 5340 var slider_parent = jQuery("#" + slider_name).parent(); 5341 5342 var parent = jQuery("#" + slider_name).parent().parent(); 5343 var component_price_min; 5344 var component_price_max; 5345 var dropdown_parent; 5346 var dropdown_label; 5347 var component_label_value; 5348 5349 if(parent.hasClass('wpestate-price-popoup-wrapper')){ 5350 component_price_min=parent.find('#component_'+price_low); 5351 component_price_max=parent.find('#component_'+price_max); 5352 var dropdown_parent=parent.parent().find('.dropdown-toggle'); 5353 dropdown_label = parent.find('.price_label_component'); 5354 5355 } 5356 5357 5358 5359 jQuery("#" + slider_name).slider({ 5360 range: true, 5361 min: parseFloat(slider_min), 5362 max: parseFloat(slider_max), 5363 values: [price_low_val, price_max_val ], 5364 slide: function (event, ui) { 5365 temp_min= ui.values[0].format() ; 5366 temp_max= ui.values[1].format(); 5367 if(control_vars.indian_format==="yes"){ 5368 temp_min=wpstrea_js_indian_format(ui.values[0]); 5369 temp_max=wpstrea_js_indian_format(ui.values[1]); 5370 } 5371 5372 5373 5374 if (!isNaN(my_custom_curr_pos) && my_custom_curr_pos !== -1) { 5375 slider_parent.find("#" + price_low).val(ui.values[0]); 5376 slider_parent.find("#" + price_max).val(ui.values[1]); 5377 5378 jQuery("#price_low").val(ui.values[0]); 5379 jQuery("#price_max").val(ui.values[1]); 5380 5381 5382 5383 5384 if (my_custom_curr_cur_post === 'before') { 5385 jQuery("#" + amount).text( wpestate_replace_plus( decodeURIComponent ( my_custom_curr_symbol ) ) + " " + temp_min + " " + control_vars.to + " " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) )+ " " + temp_max); 5386 if(parent.hasClass('wpestate-price-popoup-wrapper')){ 5387 component_price_min.val( wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) ) + " " + temp_min ); 5388 component_price_max.val( wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol) ) + " " + temp_max ); 5389 component_label_value = ""+ wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) ) + " " + wpestate_formatNumber_short(ui.values[0])+ " - " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) ) + " " + wpestate_formatNumber_short(ui.values[1]) ; 5390 5391 dropdown_parent.text(component_label_value); 5392 dropdown_label.val(component_label_value); 5393 } 5394 5395 } else { 5396 jQuery("#" + amount).text(temp_min + " " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) )+ " " + control_vars.to + " " + temp_max+ " " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) ) ); 5397 if(parent.hasClass('wpestate-price-popoup-wrapper')){ 5398 component_price_min.val( temp_min + " " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) ) ); 5399 component_price_max.val( temp_max + " " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol) ) ); 5400 component_label_value= wpestate_formatNumber_short(ui.values[0]) + " " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) ) + " - " + wpestate_formatNumber_short(ui.values[1]) + " " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) ) ; 5401 5402 dropdown_parent.text(component_label_value); 5403 dropdown_label.val(component_label_value); 5404 } 5405 } 5406 } else { 5407 slider_parent.find("#" + price_low).val(ui.values[0]); 5408 slider_parent.find("#" + price_max).val(ui.values[1]); 5409 5410 5411 jQuery("#price_low").val(ui.values[0]); 5412 jQuery("#price_max").val(ui.values[1]); 5413 5414 if (control_vars.where_curency === 'before') { 5415 jQuery("#" + amount).text( wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " " + temp_min + " " + control_vars.to + " " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " " + temp_max ); 5416 if(parent.hasClass('wpestate-price-popoup-wrapper')){ 5417 component_price_min.val( wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " " + temp_min ); 5418 component_price_max.val( wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " " + temp_max ); 5419 component_label_value = ""+ wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " " + wpestate_formatNumber_short(ui.values[0])+ " - " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " " + wpestate_formatNumber_short(ui.values[1]) ; 5420 5421 dropdown_parent.text(component_label_value); 5422 dropdown_label.val(component_label_value); 5423 5424 } 5425 } else { 5426 jQuery("#" + amount).text(temp_min + " " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " " + control_vars.to + " " + temp_max + " " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) ); 5427 if(parent.hasClass('wpestate-price-popoup-wrapper')){ 5428 component_price_min.val( temp_min + " " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) ); 5429 component_price_max.val( temp_max + " " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) ); 5430 component_label_value = wpestate_formatNumber_short(ui.values[0]) + " " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " - " + wpestate_formatNumber_short(ui.values[1]) + " " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) ; 5431 5432 dropdown_parent.text(component_label_value); 5433 dropdown_label.val(component_label_value); 5434 } 5435 } 5436 } 5437 } 5438 }); 5439} 5440 5441 5442 5443 5444 5445/* 5446* 5447* replace string 5448* 5449*/ 5450function wpestate_replace_plus(string){ 5451 return string.replace("+"," "); 5452} 5453 5454/* 5455* 5456* js indiam format 5457* 5458*/ 5459 5460function wpstrea_js_indian_format(value){ 5461 value=value.toString(); 5462 var afterPoint = ''; 5463 if(value.indexOf('.') > 0) 5464 afterPoint = value.substring(value.indexOf('.'),value.length); 5465 value = Math.floor(value); 5466 value=value.toString(); 5467 var lastThree = value.substring(value.length-3); 5468 var otherNumbers = value.substring(0,value.length-3); 5469 if(otherNumbers != '') 5470 lastThree = ',' + lastThree; 5471 var res = otherNumbers.replace(/\B(?=(\d{2})+(?!\d))/g, ",") + lastThree + afterPoint; 5472 return res; 5473} 5474 5475 5476/* 5477* 5478* Eanble Slider 5479* 5480*/ 5481function wpestate_enable_slider(slider_name, price_low, price_max, amount, my_custom_curr_pos, my_custom_curr_symbol, my_custom_curr_cur_post, my_custom_curr_coef) { 5482 5483 var price_low_val, price_max_val, temp_min, temp_max, slider_min, slider_max;
5484 price_low_val = parseInt(jQuery('#'+price_low).val(), 10); 5485 price_max_val = parseInt(jQuery('#'+price_max).val(), 10); 5486 5487 5488 slider_min = control_vars.slider_min; 5489 slider_max = control_vars.slider_max; 5490 5491 5492 if( jQuery('#'+price_max).hasClass('adv_search_elementor_price_max') ){ 5493 slider_max = jQuery('#'+price_max).attr('data-value'); 5494 slider_min = jQuery('#'+price_low).attr('data-value'); 5495 } 5496 5497 if( jQuery('#'+price_max).hasClass('wpestate_slider_in_tab') ){ 5498 slider_max = jQuery('#'+price_max).attr('data-value'); 5499 slider_min = jQuery('#'+price_low).attr('data-value'); 5500 5501 } 5502 5503 5504 5505 if (!isNaN(my_custom_curr_pos) && my_custom_curr_pos !== -1) { 5506 slider_min =slider_min *my_custom_curr_coef; 5507 slider_max =slider_max *my_custom_curr_coef; 5508 } 5509 5510 var parent = jQuery("#" + slider_name).parent().parent(); 5511 var component_price_min; 5512 var component_price_max; 5513 var dropdown_parent; 5514 var dropdown_label; 5515 var component_label_value; 5516 if(parent.hasClass('wpestate-price-popoup-wrapper')){ 5517 component_price_min=parent.find('#component_'+price_low); 5518 component_price_max=parent.find('#component_'+price_max); 5519 var dropdown_parent=parent.parent().find('.dropdown-toggle'); 5520 dropdown_label = parent.find('.price_label_component'); 5521 5522 } 5523 5524 5525 jQuery("#" + slider_name).slider({ 5526 range: true, 5527 min: parseFloat(slider_min), 5528 max: parseFloat(slider_max), 5529 values: [price_low_val, price_max_val ], 5530 slide: function (event, ui) { 5531 5532 jQuery("#" + price_low).val(ui.values[0]); 5533 jQuery("#" + price_max).val(ui.values[1]); 5534 temp_min= ui.values[0].format() ; 5535 temp_max= ui.values[1].format(); 5536 if(control_vars.indian_format==="yes"){ 5537 temp_min=wpstrea_js_indian_format(ui.values[0]); 5538 temp_max=wpstrea_js_indian_format(ui.values[1]); 5539 } 5540 5541 if (!isNaN(my_custom_curr_pos) && my_custom_curr_pos !== -1) { 5542 if (my_custom_curr_cur_post === 'before') { 5543 jQuery("#" + amount).text( wpestate_replace_plus( decodeURIComponent ( my_custom_curr_symbol ) ) + " " + temp_min + " " + control_vars.to + " " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) )+ " " + temp_max); 5544 if(parent.hasClass('wpestate-price-popoup-wrapper')){ 5545 component_price_min.val( wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) ) + " " + temp_min ); 5546 component_price_max.val( wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol) ) + " " + temp_max ); 5547 component_label_value = ""+ wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) ) + " " + wpestate_formatNumber_short(ui.values[0])+ " - " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) ) + " " + wpestate_formatNumber_short(ui.values[1]) ; 5548 5549 dropdown_parent.text(component_label_value); 5550 dropdown_label.val(component_label_value); 5551 } 5552 } else { 5553 jQuery("#" + amount).text(temp_min + " " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) )+ " " + control_vars.to + " " + temp_max + " " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) ) ); 5554 if(parent.hasClass('wpestate-price-popoup-wrapper')){ 5555 component_price_min.val( temp_min + " " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) ) ); 5556 component_price_max.val( temp_max + " " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol) ) ); 5557 component_label_value= wpestate_formatNumber_short(ui.values[0]) + " " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) ) + " - " + wpestate_formatNumber_short(ui.values[1]) + " " + wpestate_replace_plus ( decodeURIComponent ( my_custom_curr_symbol ) ) ; 5558 5559 dropdown_parent.text(component_label_value); 5560 dropdown_label.val(component_label_value); 5561 } 5562 } 5563 } else { 5564 5565 if (control_vars.where_curency === 'before') { 5566 jQuery("#" + amount).text(""+ wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " " + temp_min+ " " + control_vars.to + " " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " " + temp_max); 5567 if(parent.hasClass('wpestate-price-popoup-wrapper')){ 5568 component_price_min.val( wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " " + temp_min ); 5569 component_price_max.val( wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " " + temp_max ); 5570 component_label_value = ""+ wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " " + wpestate_formatNumber_short(ui.values[0])+ " - " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " " + wpestate_formatNumber_short(ui.values[1]) ; 5571 5572 dropdown_parent.text(component_label_value); 5573 dropdown_label.val(component_label_value); 5574 5575 } 5576 } else { 5577 jQuery("#" + amount).text(temp_min + " " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " " + control_vars.to + " " + temp_max + " " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) ); 5578 if(parent.hasClass('wpestate-price-popoup-wrapper')){ 5579 component_price_min.val( temp_min + " " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) ); 5580 component_price_max.val( temp_max + " " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) ); 5581 component_label_value = wpestate_formatNumber_short(ui.values[0]) + " " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) + " - " + wpestate_formatNumber_short(ui.values[1]) + " " + wpestate_replace_plus ( decodeURIComponent ( control_vars.curency ) ) ; 5582 5583 dropdown_parent.text(component_label_value); 5584 dropdown_label.val(component_label_value); 5585 } 5586 } 5587 } 5588 } 5589 }); 5590} 5591 5592/* 5593* 5594* enable slider for elementor 5595* 5596*/ 5597 5598function wpestate_enable_slider_elementor(){ 5599 5600 jQuery('.wpestate_elementor_search_tab_slider_wrapper').each(function(){ 5601 var slider_id = jQuery(this).find('.wpestate_elementor_search_tab_slider').attr('id'); 5602 var price_min = jQuery(this).find('.adv_search_elementor_price_low').attr('id'); 5603 var price_max = jQuery(this).find('.adv_search_elementor_price_max').attr('id'); 5604 var ammount = jQuery(this).find('.wpresidence_slider_price').attr('id'); 5605 var my_custom_curr_symbol = decodeURI ( wpestate_getCookie('my_custom_curr_symbol') ); 5606 var my_custom_curr_coef = parseFloat( wpestate_getCookie('my_custom_curr_coef')); 5607 var my_custom_curr_pos = parseFloat( wpestate_getCookie('my_custom_curr_pos')); 5608 var my_custom_curr_cur_post= wpestate_getCookie('my_custom_curr_cur_post'); 5609 wpestate_enable_slider(slider_id, price_min, price_max, ammount, my_custom_curr_pos, my_custom_curr_symbol, my_custom_curr_cur_post,my_custom_curr_coef); 5610 5611 }); 5612 5613} 5614 5615/* 5616* 5617* 5618* 5619*/ 5620function wpestate_formatNumber_short(num) { 5621 num=parseFloat(num); 5622 5623 if (num >= 1000000000) { 5624 return (num / 1000000000).toFixed(1).replace(/\.0$/, '') + 'B'; 5625 } 5626 if (num >= 1000000) { 5627 return (num / 1000000).toFixed(1).replace(/\.0$/, '') + 'M'; 5628 } 5629 if (num >= 1000) { 5630 return (num / 1000).toFixed(1).replace(/\.0$/, '') + 'K'; 5631 } 5632 return num.toString(); 5633} 5634 5635/* 5636* 5637* 5638* 5639*/ 5640 5641 5642function wpestate_done_typing(){ 5643 if (typeof (wpestate_show_pins) !== "undefined") { 5644 first_time_wpestate_show_inpage_ajax_half=1; 5645 5646 wpestate_show_pins(); 5647 } 5648} 5649 5650 5651/* 5652* 5653* 5654* 5655*/ 5656function isFunction(possibleFunction) { 5657 return typeof(possibleFunction) === typeof(Function); 5658} 5659 5660 5661 5662/* 5663* 5664* calculate morgage widget action 5665*/ 5666 5667function wpestate_zillow_widget_action(){ 5668 5669 jQuery('#zill_submit_estimate').on( 'click', function(event) { 5670 var button = jQuery(this); 5671 var container = button.parent(); 5672 var zillow_adress = jQuery('#zill_estimate_adr1').val(); 5673 var zillow_city = jQuery('#zill_estimate_city1').val(); 5674 var zillow_state = jQuery('#zill_estimate_state1').val(); 5675 5676 var full_address = zillow_adress+', '+zillow_city+', '+zillow_state; 5677 5678 if(zillow_adress==''|| zillow_city=='' || zillow_state==''){ 5679 var answer=control_vars.zillow_fields; 5680 container.find('.wpestate_zillow_answer').empty().append(answer); 5681 return; 5682 } 5683 5684 5685 5686 container.find('.wpestate_zillow_answer').empty().append(control_vars.zillow_wait); 5687 5688 ajaxurl = ajaxcalls_vars.admin_url + 'admin-ajax.php'; 5689 var nonce = jQuery('#wpestate_zillow_nonce').val(); 5690 jQuery.ajax({ 5691 type: 'POST', 5692 dataType: 'json', 5693 url: ajaxurl, 5694 data: { 5695 'action' : 'wpestate_zillow_estimation', 5696 'zillow_adress' : zillow_adress, 5697 'zillow_city' : zillow_city, 5698 'zillow_state' : zillow_state, 5699 'full_address' : full_address, 5700 'security' : nonce 5701 }, 5702 success: function (data) { 5703 5704 5705 5706 5707 if(data.total===0){ 5708 var answer=control_vars.zillow_none+" "+full_address; 5709 }else{ 5710 5711 var zillow_price = data.bundle[0].zestimate; 5712 5713 const formattedPrice = new Intl.NumberFormat('en-US', { 5714 style: 'currency', 5715 currency: 'USD', 5716 useGrouping: true 5717 }).format(zillow_price); 5718 5719 5720 var answer =control_vars.wpestate_zillow_answer+" <span class='wpestate_zillow_address'>"+full_address+"</span> "+control_vars.zillow_is+" <span class='wpestate_zillow_price'>"+formattedPrice+"</span>"; 5721 5722 } 5723 5724 5725 container.find('.wpestate_zillow_answer').empty().append(answer); 5726 5727 }, 5728 error: function (errorThrown) {} 5729 });//end ajax 5730 5731 5732 5733 5734 5735 5736 }); 5737} 5738 5739/* 5740* 5741* calculate morgage widget action 5742*/ 5743 5744function wpestate_morgate_widget_action(){ 5745 jQuery('#morg_compute').on( 'click', function(event) { 5746 5747 var intPayPer = 0; 5748 var intMthPay = 0; 5749 var intMthInt = 0; 5750 var intPerFin = 0; 5751 var intAmtFin = 0; 5752 var intIntRate = 0; 5753 var intAnnCost = 0; 5754 var intVal = 0; 5755 var salePrice = 0; 5756 5757 salePrice = jQuery('#sale_price').val(); 5758 intPerFin = jQuery('#percent_down').val() / 100; 5759 5760 intAmtFin = salePrice - salePrice * intPerFin; 5761 intPayPer = parseInt (jQuery('#term_years').val(),10) * 12; 5762 intIntRate = parseFloat (jQuery('#interest_rate').val(),10); 5763 intMthInt = intIntRate / (12 * 100); 5764 intVal = wpestate_raisePower(1 + intMthInt, -intPayPer); 5765 intMthPay = intAmtFin * (intMthInt / (1 - intVal)); 5766 intAnnCost = intMthPay * 12; 5767 5768 jQuery('#am_fin').html("<strong>"+control_vars.morg1+"</strong> " + (Math.round(intAmtFin * 100)) / 100 + " "); 5769 jQuery('#morgage_pay').html("<strong>"+control_vars.morg2+"</strong>" + (Math.round(intMthPay * 100)) / 100 + " "); 5770 jQuery('#anual_pay').html("<strong>"+control_vars.morg3+"</strong>" + (Math.round(intAnnCost * 100)) / 100 + " "); 5771 jQuery('#morg_results').show();
5772 jQuery('.mortgage_calculator_div').css('height',532+'px'); 5773 }); 5774 5775} 5776 5777/* 5778* 5779* sanitzie string to be used as classname 5780* 5781*/ 5782function wpestateSanitizeClassName(str) { 5783 // Remove leading numbers by replacing them with a prefix (e.g., 'class-') 5784 str = str.replace(/^\d+/, 'class-'); 5785 5786 // Replace invalid characters with a hyphen 5787 str = str.replace(/[^a-zA-Z0-9-_]/g, '-'); 5788 5789 // Remove multiple hyphens 5790 str = str.replace(/-+/g, '-'); 5791 5792 // Remove leading and trailing hyphens 5793 str = str.trim().replace(/(^-|-$)/g, ''); 5794 5795 return str; 5796} 5797 5798 5799/** 5800* Initialize autocomplete functionality for location search fields. 5801* 5802* This function sets up jQuery UI autocomplete on location input fields with the following features: 5803* - Filters and displays location suggestions as user types 5804* - Limits results to 12 items 5805* - Adds a reset button after selected text 5806* - Groups results by location category (City, Area, County/State) 5807* - Updates map pins on selection 5808* 5809* @since 4.9.0 5810* @param {Array} availableTags - Array of location objects with properties: 5811* @param {string} category - Location category ("City", "Area", "County or State") 5812* @param {string} labelcategory - Category identifier for CSS ("city", "area", "countystate") 5813* @param {string} label - Display name of the location 5814* @param {string} value - Location value to be used 5815* @param {string} inputID - ID of the input field to initialize autocomplete on 5816* 5817* @requires jQuery 5818* @requires jQuery UI Autocomplete 5819* 5820* DOM Requirements: 5821* - Input field must be wrapped in .adv_locations_search_component_wrapper 5822* - Input field must have class .adv_locations_search 5823* 5824* Global variables used: 5825* - first_time_wpestate_show_inpage_ajax_half 5826* 5827* Related functions: 5828* - wpestate_show_pins() - Updates map pins after selection 5829*/ 5830function wpresidenceInitializeAutocomplete(availableTags, inputID) { 5831 jQuery("#" + inputID).autocomplete({ 5832 source: function(request, response) { 5833 var results = jQuery.ui.autocomplete.filter(availableTags, request.term); 5834 response(results.slice(0, 12)); 5835 }, 5836 select: function(event, ui) { 5837 var $input = jQuery(this); 5838 var $wrapper = $input.parent(); 5839 var selectedText = ui.item.label; // Get the selected text 5840 5841 // Step 1: Keep the visible label inside the input field. 5842 // jQuery UI may otherwise insert ui.item.value, which can be a term id. 5843 $input.val(selectedText); 5844 5845 // Create reset button 5846 var $resetBtn = jQuery(` 5847 <button type="button" class="wpresidece-reset-btn"> 5848 <svg width="14px" height="14px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> 5849 <g id="SVGRepo_bgCarrier" stroke-width="0"></g> 5850 <g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g> 5851 <g id="SVGRepo_iconCarrier"> 5852 <rect width="24" height="24"></rect> 5853 <path d="M7 17L16.8995 7.10051" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path> 5854 <path d="M7 7.00001L16.8995 16.8995" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path> 5855 </g> 5856 </svg> 5857 </button>`); 5858 5859 // Remove any existing reset button first 5860 $wrapper.find('.wpresidece-reset-btn').remove(); 5861 5862 // Add the reset button after input 5863 $input.after($resetBtn); 5864 5865 // Calculate position based on selected text 5866 var $measure = jQuery('<span>').css({ 5867 'font-family': $input.css('font-family'), 5868 'font-size': $input.css('font-size'), 5869 'font-weight': $input.css('font-weight'), 5870 'position': 'absolute', 5871 'visibility': 'hidden', 5872 'white-space': 'pre' 5873 }).text(selectedText); 5874 5875 $wrapper.append($measure); 5876 5877 var inputPadding = parseInt($input.css('padding-left')); 5878 var textWidth = $measure.width(); 5879 5880 $resetBtn.css({ 5881 'left': (inputPadding + textWidth + 5) + 'px', // 5px buffer 5882 'right': 'auto' 5883 }); 5884 5885 $measure.remove(); 5886 5887 // Event handler for the reset button 5888 $resetBtn.on('click', function() { 5889 $input.val(""); 5890 jQuery(this).remove(); 5891 setTimeout(function() { 5892 first_time_wpestate_show_inpage_ajax_half = 1; 5893 wpestate_show_pins(); 5894 }, 1000); 5895 }); 5896 5897 setTimeout(function() { 5898 first_time_wpestate_show_inpage_ajax_half = 1; 5899 wpestate_show_pins(); 5900 }, 1000); 5901 5902 // Step 2: Stop jQuery UI from replacing the label with the raw value. 5903 return false;
5904 }, 5905 change: function() { 5906 } 5907 }).autocomplete("instance")._renderItem = function(ul, item) { 5908 var item_class = "wpresidence-geolocatiomarker-" + item.labelcategory; 5909 var $li = jQuery("<li>").append("<div class='" + item_class + "'>" + item.label + "</div>"); 5910 5911 var lastCategory = jQuery(ul).find(".wpresidece-dropdown-category-label:last").data("category"); 5912 if (lastCategory !== item.category) { 5913 var $categoryDiv = jQuery("<div>") 5914 .addClass("wpresidece-dropdown-category-label") 5915 .data("category", item.category) 5916 .text(item.category); 5917 jQuery(ul).append($categoryDiv); 5918 } 5919 5920 return $li.appendTo(ul); 5921 }; 5922} 5923 5924 5925 5926/* 5927* 5928* save search actions 5929* 5930*/ 5931function wpestate_save_search_actions(){ 5932 5933 jQuery('#save_search_button').on( 'click', function(event) { 5934 var nonce, search, search_name, parent, ajaxurl,meta; 5935 search_name = jQuery('#search_name').val(); 5936 search = jQuery('#search_args').val(); 5937 meta = jQuery('#meta_args').val(); 5938 nonce = jQuery('#wpestate_save_search_nonce').val(); 5939 ajaxurl = ajaxcalls_vars.admin_url + 'admin-ajax.php'; 5940 jQuery('#save_search_notice').html(control_vars.save_search); 5941 5942 jQuery.ajax({ 5943 type: 'POST', 5944 url: ajaxurl, 5945 data: { 5946 'action' : 'wpestate_save_search_function', 5947 'search_name' : search_name, 5948 'search' : search, 5949 'meta' : meta, 5950 'security' : nonce 5951 }, 5952 success: function (data) { 5953 5954 jQuery('#save_search_notice').html(data); 5955 jQuery('#search_name').val(''); 5956 }, 5957 error: function (errorThrown) { 5958 } 5959 }); 5960 5961 }); 5962} 5963 5964/* 5965* 5966* delete save search actions 5967* 5968*/ 5969function wpestate_delete_save_search_actions(){ 5970 jQuery('.delete_search').on( 'click', function(event) { 5971 var search_id, parent, ajaxurl,confirmtext; 5972 confirmtext = control_vars.deleteconfirm; 5973 5974 if (confirm(confirmtext)) { 5975 event.preventDefault(); 5976 ajaxurl = ajaxcalls_vars.admin_url + 'admin-ajax.php'; 5977 search_id = jQuery(this).attr('data-searchid'); 5978 parent = jQuery(this).parent(); 5979 jQuery(this).html(control_vars.deleting); 5980 var nonce = jQuery('#wpestate_searches_actions').val(); 5981 jQuery.ajax({ 5982 type: 'POST', 5983 url: ajaxurl, 5984 data: { 5985 'action' : 'wpestate_delete_search', 5986 'search_id' : search_id, 5987 'security' : nonce, 5988 }, 5989 success: function (data) { 5990 5991 if (data==='deleted'){ 5992 parent.remove(); 5993 } 5994 5995 }, 5996 error: function (errorThrown) { 5997 } 5998 }); 5999 6000 6001 } 6002 6003 }); 6004} 6005 6006 6007 6008/* 6009* 6010* 6011* 6012*/ 6013function wpestate_overview_map(){ 6014 jQuery('#overview_map').click(function(){ 6015 jQuery('#wpestate_overview_map_modal').appendTo("body"); 6016 jQuery('body> #wpestate_overview_map_modal').first().modal("show"); 6017 6018 }); 6019} 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029//////////////// 6030 6031/** 6032 * Creates skeleton cards in container based on existing card count 6033 * @param {jQuery} container - Container element 6034 * @param {boolean} append - If true, append skeletons; if false, empty container first (default: false) 6035 * 6036 * data-row-number="3" - blg list 6037 */ 6038function wpestate_createSkeletons(container, append) { 6039 // Default parameter handling for ES5 compatibility 6040 if (typeof append === 'undefined') { 6041 append = false; 6042 } 6043 6044 // Detect if this is a grid layout 6045 var isGrid = container.find('.shortcode_wrapper_grid_item').length > 0; 6046 6047 // Count existing cards BEFORE they get cleared 6048 var existingCards = container.find('.listing_wrapper:not(.skeleton-placeholder)'); 6049 var existingCount = existingCards.length; 6050 6051 // Handle clearing based on append parameter 6052 if (append === false) { 6053 container.empty(); 6054 } 6055 6056 // Calculate items per row from Bootstrap grid classes based on current viewport 6057 var itemsPerRow = parseInt( container.attr('data-row-number')) ; 6058 var gridClasses = 'col-lg-4 col-12 col-sm-6 col-md-6'; 6059 var cardClasses = 'property_listing property_card_default'; 6060 6061 6062 6063 if (isGrid) { 6064 // Grid layout logic 6065 6066 // For grid, we don't use Bootstrap classes 6067 gridClasses = ''; 6068 6069 // Extract card classes from existing cards 6070 if (existingCards.length > 0) { 6071 var cardElement = existingCards.first().find('.property_listing'); 6072 if (cardElement.length > 0) { 6073 cardClasses = cardElement.attr('class'); 6074 } 6075 } 6076 6077 6078 6079 } else { 6080 6081 if (existingCards.length > 0) { 6082 var firstCard = existingCards.first(); 6083 var classList = firstCard.attr('class').split(' '); 6084 6085 // Extract grid classes 6086 var extractedGridClasses = classList.filter(function(cls) { 6087 return cls.indexOf('col-') === 0; 6088 }).join(' '); 6089 if (extractedGridClasses) { 6090 gridClasses = extractedGridClasses; 6091 } 6092 6093 // Calculate items per row based on current viewport 6094 var viewportWidth = window.innerWidth; 6095 var cols = 4; // default (col-lg-4 = 12/4 = 3 per row) 6096 6097 if (viewportWidth >= 1200) {
6098 // xl breakpoint - look for col-xl-* or fallback to col-lg-* 6099 var xlClass = classList.find(function(cls) { return cls.match(/^col-xl-(\d+)$/); }); 6100 if (xlClass) { 6101 cols = parseInt(xlClass.match(/^col-xl-(\d+)$/)[1]); 6102 } else { 6103 var lgClass = classList.find(function(cls) { return cls.match(/^col-lg-(\d+)$/); }); 6104 if (lgClass) cols = parseInt(lgClass.match(/^col-lg-(\d+)$/)[1]); 6105 } 6106 } else if (viewportWidth >= 992) { 6107 // lg breakpoint 6108 var lgClass = classList.find(function(cls) { return cls.match(/^col-lg-(\d+)$/); }); 6109 if (lgClass) cols = parseInt(lgClass.match(/^col-lg-(\d+)$/)[1]); 6110 } else if (viewportWidth >= 768) { 6111 // md breakpoint 6112 var mdClass = classList.find(function(cls) { return cls.match(/^col-md-(\d+)$/); }); 6113 if (mdClass) cols = parseInt(mdClass.match(/^col-md-(\d+)$/)[1]); 6114 } else if (viewportWidth >= 576) { 6115 // sm breakpoint 6116 var smClass = classList.find(function(cls) { return cls.match(/^col-sm-(\d+)$/); }); 6117 if (smClass) cols = parseInt(smClass.match(/^col-sm-(\d+)$/)[1]); 6118 } else { 6119 // xs breakpoint - look for col-* (no breakpoint) 6120 var xsClass = classList.find(function(cls) { return cls.match(/^col-(\d+)$/); }); 6121 if (xsClass) cols = parseInt(xsClass.match(/^col-(\d+)$/)[1]); 6122 } 6123 6124 itemsPerRow = Math.floor(12 / cols); 6125 6126 // Extract card classes 6127 var cardElement = firstCard.find('.property_listing'); 6128 if (cardElement.length > 0) { 6129 cardClasses = cardElement.attr('class'); 6130 } 6131 } 6132 } 6133 6134 var skeletonCount; 6135 6136 // Simple: skeleton count = existing count (complete rows) 6137 if (append === false) { 6138 skeletonCount = Math.ceil(existingCount / itemsPerRow) * itemsPerRow; 6139 }else{ 6140 6141 6142 if(isGrid){ 6143 skeletonCount = parseInt( container.parent().attr('data-row-number')); 6144 }else{ 6145 skeletonCount = itemsPerRow; 6146 } 6147 } 6148 6149 // Create skeleton HTML 6150 var skeletonHTML = ''; 6151 for (var i = 0; i < skeletonCount; i++) { 6152 skeletonHTML += wpestate_createSkeletonCard(gridClasses, cardClasses, false); 6153 } 6154 6155 // Clear specific elements if appending (don't clear everything) 6156 6157 6158 // Add skeletons to container 6159 container.append(skeletonHTML); 6160} 6161 6162/** 6163 * Replaces skeleton cards with real cards 6164 * @param {jQuery} container - Container element 6165 * @param {string} htmlData - HTML data with real cards 6166 */ 6167function wpestate_replaceSkeletons(container, htmlData,append) { 6168 6169 6170 // Detect if this is a grid layout 6171 var isGrid = container.find('.shortcode_wrapper_grid_item').length > 0; 6172 6173 // Default parameter handling for ES5 compatibility 6174 if (typeof append === 'undefined') { 6175 append = false; 6176 } 6177 6178 // Find skeleton placeholders 6179 var skeletons = container.find('.skeleton-placeholder'); 6180 6181 // Parse new HTML data 6182 var tempDiv = jQuery('<div>').html(htmlData); 6183 var newCards = tempDiv.find('.listing_wrapper'); 6184 6185 var pagination = tempDiv.find('.pagination_ajax_search'); 6186 var pagination2 = tempDiv.find('.pagination_ajax'); 6187 var scrollHere = tempDiv.find('#scrollhere'); 6188 var no_results = tempDiv.find('.no_results'); 6189 6190 // If no skeletons, just append normally 6191 if (skeletons.length === 0) { 6192 container.append(htmlData); 6193 return; 6194 } 6195 6196 // Add scrollhere at beginning if exists 6197 if (scrollHere.length > 0) { 6198 container.prepend(scrollHere); 6199 } 6200 6201 // Replace ALL skeletons one by one - some with real cards, others removed 6202 var delay = 0; 6203 var intervalTime = 100; 6204 6205 var maxItems = Math.max(skeletons.length, newCards.length); 6206 if (append == true) { 6207 // console.log('maxItems with app ' + maxItems); 6208 } else { 6209 // console.log('maxItems no app ' + maxItems); 6210 } 6211 6212 6213 for (var i = 0; i < maxItems; i++) { 6214 6215 (function(index) { 6216 setTimeout(function() { 6217 if (index < skeletons.length && index < newCards.length) { 6218 // Replace skeleton with real card 6219 6220 if(isGrid){ 6221 var wrappedCard = jQuery('<div class="shortcode_wrapper_grid_item"></div>').append(jQuery(newCards[index])); 6222 jQuery(skeletons[index]).replaceWith(wrappedCard); 6223 }else{ 6224 jQuery(skeletons[index]).replaceWith(jQuery(newCards[index])); 6225 } 6226 6227 6228 6229 } else if (index < skeletons.length) { 6230 // Remove empty skeleton (right to left) 6231 var emptySkeletonIndex = skeletons.length - 1 - (index - newCards.length); 6232 jQuery(skeletons[emptySkeletonIndex]).fadeOut(200, function() { 6233 jQuery(this).remove(); 6234 }); 6235 } else if (index < newCards.length) { 6236 // Add extra card (more cards than skeletons) 6237 container.append(jQuery(newCards[index])); 6238 } 6239 }, delay); 6240 })(i); 6241
6242 delay += intervalTime; 6243 6244 } 6245 6246 6247 // Add pagination after all skeletons are processed 6248 if (pagination.length > 0) { 6249 setTimeout(function() { 6250 container.append(pagination); 6251 }, delay + 200); 6252 } 6253 6254 6255 // Add pagination2 after all skeletons are processed 6256 if (pagination2.length > 0) { 6257 setTimeout(function() { 6258 container.append(pagination2); 6259 }, delay + 200); 6260 } 6261 6262 // Add pagination2 after all skeletons are processed 6263 if (no_results.length > 0) { 6264 setTimeout(function() { 6265 container.append(no_results); 6266 }, delay + 200); 6267 } 6268 6269 6270 // Call restart JS after all real cards are displayed 6271 setTimeout(function() { 6272 if (typeof wpestate_restart_js_after_ajax === 'function') { 6273 wpestate_restart_js_after_ajax(); 6274 } 6275 }, delay + 300); 6276 6277} 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287/** 6288 * Creates a skeleton placeholder card 6289 */ 6290function wpestate_createSkeletonCard(gridClasses, cardClasses, is_grid) { 6291 var skeletonCard = ` 6292 <div class="${gridClasses} listing_wrapper skeleton-placeholder"> 6293 <div class="${cardClasses} skeleton-card"> 6294 <div class="listing-unit-img-wrapper"> 6295 <div class="skeleton-image skeleton-shimmer"></div> 6296 </div> 6297 <div class="property-unit-information-wrapper"> 6298 <div class="skeleton-text title skeleton-shimmer"></div> 6299 <div class="skeleton-text category skeleton-shimmer"></div> 6300 <div class="skeleton-text details skeleton-shimmer"></div> 6301 </div> 6302 </div> 6303 </div>`; 6304 6305 if (is_grid) { 6306 return `<div class="shortcode_wrapper_grid_item">${skeletonCard}</div>`; 6307 } 6308 6309 return skeletonCard; 6310} 6311 6312 6313/** 6314 * Initialize the editorial property slider with Owl Carousel 6315 * 6316 * Single-item editorial card slider with left/right chevron arrows 6317 * and RTL support. Used by the Property Slider Elementor widget. 6318 * 6319 * @param {string} slider_id - The DOM element ID of the slider container 6320 * @param {number} items - Number of items in the slider 6321 */ 6322function wpestate_property_slider_editorial(slider_id, items) { 6323 // Initialize RTL value checking both data attribute and control_vars 6324 let rtl_value = false; 6325 const $slider = jQuery('#' + slider_id); 6326 const $nav = jQuery('#' + slider_id + '_nav'); 6327 6328 // Check both data-rtl and control_vars.is_rtl for RTL support 6329 if ($slider.attr('data-rtl') === 'yes' || control_vars.is_rtl === '1') { 6330 rtl_value = true; 6331 $slider.addClass('owl-rtl'); 6332 } 6333 6334 // Initialize Owl Carousel â nav disabled, we use custom arrows 6335 $slider.owlCarousel({ 6336 loop: (items > 1), 6337 margin: 0, 6338 nav: false, 6339 items: 1, 6340 dots: false, 6341 mouseDrag: true, 6342 autoHeight: false, 6343 stagePadding: 0, 6344 rtl: rtl_value, 6345 responsive: { 6346 0: { items: 1 }, 6347 768: { items: 1 }, 6348 1024: { items: 1 } 6349 } 6350 }); 6351 6352 // Wire custom prev/next buttons to owl carousel 6353 $nav.find('.editorial_prev').on('click', function () { 6354 $slider.trigger('prev.owl.carousel'); 6355 }); 6356 $nav.find('.editorial_next').on('click', function () { 6357 $slider.trigger('next.owl.carousel'); 6358 }); 6359 6360 // Update slide counter on slide change 6361 $slider.on('changed.owl.carousel', function (event) { 6362 // Calculate current real index (accounting for clones in loop mode) 6363 var current = (event.item.index - event.relatedTarget._clones.length / 2) % event.item.count; 6364 if (current < 0) { 6365 current = event.item.count + current; 6366 } 6367 var display = String(current + 1).padStart(2, '0'); 6368 $nav.find('.editorial_current').text(display); 6369 }); 6370}
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.