diff --git a/assets/js/autocomplete.js b/assets/js/autocomplete.js index 62d5e9c9f..aa16b0941 100644 --- a/assets/js/autocomplete.js +++ b/assets/js/autocomplete.js @@ -66,6 +66,7 @@ const getTranslation = (fullName) => { parent.classList.add('hds-text-input--invalid'); const errorSpan = document.createElement('span'); errorSpan.classList.add('hds-text-input__error-text'); + errorSpan.id = 'js-locate-error'; errorSpan.textContent = Drupal.t( "We couldn't retrieve your current location. Try entering an address.", {}, @@ -229,6 +230,11 @@ const getTranslation = (fullName) => { }); // Hide location error input when changing input element.addEventListener('change', removeLocationError); + + // Focus input if there is a validation error on page load. + if (element.classList.contains('error')) { + element.focus(); + } }; Drupal.behaviors.helfi_location_autocomplete = { diff --git a/dist/js/autocomplete.min.js b/dist/js/autocomplete.min.js index 01f8bc31b..6733fb3d6 100644 --- a/dist/js/autocomplete.min.js +++ b/dist/js/autocomplete.min.js @@ -1 +1 @@ -(()=>{var t=Object.defineProperty;var e=(e,o)=>t(e,"name",{value:o,configurable:true});var o=Drupal.t("Use current Location",{},{context:"Location autocomplete"});var n="https://api.hel.fi/servicemap/v2/address/";var a="location-loading";var{currentLanguage:s}=drupalSettings.path;var r=`\n
\n \n ${o}\n
\n`;var i=new AbortController;var c=e(t=>{if(t[s]){return t[s]}if(t.fi){return t.fi}return Object.values(t)[0]},"getTranslation");((Drupal,once)=>{const t=e(t=>{if(!A11yAutocomplete){throw new Error("A11yAutocomplete object not found. Make sure the library is loaded.")}let s="geolocation"in navigator?[{label:r,value:o,index:0,item:{label:o,value:o}}]:[];const l=t.closest(".hds-text-input");const u=e(()=>{l.classList.add("hds-text-input--invalid");const t=document.createElement("span");t.classList.add("hds-text-input__error-text");t.textContent=Drupal.t("We couldn't retrieve your current location. Try entering an address.",{},{context:"Location autocomplete"});l.appendChild(t);s=[]},"displayLocationError");const d=e(()=>{l.classList.remove("hds-text-input--invalid");l.querySelector(".hds-text-input__error-text")?.remove()},"removeLocationError");const p=Drupal.t("Type @count or more characters for results",{},{context:"Location autocomplete"});const h=Drupal.t("When autocomplete results are available use up and down arrows to review and enter to select. Touch device users, explore by touch or with swipe gestures.",{},{context:"Location autocomplete"});const v=Drupal.t("No address suggestions were found",{},{context:"Location autocomplete"});const g=Drupal.t("There are @count results available.",{},{context:"Location autocomplete"});const m=Drupal.t("There is one result available.",{},{context:"Location autocomplete"});const f=Drupal.t("@selectedItem @position of @count is highlighted",{},{context:"Location autocomplete"});const L=t.dataset.autocompletePath;const w=A11yAutocomplete(t,{allowRepeatValues:true,classes:{inputLoading:"loading",wrapper:"helfi-location-autocomplete"},highlightedAssistiveHint:f,inputAssistiveHint:h,minCharAssistiveHint:p,minChars:0,noResultsAssistiveHint:v,oneResultAssistiveHint:m,someResultsAssistiveHint:g,source:e(async(t,e)=>{try{i.abort();i=new AbortController;if(t.length<3){return e(s)}const o=new URL(L,window.location.origin);o.searchParams.set("q",t);const n=await fetch(o.toString(),{signal:i.signal});const a=await n.json();e(s.concat(a))}catch(t){if(t.name==="AbortError"){return}console.error(t);e(s)}},"source")});const y=w._internal_object;const x=e(e=>{y.close();if(e){t.classList.toggle(a,true);return}t.classList.toggle(a,false)},"setLoading");t.addEventListener("autocomplete-select",e=>{if(e.detail.selected.value!==o){return}e.preventDefault();x(t,y,true);navigator.geolocation.getCurrentPosition(async t=>{const{coords:{latitude:o,longitude:a}}=t;const s=new URLSearchParams({lat:o,lon:a});const r=new URL(n);r.search=s.toString();try{const t=await fetch(r.toString());const o=await t.json();e.target.value=c(o.results[0].full_name)}catch(t){u()}finally{x(false)}},()=>{u();x(false)})});t.addEventListener("focus",()=>{if(t.classList.contains(a)){return}if(y.input.value===""&&s.length){y.displayResults(s)}});t.addEventListener("keydown",t=>{if(y.input.value===""&&s.length&&y.suggestions.length===0&&t.key==="ArrowDown"){y.displayResults(s)}});t.addEventListener("change",d)},"init");Drupal.behaviors.helfi_location_autocomplete={attach(e){once("a11y_autocomplete_element","[data-helfi-location-autocomplete]",e).forEach(t)}}})(Drupal,once)})(); \ No newline at end of file +(()=>{var t=Object.defineProperty;var e=(e,o)=>t(e,"name",{value:o,configurable:true});var o=Drupal.t("Use current Location",{},{context:"Location autocomplete"});var n="https://api.hel.fi/servicemap/v2/address/";var a="location-loading";var{currentLanguage:s}=drupalSettings.path;var r=`\n
\n \n ${o}\n
\n`;var i=new AbortController;var c=e(t=>{if(t[s]){return t[s]}if(t.fi){return t.fi}return Object.values(t)[0]},"getTranslation");((Drupal,once)=>{const t=e(t=>{if(!A11yAutocomplete){throw new Error("A11yAutocomplete object not found. Make sure the library is loaded.")}let s="geolocation"in navigator?[{label:r,value:o,index:0,item:{label:o,value:o}}]:[];const l=t.closest(".hds-text-input");const u=e(()=>{l.classList.add("hds-text-input--invalid");const t=document.createElement("span");t.classList.add("hds-text-input__error-text");t.id="js-locate-error";t.textContent=Drupal.t("We couldn't retrieve your current location. Try entering an address.",{},{context:"Location autocomplete"});l.appendChild(t);s=[]},"displayLocationError");const d=e(()=>{l.classList.remove("hds-text-input--invalid");l.querySelector(".hds-text-input__error-text")?.remove()},"removeLocationError");const p=Drupal.t("Type @count or more characters for results",{},{context:"Location autocomplete"});const h=Drupal.t("When autocomplete results are available use up and down arrows to review and enter to select. Touch device users, explore by touch or with swipe gestures.",{},{context:"Location autocomplete"});const v=Drupal.t("No address suggestions were found",{},{context:"Location autocomplete"});const g=Drupal.t("There are @count results available.",{},{context:"Location autocomplete"});const m=Drupal.t("There is one result available.",{},{context:"Location autocomplete"});const f=Drupal.t("@selectedItem @position of @count is highlighted",{},{context:"Location autocomplete"});const L=t.dataset.autocompletePath;const w=A11yAutocomplete(t,{allowRepeatValues:true,classes:{inputLoading:"loading",wrapper:"helfi-location-autocomplete"},highlightedAssistiveHint:f,inputAssistiveHint:h,minCharAssistiveHint:p,minChars:0,noResultsAssistiveHint:v,oneResultAssistiveHint:m,someResultsAssistiveHint:g,source:e(async(t,e)=>{try{i.abort();i=new AbortController;if(t.length<3){return e(s)}const o=new URL(L,window.location.origin);o.searchParams.set("q",t);const n=await fetch(o.toString(),{signal:i.signal});const a=await n.json();e(s.concat(a))}catch(t){if(t.name==="AbortError"){return}console.error(t);e(s)}},"source")});const y=w._internal_object;const x=e(e=>{y.close();if(e){t.classList.toggle(a,true);return}t.classList.toggle(a,false)},"setLoading");t.addEventListener("autocomplete-select",e=>{if(e.detail.selected.value!==o){return}e.preventDefault();x(t,y,true);navigator.geolocation.getCurrentPosition(async t=>{const{coords:{latitude:o,longitude:a}}=t;const s=new URLSearchParams({lat:o,lon:a});const r=new URL(n);r.search=s.toString();try{const t=await fetch(r.toString());const o=await t.json();e.target.value=c(o.results[0].full_name)}catch(t){u()}finally{x(false)}},()=>{u();x(false)})});t.addEventListener("focus",()=>{if(t.classList.contains(a)){return}if(y.input.value===""&&s.length){y.displayResults(s)}});t.addEventListener("keydown",t=>{if(y.input.value===""&&s.length&&y.suggestions.length===0&&t.key==="ArrowDown"){y.displayResults(s)}});t.addEventListener("change",d);if(t.classList.contains("error")){t.focus()}},"init");Drupal.behaviors.helfi_location_autocomplete={attach(e){once("a11y_autocomplete_element","[data-helfi-location-autocomplete]",e).forEach(t)}}})(Drupal,once)})(); \ No newline at end of file diff --git a/helfi_platform_config.module b/helfi_platform_config.module index 1c49fd6b8..01e901ad9 100644 --- a/helfi_platform_config.module +++ b/helfi_platform_config.module @@ -502,3 +502,12 @@ function helfi_platform_config_preprocess_page(array &$variables) : void { $variables['#attached']['library'][] = 'helfi_platform_config/heading_anchor_buttons'; } } + +/** + * Implements hook_preprocess_HOOK(). + */ +function helfi_platform_config_preprocess_form_element__helfi_location_autocomplete(array &$variables):void { + if (isset($variables['element']['#errors']) && empty($variables['errors'])) { + $variables['errors'] = $variables['element']['#errors']; + } +} diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ffcb59c0a..6059196e9 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -75,6 +75,11 @@ parameters: count: 1 path: helfi_platform_config.module + - + message: "#^Function helfi_platform_config_preprocess_form_element__helfi_location_autocomplete\\(\\) has parameter \\$variables with no value type specified in iterable type array\\.$#" + count: 1 + path: helfi_platform_config.module + - message: "#^Function helfi_platform_config_preprocess_html\\(\\) has parameter \\$variables with no type specified\\.$#" count: 1