PageSourceSearch

https://gerama.ch/wp-content/themes/wpresidence/js/control.js?ver=1.0.0

js gerama.ch collected 2026-09-25 03:13:33 UTC 232,083 bytes, 6,370 lines download raw bytes

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.