var locationSet = 0; var addressLocationInit = false; var placeSearch, autocompleteAddress; var componentForm = { street_number: 'short_name', route: 'long_name', locality: 'long_name', administrative_area_level_1: 'short_name', country: 'long_name', postal_code: 'short_name' }; // Ensure readable text/background regardless of dark mode or autofill (function ensureContrastStyleInjected(){ if (window.__gplacesContrastCSSInjected) { return; } window.__gplacesContrastCSSInjected = true; try { var css = "\n/* Force visible text for Google Places inputs (light scheme) */\n#autocompleteAddress,\ninput#autocompleteAddress,\ninput.pac-target-input {\n background-color: #ffffff !important;\n color: #111111 !important;\n -webkit-text-fill-color: #111111 !important;\n caret-color: #111111 !important;\n color-scheme: light;\n}\n#autocompleteAddress::placeholder,\ninput.pac-target-input::placeholder {\n color: #6c757d !important;\n opacity: 1;\n}\n/* New Places Web Component host created by our code */\n[id$='-pac'] {\n --gmpx-color-surface: #ffffff;\n --gmpx-color-on-surface: #111111;\n color-scheme: light;\n}\n/* Google Places dropdown (legacy) */\n.pac-container {\n background-color: #ffffff !important;\n color: #111111 !important;\n border-color: rgba(0,0,0,0.15) !important;\n}\n.pac-item, .pac-item-query {\n color: #111111 !important;\n}\n.pac-item:hover {\n background-color: #f1f3f5 !important;\n}\n/* Autofill cases */\ninput#autocompleteAddress:-webkit-autofill,\ninput.pac-target-input:-webkit-autofill {\n -webkit-text-fill-color: #111111 !important;\n -webkit-box-shadow: 0 0 0px 1000px #ffffff inset !important;\n}\n"; var style = document.createElement('style'); style.setAttribute('data-gplaces-contrast', '1'); style.textContent = css; (document.head || document.documentElement).appendChild(style); } catch (e) {} })(); var autoCompleteAddressListener = null; var autocompleteAddressInputTimeout = null; var pacElementAddress = null; var pendingGeoData = null; function createOrAttachPlaceAutocomplete(inputId, onPlaceChange) { var input = document.getElementById(inputId); if (!input || !window.google || !google.maps || !google.maps.places || !google.maps.places.PlaceAutocompleteElement) { return null; } // Always use the new PlaceAutocompleteElement var existing = document.getElementById(inputId + '-pac'); if (existing) { existing.remove(); } var pac = new google.maps.places.PlaceAutocompleteElement(); pac.id = inputId + '-pac'; pac.setAttribute('for', inputId); try { pac.types = ['address']; } catch (e) {} try { pac.fields = ['addressComponents', 'location']; } catch (e) {} // Hide the original input to prevent duplicate UI and copy sizing styles try { input.setAttribute('aria-hidden', 'true'); input.style.display = 'none'; var cs = window.getComputedStyle(input); pac.style.display = 'block'; pac.style.width = '100%'; pac.style.boxSizing = 'border-box'; if (cs && cs.height) { pac.style.height = cs.height; } if (cs && cs.fontSize) { pac.style.fontSize = cs.fontSize; } if (cs && cs.padding) { pac.style.padding = cs.padding; } if (cs && cs.borderRadius) { pac.style.borderRadius = cs.borderRadius; } if (cs && cs.border) { pac.style.border = cs.border; } if (input.className) { pac.className = input.className; } // Force readable colors in dark mode pac.style.backgroundColor = '#ffffff'; pac.style.color = '#111111'; try { pac.style.setProperty('color-scheme', 'light'); } catch(e) {} try { pac.style.setProperty('--gmpx-color-surface', '#ffffff'); } catch(e) {} try { pac.style.setProperty('--gmpx-color-on-surface', '#111111'); } catch(e) {} // Suppress gaudy blue outline/glow on focus pac.style.outline = 'none'; pac.style.boxShadow = 'none'; pac.addEventListener('focus', function(){ this.style.outline='none'; this.style.boxShadow='none'; }); pac.addEventListener('focusin', function(){ this.style.outline='none'; this.style.boxShadow='none'; }); pac.addEventListener('blur', function(){ this.style.outline='none'; this.style.boxShadow='none'; }); } catch (e) {} // Insert right after the input so it can attach input.insertAdjacentElement('afterend', pac); pac.addEventListener('gmp-select', async ({ placePrediction }) => { const place = placePrediction.toPlace(); await place.fetchFields({ fields: ['addressComponents','formattedAddress','location'] }); if (typeof onPlaceChange === 'function') { onPlaceChange(place); } }); return { mode: 'element', control: pac }; } async function checkPlacesEnabled({ apiKey }) { const url = 'https://places.googleapis.com/v1/places:autocomplete'; const body = { input: "a" }; // minimal probe const headers = { 'Content-Type': 'application/json', 'X-Goog-Api-Key': apiKey, // minimal field mask to keep payload tiny 'X-Goog-FieldMask': 'suggestions.placePrediction.placeId' }; const resp = await fetch(url, { method: 'POST', headers, body: JSON.stringify(body) }); if (!resp.ok) { const data = await resp.json().catch(() => ({})); const msg = data?.error?.message || `HTTP ${resp.status}`; throw new Error(msg); } } function initAutocomplete() { var setup = createOrAttachPlaceAutocomplete('autocompleteAddress', fillInAddress); if (setup && setup.mode === 'element') { pacElementAddress = setup.control; // Apply pending geolocation bias if available and Google Maps is ready if (pendingGeoData && window.google && google.maps && google.maps.Circle) { try { var circle = new google.maps.Circle({ center: { lat: pendingGeoData.lat, lng: pendingGeoData.lng }, radius: pendingGeoData.accuracy }); pacElementAddress.locationBias = circle.getBounds(); } catch (e) {} } } } // [START region_fillform] function fillInAddress(data) { // Prefer provided place (from onPlaceChange) when available; fallback to current controls var place = (data && (data.address_components || data.addressComponents)) ? data : null; if (!place) { if (pacElementAddress && pacElementAddress.value) { place = pacElementAddress.value; } else if (autocompleteAddress && typeof autocompleteAddress.getPlace === 'function') { place = autocompleteAddress.getPlace(); } } $('#contactFormFieldset #address').show(); $('#shippingForm #address').show(); $('#shippingAddressForm #address').show(); $('#newShippingAddressForm #address').show(); $('.editShippingTable').show(); combineAddress(); setTimeout(function(){ combineAddress(); }, 100); for (var component in componentForm) { document.getElementById(component).value = ''; document.getElementById(component).disabled = false; } if (!place || !(place.address_components || place.addressComponents)) { return; } // Get each component of the address from the place details // and fill the corresponding field on the form. var addrComps = place && (place.address_components || place.addressComponents) || []; for (var i = 0; i < addrComps.length; i++) { var comp = addrComps[i]; var addressType = comp.types && comp.types[0]; if (componentForm[addressType]) { var val = ''; if (comp.hasOwnProperty(componentForm[addressType])) { val = comp[componentForm[addressType]]; // legacy short_name/long_name } else if (componentForm[addressType] === 'short_name' && (comp.short_name || comp.shortText)) { val = comp.short_name || comp.shortText; } else if (componentForm[addressType] === 'long_name' && (comp.long_name || comp.longText)) { val = comp.long_name || comp.longText; } else if (comp.shortText || comp.longText) { val = comp.shortText || comp.longText; } var targetEl = document.getElementById(addressType); if (targetEl) { targetEl.value = val; } if (addressType === 'administrative_area_level_1') { // Support either a select with id=administrative_area_level_1 or a legacy select#state (contact form) var stateSelect = document.getElementById('administrative_area_level_1'); if (!stateSelect || stateSelect.tagName !== 'SELECT') { stateSelect = document.getElementById('state'); } if (stateSelect && stateSelect.tagName === 'SELECT') { var $sel = $(stateSelect); if ($sel.find('option[value="' + val + '"]').length === 0) { $sel.append(''); } $sel.val(val); } } } } $('#country').change(); } // [END region_fillform] // [START region_geolocation] // Bias the autocompleteAddress object to the user's geographical location, // as supplied by the browser's 'navigator.geolocation' object. function geolocate() { if (typeof isSecureContext == 'undefined' || !isSecureContext) { return false; } if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(success,error,{enableHighAccuracy:true, timeout:10000}); // This loads the location once. locationSet = 1; } } function success(position) { var lat = position.coords.latitude; var lng = position.coords.longitude; var accuracy = position.coords.accuracy; pendingGeoData = { lat: lat, lng: lng, accuracy: accuracy }; // Attach autocomplete if not already attached initAutocomplete(); // If Google Maps JS isn't loaded yet, defer applying location bias if (!window.google || !google.maps || !google.maps.Circle) { return; } try { var circle = new google.maps.Circle({ center: { lat: lat, lng: lng }, radius: accuracy }); if (pacElementAddress) { try { pacElementAddress.locationBias = circle.getBounds(); } catch (e) {} } } catch (e) {} } function error() { geolocation = null; } // [END region_geolocation] function combineAddress(){ $('#contactFormFieldset #address1').val( $('#street_number').val() + " " + $('#route').val()); $('#shippingForm #address1').val( $('#street_number').val() + " " + $('#route').val()); $('#shippingAddressForm #address1').val( $('#street_number').val() + " " + $('#route').val()); $('#newShippingAddressForm #address1').val( $('#street_number').val() + " " + $('#route').val()); // $('#address1').val( $('#street_number').val() + " " + $('#route').val()); } // Safe DOM ready helper that works with or without jQuery function domReady(fn) { if (window.jQuery && jQuery.fn && (jQuery.fn.ready || jQuery.fn.on)) { // Prefer jQuery's shorthand if available jQuery(fn); return; } if (document.readyState === 'complete' || document.readyState === 'interactive') { // DOM is already ready setTimeout(fn, 0); } else { document.addEventListener('DOMContentLoaded', fn, { once: true }); } } domReady(function() { if(locationSet === 0){ geolocate(); } $('#autocompleteAddress').on('keyup paste click', function(){ if(locationSet === 0){ geolocate(); } }); // This example displays an address form, using the autocompleteAddress feature // of the Google Places API to help users fill in the information. $('#street_number, #route').on('change keyup paste click', function(){ combineAddress(); }); // Ensure PAC is attached once on load try { initAutocomplete(); } catch (e) {} $('#autocompleteAddress').keyup(function() { if (autocompleteAddressInputTimeout !== null) { clearTimeout(autocompleteAddressInputTimeout); } autocompleteAddressInputTimeout = setTimeout(initAutocomplete, 300); }); }); // Below is a hack for styling the Google Places input element. // Guard against double execution when this script is included multiple times. (function(){ if (Element.prototype.__placesAttachShadowPatched) { return; } Element.prototype.__placesAttachShadowPatched = true; const originalAttachShadow = Element.prototype.attachShadow; Element.prototype.attachShadow = function(init){ // Check if we are the new Google places autocomplete element... if (this.localName === 'gmp-place-autocomplete' || this.localName === 'gmpx-place-autocomplete') { // Force mode:'open' so we can inject styles into the shadow DOM. const shadow = originalAttachShadow.call(this, { ...init, mode: 'open' }); const style = document.createElement('style'); // Apply our own styles to the shadow DOM. style.textContent = `[part=\"leading-icon\"],[part=\"trailing-icon\"],[part=\"clear-button\"],.clear-button,.autocomplete-icon, button.clear-button,.focus-ring{display:none!important;} .clear-button{width:24px!important;height:24px!important;min-width:24px!important;min-height:24px!important;padding:0!important;line-height:24px!important;margin:2px!important;box-shadow:none!important;} .clear-button svg{width:16px!important;height:16px!important;}`; shadow.appendChild(style); return shadow; } // For other elements, proceed with the original behaviour of attachShadow(). return originalAttachShadow.call(this, init); }; // If a Places element was already created before we patched attachShadow, // inject the same style into its existing shadow root. try { var nodes = document.querySelectorAll('gmp-place-autocomplete, gmpx-place-autocomplete'); nodes.forEach(function(el){ if (el.shadowRoot && !el.shadowRoot.__placesStylePatched) { var style = document.createElement('style'); style.textContent = `[part=\"leading-icon\"],[part=\"trailing-icon\"],[part=\"clear-button\"],.clear-button,.focus-ring{display:none!important;} .clear-button{width:24px!important;height:24px!important;min-width:24px!important;min-height:24px!important;padding:0!important;line-height:24px!important;margin:2px!important;box-shadow:none!important;} .clear-button svg{width:16px!important;height:16px!important;}`; el.shadowRoot.appendChild(style); el.shadowRoot.__placesStylePatched = true; } }); } catch(e) {} })(); // Expose key functions globally for inline scripts/templates expecting them if (typeof window !== 'undefined') { try { window.geolocate = window.geolocate || geolocate; } catch(e) {} try { window.initAutocomplete = window.initAutocomplete || initAutocomplete; } catch(e) {} try { window.combineAddress = window.combineAddress || combineAddress; } catch(e) {} }