diff --git a/includes/class.rest-api.php b/includes/class.rest-api.php index d924f0b..c43c96a 100644 --- a/includes/class.rest-api.php +++ b/includes/class.rest-api.php @@ -325,6 +325,12 @@ protected function registerRoutes() 'callback' => array($this, 'geocodeCache'), 'useCompressedPathVariable' => true )); + + $this->registerRoute('/query-nominatim', array( + 'methods' => array('GET'), + 'callback' => array($this, 'queryNominatim'), + 'useCompressedPathVariable' => true + )); $this->registerRoute('/decompress', array( 'methods' => array('GET'), @@ -1088,6 +1094,30 @@ public function geocodeCache($request) return $record; } + + public function queryNominatim(){ + $params = $this->getRequestParameters(); + $cache = new NominatimGeocodeCache(); + + if(!empty($params) && !empty($params['data'])){ + $query = (object) $params['data']; + $results = $cache->queryNominatimProxy($query); + if(!empty($results)){ + if(!empty($query->_query) && empty($results->error)){ + /* Cache key passed */ + try{ + $cache->set(sanitize_text_field($query->_query), $results); + } catch (\Exception $ex){ + + } catch (\Error $err){ + + } + } + return $results; + } + } + return array(); + } public function decompress($request) { diff --git a/includes/open-layers/class.nominatim-geocode-cache.php b/includes/open-layers/class.nominatim-geocode-cache.php index 5efd6e8..c6df27b 100644 --- a/includes/open-layers/class.nominatim-geocode-cache.php +++ b/includes/open-layers/class.nominatim-geocode-cache.php @@ -135,6 +135,73 @@ public function clear() $stmt = $wpdb->query("TRUNCATE TABLE {$this->table}"); } + /** + * Queries the nominatim directly, as if it was a client side request + * + * This offloads the process from the client, adding security and reliability to the request + * + * Ideally this would be in some nominatim shared class, but this was a later addition to mitigate cache poisoning and + * as such needs to exist here fro backwards compat, and long term reuse. + * + * We'll likely streamline this down the road into one geocoder system or something + * + * @param object $query + * + * @return array + */ + public function queryNominatimProxy($query){ + if(!empty($query) && !empty($query->q)){ + $args = array( + 'q' => $query->q, + 'format' => !empty($query->format) ? $query->format : 'json' + ); + + if(!empty($query->countrycodes)){ + $args['countrycodes'] = $query->countrycodes; + } + + $endpoint = 'https://nominatim.openstreetmap.org/search'; + + $url = add_query_arg($args, $endpoint); + + $siteUrl = get_site_url(); + $response = wp_remote_get($url, + array( + 'headers' => array( + 'User-Agent' => 'WPGoMapsGeocoder (' . $siteUrl . ')', + 'Referer' => $siteUrl + ), + 'timeout' => 10 + ) + ); + + if(!is_wp_error($response)){ + try { + $response = wp_remote_retrieve_body($response); + $json = json_decode($response); + + if(!empty($json)){ + return $json; + } else { + /* Check if the user has been blocked by OSM/Nominatim */ + if(strpos($response, 'Access blocked') !== FALSE){ + $notice = strip_tags($response); + $notice = str_replace("Access blocked", "", $notice); + return (object) array( + 'error' => $notice + ); + } + } + } catch (\Exception $ex){ + return false; + } catch (\Error $err){ + return false; + } + } + } + return false; + } + public function sanitizeDataRecursive($data){ if(!is_array($data) && !is_object($data)){ return sanitize_text_field($data); @@ -167,14 +234,16 @@ public function sanitizeDataRecursive($data){ */ function query_nominatim_cache() { - $cache = new NominatimGeocodeCache(); - $record = $cache->get(sanitize_text_field($_GET['query'])); + return; + + // $cache = new NominatimGeocodeCache(); + // $record = $cache->get(sanitize_text_field($_GET['query'])); - if(!$record) - $record = array(); + // if(!$record) + // $record = array(); - wp_send_json($record); - exit; + // wp_send_json($record); + // exit; } /** @@ -183,25 +252,27 @@ function query_nominatim_cache() */ function store_nominatim_cache() { - $cache = new NominatimGeocodeCache(); - try{ - $cache->set(sanitize_text_field($_POST['query']), $_POST['response']); + return; + + // $cache = new NominatimGeocodeCache(); + // try{ + // $cache->set(sanitize_text_field($_POST['query']), $_POST['response']); - wp_send_json(array( - 'success' => 1 - )); - } catch (\Exception $ex){ - wp_send_json(array( - 'success' => 0, - 'message' => $ex->getMessage() - )); - } catch (\Error $err){ - wp_send_json(array( - 'success' => 0, - 'message' => $err->getMessage() - )); - } - exit; + // wp_send_json(array( + // 'success' => 1 + // )); + // } catch (\Exception $ex){ + // wp_send_json(array( + // 'success' => 0, + // 'message' => $ex->getMessage() + // )); + // } catch (\Error $err){ + // wp_send_json(array( + // 'success' => 0, + // 'message' => $err->getMessage() + // )); + // } + // exit; } /** @@ -226,10 +297,11 @@ function clear_nominatim_cache() exit; } -add_action('wp_ajax_wpgmza_query_nominatim_cache', 'WPGMZA\\query_nominatim_cache'); -add_action('wp_ajax_nopriv_wpgmza_query_nominatim_cache', 'WPGMZA\\query_nominatim_cache'); +/* Deprecated since 9.0.49 */ +// add_action('wp_ajax_wpgmza_query_nominatim_cache', 'WPGMZA\\query_nominatim_cache'); +// add_action('wp_ajax_nopriv_wpgmza_query_nominatim_cache', 'WPGMZA\\query_nominatim_cache'); -add_action('wp_ajax_wpgmza_store_nominatim_cache', 'WPGMZA\\store_nominatim_cache'); -add_action('wp_ajax_nopriv_wpgmza_store_nominatim_cache', 'WPGMZA\\store_nominatim_cache'); +// add_action('wp_ajax_wpgmza_store_nominatim_cache', 'WPGMZA\\store_nominatim_cache'); +// add_action('wp_ajax_nopriv_wpgmza_store_nominatim_cache', 'WPGMZA\\store_nominatim_cache'); add_action('wp_ajax_wpgmza_clear_nominatim_cache', 'WPGMZA\\clear_nominatim_cache'); diff --git a/js/v8/open-layers/ol-geocoder.js b/js/v8/open-layers/ol-geocoder.js index 885d5e7..89b8cf0 100644 --- a/js/v8/open-layers/ol-geocoder.js +++ b/js/v8/open-layers/ol-geocoder.js @@ -33,26 +33,15 @@ jQuery(function($) { query: JSON.stringify(query) }, success: function(response, xhr, status) { - // Legacy compatibility support - response.lng = response.lon; + if(response && response.lon){ + // Legacy compatibility support + response.lng = response.lon; + } callback(response); }, useCompressedPathVariable: true }); - - /*$.ajax(WPGMZA.ajaxurl, { - data: { - action: "wpgmza_query_nominatim_cache", - query: JSON.stringify(query) - }, - success: function(response, xhr, status) { - // Legacy compatibility support - response.lng = response.lon; - - callback(response); - } - });*/ } /** @@ -74,11 +63,26 @@ jQuery(function($) { } else if(options.country){ data.countrycodes = options.country; } - - $.ajax("https://nominatim.openstreetmap.org/search", { - data: data, + + if(options._query){ + data._query = options._query; + } + + WPGMZA.restAPI.call("/query-nominatim", { + data: { + data: data, + }, success: function(response, xhr, status) { - callback(response); + if(response && response.length){ + callback(response); + } else { + if(response && response.error){ + /* There may be an additional error in place */ + callback(response.error, WPGMZA.Geocoder.FAIL) + } else { + callback(null, WPGMZA.Geocoder.FAIL) + } + } }, error: function(response, xhr, status) { callback(null, WPGMZA.Geocoder.FAIL) @@ -89,21 +93,14 @@ jQuery(function($) { /** * @function cacheResponse * @access protected - * @summary Caches a response on the server, usually after it's been returned from Nominatim + * @summary Caches a response on the server, usually after it's been returned from Nominatim. Deprecated * @param {string} address The street address * @param {object|array} response The response to cache * @returns {void} */ WPGMZA.OLGeocoder.prototype.cacheResponse = function(query, response) { - $.ajax(WPGMZA.ajaxurl, { - data: { - action: "wpgmza_store_nominatim_cache", - query: JSON.stringify(query), - response: JSON.stringify(response) - }, - method: "POST" - }); + } /** @@ -231,11 +228,11 @@ jQuery(function($) { finish(response, WPGMZA.Geocoder.SUCCESS); return; } - - self.getResponseFromNominatim($.extend(options, {address: location}), function(response, status) { + + self.getResponseFromNominatim($.extend(options, {address: location, _query : JSON.stringify({location: location, options: options})}), function(response, status) { if(status == WPGMZA.Geocoder.FAIL) { - callback(null, WPGMZA.Geocoder.FAIL); + callback(typeof response === 'string' ? response : null, WPGMZA.Geocoder.FAIL); return; } @@ -246,8 +243,6 @@ jQuery(function($) { } finish(response, WPGMZA.Geocoder.SUCCESS); - - self.cacheResponse(query, response); }); }); } diff --git a/js/v8/store-locator.js b/js/v8/store-locator.js index 6d843dc..54a179b 100644 --- a/js/v8/store-locator.js +++ b/js/v8/store-locator.js @@ -300,12 +300,18 @@ jQuery(function($) { if(status == WPGMZA.Geocoder.SUCCESS) callback(results, status); else{ + let error = WPGMZA.localized_strings.address_not_found; + if(status == WPGMZA.Geocoder.FAIL && typeof results === 'string'){ + error = results; + } + if(WPGMZA.InternalEngine.isLegacy()){ - alert(WPGMZA.localized_strings.address_not_found); + alert(error); } else { - self.showError(WPGMZA.localized_strings.address_not_found); + self.showError(error); self.setVisualState(false); } + } }); diff --git a/js/v8/wp-google-maps.combined.js b/js/v8/wp-google-maps.combined.js index bb2ab28..233c623 100644 --- a/js/v8/wp-google-maps.combined.js +++ b/js/v8/wp-google-maps.combined.js @@ -13489,12 +13489,18 @@ jQuery(function($) { if(status == WPGMZA.Geocoder.SUCCESS) callback(results, status); else{ + let error = WPGMZA.localized_strings.address_not_found; + if(status == WPGMZA.Geocoder.FAIL && typeof results === 'string'){ + error = results; + } + if(WPGMZA.InternalEngine.isLegacy()){ - alert(WPGMZA.localized_strings.address_not_found); + alert(error); } else { - self.showError(WPGMZA.localized_strings.address_not_found); + self.showError(error); self.setVisualState(false); } + } }); @@ -20946,26 +20952,15 @@ jQuery(function($) { query: JSON.stringify(query) }, success: function(response, xhr, status) { - // Legacy compatibility support - response.lng = response.lon; + if(response && response.lon){ + // Legacy compatibility support + response.lng = response.lon; + } callback(response); }, useCompressedPathVariable: true }); - - /*$.ajax(WPGMZA.ajaxurl, { - data: { - action: "wpgmza_query_nominatim_cache", - query: JSON.stringify(query) - }, - success: function(response, xhr, status) { - // Legacy compatibility support - response.lng = response.lon; - - callback(response); - } - });*/ } /** @@ -20987,11 +20982,26 @@ jQuery(function($) { } else if(options.country){ data.countrycodes = options.country; } - - $.ajax("https://nominatim.openstreetmap.org/search", { - data: data, + + if(options._query){ + data._query = options._query; + } + + WPGMZA.restAPI.call("/query-nominatim", { + data: { + data: data, + }, success: function(response, xhr, status) { - callback(response); + if(response && response.length){ + callback(response); + } else { + if(response && response.error){ + /* There may be an additional error in place */ + callback(response.error, WPGMZA.Geocoder.FAIL) + } else { + callback(null, WPGMZA.Geocoder.FAIL) + } + } }, error: function(response, xhr, status) { callback(null, WPGMZA.Geocoder.FAIL) @@ -21002,21 +21012,14 @@ jQuery(function($) { /** * @function cacheResponse * @access protected - * @summary Caches a response on the server, usually after it's been returned from Nominatim + * @summary Caches a response on the server, usually after it's been returned from Nominatim. Deprecated * @param {string} address The street address * @param {object|array} response The response to cache * @returns {void} */ WPGMZA.OLGeocoder.prototype.cacheResponse = function(query, response) { - $.ajax(WPGMZA.ajaxurl, { - data: { - action: "wpgmza_store_nominatim_cache", - query: JSON.stringify(query), - response: JSON.stringify(response) - }, - method: "POST" - }); + } /** @@ -21144,11 +21147,11 @@ jQuery(function($) { finish(response, WPGMZA.Geocoder.SUCCESS); return; } - - self.getResponseFromNominatim($.extend(options, {address: location}), function(response, status) { + + self.getResponseFromNominatim($.extend(options, {address: location, _query : JSON.stringify({location: location, options: options})}), function(response, status) { if(status == WPGMZA.Geocoder.FAIL) { - callback(null, WPGMZA.Geocoder.FAIL); + callback(typeof response === 'string' ? response : null, WPGMZA.Geocoder.FAIL); return; } @@ -21159,8 +21162,6 @@ jQuery(function($) { } finish(response, WPGMZA.Geocoder.SUCCESS); - - self.cacheResponse(query, response); }); }); } diff --git a/js/v8/wp-google-maps.min.js b/js/v8/wp-google-maps.min.js index 145f9d4..3da5620 100644 --- a/js/v8/wp-google-maps.min.js +++ b/js/v8/wp-google-maps.min.js @@ -1 +1 @@ -jQuery(function($){var core={MARKER_PULL_DATABASE:"0",MARKER_PULL_XML:"1",PAGE_MAP_LIST:"map-list",PAGE_MAP_EDIT:"map-edit",PAGE_SETTINGS:"map-settings",PAGE_STYLING:"map-styling",PAGE_SUPPORT:"map-support",PAGE_INSTALLER:"installer",PAGE_CATEGORIES:"categories",PAGE_ADVANCED:"advanced",PAGE_CUSTOM_FIELDS:"custom-fields",MOBILE_RESOLUTION_THRESHOLD:1e3,maps:[],events:null,settings:null,restAPI:null,localized_strings:null,loadingHTML:'
...
',preloaderHTML:"
",getCurrentPage:function(){switch(WPGMZA.getQueryParamValue("page")){case"wp-google-maps-menu":return window.location.href.match(/action=edit/)&&window.location.href.match(/map_id=\d+/)?WPGMZA.PAGE_MAP_EDIT:window.location.href.match(/action=installer/)?WPGMZA.PAGE_INSTALLER:WPGMZA.PAGE_MAP_LIST;case"wp-google-maps-menu-settings":return WPGMZA.PAGE_SETTINGS;case"wp-google-maps-menu-styling":return WPGMZA.PAGE_STYLING;case"wp-google-maps-menu-support":return WPGMZA.PAGE_SUPPORT;case"wp-google-maps-menu-categories":return WPGMZA.PAGE_CATEGORIES;case"wp-google-maps-menu-advanced":return WPGMZA.PAGE_ADVANCED;case"wp-google-maps-menu-custom-fields":return WPGMZA.PAGE_CUSTOM_FIELDS;default:return null}},getScrollAnimationOffset:function(){return(WPGMZA.settings.scroll_animation_offset||0)+($("#wpadminbar").height()||0)},getScrollAnimationDuration:function(){return WPGMZA.settings.scroll_animation_milliseconds||500},animateScroll:function(element,milliseconds){var offset=WPGMZA.getScrollAnimationOffset();milliseconds=milliseconds||WPGMZA.getScrollAnimationDuration(),$("html, body").animate({scrollTop:$(element).offset().top-offset},milliseconds)},extend:function(child,parent){var constructor=child;child.prototype=Object.create(parent.prototype),child.prototype.constructor=constructor},guid:function(){var d=(new Date).getTime();return"undefined"!=typeof performance&&"function"==typeof performance.now&&(d+=performance.now()),"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"===c?r:3&r|8).toString(16)})},hexOpacityToRGBA:function(colour,opacity){colour=parseInt(colour.replace(/^#/,""),16);return[(16711680&colour)>>16,(65280&colour)>>8,255&colour,parseFloat(opacity)]},hexOpacityToString:function(colour,opacity){colour=WPGMZA.hexOpacityToRGBA(colour,opacity);return"rgba("+colour[0]+", "+colour[1]+", "+colour[2]+", "+colour[3]+")"},hexToRgba:function(hex){return/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)?{r:(hex="0x"+(hex=3==(hex=hex.substring(1).split("")).length?[hex[0],hex[0],hex[1],hex[1],hex[2],hex[2]]:hex).join(""))>>16&255,g:hex>>8&255,b:255&hex,a:1}:0},rgbaToString:function(rgba){return"rgba("+rgba.r+", "+rgba.g+", "+rgba.b+", "+rgba.a+")"},latLngRegexp:/^(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)$/,isLatLngString:function(str){return"string"==typeof str&&(str=(str=str.match(/^\(.+\)$/)?str.replace(/^\(|\)$/,""):str).match(WPGMZA.latLngRegexp))?new WPGMZA.LatLng({lat:parseFloat(str[1]),lng:parseFloat(str[3])}):null},stringToLatLng:function(str){str=WPGMZA.isLatLngString(str);if(str)return str;throw new Error("Not a valid latLng")},isHexColorString:function(str){return"string"==typeof str&&!!str.match(/#[0-9A-F]{6}/i)},imageDimensionsCache:{},getImageDimensions:function(src,callback){var img;WPGMZA.imageDimensionsCache[src]?callback(WPGMZA.imageDimensionsCache[src]):((img=document.createElement("img")).onload=function(event){var result={width:img.width,height:img.height};WPGMZA.imageDimensionsCache[src]=result,callback(result)},img.src=src)},decodeEntities:function(input){return input.replace(/&(nbsp|amp|quot|lt|gt);/g,function(m,e){return m[e]}).replace(/&#(\d+);/gi,function(m,e){return String.fromCharCode(parseInt(e,10))})},isDeveloperMode:function(){return this.settings.developer_mode||window.Cookies&&window.Cookies.get("wpgmza-developer-mode")},isProVersion:function(){return"1"==this._isProVersion},openMediaDialog:function(callback,config){var file_frame;file_frame?file_frame.uploader.uploader.param("post_id",set_to_post_id):(file_frame=wp.media.frames.file_frame=config?wp.media(config):wp.media({title:"Select a image to upload",button:{text:"Use this image"},multiple:!1})).on("select",function(){attachment=file_frame.state().get("selection").first().toJSON(),callback(attachment.id,attachment.url,attachment)}),file_frame.open()},getCurrentPosition:function(callback,error,watch){var options,nativeFunction="getCurrentPosition";WPGMZA.userLocationDenied?error&&error({code:1,message:"Location unavailable"}):(watch&&(nativeFunction="watchPosition"),navigator.geolocation?(options={enableHighAccuracy:!0},navigator.geolocation[nativeFunction]?navigator.geolocation[nativeFunction](function(position){callback&&callback(position),WPGMZA.events.trigger("userlocationfound")},function(err){options.enableHighAccuracy=!1,navigator.geolocation[nativeFunction](function(position){callback&&callback(position),WPGMZA.events.trigger("userlocationfound")},function(err){console.warn(err.code,err.message),1==err.code&&(WPGMZA.userLocationDenied=!0),error&&error(err)},options)},options):console.warn(nativeFunction+" is not available")):console.warn("No geolocation available on this device"))},watchPosition:function(callback,error){return WPGMZA.getCurrentPosition(callback,error,!0)},runCatchableTask:function(callback,friendlyErrorContainer){if(WPGMZA.isDeveloperMode())callback();else try{callback()}catch(e){callback=new WPGMZA.FriendlyError(e);$(friendlyErrorContainer).html(""),$(friendlyErrorContainer).append(callback.element),$(friendlyErrorContainer).show()}},capitalizeWords:function(string){return(string+"").replace(/^(.)|\s+(.)/g,function(m){return m.toUpperCase()})},pluralize:function(string){return WPGMZA.singularize(string)+"s"},singularize:function(string){return string.replace(/s$/,"")},assertInstanceOf:function(instance,instanceName){var pro=WPGMZA.isProVersion()?"Pro":"",engine="open-layers"===WPGMZA.settings.engine?"OL":"Google",pro=WPGMZA[engine+pro+instanceName]&&engine+instanceName!="OLFeature"?engine+pro+instanceName:WPGMZA[pro+instanceName]?pro+instanceName:WPGMZA[engine+instanceName]&&WPGMZA[engine+instanceName].prototype?engine+instanceName:instanceName;if("OLFeature"!=pro&&!(instance instanceof WPGMZA[pro]))throw new Error("Object must be an instance of "+pro+" (did you call a constructor directly, rather than createInstance?)")},getMapByID:function(id){for(var i=0;i";jQuery("body").append(html),setTimeout(function(){jQuery("body").find(".wpgmza-popup-notification").remove()},time)},initMaps:function(){$(document.body).find(".wpgmza_map:not(.wpgmza-initialized)").each(function(index,el){if(el.wpgmzaMap)console.warn("Element missing class wpgmza-initialized but does have wpgmzaMap property. No new instance will be created");else try{el.wpgmzaMap=WPGMZA.Map.createInstance(el)}catch(ex){console.warn("Map initalization: "+ex)}}),WPGMZA.Map.nextInitTimeoutID=setTimeout(WPGMZA.initMaps,3e3)},initCapsules:function(){WPGMZA.capsuleModules=WPGMZA.CapsuleModules.createInstance()},onScroll:function(){$(".wpgmza_map").each(function(index,el){var isInView=WPGMZA.isElementInView(el);el.wpgmzaScrollIntoViewTriggerFlag?isInView||(el.wpgmzaScrollIntoViewTriggerFlag=!1):isInView&&($(el).trigger("mapscrolledintoview.wpgmza"),el.wpgmzaScrollIntoViewTriggerFlag=!0)})},initInstallerRedirect:function(url){$(".wpgmza-wrap").hide(),window.location.href=url},delayedReloader(){setTimeout(()=>{try{WPGMZA.restAPI=WPGMZA.RestAPI.createInstance(),WPGMZA.CloudAPI&&(WPGMZA.cloudAPI=WPGMZA.CloudAPI.createInstance()),$(document.body).trigger("preinit.wpgmza"),WPGMZA.initMaps(),WPGMZA.onScroll(),WPGMZA.initCapsules(),$(document.body).trigger("postinit.wpgmza")}catch(ex){WPGMZA.delayedReloader()}},1e3)}},wpgmzaisFullScreen=!1;for(key in[]){console.warn("It appears that the built in JavaScript Array has been extended, this can create issues with for ... in loops, which may cause failure.");break}for(key in window.WPGMZA?window.WPGMZA=$.extend(window.WPGMZA,core):window.WPGMZA=core,window.uc&&window.uc.reloadOnOptIn&&(window.uc.reloadOnOptIn("S1pcEj_jZX"),window.uc.reloadOnOptOut("S1pcEj_jZX")),WPGMZA_localized_data){var value=WPGMZA_localized_data[key];WPGMZA[key]=value}var apiKeyIndex;for(apiKeyIndex of["googleMapsApiKey","wpgmza_google_maps_api_key","google_maps_api_key"])WPGMZA.settings[apiKeyIndex]&&(WPGMZA.settings[apiKeyIndex]=atob(WPGMZA.settings[apiKeyIndex]));var key,wpgmzaisFullScreen=!1;for(key in[]){console.warn("It appears that the built in JavaScript Array has been extended, this can create issues with for ... in loops, which may cause failure.");break}window.WPGMZA?window.WPGMZA=$.extend(window.WPGMZA,core):window.WPGMZA=core,window.uc&&window.uc.reloadOnOptIn&&(window.uc.reloadOnOptIn("S1pcEj_jZX"),window.uc.reloadOnOptOut("S1pcEj_jZX"));try{if(WPGMZA&&WPGMZA.settings&&WPGMZA.settings.disable_google_fonts){const _wpgmzaGoogleFontDisabler={head:document.getElementsByTagName("head")[0]};_wpgmzaGoogleFontDisabler.head&&(_wpgmzaGoogleFontDisabler.insertBefore=_wpgmzaGoogleFontDisabler.head.insertBefore,_wpgmzaGoogleFontDisabler.head.insertBefore=(nElem,rElem)=>{var excl;if(nElem.href&&-1!==nElem.href.indexOf("//fonts.googleapis.com/css"))for(excl of["Roboto","Google"])if(-1!==nElem.href.indexOf("?family="+excl))return;_wpgmzaGoogleFontDisabler.insertBefore.call(_wpgmzaGoogleFontDisabler.head,nElem,rElem)})}}catch(_wpgmzaDisableFontException){}for(key in WPGMZA_localized_data){value=WPGMZA_localized_data[key];WPGMZA[key]=value}WPGMZA.settings.useLegacyGlobals=!0,$(document).on("fullscreenchange mozfullscreenchange webkitfullscreenchange",function(){wpgmzaisFullScreen=!!document.fullscreenElement,$(document.body).trigger("fullscreenchange.wpgmza")}),$("body").on("click","#wpgmzaCloseChat",function(e){e.preventDefault(),$.ajax(WPGMZA.ajaxurl,{method:"POST",data:{action:"wpgmza_hide_chat",nonce:WPGMZA_localized_data.ajaxnonce}}),$(".wpgmza-chat-help").remove()}),$(window).on("scroll",WPGMZA.onScroll),$(document.body).on("click","button.wpgmza-api-consent",function(event){Cookies.set("wpgmza-api-consent-given",!0),window.location.reload()}),$(document.body).on("keydown",function(event){event.altKey&&(WPGMZA.altKeyDown=!0)}),$(document.body).on("keyup",function(event){event.altKey||(WPGMZA.altKeyDown=!1)}),$(document.body).on("preinit.wpgmza",function(){$(window).trigger("ready.wpgmza"),$(document.body).trigger("ready.body.wpgmza"),$("script[src*='wp-google-maps.combined.js'], script[src*='wp-google-maps-pro.combined.js']").length&&console.warn("Minified script is out of date, using combined script instead.");var key,elements=$("script[src]").filter(function(){return this.src.match(/(^|\/)jquery\.(min\.)?js(\?|$)/i)});1

'+WPGMZA.localized_strings.unsecure_geolocation+"

",$(".wpgmza-geolocation-setting").first().after($(elements))),WPGMZA.googleAPIStatus&&"USER_CONSENT_NOT_GIVEN"==WPGMZA.googleAPIStatus.code&&jQuery(".wpgmza-gdpr-compliance").length<=0&&($(".wpgmza-inner-stack").hide(),$("button.wpgmza-api-consent").on("click",function(event){Cookies.set("wpgmza-api-consent-given",!0),window.location.reload()}))}),function($){$(function(){try{WPGMZA.restAPI=WPGMZA.RestAPI.createInstance(),WPGMZA.CloudAPI&&(WPGMZA.cloudAPI=WPGMZA.CloudAPI.createInstance()),$(document.body).trigger("preinit.wpgmza"),WPGMZA.initMaps(),WPGMZA.onScroll(),WPGMZA.initCapsules(),$(document.body).trigger("postinit.wpgmza")}catch(ex){WPGMZA&&"function"==typeof WPGMZA.delayedReloader&&WPGMZA.delayedReloader()}})}($)}),jQuery(function($){WPGMZA.Compatibility=function(){this.preventDocumentWriteGoogleMapsAPI()},WPGMZA.Compatibility.prototype.preventDocumentWriteGoogleMapsAPI=function(){var old=document.write;document.write=function(content){content.match&&content.match(/maps\.google/)||old.call(document,content)}},WPGMZA.compatiblityModule=new WPGMZA.Compatibility}),function(root,factory){"object"==typeof exports?module.exports=factory(root):"function"==typeof define&&define.amd?define([],factory.bind(root,root)):factory(root)}("undefined"!=typeof global?global:this,function(root){var cssEscape;return root.CSS&&root.CSS.escape?root.CSS.escape:(cssEscape=function(value){if(0==arguments.length)throw new TypeError("`CSS.escape` requires an argument.");for(var codeUnit,string=String(value),length=string.length,index=-1,result="",firstCodeUnit=string.charCodeAt(0);++index>8,compressedBuffer[compressedBufferPointer1++]=255&list.length>>16,compressedBuffer[compressedBufferPointer1++]=255&list.length>>24,compressedBuffer[compressedBufferPointer1++]=255&lowBitsLength,list.forEach(function(docID){var docIDDelta=docID-lastDocID-1;if(!WPGMZA.isNumeric(docID))throw new Error("Value is not numeric");if(docID=parseInt(docID),null!==prev&&docID<=prev)throw new Error("Elias Fano encoding can only be used on a sorted, ascending list of unique integers.");for(prev=docID,buffer1=buffer1<>bufferLength1;docIDDelta=1+(docIDDelta>>lowBitsLength);for(buffer2=buffer2<>bufferLength2;lastDocID=docID}),0>=lowBitsCount-=lowBitsLength)+((decodingTableHighBits[cb][i]<{1{this.findLocations()},this.autocomplete.delayTime))}),this.element.addEventListener("focusout",event=>{setTimeout(()=>{this.hideAutocomplete()},500)}),this.element.addEventListener("focusin",event=>{this.showAutocomplete(),this.autoplaceAutocomplete()}),this.element.addEventListener("click",event=>{this.showAutocomplete(),this.autoplaceAutocomplete()}),document.addEventListener("scroll",event=>{this.hideAutocomplete()})},WPGMZA.AddressInput.prototype.findLocations=function(){var term=this.element.value;this.hideAutocomplete(),!term||term.trim().length<0||this.autocompleteProvider===WPGMZA.AddressInput.AutocompleteProviders.GOOGLE_PLACES&&WPGMZA.isGooglePlacesSearchSupported()&&(term=this.getConfigGooglePlacesSearch(term),this.options&&this.options.country&&(term.region=this.options.country),google.maps.places.Place.searchByText(term).then(locations=>{locations&&locations.places&&this.presentLocations(locations.places)}))},WPGMZA.AddressInput.prototype.presentLocations=function(locations){if(this.autocomplete.list.innerHTML="",locations&&locations.length){let compiled="";for(var location of locations){var locationType,adrLabel;location.displayName&&(locationType=location.primaryTypeDisplayName||"Location",adrLabel=location.adrFormatAddress||"",compiled=(compiled=(compiled+=`
`)+`${location.displayName}`+`${adrLabel}`)+`${locationType.replaceAll("_"," ")}`+"
")}if(compiled&&compiled.length){this.autocomplete.list.innerHTML=compiled,this.showAutocomplete(),this.autoplaceAutocomplete();for(let item of this.autocomplete.list.querySelectorAll(".wpgmza-internal-autocomplete-location"))item.addEventListener("click",event=>{event.preventDefault();let address=item.querySelector('[data-autocomplete-field="adr"]');(address=address?address.innerText:item.getAttribute("data-address"))&&(this.element.value=address),this.hideAutocomplete(),this.autocomplete.list.innerHTML=""})}}else this.hideAutocomplete()},WPGMZA.AddressInput.prototype.showAutocomplete=function(){this.autocomplete&&this.autocomplete.list&&this.autocomplete.list.innerHTML.length&&this.autocomplete.list.classList.remove("wpgmza-hidden")},WPGMZA.AddressInput.prototype.hideAutocomplete=function(){this.autocomplete&&this.autocomplete.list&&this.autocomplete.list.classList.add("wpgmza-hidden")},WPGMZA.AddressInput.prototype.autoplaceAutocomplete=function(){var boundingRect;this.autocomplete&&this.autocomplete.list&&(boundingRect=this.element.getBoundingClientRect()).width&&(this.autocomplete.list.style.width=boundingRect.width+"px",this.autocomplete.list.style.left=boundingRect.left+"px",this.autocomplete.list.style.top=boundingRect.bottom+"px")},WPGMZA.AddressInput.prototype.getConfigGooglePlacesSearch=function(term){return{textQuery:term.trim(),fields:["displayName","adrFormatAddress","primaryTypeDisplayName"],maxResultCount:8}}}),jQuery(function($){WPGMZA.CapsuleModules=function(){WPGMZA.EventDispatcher.call(this),this.proxies={},this.capsules=[],this.prepareCapsules(),this.flagCapsules()},WPGMZA.extend(WPGMZA.CapsuleModules,WPGMZA.EventDispatcher),WPGMZA.CapsuleModules.getConstructor=function(){return WPGMZA.isProVersion()?WPGMZA.ProCapsuleModules:WPGMZA.CapsuleModules},WPGMZA.CapsuleModules.createInstance=function(){return new(WPGMZA.CapsuleModules.getConstructor())},WPGMZA.CapsuleModules.prototype.proxyMap=function(id,settings){return this.proxies[id]||(this.proxies[id]=Object.create(this),this.proxies[id].id=id,this.proxies[id].markers=[],this.proxies[id].showPreloader=function(){},this.proxies[id].getMarkerByID=function(){return{}},this.proxies[id].markerFilter=WPGMZA.MarkerFilter.createInstance(this.proxies[id])),settings&&(this.proxies[id].settings=settings),this.proxies[id]},WPGMZA.CapsuleModules.prototype.flagCapsules=function(){if(this.capsules)for(var i in this.capsules)this.capsules[i].element&&$(this.capsules[i].element).addClass("wpgmza-capsule-module")},WPGMZA.CapsuleModules.prototype.prepareCapsules=function(){this.registerStoreLocator()},WPGMZA.CapsuleModules.prototype.registerStoreLocator=function(){$(".wpgmza-store-locator").each((index,element)=>{var settings,mapId=$(element).data("map-id"),url=$(element).data("url");mapId&&!WPGMZA.getMapByID(mapId)&&(url?(settings=$(element).data("map-settings"),settings=this.proxyMap(mapId,settings),(settings={type:"store_locator",element:element,instance:WPGMZA.StoreLocator.createInstance(settings,element)}).instance.isCapsule=!0,settings.instance.redirectUrl=url,this.capsules.push(settings)):console.warn('WPGMZA: You seem to have added a stadalone store locator without a map page URL. Please add a URL to your shortcode [wpgmza_store_locator id="'+mapId+'" url="{URL}"] and try again'))})}}),jQuery(function($){WPGMZA.ColorInput=function(element,options){if(!(element instanceof HTMLInputElement))throw new Error("Element is not an instance of HTMLInputElement");this.element=$(element),this.dataAttributes=this.element.data(),this.type=element.type,this.value=element.value,this.options={format:"hex",anchor:"left",container:!1,autoClose:!0,autoOpen:!1,supportAlpha:!0,supportPalette:!0,wheelBorderWidth:10,wheelPadding:6,wheelBorderColor:"rgb(255,255,255)"},this.parseOptions(options),this.state={initialized:!1,sliderInvert:!1,lockSlide:!1,lockPicker:!1,open:!1,mouse:{down:!1}},this.color={h:0,s:0,l:100,a:1},this.wrap(),this.renderControls(),this.parseColor(this.value)},WPGMZA.extend(WPGMZA.ColorInput,WPGMZA.EventDispatcher),WPGMZA.ColorInput.createInstance=function(element){return new WPGMZA.ColorInput(element)},WPGMZA.ColorInput.prototype.clamp=function(min,max,value){return isNaN(value)&&(value=0),Math.min(Math.max(value,min),max)},WPGMZA.ColorInput.prototype.degreesToRadians=function(degrees){return degrees*(Math.PI/180)},WPGMZA.ColorInput.prototype.hueToRgb=function(p,q,t){return t<0&&(t+=1),1"),this.container.insertAfter(this.element),this.container.append(this.element),this.options.autoClose&&($(document.body).on("click",function(){self.state.open&&(self.state.mouse.down=!1,self.onTogglePicker())}),$(document.body).on("colorpicker.open.wpgmza",function(event){event.instance!==self&&self.state.open&&self.onTogglePicker()}))},WPGMZA.ColorInput.prototype.renderControls=function(){var self=this;this.container&&(this.preview=$("
"),this.swatch=$("
"),this.picker=$("
"),this.preview.append(this.swatch),this.picker.addClass("anchor-"+this.options.anchor),this.preview.addClass("anchor-"+this.options.anchor),this.preview.on("click",function(event){event.stopPropagation(),self.onTogglePicker()}),this.picker.on("click",function(event){event.stopPropagation()}),this.container.append(this.preview),this.options.container&&0<$(this.options.container).length?($(this.options.container).append(this.picker),$(this.options.container).addClass("wpgmza-color-input-host")):this.container.append(this.picker),this.options.autoOpen)&&this.preview.trigger("click")},WPGMZA.ColorInput.prototype.renderPicker=function(){this.state.initialized||(this.renderWheel(),this.renderFields(),this.renderPalette(),this.state.initialized=!0)},WPGMZA.ColorInput.prototype.renderWheel=function(){var self=this;this.wheel={wrap:$("
"),element:$(""),handle:$("
"),slider:$("
")},this.wheel.target=this.wheel.element.get(0),this.wheel.target.height=256,this.wheel.target.width=256,this.wheel.radius=(this.wheel.target.width-2*(this.options.wheelBorderWidth+this.options.wheelPadding))/2,this.wheel.degreeStep=1/this.wheel.radius,this.wheel.context=this.wheel.target.getContext("2d"),this.wheel.context.clearRect(0,0,this.wheel.target.width,this.wheel.target.height),this.wheel.grid={canvas:document.createElement("canvas")},this.wheel.grid.canvas.width=20,this.wheel.grid.canvas.height=20,this.wheel.grid.context=this.wheel.grid.canvas.getContext("2d"),this.wheel.grid.context.fillStyle="rgb(255,255,255)",this.wheel.grid.context.fillRect(0,0,this.wheel.grid.canvas.width,this.wheel.grid.canvas.height),this.wheel.grid.context.fillStyle="rgb(180,180,180)",this.wheel.grid.context.fillRect(0,0,this.wheel.grid.canvas.width/2,this.wheel.grid.canvas.height/2),this.wheel.grid.context.fillRect(this.wheel.grid.canvas.width/2,this.wheel.grid.canvas.height/2,this.wheel.grid.canvas.width/2,this.wheel.grid.canvas.height/2),this.wheel.element.on("mousedown",function(event){self.state.mouse.down=!0,self.onPickerMouseSelect(event)}),this.wheel.element.on("mousemove",function(event){self.state.mouse.down&&self.onPickerMouseSelect(event)}),this.wheel.element.on("mouseup",function(event){self.clearStates()}),this.wheel.element.on("mouseleave",function(event){self.clearStates()}),this.wheel.wrap.append(this.wheel.element),this.wheel.wrap.append(this.wheel.handle),this.wheel.wrap.append(this.wheel.slider),this.picker.append(this.wheel.wrap)},WPGMZA.ColorInput.prototype.renderFields=function(){var group,self=this;for(group in this.fields={wrap:$("
"),toggle:$("
"),blocks:{hsla:{keys:["h","s","l","a"]},rgba:{keys:["r","g","b","a"]},hex:{keys:["hex"]}}},this.fields.toggle.on("click",function(){var view=self.fields.view;switch(view){case"hex":view="hsla";break;case"hsla":view="rgba";break;case"rgba":view="hex"}self.updateFieldView(view)}),this.fields.wrap.append(this.fields.toggle),this.fields.blocks){var index,keys=this.fields.blocks[group].keys;for(index in this.fields.blocks[group].wrap=$("
"),this.fields.blocks[group].rows={labels:$("
"),controls:$("
")},this.fields.blocks[group].wrap.append(this.fields.blocks[group].rows.controls),this.fields.blocks[group].wrap.append(this.fields.blocks[group].rows.labels),this.options.supportAlpha||-1===keys.indexOf("a")||this.fields.blocks[group].wrap.addClass("alpha-disabled"),keys){var name=keys[index],label=$("
");label.text(name),this.fields.blocks[group][name]=$(""),this.fields.blocks[group].rows.controls.append(this.fields.blocks[group][name]),this.fields.blocks[group].rows.labels.append(label),this.fields.blocks[group][name].on("keydown",function(event){var originalEvent=event.originalEvent;"Enter"===originalEvent.key&&(originalEvent.preventDefault(),originalEvent.stopPropagation(),$(event.currentTarget).trigger("change"))}),this.fields.blocks[group][name].on("change",function(){self.onFieldChange(this)})}this.fields.wrap.append(this.fields.blocks[group].wrap)}this.picker.append(this.fields.wrap),this.updateFieldView()},WPGMZA.ColorInput.prototype.renderPalette=function(){var self=this;if(this.options.supportPalette){for(var i in this.palette={wrap:$("
"),variations:[{s:-10,l:-10},{h:15},{h:30},{h:-15},{h:-30},{h:100,s:10},{h:-100,s:-10},{h:180}],controls:[]},this.palette.variations){var mutator,variation=this.palette.variations[i],control=$("
");for(mutator in variation)control.attr("data-"+mutator,variation[mutator]);control.on("click",function(){var elem=$(this);self.parseColor(elem.css("background-color")),self.element.trigger("input")}),this.palette.wrap.append(control),this.palette.controls.push(control)}this.picker.append(this.palette.wrap)}},WPGMZA.ColorInput.prototype.updateWheel=function(){this.wheel.center={x:this.wheel.radius+this.options.wheelBorderWidth+this.options.wheelPadding,y:this.wheel.radius+this.options.wheelBorderWidth+this.options.wheelPadding},this.color.a<1&&(this.wheel.grid.pattern=this.wheel.context.createPattern(this.wheel.grid.canvas,"repeat"),this.wheel.context.fillStyle=this.wheel.grid.pattern,this.wheel.context.beginPath(),this.wheel.context.arc(this.wheel.center.x,this.wheel.center.y,this.wheel.radius,0,2*Math.PI,!0),this.wheel.context.closePath(),this.wheel.context.fill());for(var i=0;i<360;i++){var startAngle=(i-1)*Math.PI/180,endAngle=(i+1)*Math.PI/180;this.wheel.context.beginPath(),this.wheel.context.moveTo(this.wheel.center.x,this.wheel.center.y),this.wheel.context.arc(this.wheel.center.x,this.wheel.center.y,this.wheel.radius,startAngle,endAngle),this.wheel.context.closePath(),this.wheel.context.fillStyle="hsla("+i+", 100%, 50%, "+this.color.a+")",this.wheel.context.fill()}var gradient=this.wheel.context.createRadialGradient(this.wheel.center.x,this.wheel.center.y,0,this.wheel.center.x,this.wheel.center.y,this.wheel.radius),gradient=(gradient.addColorStop(0,"rgba(255, 255, 255, 1)"),gradient.addColorStop(1,"rgba(255, 255, 255, 0)"),this.wheel.context.fillStyle=gradient,this.wheel.context.beginPath(),this.wheel.context.arc(this.wheel.center.x,this.wheel.center.y,this.wheel.radius,0,2*Math.PI,!0),this.wheel.context.closePath(),this.wheel.context.fill(),this.wheel.context.lineWidth=2,this.wheel.context.strokeStyle=this.options.wheelBorderColor,this.wheel.context.stroke(),this.wheel.context.createLinearGradient(this.wheel.center.x,0,this.wheel.center.x,this.wheel.target.height)),gradient=(gradient.addColorStop(0,this.getColor({l:95},"hsl")),gradient.addColorStop(.5,this.getColor({l:50},"hsl")),gradient.addColorStop(1,this.getColor({l:5},"hsl")),this.wheel.context.beginPath(),this.wheel.context.lineWidth=this.options.wheelBorderWidth,this.wheel.context.strokeStyle=gradient,this.wheel.context.arc(this.wheel.center.x,this.wheel.center.y,this.wheel.radius+this.options.wheelPadding+this.options.wheelBorderWidth/2,0,2*Math.PI),this.wheel.context.stroke(),this.wheel.context.beginPath(),this.wheel.context.lineWidth=1,this.wheel.context.strokeStyle=this.options.wheelBorderColor,this.wheel.context.arc(this.wheel.center.x,this.wheel.center.y,this.wheel.radius+this.options.wheelPadding+this.options.wheelBorderWidth,0,2*Math.PI),this.wheel.context.stroke(),this.wheel.context.beginPath(),this.wheel.context.arc(this.wheel.center.x,this.wheel.center.y,this.wheel.radius+this.options.wheelPadding,0,2*Math.PI),this.wheel.context.stroke(),this.wheel.context.createRadialGradient(this.wheel.center.x,this.wheel.center.y,0,this.wheel.center.x,this.wheel.center.y,this.wheel.radius));gradient.addColorStop(0,"rgba(80, 80, 80, 0)"),gradient.addColorStop(.95,"rgba(80, 80, 80, 0.0)"),gradient.addColorStop(1,"rgba(80, 80, 80, 0.1)"),this.wheel.context.beginPath(),this.wheel.context.lineWidth=6,this.wheel.context.strokeStyle=gradient,this.wheel.context.arc(this.wheel.center.x,this.wheel.center.y,this.wheel.radius-3,0,2*Math.PI),this.wheel.context.stroke()},WPGMZA.ColorInput.prototype.update=function(){this.updateHandles(),this.updateWheel(),this.updateFields(),this.updatePalette()},WPGMZA.ColorInput.prototype.updateHandles=function(){var localRadius=this.wheel.element.width()/2,localHandleOffset=(localRadius-this.options.wheelBorderWidth-this.options.wheelPadding)/100*this.color.s,localHandleOffset={left:localRadius+localHandleOffset*Math.cos(this.degreesToRadians(this.color.h))+"px",top:localRadius+localHandleOffset*Math.sin(this.degreesToRadians(this.color.h))+"px"},localHandleOffset=(this.wheel.handle.css(localHandleOffset),this.color.l/100*360/2),localRadius=(this.state.sliderInvert&&(localHandleOffset=360-localHandleOffset),{left:localRadius+(localRadius-this.options.wheelBorderWidth/2)*Math.cos(this.degreesToRadians(localHandleOffset+90))+"px",top:localRadius+(localRadius-this.options.wheelBorderWidth/2)*Math.sin(this.degreesToRadians(localHandleOffset+90))+"px"});this.wheel.slider.css(localRadius)},WPGMZA.ColorInput.prototype.updatePreview=function(){this.swatch.css({background:this.getColor(!1,"rgba")})},WPGMZA.ColorInput.prototype.updateFields=function(){var group,hsl=Object.assign({},this.color);for(group in this.fields.blocks)switch(group){case"hsla":this.fields.blocks[group].h.val(hsl.h),this.fields.blocks[group].s.val(hsl.s),this.fields.blocks[group].l.val(hsl.l),this.fields.blocks[group].a.val(hsl.a);break;case"rgba":var rgb=this.hslToRgb(hsl.h,hsl.s,hsl.l,hsl.a);this.fields.blocks[group].r.val(rgb.r),this.fields.blocks[group].g.val(rgb.g),this.fields.blocks[group].b.val(rgb.b),this.fields.blocks[group].a.val(rgb.a);break;case"hex":var rgb=this.hslToRgb(hsl.h,hsl.s,hsl.l,hsl.a),hex=this.rgbToHex(rgb.r,rgb.g,rgb.b,rgb.a);this.fields.blocks[group].hex.val(hex)}},WPGMZA.ColorInput.prototype.updatePalette=function(){if(this.options.supportPalette)for(var i in this.palette.controls){var mutator,hsl=Object.assign({},this.color),i=this.palette.controls[i],data=i.data();for(mutator in 0===hsl.l?(data.h&&(hsl.l+=Math.abs(data.h)/360*100),hsl.l+=10):100===hsl.l&&(data.h&&(hsl.l-=Math.abs(data.h)/360*100),hsl.l-=10),data)hsl[mutator]+=data[mutator];hsl.h<0?hsl.h+=360:360"),this.container.insertAfter(this.element),this.container.append(this.element)},WPGMZA.CSSBackdropFilterInput.prototype.renderControls=function(){if(this.container)for(var type in this.itemWrappers={},this.filters){var data=this.filters[type],printType=type.replace("_"," "),wrapper=$("
"),toggleWrap=$("
"),toggleInput=$(""),toggleLabel=$("