const WIDGET_AUTOCOMPLETE_INPUT_ID='buyside-widget-containerinputId' var buyside_widget_settings = {}; buyside_widget_settings.form_url = ''; buyside_widget_settings.states_allowed = ''; buyside_widget_settings.autocompleteurl = "https://api.bridge.percyai.io/autocomplete-all"; buyside_widget_settings.api_key = 'szhmqJlOxa3bnyQYH3oLA8gSeXRhrJ6e3RY8DRBb'; buyside_widget_settings.keyvalidateurl = '//api.buyermls.com/widget/verify-json?key='; buyside_widget_settings.style_tag = document.createElement('style'); buyside_widget_settings.style_tag.type = 'text/css'; buyside_widget_settings.style_tag.appendChild(document.createTextNode(buyside_widget_settings_stylesheet())); (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(buyside_widget_settings.style_tag); buyside_widget_settings.waiting = false; /* sample config - key: "", widgetSource: "", widgetContainerId: "widget-container", inputPlaceHolder: "Enter your address", invalidMessage: "Address not found", inputClass: "", customSubmitBtn: "", submitBtnClass: "", submitSelector: "btn-submit", submitBtnValue: "Submit", openNewWindow: false, customCssLink: '', userName: '', contactID: '', contactFirstName: '', contactLastName: '', contactEmail: '', defaultLabel: { active: true, label: 'Address to search' }, */ function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } function buyside_widget(config) { var currentFocus; var arr = []; if (typeof buyside_widget_settings.containerId != "undefined") return; create_input_fields(config); buyside_widget_settings.config = config; // store called config buyside_widget_settings.containerId = config.widgetContainerId; buyside_widget_settings.inputId = config.widgetInputId; if ('submitSelector' in config) buyside_widget_settings.buttonId = config.submitSelector; buyside_widget_settings.widgetSource = config.widgetSource; buyside_widget_settings.errorMsg = ('invalidMessage' in config) ? config.invalidMessage : ''; buyside_widget_settings.userName = ('userName' in config) ? config.userName : ''; buyside_widget_settings.openNewWindow = ('openNewWindow' in config) ? config.openNewWindow : false; if (buyside_widget_settings.openNewWindow != '1' && buyside_widget_settings.openNewWindow != 'test' && buyside_widget_settings.openNewWindow != 'call' && buyside_widget_settings.openNewWindow != true) buyside_widget_settings.openNewWindow = false; buyside_widget_settings.form_url = ('form_url' in config) ? config.form_url : ''; buyside_widget_settings.states_allowed = ('states_allowed' in config) ? config.states_allowed : ''; buyside_widget_settings.inp = document.getElementById(buyside_widget_settings.inputId); buyside_widget_settings.btn = document.getElementById(buyside_widget_settings.buttonId); // store stuff that will be passed on redirect buyside_widget_settings.contactID = ('contactID' in config) ? config.contactID : ''; buyside_widget_settings.contactFirstName = ('contactFirstName' in config) ? config.contactFirstName : ''; buyside_widget_settings.contactLastName = ('contactLastName' in config) ? config.contactLastName : ''; buyside_widget_settings.contactEmail = ('contactEmail' in config) ? config.contactEmail : ''; // // adjust to stage as needed // if ('useStage' in config) { if (config.useStage) { buyside_widget_settings.keyvalidateurl = buyside_widget_settings.keyvalidateurl.replace('//api.', '//stage.'); } } if ('api_prefix' in config) { buyside_widget_settings.api_prefix = config.api_prefix; buyside_widget_settings.autocompleteurl = config.api_prefix + '/properties/autocomplete_all'; buyside_widget_settings.autocompleteurl = buyside_widget_settings.autocompleteurl.replace('staging.api', 'dev.api'); } if ('api_key' in config) { buyside_widget_settings.api_key = config.api_key; } // // validate the key // var xmlHttp = new XMLHttpRequest(); xmlHttp.onreadystatechange = function() { if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { var x = JSON.parse(xmlHttp.responseText); if (x.status == 'OK') { // don't wipe config settings if they are present if (buyside_widget_settings.form_url == ''){ if (config.useStage){ let regexHttp = new RegExp("^(http|https)://", "i"); let url = x.url; let dotsToHyphens = url.split('.').join('-'); let stageUrl2 = dotsToHyphens.replace(regexHttp,'http://stage-') buyside_widget_settings.form_url = `${stageUrl2}.hvs.buyermls.com`; }else{ buyside_widget_settings.form_url = x.url; } } if (buyside_widget_settings.states_allowed == '') buyside_widget_settings.states_allowed = x.states_allowed; } else { alert("Invalid Buyside Widget Key"); return (false); } } } xmlHttp.open("GET", buyside_widget_settings.keyvalidateurl + config.key, true); xmlHttp.send(null); // // add custom css if provided // if ('customCssLink' in config) { var x = document.createElement('link'); x.setAttribute("type","text/css"); x.setAttribute("rel","stylesheet"); x.setAttribute("href", config.customCssLink); (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(x); } // // add event listeners for input, keydown, and click // const debounceInput = debounce(function(event) { userinput() }, 1000); buyside_widget_settings.inp.addEventListener("input", debounceInput); buyside_widget_settings.inp.addEventListener("keydown", keydown); if (buyside_widget_settings.btn) buyside_widget_settings.btn.addEventListener("click", buttonclick); var buyside_widget_all_states_allowed = false; function getInputValue() { return document.getElementById(buyside_widget_settings.inputId).value; } function positionDropdownListBasedOnInputPosition() { const inputElement = document.getElementsByClassName('buyside_widget_input_class')[0]; const position = inputElement.getBoundingClientRect(); document.getElementById(getAutocompleteContainerId()).style.top = (position.height + 2) + 'px'; document.getElementById(getAutocompleteContainerId()).style.left = 0; } function positionLoader() { const inputElement = document.getElementsByClassName('buyside_widget_input_class')[0]; const loaderElement = document.getElementById('loader'); const position = inputElement.getBoundingClientRect(); loaderElement.style.top = ((loaderElement.getBoundingClientRect().height / 2) - (position.height / 2)) + 'px'; loaderElement.style.right = 5 + 'px'; } function activateLoader() { positionLoader(); const loaderElement = document.getElementById('loader'); loaderElement.classList.add('activate-loader'); } function closeLoader() { const loaderElement = document.getElementById('loader'); loaderElement.classList.remove('activate-loader'); } async function fetchAddressAutocomplete(inputValue) { let url = `${buyside_widget_settings.autocompleteurl}?query=${encodeURIComponent(inputValue)}`; if (!buyside_widget_all_states_allowed) { url += `&state_filters=${buyside_widget_settings.states_allowed}`; } url += "&limit=30"; buyside_widget_all_states_allowed = false; buyside_widget_settings.waiting = true; try { const response = await fetch(url, { headers: { "x-api-key": buyside_widget_settings.api_key } }); const json = await response.json(); const arr = parse_autocomplete_results(json); closeLoader(); const a = create_autocomplete_container(arr.length); positionDropdownListBasedOnInputPosition(); for (let i = 0; i < arr.length; i++) { add_address_to_list(a, arr[i], inputValue); } } catch (error) { console.error(error); closeLoader(); } finally { buyside_widget_settings.waiting = false; } } async function userinput() { const val = getInputValue(); closeAllLists(); if (!val) { closeLoader(); return false; } currentFocus = -1; if (val.length > 3) { activateLoader(); await fetchAddressAutocomplete(val) } } function keydown(e) { var x = document.getElementById(getAutocompleteContainerId()); if (x) x = x.getElementsByTagName("div"); if (e.keyCode == 40) { currentFocus++; addActive(x); } else if (e.keyCode == 38) { //up currentFocus--; addActive(x); } else if (e.keyCode == 13) { e.preventDefault(); var a = simpleparseaddr(document.getElementById(buyside_widget_settings.inputId).value); if (currentFocus == -1 && a != "") { x[0].getElementsByTagName("input")[0].value = a; x[0].click(); } else { if (currentFocus == -1) currentFocus = 0; // use first entry in list if (currentFocus > -1) { if (x) x[currentFocus].click(); else { // user has pressed enter with a non-validated address buyside_widget_all_states_allowed = true; userinput(); } } } } } function buttonclick(e) { e.preventDefault(); e.stopPropagation(); var x = document.getElementById(getAutocompleteContainerId()); if (x) x = x.getElementsByTagName("div"); if (x) { // look for an entry that's marked active for (i = 0; i < x.length; i++) { if (x[i].classList.contains("buyside_widget_autocomplete-active")) { x[i].click(); return; } } // just click the first entry x[0].click(); } else { // user has clicked button with a non-validated address buyside_widget_all_states_allowed = true; userinput(); } } function add_address_to_list(a, arri, val) { var display_address = arri.display_address; // display not found message if (display_address.includes('##ERROR##')) { b = document.createElement("DIV"); if (buyside_widget_settings.errorMsg != '') b.innerHTML = "" + buyside_widget_settings.errorMsg + ""; else b.innerHTML = "" + 'No available results' + ""; b.className = 'buyside_widget_autocomplete_item buyside_widget_autocomplete_error_message'; a.appendChild(b); } // display start of apartment cluster else if (arri.startsub) { b = document.createElement("DIV"); b.innerHTML = "" + display_address.substr(0, val.length) + ""; b.innerHTML += display_address.substr(val.length); b.innerHTML += ''; b.className = 'buyside_widget_autocomplete_item buyside_widget_autocomplete_startsub'; a.appendChild(b); b.addEventListener("click", function(e) { var h = e.currentTarget.innerHTML.match(/\#\#\#(\d+)\#\#\#/); if (h.length > 1) { hash = h[1]; clusterclick(hash); e.stopPropagation(); } }); } // display others else { b = document.createElement("DIV"); b.innerHTML = "" + display_address.substr(0, val.length) + ""; b.innerHTML += display_address.substr(val.length); b.innerHTML += ''; b.innerHTML += ''; b.innerHTML += ''; b.className = 'buyside_widget_autocomplete_item'; if (arri.hash) b.className = 'buyside_widget_autocomplete_item buyside_widget_autocomplete_hidden bswhash' + arri.hash; b.addEventListener("click", function(e) { // // redirect to form_url for the broker // var url_address = this.getElementsByTagName("input")[0].value; var display_address = this.getElementsByTagName("input")[1].value; var latlng = this.getElementsByTagName("input")[2].value; // strip any zipcode extension url_address = url_address.trim(); url_address = url_address.replace(/\-\d\d\d\d$/, ''); // show the address that was clicked buyside_widget_settings.inp.value = display_address; send_to_hvs(url_address, latlng); }); a.appendChild(b); } } function addActive(x) { if (!x) return false; removeActive(x); if (currentFocus >= x.length) currentFocus = 0; if (currentFocus < 0) currentFocus = (x.length - 1); x[currentFocus].classList.add("buyside_widget_autocomplete-active"); } function removeActive(x) { for (var i = 0; i < x.length; i++) { x[i].classList.remove("buyside_widget_autocomplete-active"); } } // show/hide hidden apartments when a cluster listing is clicked function clusterclick(hash) { var x = document.getElementsByClassName("bswhash" + hash); for (i = 0; i < x.length; i++) { var newclass = 'buyside_widget_autocomplete_item buyside_widget_autocomplete_hidden bswhash' + hash; if (x[i].className.indexOf('buyside_widget_autocomplete_hidden') >= 0) newclass = 'buyside_widget_autocomplete_item bswhash' + hash; x[i].className = newclass; x[i].style.paddingLeft = "20px"; } } // poplulate the widget container function create_input_fields(config) { // return if container has already been created if ('inputId' in buyside_widget_settings) { config.widgetInputId = buyside_widget_settings.inputId; return; } if (!('widgetInputId' in config)) config.widgetInputId = ''; if (!('widgetContainerId' in config)) config.widgetContainerId = ''; if (config.widgetInputId != '' && config.widgetContainerId == '') return; // customer has specified the input field only // set some defaults if (!('inputPlaceHolder' in config) || config.inputPlaceHolder == '') config.inputPlaceHolder = 'Enter your address'; if (!('inputClass' in config) || config.inputClass == '') config.inputClass = ''; if (!('customSubmitBtn' in config) || config.customSubmitBtn == '') config.customSubmitBtn = ''; if (!('submitBtnClass' in config) || config.submitBtnClass == '') config.submitBtnClass = ''; if (!('submitSelector' in config) || config.submitSelector == '') config.submitSelector = 'buyside_widget_submit_id'; if (!('submitBtnValue' in config) || config.submitBtnValue == '') config.submitBtnValue = 'Get Report'; if ('defaultLabel' in config){ if (config.defaultLabel.active == true){ document.getElementById('buyside-widget-container').innerHTML += ""; } else { config.defaultLabel = 'Address to search'; document.getElementById('buyside-widget-container').innerHTML += ""; } } // create the input field and the button x = document.createElement("DIV"); config.widgetInputId = config.widgetContainerId + 'inputId'; if (config.customSubmitBtn != '') x.innerHTML = config.customSubmitBtn; else { var cl = ''; if (config.submitBtnClass != '') cl = ' class="' + config.submitBtnClass + '" '; x.innerHTML = ''; } x.innerHTML += '