(function ($) { "use strict"; /* ----------- START OF LOCATIONS SELECT BOXES CODE ----------- */ if (typeof realhomesLocationsData !== 'undefined') { const hierarchicalLocations = realhomesLocationsData.all_locations; /* All locations */ const selectBoxesIDs = realhomesLocationsData.select_names; /* Select boxes names that can be used as ids */ const selectBoxesCount = parseInt(realhomesLocationsData.select_count); /* Number of select boxes to manage */ const multiSelect = realhomesLocationsData.multi_select_locations; /* Location boxes are multiselect or not */ const anyText = realhomesLocationsData.any_text; /* "Any" text as it could be translated */ const anyValue = realhomesLocationsData.any_value; /* "any" value */ const slugsInQueryParams = realhomesLocationsData.locations_in_params; /* parameters related to location boxes */ const consoleLogEnabled = false; /* A flag to enable disable console logging while development OR troubleshooting */ /* logging while development OR troubleshooting */ if (consoleLogEnabled) { console.log('realhomesLocationsData.locations_in_params: '); console.log(slugsInQueryParams); } /** * Initialize Locations Select Boxes * * Following function automatically runs to initialize locations boxes */ (function () { /* prepare select boxes */ prepareSelectBoxes(); let parentLocations = []; for (let selectIndex = 0; selectIndex < selectBoxesCount; selectIndex++) { const currentSelect = $('#' + selectBoxesIDs[selectIndex]); /* loop's current select box */ const currentIsLast = (selectBoxesCount === (selectIndex + 1)); /* check if current select box is last */ if (selectIndex === 0) { /* First iteration */ parentLocations = addParentLocations(currentSelect, currentIsLast); } else { /* later iterations */ /* If parents locations array is not empty then there could be children to add in current select box */ if (parentLocations.length > 0) { let currentLocations = []; const previousSelect = $('#' + selectBoxesIDs[selectIndex - 1]); /* loop through all if value is "any" */ if (previousSelect.val() === anyValue) { for (let i = 0; i < parentLocations.length; i++) { let tempLocations = addChildrenLocations(currentSelect, parentLocations[i].children, '', currentIsLast); if (tempLocations.length > 0) { currentLocations = $.merge(currentLocations, tempLocations); } } } else { /* Otherwise add only children of previous selected location, It there are any. */ let previousLocation = searchLocation(previousSelect.val(), hierarchicalLocations); if (previousLocation && previousLocation.children.length > 0) { currentLocations = addChildrenLocations(currentSelect, previousLocation.children, '', currentIsLast); } } /* hook up updateChildSelect function with previous select change event */ previousSelect.change(updateChildSelect); /* currentLocations variable is passed to parentLocations for code below and for next iteration */ parentLocations = currentLocations; } } /* If parentLocations is empty */ if (parentLocations.length === 0) { /* disable current select and children selects if any */ disableSelect(currentSelect); /* No need for further iterations */ break; } else { /* Select the right option within current select based on query parameters */ selectParamOption(currentSelect); } } /* end of loop */ })(); /* Run the function immediately after declaration */ /** * Adds top level locations to given select box, If addAllChildren is true then it adds all children locations as well * @param targetSelect * @param addAllChildren * @returns {*[]} */ function addParentLocations(targetSelect, addAllChildren) { let addedLocations = []; let insertionCounter = 0; /* loop through top level locations */ hierarchicalLocations.forEach(function (currentLocation, index, locationsArray) { targetSelect.append(''); addedLocations[insertionCounter++] = currentLocation; /* logging while development OR troubleshooting */ if (consoleLogEnabled) { console.log('addParentLocations: ' + currentLocation.slug + ' in ' + targetSelect.attr('id')); } if (addAllChildren && currentLocation.children.length) { addChildrenLocations(targetSelect, currentLocation.children, '- ', addAllChildren); } }); return addedLocations; } /** * Adds top level locations form given childrenLocations array to targetSelect box, If addAllChildren is true then it adds all children locations as well * @param targetSelect * @param childrenLocations * @param prefix * @param addAllChildren * @returns {*[]} */ function addChildrenLocations(targetSelect, childrenLocations, prefix, addAllChildren) { let addedChildrenLocations = []; let insertionCounter = 0; /* loop through all children locations */ childrenLocations.forEach(function (currentLocation, index, locationsArray) { targetSelect.append(''); addedChildrenLocations[insertionCounter++] = currentLocation; /* logging while development OR troubleshooting */ if (consoleLogEnabled) { console.log(prefix + 'addChildrenLocations: ' + currentLocation.slug + ' in ' + targetSelect.attr('id')); } /* If a current location has children then add those as well */ if (addAllChildren && currentLocation.children.length) { let tempLocations = addChildrenLocations(targetSelect, currentLocation.children, prefix + '- ', addAllChildren); if (tempLocations.length > 0) { /* merge newly added children locations with existing children locations array */ addedChildrenLocations = $.merge(addedChildrenLocations, tempLocations); } } }); return addedChildrenLocations; } /** * Search a location from given locations array for given slug * @param slug * @param locations * @returns {boolean} location OR false if no location is found */ function searchLocation(slug, locations) { let targetLocation = false; for (let index = 0; index < locations.length; index++) { let currentLocation = locations[index]; if (currentLocation.slug === slug) { /* logging while development OR troubleshooting */ if (consoleLogEnabled) { console.log('searchLocation: Found'); console.log(currentLocation); } targetLocation = currentLocation; break; } if (currentLocation.children.length > 0) { targetLocation = searchLocation(slug, currentLocation.children); if (targetLocation) { break; } } } return targetLocation; } /** * Update child select box based on change in selected value of parent select box * @param event */ function updateChildSelect(event) { let selectedSlug = $(this).val(); let currentSelectIndex = selectBoxesIDs.indexOf($(this).attr('id')); /* logging while development OR troubleshooting */ if (consoleLogEnabled) { console.log('updateChildSelect: ' + $(this).attr('id') + ' select box is changed to ' + selectedSlug + ' slug '); } /* When "any" is selected, Also no need to run this on last select box */ if (selectedSlug === anyValue && (currentSelectIndex > -1) && (currentSelectIndex < (selectBoxesCount - 1))) { for (let s = currentSelectIndex; s < (selectBoxesCount - 1); s++) { /* check if child select is Last */ let childSelectIsLast = (selectBoxesCount === (s + 2)); /* find child select box, empty it and add any options to it */ let childSelect = $('#' + selectBoxesIDs[s + 1]); childSelect.empty(); addAnyOption(childSelect); /* loop through select options to find and add children locations into next select */ let anyChildLocations = []; $('#' + selectBoxesIDs[s] + ' > option').each(function () { if (this.value !== anyValue) { let relatedLocation = searchLocation(this.value, hierarchicalLocations); if (relatedLocation && relatedLocation.children.length > 0 ) { let tempChildrenLocations = addChildrenLocations(childSelect, relatedLocation.children, '', childSelectIsLast); if (tempChildrenLocations.length > 0) { anyChildLocations = $.merge(anyChildLocations, tempChildrenLocations); } } } }); /* enable next select if options are added otherwise disable it */ if (anyChildLocations.length > 0) { enableSelect(childSelect); } else { disableSelect(childSelect); break; } } /* end of for loop */ } else { /* In case of valid location selection */ let selectedParentLocation = searchLocation(selectedSlug, hierarchicalLocations); if (selectedParentLocation) { let childLocations = []; for (let childSelectIndex = currentSelectIndex + 1; childSelectIndex < selectBoxesCount; childSelectIndex++) { /* check if child select is Last */ let childSelectIsLast = (selectBoxesCount === (childSelectIndex + 1)); /* find and empty child select box */ let childSelect = $('#' + selectBoxesIDs[childSelectIndex]); childSelect.empty(); /* First iteration */ if (childLocations.length === 0 ) { if (selectedParentLocation.children.length > 0) { addAnyOption(childSelect); let tempLocations = addChildrenLocations(childSelect, selectedParentLocation.children, '', childSelectIsLast); if (tempLocations.length > 0) { childLocations = tempLocations; } } } else if (childLocations.length > 0) { /* 2nd and later iterations */ let currentLocations = []; for (let i = 0; i < childLocations.length; i++) { let tempChildLocation = childLocations[i]; if (tempChildLocation.children.length > 0) { addAnyOption(childSelect); let tempLocations = addChildrenLocations(childSelect, tempChildLocation.children, '', childSelectIsLast); if (tempLocations.length > 0) { currentLocations = $.merge(currentLocations, tempLocations); } } } /* If there are current locations OR none, assign current locations array to child locations*/ childLocations = currentLocations; } if (childLocations.length > 0) { enableSelect(childSelect); } else { disableSelect(childSelect); break; } } /* end of for loop */ } else { /* logging while development OR troubleshooting */ if (consoleLogEnabled) { console.log('updateChildSelect: Not Found ' + selectedSlug + ' slug in hierarchicalLocations!'); console.log(hierarchicalLocations); } } } } /** * Adds Any value and select index based place holder text to given select box. * @param targetSelect */ function addAnyOption(targetSelect) { if (targetSelect.has('option').length > 0){ return; } let targetSelectIndex = selectBoxesIDs.indexOf(targetSelect.attr('id')); /* current select box index */ /* For location fields in search form */ if (targetSelect.parents('.rh_prop_search__select').hasClass('rh_location_prop_search_' + targetSelectIndex)) { let targetSelectPlaceholder = targetSelect.parents('.rh_prop_search__select').data('get-location-placeholder'); targetSelect.append(''); /* logging while development OR troubleshooting */ if (consoleLogEnabled) { console.log('addAnyOption: to select box: ' + targetSelect.attr('id')); } /* For location fields in dashboard property form */ } else if (targetSelect.parents('.rh_prop_loc__select').hasClass('rh_location_prop_loc_' + targetSelectIndex)) { targetSelect.append(''); /* logging while development OR troubleshooting */ if (consoleLogEnabled) { console.log('addAnyOption: to select box: ' + targetSelect.attr('id')); } } } /** * Disable a select box and next select boxes if exists * @param targetSelect */ function disableSelect(targetSelect) { let targetSelectID = targetSelect.attr('id'); /* logging while development OR troubleshooting */ if (consoleLogEnabled) { console.log('disableSelect: ' + targetSelectID); } targetSelect.empty(); targetSelect.closest('.option-bar').addClass('disabled'); if (targetSelect.is(':enabled')) { targetSelect.prop('disabled', true); targetSelect.parents('.rh_prop_search__select').addClass('rh_disable_parent'); } let targetSelectIndex = selectBoxesIDs.indexOf(targetSelectID); // target select box index let nextSelectBoxesCount = selectBoxesCount - (targetSelectIndex + 1); /* Disable next select box as well */ if (nextSelectBoxesCount > 0) { let nextSelect = $('#' + selectBoxesIDs[targetSelectIndex + 1]); disableSelect(nextSelect); } } /** * Enable a select box * @param targetSelect */ function enableSelect(targetSelect) { let targetSelectID = targetSelect.attr('id'); /* logging while development OR troubleshooting */ if (consoleLogEnabled) { console.log('enableSelect: ' + targetSelectID); } if (targetSelect.is(':disabled')) { targetSelect.prop('disabled', false); } // remove class from parents targetSelect.parents('.rh_prop_search__select').map(function (){ if( $(this).hasClass('rh_disable_parent')){ $(this).removeClass('rh_disable_parent'); } }); /* Remove .option-bar's disabled class */ let optionWrapper = targetSelect.closest('.option-bar'); if (optionWrapper.hasClass('disabled')) { optionWrapper.removeClass('disabled'); // todo: remove the following line after testing //optionWrapper.parents('.rh_prop_search__select').removeClass('rh_disable_parent'); } // for classic property submit/edit form's locations fields // targetSelect.siblings('.btn').removeClass('disabled'); /* Remove .bootstrap-select disabled class - especially for classic */ // let bootstrapSelect = targetSelect.closest('.bootstrap-select'); // if (bootstrapSelect.hasClass('disabled')) { // bootstrapSelect.removeClass('disabled'); // } } /** * Mark the current value in query params as selected in related select box * @param currentSelect */ function selectParamOption(currentSelect) { if (Object.keys(slugsInQueryParams).length > 0) { let selectName = currentSelect.attr('name'); selectName = selectName.replace(/[\[\]]+/g,''); /* remove box brackets as for multi select location brackets comes with name */ if (typeof slugsInQueryParams[selectName] !== 'undefined') { let tempValue = slugsInQueryParams[selectName]; if (Array.isArray(tempValue)){ for (let i = 0; i < tempValue.length; i++) { currentSelect.find('option[value="' + tempValue[i] + '"]').prop('selected', true); } } else { currentSelect.find('option[value="' + tempValue + '"]').prop('selected', true); } } } } /** * Append options with Any value or None value depending on conditions */ function prepareSelectBoxes(){ /* Loop through select boxes and prepare them with basic option */ for (let selectIndex = 0; selectIndex < selectBoxesCount; selectIndex++) { let currentSelectId = selectBoxesIDs[selectIndex]; let currentSelect = $('#' + currentSelectId); /* For location fields in search form */ if ((multiSelect === 'no') && (currentSelect.has('option').length === 0) && (currentSelect.parents('.rh_prop_search__select').hasClass('rh_location_prop_search_' + selectIndex))) { if(consoleLogEnabled){ console.log('prepareSelectBoxes 1st if: ' + currentSelectId); } addAnyOption(currentSelect); } /* For location fields in dashboard property form */ if ((currentSelect.has('option').length === 0) && (currentSelect.parents('.rh_prop_loc__select').hasClass('rh_location_prop_loc_' + selectIndex))) { if(consoleLogEnabled){ console.log('prepareSelectBoxes 2nd if: ' + currentSelectId); } addAnyOption(currentSelect); } } } } /* ----------- END OF LOCATIONS SELECT BOXES CODE ----------- */ })(jQuery);; (function ($) { "use strict"; /** * Initializes the similar properties filters. * * @since 3.13 */ function similarPropertiesFilters() { const similarPropertiesFiltersWrap = $( '#similar-properties-filters-wrapper' ); if ( similarPropertiesFiltersWrap.length ) { const similarPropertiesFilters = similarPropertiesFiltersWrap.find( 'a' ), similarPropertiesWrapper = $( '#similar-properties-wrapper' ), similarProperties = $( '#similar-properties' ), similarPropertiesHtml = similarProperties.html(), similarNonce = similarPropertiesFiltersWrap.data( 'similar-properties-request-nonce' ); // Check for localized similar properties data if ( typeof similarPropertiesData !== "undefined" ) { const design = similarPropertiesData.design; let buttonClass = 'rh-btn rh-btn-primary'; let buttonClassCurrent = 'rh-btn rh-btn-secondary'; if ( 'classic' === design ) { buttonClass = ''; buttonClassCurrent = 'current'; } similarPropertiesFiltersWrap.on( 'click', 'a', function ( event ) { event.preventDefault(); const self = $( this ); const propertyFilter = self.data( 'similar-properties-filter' ); // Update UI for the selected filter button similarPropertiesFilters.removeClass( buttonClassCurrent ).addClass( buttonClass ); self.removeClass( buttonClass ).addClass( buttonClassCurrent ); // Handle recommended properties (no AJAX required) if ( 'recommended' === propertyFilter ) { similarProperties.html( similarPropertiesHtml ); return; } // Make AJAX request to filter similar properties $.ajax( { url : ajaxurl, type : 'post', dataType : 'json', // Expect JSON response data : { action : 'realhomes_filter_similar_properties', property_id : similarPropertiesData.propertyId, properties_per_page : similarPropertiesData.propertiesPerPage, property_filter : propertyFilter, design : design, nonce : similarNonce }, beforeSend : function () { similarPropertiesWrapper.addClass( 'loading' ); }, success : function ( response ) { similarPropertiesWrapper.removeClass( 'loading' ); if ( response.success ) { similarProperties.html( response.data ); } else { console.warn( response.data.message || 'An unknown error occurred.' ); similarProperties.html( '
' ); } }, error : function ( jqXHR, textStatus, errorThrown ) { // Remove loading state similarPropertiesWrapper.removeClass( 'loading' ); // Handle HTTP errors (e.g., 404, 500, timeout) console.error( 'AJAX Error:', textStatus, errorThrown ); similarProperties.html( ' ' ); } } ); } ); } else { // Hide filters when no data available similarPropertiesFiltersWrap.hide(); } } } /** * Adds css class in body to stack the floating features div if the property agent sticky bar exists in DOM. * * @since 3.14 */ function agentStickyBarHandler() { const agentStickyBar = $('#property-agent-contact-methods-wrapper'); if (767 > $(window).width() && agentStickyBar.length) { $('body').addClass('has-agent-sticky-bar'); } } $(document).ready(function () { // Elementor Based Membership Packages Page let getStarted = document.querySelectorAll( '#membership-plans' ); if ( typeof getStarted !== 'undefined' ) { let loginModel = $( 'body' ).find( '.rh_login_modal_wrapper' ); let membershipPage = dashboardData.membershipPage; let redirectTo = document.querySelector( '.rh_login_modal_wrapper input[name="redirect_to"]' ); if ( ! loginModel.length && typeof membershipPage !== 'undefined' ) { getStarted.forEach( function ( link ) { link.setAttribute( 'href', membershipPage + '&submodule=checkout&package_id=' + link.getAttribute( "href" ).replace( '#', '' ) ); } ) } else { getStarted.forEach( function ( link ) { link.addEventListener( 'click', function () { if ( loginModel.length ) { redirectTo.setAttribute( 'value', membershipPage + '&submodule=checkout&package_id=' + link.getAttribute( "href" ).replace( '#', '' ) ); } } ) } ); } } // End of Membership Packages var $window = $(window), $body = $('body'), isRtl = $body.hasClass('rtl'); similarPropertiesFilters(); agentStickyBarHandler(); // TODO: need to find a way to run this code only on property single page. $window.on('resize', function () { agentStickyBarHandler(); }); // Stop propagation of click event on favorites button when user is not logged in. $('.add-favorites-without-login, .save-search-without-login').on('click', function (event) { event.stopPropagation(); }); /*-----------------------------------------------------------------*/ /* Save Searches for Email Alerts /*-----------------------------------------------------------------*/ $('#rh_save_search_btn').on('click', function (e) { e.preventDefault(); let button = $(this); let $form = button.closest('form'); let searchArguments = $form.find('.rh_wp_query_args').val(); let searchURL = $form.find('.rh_url_query_str').val(); let icon = button.find('i'); let savedLabel = button.data('saved-label'); icon.addClass('fa-spin'); if (button.hasClass('require-login')) { // Prepare new alert object to store in local storage. let currentTime = $form.find('.rh_current_time').val(); let newSavedSearch = { 'wp_query_args': searchArguments, 'query_str': searchURL, 'time': currentTime }; // Add new alert to the local storage. var oldSavedSearches = window.localStorage.getItem('realhomes_saved_searches'); if (oldSavedSearches) { allSavedSearches = JSON.parse(oldSavedSearches); allSavedSearches.push(newSavedSearch); window.localStorage.setItem('realhomes_saved_searches', JSON.stringify(allSavedSearches)); } else { window.localStorage.setItem('realhomes_saved_searches', JSON.stringify([newSavedSearch])); } // Update the save alert button. button.addClass('search-saved'); icon.removeClass('fa-spin'); button.html('' + savedLabel); // Open the login/register dialoage box. var loginModel = $('body').find('.rh_login_modal_wrapper'); if (loginModel.length) { $('.rh_login_modal_wrapper').css("display", "flex").hide().fadeIn(500); } else { window.location = button.data('login'); } } else { let nonce = $form.find('.rh_save_search_nonce').val(); $.post(ajaxurl, { nonce: nonce, action: 'inspiry_save_search', search_args: searchArguments, search_url: searchURL, }, function (response) { response = JSON.parse(response); if (response.success) { // Update the save search button. button.addClass('search-saved'); icon.removeClass('fa-spin'); button.html('' + savedLabel); } } ); } }); /* * Migrate saved searches from local to server. */ var allSavedSearches = JSON.parse(window.localStorage.getItem('realhomes_saved_searches')); if (allSavedSearches && $('body').hasClass('logged-in')) { var migrateSavedSearches = { type: 'post', url: ajaxurl, data: { action: 'realhomes_saved_searches_migration', saved_searches: allSavedSearches, }, success: function (response) { if ('true' === response) { // Clear all saved searches from local storage. window.localStorage.removeItem('realhomes_saved_searches'); } } }; $.ajax(migrateSavedSearches); } /*-----------------------------------------------------------------*/ /* Mortgage Calculator /*-----------------------------------------------------------------*/ if ($('.rh_property__mc_wrap').length) { let mc_reassign_fields = function ($this = null) { if ('object' === typeof $this && typeof $this.closest('.rh_property__mc')) { $this = $this.closest('.rh_property__mc'); mcState.fields = { 'term': $this.find('select.mc_term'), 'interest_text': $this.find('.mc_interset'), 'interest_slider': $this.find('.mc_interset_slider'), 'price_text': $this.find('.mc_home_price'), 'price_slider': $this.find('.mc_home_price_slider'), 'downpayment_text': $this.find('.mc_downpayment'), 'downpayment_text_p': $this.find('.mc_downpayment_percent'), 'downpayment_slider': $this.find('.mc_downpayment_slider'), 'tax': $this.find('.mc_cost_tax_value'), 'hoa': $this.find('.mc_cost_hoa_value'), 'currency_sign': $this.find('.mc_currency_sign'), 'sign_position': $this.find('.mc_sign_position'), 'info_term': $this.find('.mc_term_value'), 'info_interest': $this.find('.mc_interest_value'), 'info_cost_interst': $this.find('.mc_cost_interest span'), 'info_cost_total': $this.find('.mc_cost_total span'), 'graph_interest': $this.find('.mc_graph_interest'), 'graph_tax': $this.find('.mc_graph_tax'), 'graph_hoa': $this.find('.mc_graph_hoa'), } if ($('.mc_cost_over_graph').length > 0) { mcState.fields.info_cost_total = $this.find('.mc_cost_over_graph'); } } } let mc_only_numeric = function (data) { if ('string' === typeof data) { return (data.replace(/[^0-9-.]/g, '')).replace(/^\./, ''); // leave only numeric value. } return data; } let mc_input_focus = function () { $(this).val(mc_only_numeric($(this).val())); // leave only numeric value. } let mc_input_blur = function () { // percentage value. mcState.fields.interest_text.val(mc_only_numeric(mcState.fields.interest_text.val()) + '%'); mcState.fields.downpayment_text_p.val(mc_only_numeric(mcState.fields.downpayment_text_p.val()) + '%'); // formatted amount value. mcState.fields.price_text.val(mc_format_amount(mcState.fields.price_text.val())); mcState.fields.downpayment_text.val(mc_format_amount(mcState.fields.downpayment_text.val())); } let mc_format_amount = function (amount) { if ('after' === mcState.values.sign_position) { return new Intl.NumberFormat('en-us').format(mc_only_numeric(amount)) + mcState.values.currency_sign; } return mcState.values.currency_sign + new Intl.NumberFormat('en-us').format(mc_only_numeric(amount)); } let mc_update_fields_values = function () { const $this = $(this); mc_reassign_fields($this); mcState.values = mc_get_input_values(); // get all input values to be used for the calculation. if ('range' === $this.attr('type')) { if ($this.hasClass('mc_interset_slider')) { // Interest slider changed. mcState.fields.interest_text.val($this.val() + '%'); // update interest percentage text field value. } else if ($this.hasClass('mc_home_price_slider')) { // Price slider changed. mcState.fields.price_text.val(mc_format_amount($this.val())); // update price text field value. // update downpayment amount text field value according to the selected percentage. let home_price = $this.val(); let dp_percent = mcState.values.downpayment_percent; let downpayment = Math.round((home_price * dp_percent) / 100); mcState.fields.downpayment_text.val(mc_format_amount(downpayment)); } else if ($this.hasClass('mc_downpayment_slider')) { // Downpayment slider. mcState.fields.downpayment_text_p.val($this.val() + '%'); let home_price = mcState.values.price; let dp_percent = $this.val(); let downpayment = Math.round((home_price * dp_percent) / 100); mcState.fields.downpayment_text.val(mc_format_amount(downpayment)); } } else if ('text' === $this.attr('type')) { if ($this.hasClass('mc_interset')) { mcState.fields.interest_slider.val(mcState.values.interest); } else if ($this.hasClass('mc_home_price')) { mcState.fields.price_slider.val(mcState.values.price); let home_price = mcState.values.price; let dp_percent = mcState.values.downpayment_percent; let downpayment = Math.round((home_price * dp_percent) / 100); mcState.fields.downpayment_text.val(mc_format_amount(downpayment)); } else if ($this.hasClass('mc_downpayment_percent')) { mcState.fields.downpayment_slider.val(mcState.values.downpayment_percent); let home_price = mcState.values.price; let dp_percent = mcState.values.downpayment_percent; let downpayment = (home_price * dp_percent) / 100; mcState.fields.downpayment_text.val(mc_format_amount(downpayment)); } else if ($this.hasClass('mc_downpayment')) { let home_price = mcState.values.price; let downpayment = mcState.values.downpayment; let price = (home_price < downpayment) ? downpayment : home_price; let dp_percent = ((downpayment * 100) / price).toFixed(2).replace(/[.,]00$/, ""); mcState.fields.downpayment_text_p.val(dp_percent + '%'); mcState.fields.downpayment_slider.val(dp_percent); } } mc_calculate(); } let mc_get_input_values = function () { let interest = mc_only_numeric(mcState.fields.interest_text.val()); let price = mc_only_numeric(mcState.fields.price_text.val()); let downpayment = mc_only_numeric(mcState.fields.downpayment_text.val()); let downpayment_percent = mc_only_numeric(mcState.fields.downpayment_text_p.val()); let tax = mc_only_numeric(mcState.fields.tax.val()); let hoa = mc_only_numeric(mcState.fields.hoa.val()); let currency_sign = mcState.fields.currency_sign.val(); let sign_position = mcState.fields.sign_position.val(); let mcInputVals = { term: parseInt(mcState.fields.term.val()), interest: ('' === interest.replace('-', '')) ? 0 : parseFloat(interest), price: ('' === price.replace('-', '')) ? 0 : parseFloat(price), downpayment: ('' === downpayment.replace('-', '')) ? 0 : parseFloat(downpayment), downpayment_percent: ('' === downpayment_percent.replace('-', '')) ? 0 : parseFloat(downpayment_percent), tax: ('' === tax.replace('-', '')) ? 0 : parseFloat(tax), hoa: ('' === hoa.replace('-', '')) ? 0 : parseFloat(hoa), currency_sign: ('' === currency_sign) ? '$' : currency_sign, sign_position: ('' === sign_position) ? 'before' : sign_position, }; return mcInputVals; } let mc_get_principle_interest = function () { let home_price = parseFloat(mcState.values.price); let downpayment = parseFloat(mcState.values.downpayment); let loanBorrow = home_price - downpayment; let totalTerms = 12 * mcState.values.term; if (0 === parseInt(mcState.values.interest)) { return loanBorrow / totalTerms; } let interestRate = parseFloat(mcState.values.interest) / 1200; return Math.round(loanBorrow * interestRate / (1 - (Math.pow(1 / (1 + interestRate), totalTerms)))); } let mc_get_payment_per_month = function () { let principal_interest = parseFloat(mcState.princial_interest); let property_tax = parseFloat(mcState.values.tax); let hoa_dues = parseFloat(mcState.values.hoa); return Math.round(principal_interest + property_tax + hoa_dues); } let mc_get_data_percentage = function () { let principal_interest = mcState.princial_interest; let property_tax = mcState.values.tax; let hoa_dues = mcState.values.hoa; let p_i = (principal_interest * 100) / mcState.payment_per_month; let tax = (property_tax * 100) / mcState.payment_per_month; let hoa = (hoa_dues * 100) / mcState.payment_per_month; let data_percentage = { p_i, tax, hoa }; return data_percentage; } let mc_render_information = function () { // Update calculated information. mcState.fields.info_term.text(mcState.values.term); mcState.fields.info_interest.text(mcState.values.interest); mcState.fields.info_cost_interst.text(mc_format_amount(Math.round(mcState.princial_interest))); if ($('.mc_cost_over_graph').length > 0) { // Update circle graph and total cost. let cost_prefix = mcState.fields.info_cost_total.attr('data-cost-prefix'); mcState.fields.info_cost_total.html('' + mc_format_amount(mcState.payment_per_month) + '' + cost_prefix); var $circle = mcState.fields.graph_interest; var circle_pct = mcState.percentage.p_i; var r = $circle.attr('r'); var c = Math.PI * (r * 2); if (circle_pct < 0) { circle_pct = 0; } if (circle_pct > 100) { circle_pct = 100; } var pct = ((100 - circle_pct) / 100) * c; $circle.css({strokeDashoffset: pct}); var $circle = mcState.fields.graph_tax; var circle_pct = mcState.percentage.tax + mcState.percentage.p_i; var r = $circle.attr('r'); var c = Math.PI * (r * 2); if (circle_pct < 0) { circle_pct = 0; } if (circle_pct > 100) { circle_pct = 100; } var pct = ((100 - circle_pct) / 100) * c; $circle.css({strokeDashoffset: pct}); var $circle = mcState.fields.graph_hoa; var circle_pct = mcState.percentage.hoa + mcState.percentage.tax + mcState.percentage.p_i; var r = $circle.attr('r'); var c = Math.PI * (r * 2); if (circle_pct < 0) { circle_pct = 0; } if (circle_pct > 100) { circle_pct = 100; } var pct = ((100 - circle_pct) / 100) * c; $circle.css({strokeDashoffset: pct}); } else { // Update bar graph and total cost. mcState.fields.info_cost_total.text(mc_format_amount(mcState.payment_per_month)); mcState.fields.graph_interest.css('width', (mcState.percentage.p_i) + '%'); mcState.fields.graph_tax.css('width', (mcState.percentage.tax) + '%'); mcState.fields.graph_hoa.css('width', (mcState.percentage.hoa) + '%'); } } let mc_calculate = function () { mcState.values = mc_get_input_values(); // get all input vaues to be used for the calculation. mcState.princial_interest = mc_get_principle_interest(); // caclcualte and get the principle and interest amount. mcState.payment_per_month = mc_get_payment_per_month(); // calculate and get the per month payment to be paid. mcState.percentage = mc_get_data_percentage(); // calculate and get the percentages of the data for the graph display. mc_render_information(); // Display the information on frontend side. } const mcState = {}; mcState.fields = { 'term': $('select.mc_term'), 'interest_text': $('.mc_interset'), 'interest_slider': $('.mc_interset_slider'), 'price_text': $('.mc_home_price'), 'price_slider': $('.mc_home_price_slider'), 'downpayment_text': $('.mc_downpayment'), 'downpayment_text_p': $('.mc_downpayment_percent'), 'downpayment_slider': $('.mc_downpayment_slider'), 'tax': $('.mc_cost_tax_value'), 'hoa': $('.mc_cost_hoa_value'), 'currency_sign': $('.mc_currency_sign'), 'sign_position': $('.mc_sign_position'), 'info_term': $('.mc_term_value'), 'info_interest': $('.mc_interest_value'), 'info_cost_interst': $('.mc_cost_interest span'), 'info_cost_total': $('.mc_cost_total span'), 'graph_interest': $('.mc_graph_interest'), 'graph_tax': $('.mc_graph_tax'), 'graph_hoa': $('.mc_graph_hoa'), } if ($('.mc_cost_over_graph').length > 0) { mcState.fields.info_cost_total = $('.mc_cost_over_graph'); } mc_calculate(); // Initiate Mortgage Calculator. mc_input_blur(); // Format the amounts in the text fields. // Apply calculation action on calculator values change. $('.rh_mc_field select, .rh_mc_field input[type=range]').on('change', mc_update_fields_values); $('.rh_mc_field input[type=range]').on('input', mc_update_fields_values); $('.rh_mc_field input[type=text]').on('keyup', mc_update_fields_values); // Add focus and blur actions on text input fields. $('.rh_mc_field input[type=text]').on('focus', mc_input_focus); $('.rh_mc_field input[type=text]').on('blur', mc_input_blur); } /*-----------------------------------------------------------------------------------*/ /* Language Switcher /*-----------------------------------------------------------------------------------*/ $body.on( 'click', '.inspiry-language', function ( e ) { if ( $( '.inspiry-language-switcher' ) .find( '.rh_languages_available' ) .children( '.inspiry-language' ).length > 0 ) { const wrapper_language_switcher = $( '.rh_wrapper_language_switcher' ); wrapper_language_switcher.toggleClass( 'parent_open' ); if ( wrapper_language_switcher.hasClass( 'parent_open' ) ) { $( this ).addClass( 'open' ); $( '.rh_languages_available' ).fadeIn( 200 ); } else { $( this ).removeClass( 'open' ); $( '.rh_languages_available' ).fadeOut( 200 ); } } e.stopPropagation(); } ); $('html').on('click', function () { $('.rh_wrapper_language_switcher').removeClass('parent_open'); $('html .inspiry-language').removeClass('open'); $('.rh_languages_available').fadeOut(200); }); /*-----------------------------------------------------------------------------------*/ /* Partners Carousel /*-----------------------------------------------------------------------------------*/ if (jQuery().owlCarousel) { $('.brands-owl-carousel').owlCarousel({ nav: true, dots: false, navText: ['', ''], loop: true, autoplay: true, autoplayTimeout: 4500, autoplayHoverPause: true, margin: 0, rtl: isRtl, responsive: { 0: { items: 1 }, 480: { items: 2 }, 768: { items: 3 }, 992: { items: 4 }, 1199: { items: 5 } } }); } /*-----------------------------------------------------------------------------------*/ /* Agent form's validation script for property detail page. /*-----------------------------------------------------------------------------------*/ function inspiryValidateForm(form) { var $form = $(form), submitButton = $form.find('.submit-button'), ajaxLoader = $form.find('.ajax-loader'), messageContainer = $form.find('.message-container'), errorContainer = $form.find(".error-container"), formOptions = { beforeSubmit: function () { submitButton.attr('disabled', 'disabled'); ajaxLoader.fadeIn('fast').css("display", "inline-block"); messageContainer.fadeOut('fast'); errorContainer.fadeOut('fast'); }, success: function (ajax_response, statusText, xhr, $form) { var response = $.parseJSON(ajax_response); ajaxLoader.fadeOut('fast'); submitButton.removeAttr('disabled'); if (response.success) { $form.resetForm(); messageContainer.html(response.message).fadeIn('fast'); // call reset function if it exists if (typeof inspiryResetReCAPTCHA == 'function') { inspiryResetReCAPTCHA(); } if (typeof agentData !== 'undefined') { setTimeout(function () { window.location.replace(agentData.redirectPageUrl); }, 1000); } else { setTimeout(function () { messageContainer.fadeOut('slow') }, 3000); } } else { errorContainer.html(response.message).fadeIn('fast'); } } }; $form.validate({ errorLabelContainer: errorContainer, submitHandler: function (form) { $(form).ajaxSubmit(formOptions); } }); } if (jQuery().validate && jQuery().ajaxSubmit) { if ($body.hasClass('single-property')) { var getAgentForms = $('.agent-form'); if (getAgentForms.length) { $.each(getAgentForms, function (i, form) { var id = $(form).attr("id"); inspiryValidateForm('#' + id); }); } } } /*-----------------------------------------------------------------------------------*/ /* Login Required Function /*-----------------------------------------------------------------------------------*/ $('body').on('click', '.inspiry_submit_login_required', function (e) { e.preventDefault(); $('.rh_login_modal_wrapper').css("display", "flex").hide().fadeIn(500); }); /*-----------------------------------------------------------------------------------*/ /* Report property modal script. /*-----------------------------------------------------------------------------------*/ if ($body.hasClass('single-property')) { const reportThisProperty = $( '.report-this-property' ); if ( reportThisProperty.length ) { reportThisProperty.on('click', null,function (event) { // Target model id let targetModelID = $(this).attr('href'); let reportPropertyModal = $(targetModelID); if (reportPropertyModal.length) { const reportPropertyForm = $("#report-property-form"), ajaxLoader = reportPropertyForm.find(".ajax-loader"), submitButton = reportPropertyForm.find("#btn-submit"), responseContainer = reportPropertyForm.find('#response-container'), errorContainer = reportPropertyForm.find('#error-container'), mainOptionsContainer = reportPropertyForm.find("#report-property-form-main-options"), childOptionsContainer = reportPropertyForm.find("#report-property-form-child-options"), customMessage = reportPropertyForm.find("#feedback-custom-message"), backButton = reportPropertyForm.find("#btn-back"); reportPropertyModal.css("display", "flex").hide().fadeIn(250).addClass("show"); reportPropertyModal.find(".btn-close").on('click', function (event) { reportPropertyModal.removeClass("show").fadeOut(250, function() { reportPropertyModal.removeClass("has-response"); responseContainer.addClass("hide"); responseContainer.find(".response-title").html(''); responseContainer.find(".response-text").html(''); backButton.trigger("click"); reportPropertyForm.resetForm(); }); event.preventDefault(); }); reportPropertyForm.find("#feedback-option-custom-parent-item").on('click', function (event) { mainOptionsContainer.addClass("hide"); childOptionsContainer.removeClass("hide") backButton.removeClass("hide"); errorContainer.hide(); }); reportPropertyForm.find("#feedback-child-option-custom-child-item").on('change', function (event) { if ($(this).is(":checked")) { customMessage.removeClass("hide"); } else { customMessage.addClass("hide").removeClass('error'); errorContainer.hide(); } }); backButton.on('click', function (event) { $(this).addClass("hide"); reportPropertyForm.find("input[type='radio']").prop("checked", false); reportPropertyForm.find("input[type='checkbox']").prop("checked", false); childOptionsContainer.addClass("hide"); mainOptionsContainer.removeClass("hide"); customMessage.addClass("hide").removeClass('error'); errorContainer.hide(); }); if (jQuery().validate && jQuery().ajaxSubmit) { reportPropertyForm.validate({ rules: { "feedback-option": { required: true }, "feedback-child-options[]": { required: "#feedback-option-custom-parent-item:checked" }, "feedback-custom-message": { required: "#feedback-child-option-custom-child-item:checked" }, }, errorLabelContainer: errorContainer, submitHandler: function (form) { reportPropertyForm.ajaxSubmit({ beforeSubmit: function () { ajaxLoader.fadeIn("fast").css("display", "inline-block"); submitButton.attr("disabled", "disabled"); backButton.addClass("hide"); responseContainer.addClass("hide"); reportPropertyModal.removeClass("has-response") errorContainer.fadeOut(250); }, success: function (ajax_response, statusText, xhr, form) { const response = $.parseJSON(ajax_response); ajaxLoader.fadeOut("fast"); submitButton.removeAttr("disabled"); backButton.removeClass("hide"); reportPropertyModal.addClass("has-response"); responseContainer.removeClass("hide").fadeIn("fast"); responseContainer.find(".response-title").html(response.title); responseContainer.find(".response-text").html(response.message); if (response.success) { reportPropertyForm.resetForm(); } } }); } }); } } event.preventDefault(); }); } } /*-----------------------------------------------------------------------------------*/ /* BootStrap Select /*-----------------------------------------------------------------------------------*/ window.inspirySelectPicker = function (id) { if (jQuery().selectpicker) { jQuery(id).selectpicker({ iconBase: 'fas', width: "100%", size: 5, tickIcon: 'fa-check', selectAllText: ' ', deselectAllText: '', }); $(".rh_sort_controls .inspiry_select_picker_trigger").click(function (e) { if (!$(this).hasClass('open')) { $(this).addClass('open'); e.stopPropagation(); } else { $(this).removeClass('open'); e.stopPropagation(); } }); } }; // TODO: This commented code should be removed if it is not needed. // if ($('.dsidx-resp-search-form')) { // $('.dsidx-resp-search-form select').addClass('inspiry_select_picker_trigger inspiry_bs_default_mod inspiry_bs_green show-tick'); // // if ($('.dsidx-sorting-control')) { // $('.dsidx-sorting-control select').addClass('inspiry_select_picker_trigger inspiry_bs_default_mod inspiry_bs_green show-tick'); // } // if ($('#dsidx-search-form-main')) { // $('#dsidx-search-form-main select').addClass('inspiry_select_picker_trigger inspiry_bs_default_mod inspiry_bs_green show-tick'); // } // if ($('#dsidx.dsidx-details')) { // $('.dsidx-contact-form-schedule-date-row select').addClass('inspiry_select_picker_trigger inspiry_bs_default_mod inspiry_bs_green show-tick'); // } // // inspirySelectPicker('body .inspiry_select_picker_trigger'); // } inspirySelectPicker('body .inspiry_select_picker_trigger'); inspirySelectPicker('body .widget_categories select'); inspirySelectPicker('body .widget_archive select'); // TODO: Remove this if it is not required. // inspirySelectPicker('.inspiry_select_picker_mod'); $(".inspiry_multi_select_picker_location").on('change', function (e, clickedIndex, isSelected, previousValue) { setTimeout(function () { $('.inspiry_multi_select_picker_location').selectpicker('refresh'); }, 500); }); $(".inspiry_bs_submit_location").on('changed.bs.select', function () { $('.inspiry_bs_submit_location').selectpicker('refresh'); }); $(".inspiry_select_picker_status").on('changed.bs.select', function () { $('.inspiry_select_picker_price').selectpicker('refresh'); }); $('.inspiry_select_picker_trigger').on('show.bs.select', function () { $(this).parents('.rh_prop_search__option').addClass('inspiry_bs_is_open') }); $('.inspiry_select_picker_trigger').on('hide.bs.select', function () { $(this).parents('.rh_prop_search__option').removeClass('inspiry_bs_is_open') }); var locationSuccessList = function (data, thisParent, refreshList = false) { if (true === refreshList) { thisParent.find('option').not(':selected, .none').remove().end(); } var getSelected = $(thisParent).val(); jQuery.each(data, function (index, text) { if (getSelected) { if (getSelected.indexOf(text[0]) < 0) { thisParent.append( $('') ); } } else { thisParent.append( $('') ); } }); thisParent.selectpicker('refresh'); $(parent).find('ul.dropdown-menu li:first-of-type a').focus(); $(parent).find('input').focus(); }; var loaderFadeIn = function () { $('.rh-location-ajax-loader').fadeIn('fast'); }; var loaderFadeOut = function () { $('.rh-location-ajax-loader').fadeOut('fast'); }; var rhTriggerAjaxOnLoad = function (thisParent, fieldValue = '') { $.ajax({ url: localizeSelect.ajax_url, dataType: 'json', delay: 250, // delay in ms while typing when to perform a AJAX search data: { action: 'inspiry_get_location_options', // AJAX action for admin-ajax.php query: fieldValue, // TODO: review the commented code below and remove if it is not required. // hideemptyfields: localizeSelect.hide_empty_locations, // sortplpha: localizeSelect.sort_location, }, beforeSend: loaderFadeIn(), success: function (data) { loaderFadeOut(); locationSuccessList(data, thisParent, true); } }); }; var rhTriggerAjaxOnScroll = function (thisParent, farmControl, fieldValue = '') { var paged = 2; farmControl.on('keyup', function (e) { paged = 2; fieldValue = $(this).val(); }); $('div.inspiry_ajax_location_field div.inner').on('scroll', function () { var thisInner = $(this); var thisInnerHeight = thisInner.innerHeight(); var getScrollIndex = thisInner.scrollTop() + thisInnerHeight; if (getScrollIndex >= $(this)[0].scrollHeight) { $.ajax({ url: localizeSelect.ajax_url, dataType: 'json', delay: 250, // delay in ms while typing when to perform a AJAX search data: { action: 'inspiry_get_location_options', // AJAX action for admin-ajax.php query: fieldValue, page: paged, // TODO: review the commented code below and remove if it is not required. // hideemptyfields: localizeSelect.hide_empty_locations, // sortplpha: localizeSelect.sort_location, }, beforeSend: loaderFadeIn(), success: function (data) { loaderFadeOut(); if (!$.trim(data)) { $('.rh-location-ajax-loader').fadeTo("fast", 0); } paged++; locationSuccessList(data, thisParent, false); } }); } }); }; var inspiryAjaxSelect = function (parent, id) { var farmControl = $(parent).find('.form-control'); var thisParent = $(id); rhTriggerAjaxOnScroll(thisParent, farmControl); rhTriggerAjaxOnLoad(thisParent); farmControl.on('keyup', function (e) { var fieldValue = $(this).val(); fieldValue = fieldValue.trim(); var wordcounts = jQuery.trim(fieldValue).length; // TODO: review the commented code below and remove if it is not required. // rhTriggerAjaxLoadMore(thisParent,fieldValue); $('.rh-location-ajax-loader').fadeTo("fast", 1); if (wordcounts > 0) { $.ajax({ url: localizeSelect.ajax_url, dataType: 'json', delay: 250, // delay in ms while typing when to perform a AJAX search data: { action: 'inspiry_get_location_options', // AJAX action for admin-ajax.php query: fieldValue, // TODO: review the commented code below and remove if it is not required. // hideemptyfields: localizeSelect.hide_empty_locations, // sortplpha: localizeSelect.sort_location, }, beforeSend: loaderFadeIn(), success: function (data) { loaderFadeOut(); thisParent.find('option').not(':selected, .none').remove().end(); // TODO: review the commented code below and remove if it is not required. // var options = []; if (fieldValue && data) { locationSuccessList(data, thisParent); } else { thisParent.find('option').not(':selected, .none').remove().end(); thisParent.selectpicker('refresh'); $(parent).find('ul.dropdown-menu li:first-of-type a').focus(); $(parent).find('input').focus(); } }, }); // TODO: review the commented code below and remove if it is not required. // rhTriggerAjaxLoadMore(thisParent,fieldValue); } else { rhTriggerAjaxOnLoad(thisParent); } }); }; inspiryAjaxSelect('.inspiry_ajax_location_wrapper', 'select.inspiry_ajax_location_field'); // Show on document ready to avoid glitching screen $('.rhea_long_screen_header_temp').removeClass('rhea-hide-before-load'); $('.rh_apply_sticky_wrapper_footer').removeClass('rhea-hide-before-load'); $('.rh-custom-search-form-wrapper').removeClass('rhea-hide-before-load'); $('.ere-custom-search-form-wrapper').removeClass('rhea-hide-before-load'); $('div').removeClass('rh-hide-before-ready'); }); //Remove class that hide elements before load to avoid glitching screen $(window).on('load',function () { $('div').removeClass('rh-hide-before-load'); }); window.rhUltraTooltip = function(selector) { $(selector).tooltip({ classes: { "ui-tooltip": "rh-ultra-tooltip" }, position: { my: "center bottom-10", at: "center top", using: function( position, feedback ) { $( this ).css( position ); $( "