Spiagge di sabbia e ghiaia
Numerose bandiere blu certificano la qualità delle acque e dei servizi, 180 chilometri di costa, più di 20 località che si affacciano sul Mare Adriatico, oltre al porto marittimo di Ancona e 9 porti turistici: questa è l'ampia offerta certificata di qualità per una vacanza al mare nelle Marche.
Lunghi litorali di sabbia finissima, acque limpide che si rifrangono sugli scogli, piccole e raccolte baie immerse in paesaggi incontaminati. Il mare delle Marche è a due passi dai centri storici: un alternarsi di lunghe spiagge e ripide pareti rocciose che precipitano nelle acque azzurre e, come sfondo, le dolci colline che caratterizzano l’immediato entroterra.
Read all
Read less
An error occurred while processing the template.
The following has evaluated to null or missing: ==> curExtraSearchField.inputAspect [in template "20097#20123#204862" at line 108, column 94] ---- Tip: It's the step after the last dot that caused this error, not those before it. ---- Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)?? ---- ---- FTL stack trace ("~" means nesting-related): - Failed at: #if curExtraSearchField.inputAspect =... [in template "20097#20123#204862" at line 108, column 89] - Reached through: @ricerca_components["ricerca-form"] s... [in template "20097#20123#204862" at line 58, column 33] ----
1<#-- instance id -->
2<#assign instanceId = themeDisplay.getPortletDisplay().getId()?keep_after("INSTANCE_") />
3
4<#-- Ricavo servizi utili in seguito -->
5<#-- Servizio per i layout di pagina -->
6<#assign layoutLocalService = serviceLocator.findService("com.liferay.portal.kernel.service.LayoutLocalService") />
7<#-- Servizio utile per ricavare i documenti della DM -->
8<#assign dlFileEntryLocalService = serviceLocator.findService('com.liferay.document.library.kernel.service.DLFileEntryLocalService') />
9
10<#-- Etichette -->
11<#-- localita -->
12<#assign label_localita_s = languageUtil.get(locale, "label_localita_s") />
13<#assign label_localita_p = languageUtil.get(locale, "label_localita_p") />
14<#assign ricerca_extra_field_place = languageUtil.get(locale, "ricerca_extra_field_place") />
15<#assign ricerca_extra_field_place_placeholder = languageUtil.get(locale, "ricerca_extra_field_place_placeholder") />
16<#assign label_chiama_telefono = languageUtil.get(locale, "label_chiama_telefono") />
17<#assign label_invia_email_a = languageUtil.get(locale, "label_invia_email_a") />
18<#assign label_e_mail = languageUtil.get(locale, "label_e_mail") />
19<#assign label_sito_web = languageUtil.get(locale, "label_sito_web") />
20<#assign label_vai_sito_web = languageUtil.get(locale, "label_vai_sito_web") />
21<#-- generiche -->
22<#assign label_filtro_cosa = languageUtil.get(locale, "label_filtro_cosa") />
23<#assign label_placeholder_filtro_cosa = languageUtil.get(locale, "label_placeholder_filtro_cosa") />
24<#assign label_button_cerca = languageUtil.get(locale, "label_button_cerca") />
25<#assign label_button_cerca_su_mappa = languageUtil.get(locale, "label_button_cerca_su_mappa") />
26<#assign label_categorie = languageUtil.get(locale, "label_categorie") />
27<#assign label_seleziona = languageUtil.get(locale, "label_seleziona") />
28<#assign label_vai_dettaglio = languageUtil.get(locale, "label_vai_dettaglio") />
29<#assign label_leggi_tutto = languageUtil.get(locale, "label_leggi_tutto") />
30<#assign label_aggiungi_lista_viaggio = languageUtil.get(locale, "label_aggiungi_lista_viaggio") />
31<#assign label_scarica_formato_csv = languageUtil.get(locale, "label_scarica_formato_csv") />
32
33<#-- Inclusione widget template con macros e relativi servizi -->
34<#include "${templatesPath}/RICERCA_COMMON_MACROS" />
35
36<#-- campi personalizzati -->
37<#-- ricavo il valore del vocabolario DESTINAZIONI, che serve per recuperare le relative categorie -->
38<#assign DESTINAZIONI_VOCABULARY_ID = "" />
39<#if validator.isNotNull(themeDisplay.getLayout().getGroup().getExpandoBridge()) >
40 <#if (( themeDisplay.getLayout().getGroup().getExpandoBridge().hasAttribute("destinazioni_vocabulary_id"))) >
41 <#if themeDisplay.getLayout().getGroup().getExpandoBridge().getAttribute("destinazioni_vocabulary_id")??>
42 <#assign DESTINAZIONI_VOCABULARY_ID = themeDisplay.getLayout().getGroup().getExpandoBridge().getAttribute("destinazioni_vocabulary_id")/>
43 </#if>
44 </#if>
45</#if>
46
47<#-- html -->
48<div class="col-12">
49 <div class="search-template search-template-localita">
50
51 <#-- da qui inizia l'html così come da mockup: solo modalita desktop -->
52 <div class="search-form-container search-form-container-desktop py-3">
53 <#-- aggiunta classe m-0 -->
54 <div class="row m-0">
55 <div class="col-12">
56
57 <#-- form con ricerca testuale, per data, e pulsanti -->
58 <@ricerca_components["ricerca-form"] searchUrl="${searchUrl}" method="get" id="search-localita-form-desktop">
59
60 <#-- contenitore con sfondo -->
61 <div class="search-form">
62
63 <#-- campo hidden per ricerca senza risultati -->
64 <input type="hidden" name="searchSubmit" value="true">
65
66 <#-- campo hidden per ordinamento: non usato -->
67 <#--
68 <input type="hidden" value="${searchInput.orderBy}" name="orderBy" id="orderByInputHiddenDesktop">
69 -->
70
71 <#-- campo hidden per cambio vista: non usato -->
72 <#--
73 <input type="hidden" value="${viewTypeKey}${ricercaPortletConfig.configViewParamsSeparator}${viewTypeValue}" name="viewParams" id="input-viewParams-viewType">
74 -->
75
76 <#-- inizio barra filtri orizzontatli -->
77 <div class="form-row align-items-center">
78
79 <#if ricercaPortletConfig.configInputqTitleLabel != "">
80 <#assign label_filtro_cosa = ricercaPortletConfig.configInputqTitleLabel />
81 </#if>
82
83 <#-- campo di ricerca testuale -->
84 <div class="col-12 <#if searchInput.extraSearchFields?has_content || (ricercaPortletConfig.configShowCategoriesFilterInSearchbar == true)>col-md mb-md-2<#else>col-md</#if> text-uppercase search-form-title">
85 <label for="input-ricerca-q" class="mb-0">${label_filtro_cosa}</label>
86 <@ricerca_components["ricerca-input-q"] cssClass="form-control"
87 value="${searchInput.q}"
88 placeholder="${label_placeholder_filtro_cosa}">
89 </@>
90 <#if SUGGERIMENTI_RICERCA_CONTENT?? && SUGGERIMENTI_RICERCA_CONTENT !="">
91 ${SUGGERIMENTI_RICERCA_CONTENT}
92 </#if>
93 </div>
94
95 <#-- campo di ricerca per località: campo dinamico prelevato da configurazione -->
96 <#if searchInput.extraSearchFields?has_content>
97 <#list searchInput.extraSearchFields as curExtraSearchField >
98 <#assign curExtraSearchFieldValue = "" />
99 <#if curExtraSearchField.value?has_content>
100 <#assign curExtraSearchFieldValue = curExtraSearchField.value />
101 </#if>
102
103 <#assign curExtraSearchFieldName = curExtraSearchField.fieldNamePrefix+curExtraSearchField.field />
104 <#assign curExtraSearchFieldLabel = curExtraSearchField.fieldLabel />
105
106 <div id="${curExtraSearchFieldName}_container" class="col-12 col-md text-uppercase search-form-extra-field mb-md-2">
107 <label for="${curExtraSearchFieldName}" class="mb-0">${curExtraSearchFieldLabel}</label>
108 <#if curExtraSearchField.inputAspect = "OPTIONS">
109 <select class="form-control" id="${curExtraSearchFieldName}" name="${curExtraSearchFieldName}" value="${curExtraSearchFieldValue}">
110 <option value="">${label_seleziona}</option>
111 <#assign keyName = curExtraSearchField.field />
112 <#assign selectOptions = selectsItemsLabels[keyName] />
113 <#if selectOptions?has_content>
114 <#list selectOptions as opt>
115 <#assign isSelected = "" />
116 <#if curExtraSearchFieldValue?string?lower_case == opt?lower_case>
117 <#assign isSelected = "selected" />
118 </#if>
119 <option value="${opt}" ${isSelected}>${opt}</option>
120 </#list>
121 </#if>
122 </select>
123 <#else>
124 <input type="text" class="form-control" id="${curExtraSearchFieldName}" name="${curExtraSearchFieldName}" value="${curExtraSearchFieldValue}" placeholder="${label_placeholder_filtro_cosa}">
125 </#if>
126 </div>
127
128 <#if curExtraSearchField.autoCompleteUrl?? && curExtraSearchField.autoCompleteUrl != "">
129 <#if curExtraSearchField.inputAspect = "TEXTFIELD">
130 <script>
131 $('#${curExtraSearchFieldName}').autocomplete({
132 paramName: 'q',
133 appendTo: '#${curExtraSearchFieldName}_container',
134 serviceUrl: '${curExtraSearchField.autoCompleteUrl}',
135 dataType: 'json',
136 transformResult: function(response) {
137 return {
138 suggestions: $.map(response.data, function(dataItem) {
139 return dataItem.displayName;
140 })
141 };
142 }
143 });
144 </script>
145 </#if>
146 </#if>
147 </#list>
148 </#if>
149
150 <#if ricercaPortletConfig.configSearchbarCategoriesFieldLabel != "">
151 <#assign label_categorie = ricercaPortletConfig.configSearchbarCategoriesFieldLabel />
152 </#if>
153
154 <#if (ricercaPortletConfig.configShowCategoriesFilterInSearchbar == true)>
155 <#-- visualizzo searchbar categories -->
156 <#if (searchbarCategoriesAsKeyValue?size > 0)>
157 <div class="col-12 col-md text-uppercase search-form-extra-field mb-md-2">
158 <label for="searchbar-select-ricerca-categorie" class="mb-0">${label_categorie}</label>
159 <select name="categoryIdsSearchbar" class="form-control" id="searchbar-select-ricerca-categorie">
160 <option value="">${label_seleziona}</option>
161 <#list searchbarCategoriesAsKeyValue?keys as prop>
162 <#assign isSelected = "" />
163 <#if searchInput.categoryIdsSearchbar?has_content>
164 <#list searchInput.categoryIdsSearchbar as categoryId>
165 <#if categoryId?string == prop>
166 <#assign isSelected = "selected" />
167 </#if>
168 </#list>
169 </#if>
170 <option value="${prop}" ${isSelected}>${searchbarCategoriesAsKeyValue[prop]}</option>
171 </#list>
172 </select>
173 </div>
174 </#if>
175 <#-- visualizzo searchbar extra categories -->
176 <#if categoriesExtraSearchFieldsObject?has_content>
177 <#list categoriesExtraSearchFieldsObject as curVoc>
178 <div class="col-12 col-md text-uppercase search-form-extra-field mb-md-2">
179 <label for="searchbar-select-ricerca-categorie-${curVoc.vocabularyId}" class="mb-0">
180 ${curVoc.vocabularyLabel}
181 </label>
182 <select name="categoryIdsSearchbar" class="form-control" id="searchbar-select-ricerca-categorie-${curVoc.vocabularyId}">
183 <option value="">
184 ${label_seleziona}
185 </option>
186 <#list curVoc.categories?keys as curCat>
187 <#assign isSelected="" />
188 <#if searchInput.categoryIdsSearchbar?has_content>
189 <#list searchInput.categoryIdsSearchbar as categoryId>
190 <#if categoryId?string == curCat>
191 <#assign isSelected="selected" />
192 </#if>
193 </#list>
194 </#if>
195 <option value="${curCat}" ${isSelected}>
196 ${curVoc.categories[curCat]}
197 </option>
198 </#list>
199 </select>
200 </div>
201 </#list>
202 </#if>
203 </#if>
204
205 <#-- pulsante di ricerca -->
206 <div class="col-12 col-md-2 search-form-button">
207 <button type="submit" class="btn-dark btn-block"><span class="fa fa-search mr-1" aria-hidden="true"></span>${label_button_cerca}</button>
208 </div>
209
210 <#-- codice aggiunto per la ricerca geo su mappa, funziona con la variabile impostata a true nell'init -->
211 <#assign latValue="" />
212 <#if searchInput.lat?has_content>
213 <#assign latValue="${searchInput.lat}" />
214 </#if>
215 <#assign lngValue="" />
216 <#if searchInput.lng?has_content>
217 <#assign lngValue="${searchInput.lng}" />
218 </#if>
219 <#assign distanceValue="" />
220 <#if searchInput.distance?has_content>
221 <#assign distanceValue="${searchInput.distance}" />
222 </#if>
223
224 <#-- variabili per gestire accessibilità e visualizzazione mappa, nel caso in cui cè una ricerca geo in atto -->
225 <#assign statusCollapse = "" />
226 <#assign statusCollapseAria = "false" />
227 <#if (searchInput.lat?has_content) && (searchInput.lng?has_content) && (searchInput.distance?has_content)>
228 <#assign statusCollapse = "show" />
229 <#assign statusCollapseAria = "true" />
230 </#if>
231
232 <#-- pulsante per visualizzare la mappa nascosta -->
233 <div class="col-12 col-md-3 search-form-map-button">
234 <button class="container-fluid position-relative transition btn-dark btn-map" type="button" data-toggle="collapse" data-target="#map-container-desktop" aria-expanded="${statusCollapseAria}" aria-controls="map-container-desktop">
235 <span class="position-relative"><span class="fa fa-map-marker mr-1" aria-hidden="true"></span>${label_button_cerca_su_mappa}</span>
236 </button>
237 </div>
238 </div>
239
240 <#-- richiamo taglib mappa: ha il suo html base -->
241 <#-- rich-map: wrapper class for rich marker -->
242 <div id="map-container-desktop" class="rich-map-container collapse my-4 ${statusCollapse}">
243 <@ricerca_components["ricerca-map"]>
244 </@>
245 </div>
246 </div>
247
248 <#-- IMPORTANTE: inizializzo la mappa, da fare subito dopo la chiusura della taglib -->
249 <#-- poichè il form ha un id custom, lo riporto come parametro nell'init -->
250 <script>
251 TglSearchMap.init({
252 centerLatitude: 43.3285259,
253 centerLongitude: 13.0509109,
254 initialZoom: 13,
255 geoSearch: true,
256 searchFormId: "search-localita-form-desktop",
257 submitOnGeoSearch: true
258 });
259 </script>
260
261 <#-- nel caso di una ricerca geo, passo alla mappa i valori impostati nelle variabili sopra create-->
262 <script type="text/javascript">
263 TglSearchMap.setSearchCircle('${latValue}', '${lngValue}', '${distanceValue}');
264 </script>
265
266 </@>
267 </div>
268 </div>
269 </div>
270
271 <#if entries?has_content>
272 <#list entries as curEntry>
273
274 <#-- sezione divisa in due colonne: categorie e lista risultati -->
275 <div id="search-results" class="search-results">
276
277 <#-- aggiunta classe m-0 -->
278 <div class="row m-0">
279
280 <#-- ricerca per categorie -->
281 <#if (ricercaPortletConfig.configSearchByCategories == true) && (ricercaPortletConfig.configShowCategoriesFilterInSidebar == true) && (categoriesAsKeyValue?size > 0)>
282
283 <#-- setto una variabile booleana per far partire gli accordion o aperti o chiusi a seconda della configurazione -->
284 <#assign vocabulariesCollapsed = false />
285 <#if ricercaPortletConfig.configStartWithCollapsedVocabularies?? && ricercaPortletConfig.configStartWithCollapsedVocabularies == true>
286 <#assign vocabulariesCollapsed = true />
287 </#if>
288
289 <#-- modificato da col-md-3 a col-lg-3 -->
290 <div class="col-12 col-lg-3 search-filters-container">
291
292 <div class="search-filters filters-desktop">
293 <#-- caso di ricerca per categorie multiple -->
294 <#if ricercaPortletConfig.configSelectMultipleCategories == true>
295 <#-- caso di visualizzazione di tutte le categorie -->
296 <#if ricercaPortletConfig.allVocabulariesCategories == true>
297 <#-- caso di elenco di categorie e sottocategorie indentate con nome vocabolario - sfrutta macro presente nel template RICERCA_COMMON_MACROS -->
298 <#if ricercaPortletConfig.configAllowVocabulariesLabelFilter == true>
299 <span class="d-flex align-items-center justify-content-between text-uppercase" data-toggle="collapse" data-target="#list-filters" role="button" aria-expanded="true" aria-controls="list-filters">
300 <span>${label_categorie}
301 <#if searchInput.categoryIds?has_content>
302 <span class="badge">${searchInput.categoryIds?size}</span>
303 </#if>
304 </span>
305 </span>
306 <div id="list-filters" class="list-filters collapse show mt-4">
307 <ul class="list-unstyled">
308 <#list hierarchicalVocabulariesOptions as voKey, voValue>
309 <#if voKey == DESTINAZIONI_VOCABULARY_ID>
310 <#-- nn lo visualizzo -->
311 <#else>
312 <li class="mb-2">
313 <a class="accordion-title h4" href="#accordion-content_${voKey}" data-toggle="collapse" aria-expanded="<#if !vocabulariesCollapsed>true<#else>false</#if>">
314 ${voValue.value.label}
315 </a>
316 <div id="accordion-content_${voKey}" class="accordion-content collapse <#if !vocabulariesCollapsed>show</#if>">
317 <@getAllCategoriesDesktop voValue.children />
318 </div>
319 </li>
320 </#if>
321 </#list>
322 </ul>
323 </div>
324 <#else>
325 <#-- caso di elenco categorie e sottocategorie indentate ma senza nome vocabolario - sfrutta macro presente nel template RICERCA_COMMON_MACROS -->
326 <#if hierarchicalCategoriesOptions?? && hierarchicalCategoriesOptions?has_content>
327 <span class="d-flex align-items-center justify-content-between text-uppercase" data-toggle="collapse" data-target="#list-filters" role="button" aria-expanded="true" aria-controls="list-filters">
328 <span>${label_categorie}
329 <#if searchInput.categoryIds?has_content>
330 <span class="badge">${searchInput.categoryIds?size}</span>
331 </#if>
332 </span>
333 </span>
334 <div id="list-filters" class="list-filters collapse show mt-4">
335 <#-- ciclo sulle categorie -->
336 <@getAllCategoriesDesktop hierarchicalCategoriesOptions />
337 </div>
338 </#if>
339 </#if>
340 <#else>
341 <#-- caso di categorie selezionate manualmente dalla select di configurazione -->
342 <#-- caso di elenco di categorie e sottocategorie indentate con nome vocabolario - sfrutta macro presente nel template RICERCA_COMMON_MACROS -->
343 <#if ricercaPortletConfig.configAllowVocabulariesLabelFilter == true>
344 <span class="d-flex align-items-center justify-content-between text-uppercase" data-toggle="collapse" data-target="#list-filters" role="button" aria-expanded="true" aria-controls="list-filters">
345 <span>${label_categorie}
346 <#if searchInput.categoryIds?has_content>
347 <span class="badge">${searchInput.categoryIds?size}</span>
348 </#if>
349 </span>
350 </span>
351 <div id="list-filters" class="list-filters collapse show mt-4">
352 <ul class="list-unstyled">
353 <#list flatVocabulariesAndCategoriesAsKeyValueForMultiSelect as voKey, voValue>
354 <#if voKey == DESTINAZIONI_VOCABULARY_ID>
355 <#-- nn lo visualizzo -->
356 <#else>
357 <li class="mb-2">
358 <a class="accordion-title h4" href="#accordion-content_${voKey}" data-toggle="collapse" aria-expanded="<#if !vocabulariesCollapsed>true<#else>false</#if>">
359 ${voValue.value.label}
360 </a>
361 <div id="accordion-content_${voKey}" class="accordion-content collapse <#if !vocabulariesCollapsed>show</#if>">
362 <@getAllCategoriesDesktop voValue.children />
363 </div>
364 </li>
365 </#if>
366 </#list>
367 </ul>
368 </div>
369 <#else>
370 <#-- caso di elenco categorie e sottocategorie indentate ma senza nome vocabolario - sfrutta macro presente nel template RICERCA_COMMON_MACROS -->
371 <#if flatCategoriesAsKeyValueForMultiSelect?? && flatCategoriesAsKeyValueForMultiSelect?has_content>
372 <span class="d-flex align-items-center justify-content-between text-uppercase" data-toggle="collapse" data-target="#list-filters" role="button" aria-expanded="true" aria-controls="list-filters">
373 <span>${label_categorie}
374 <#if searchInput.categoryIds?has_content>
375 <span class="badge">${searchInput.categoryIds?size}</span>
376 </#if>
377 </span>
378 </span>
379 <div id="list-filters" class="list-filters collapse show mt-4">
380 <@getAllCategoriesDesktop flatCategoriesAsKeyValueForMultiSelect />
381 </div>
382 </#if>
383 </#if>
384 </#if>
385 <#else>
386 <#-- visualizzo una select singola -->
387 <label for="select-ricerca-categorie" class="d-block text-uppercase mb-4">${label_categorie}</label>
388 <select name="categoryIds" class="form-control" id="select-ricerca-categorie">
389 <option value="">${label_seleziona}</option>
390 <#list categoriesAsKeyValue?keys as prop>
391 <#assign isSelected = "" />
392 <#if searchInput.categoryIds?has_content>
393 <#list searchInput.categoryIds as categoryId>
394 <#if categoryId?string == prop>
395 <#assign isSelected = "selected" />
396 </#if>
397 </#list>
398 </#if>
399 <option value="${prop}" ${isSelected}>${categoriesAsKeyValue[prop]}</option>
400 </#list>
401 </select>
402 </#if>
403 </div>
404 </div>
405 </#if>
406
407 <#-- lista risultati -->
408 <#-- modificato da col-md-9 a col-lg-9 -->
409 <#if (ricercaPortletConfig.configSearchByCategories == true) && (ricercaPortletConfig.configShowCategoriesFilterInSidebar == true) && (categoriesAsKeyValue?size > 0)>
410 <div class="col-12 col-lg-9 p-0 search-list-results-container">
411 <#else>
412 <div class="col-12 p-0 search-list-results-container">
413 </#if>
414 <#-- numero risultati + range di ricerca corrente + pulsante cambio data -->
415 <#-- aggiunta classe m-0 -->
416 <#if (ricercaPortletConfig.configShowResultNumber == true) ||
417 (ricercaPortletConfig.configShowResultTitle == true && ricercaPortletConfig.configResultTitleLabel != "")||
418 (ricercaPortletConfig.configCanExportSearchResults == true)>
419 <div class="row search-list-results-setting m-0">
420 <div class="col-10 col-sm-10 col-md-10 col-lg-10 col-xl-8 d-flex align-items-center">
421 <#if (ricercaPortletConfig.configShowResultNumber == true) || (ricercaPortletConfig.configShowResultTitle == true && ricercaPortletConfig.configResultTitleLabel != "")>
422 <div class="d-inline-block mb-0 position-relative h3 search-list-results-number no-arrow">
423 <#if ricercaPortletConfig.configShowResultNumber == true>${curEntry.paging.totalRecordsCount} </#if><#if ricercaPortletConfig.configShowResultTitle == true && ricercaPortletConfig.configResultTitleLabel != "">${ricercaPortletConfig.configResultTitleLabel}</#if>
424 </div>
425 </#if>
426 </div>
427
428 <#if ricercaPortletConfig.configCanExportSearchResults == true>
429 <div class="col-2 col-sm-2 col-md-2 col-lg-2 col-xl-4">
430 <button onclick="downloadCsv('${ricercaPortletConfig.configExportCsvUrl}')" class="btn btn-secondary btn-sm float-right" title="${label_scarica_formato_csv}"><span class="fa-solid fa-download" aria-hidden="true"></span></button>
431 </div>
432 </#if>
433 </div>
434 </#if>
435
436 <#if curEntry.records?has_content>
437 <#-- GRIGLIA: solo questa modalita, per cui non vengono utilizzati i vari controlli per lo switch -->
438 <#-- contenitori vista griglia -->
439 <div class="search-list-results grid-view">
440 <div class="grid-view-container">
441 <#-- aggiunta classe m-0 -->
442 <div class="row row-cols-2 row-cols-sm-2 row-cols-md-2 row-cols-lg-3 list-results m-0">
443
444 <#-- ciclo sugli elementi restituiti dalla ricerca -->
445 <#list curEntry.records as record>
446 <#if record.metadata?has_content>
447
448 <#-- assegno alla variabile il titolo di liferay o di struttura, ripulito dai caratteri accentati, da usare come alt o title -->
449 <#assign titoloScheda = "" />
450 <#if record.title?has_content>
451 <#assign titoloScheda = htmlUtil.escapeAttribute(record.title) />
452 </#if>
453 <#if record.metadata.destinationDestinationName?has_content && record.metadata.destinationDestinationName.value?has_content>
454 <#assign titoloScheda = htmlUtil.escapeAttribute(record.metadata.destinationDestinationName.value) />
455 </#if>
456
457 <#-- singolo elemento -->
458 <div class="col position-relative">
459 <#-- funzione aggiungi a trip planner: visualizzo il cuore solo se esistono le coordinate -->
460 <#-- creo variabile di appoggio, poiche devo eventualmente anche eliminare l'angolo bianco della card che sta sotto -->
461 <#-- al contrario dei template, qui i valori delle coordinate sono numeri e non stringhe -->
462 <#assign existLatLong = false />
463 <#if (record.latitude?has_content && record.latitude != 0) && (record.longitude?has_content && record.longitude != 0)>
464 <#assign existLatLong = true />
465 <span class="fa-regular fa-heart transition" title="${label_aggiungi_lista_viaggio}" data-id="idPoi_${record.entryClassPk}"></span>
466 </#if>
467
468 <div class="result-container">
469 <#-- aggiunta classe m-0 -->
470 <div class="row d-flex justify-content-center align-items-center position-relative card-container <#if !existLatLong>no-fa-heart</#if> transition m-0">
471
472 <#-- richiamo l'immagine: fa parte di un fieldset ripetibile, e potrebbe essere una sequenza o una semplice stringa -->
473 <#-- creo una variabile di appoggio per l'url dell'img da usare nella mappa -->
474 <#assign mapImageUrlJs = "" />
475 <#if record.metadata.destinationImage?has_content && record.metadata.destinationImage.value?has_content>
476 <#if record.metadata.destinationImage.value?is_sequence>
477 <#assign numImg = 0 />
478 <#list record.metadata.destinationImage.value as curImage>
479 <#if curImage?? && curImage?has_content>
480 <#attempt>
481 <#assign curImageJson = jsonFactoryUtil.createJSONObject(curImage) />
482 <#if curImageJson?? && curImageJson?has_content && curImageJson.uuid?? && curImageJson.groupId??>
483 <#assign numImg = numImg + 1 />
484 <#assign curImageDLFileEntry = dlFileEntryLocalService.getFileEntryByUuidAndGroupId(curImageJson.uuid,curImageJson.groupId?number) />
485 <#assign curImageUrl = "/documents/"+groupId+"/"+curImageDLFileEntry.getFolderId()+"/"+curImageDLFileEntry.getFileName()+"/"+curImageJson.uuid />
486 <#assign mapImageUrlJs = curImageUrl />
487
488 <div class="col-12 p-0 m-0">
489 <div class="position-relative image-container transition">
490 <img src="${curImageUrl}" class="image-preview-object-fit" alt="${titoloScheda}">
491 </div>
492 </div>
493
494 </#if>
495 <#recover>
496 <#-- in caso di problemi sull'immagine, non visualizzo nulla -->
497 </#attempt>
498 </#if>
499 <#if numImg == 1>
500 <#break>
501 </#if>
502 </#list>
503 <#else>
504 <#attempt>
505 <#assign imageJson = jsonFactoryUtil.createJSONObject(record.metadata.destinationImage.value) />
506 <#if imageJson?? && imageJson?has_content && imageJson.uuid?? && imageJson.groupId??>
507 <#assign imageDLFileEntry = dlFileEntryLocalService.getFileEntryByUuidAndGroupId(imageJson.uuid,imageJson.groupId?number) />
508 <#assign imageUrl = "/documents/"+groupId+"/"+imageDLFileEntry.getFolderId()+"/"+imageDLFileEntry.getFileName()+"/"+imageJson.uuid />
509 <#assign mapImageUrlJs = imageUrl />
510
511 <div class="col-12 p-0 m-0">
512 <div class="position-relative image-container transition">
513 <img src="${imageUrl}" class="image-preview-object-fit" alt="${titoloScheda}">
514 </div>
515 </div>
516 </#if>
517 <#recover>
518 <#-- in caso di problemi sull'immagine, non visualizzo nulla -->
519 </#attempt>
520 </#if>
521 </#if>
522
523 <#-- testi -->
524 <div class="col-md-12 p-3">
525 <div class="text-center text-container">
526
527 <#-- titolo di struttura -->
528 <#if record.metadata.destinationDestinationName?has_content && record.metadata.destinationDestinationName.value?has_content>
529 <#if record.detailUrl?has_content>
530 <a href="${record.detailUrl}" title="${label_vai_dettaglio} ${htmlUtil.escapeAttribute(record.metadata.destinationDestinationName.value)}">
531 <#else>
532 <a href="javascript:void(0);" title="${label_vai_dettaglio} ${htmlUtil.escapeAttribute(record.metadata.destinationDestinationName.value)}">
533 </#if>
534 <div class="transition tit-link check-highlight">
535 <span class="fa fa-map-marker" aria-hidden="true"></span> ${record.metadata.destinationDestinationName.value?trim}
536 </div>
537 </a>
538 </#if>
539
540 <#-- luogo -->
541 <#assign mapAddressJs = "" />
542 <#if (record.metadata.destinationAddressCity?has_content && record.metadata.destinationAddressCity.value?has_content) ||
543 (record.metadata.destinationAddressProvince?has_content && record.metadata.destinationAddressProvince.value?has_content)>
544 <div class="mb-3 search-extra-field-place">
545 <strong class="text-uppercase">(
546 <#if record.metadata.destinationAddressCity?has_content && record.metadata.destinationAddressCity.value?has_content>
547 <#assign mapAddressJs = mapAddressJs + record.metadata.destinationAddressCity.value />
548 ${record.metadata.destinationAddressCity.value}
549 </#if>
550 <#if (record.metadata.destinationAddressCity?has_content && record.metadata.destinationAddressCity.value?has_content) &&
551 (record.metadata.destinationAddressProvince?has_content && record.metadata.destinationAddressProvince.value?has_content)>
552 <#assign mapAddressJs = mapAddressJs + " - " />
553 <span> - </span>
554 </#if>
555 <#if record.metadata.destinationAddressProvince?has_content && record.metadata.destinationAddressProvince.value?has_content>
556 <#assign mapAddressJs = mapAddressJs + record.metadata.destinationAddressProvince.value />
557 ${record.metadata.destinationAddressProvince.value}
558 </#if>
559 )</strong>
560 </div>
561 </#if>
562
563 <#-- sito web: campo visibile nella card, mentre gli altri li aggiungo solo nel marker -->
564 <#assign mapInfoJs = "" />
565 <#if record.metadata.destinationWebsite?has_content && record.metadata.destinationWebsite.value?has_content>
566 <#assign mapInfoJs += "<a href='${record.metadata.destinationWebsite.value?ensure_starts_with('[a-zA-Z]+://', 'http://')}' target='_blank' class='link sito d-inline-block mx-1' title='${label_vai_sito_web}: ${record.metadata.destinationWebsite.value}'><span class='fa-solid fa-earth' aria-hidden='true'></span> ${label_sito_web}</a>" />
567 <a href="${record.metadata.destinationWebsite.value?ensure_starts_with('[a-zA-Z]+://', 'http://')}" target="_blank" class="link sito d-inline-block" title="${label_vai_sito_web}: ${record.metadata.destinationWebsite.value}">
568 <span class="fa-solid fa-earth" aria-hidden="true"></span>
569 ${label_sito_web}
570 </a>
571 </#if>
572 <#if record.metadata.destinationPhoneNumber?has_content && record.metadata.destinationPhoneNumber.value?has_content && record.metadata.destinationPhoneNumber.value != "0039">
573 <#assign mapInfoJs += "<a href='tel:${record.metadata.destinationPhoneNumber.value}' class='link tel d-inline-block mx-1' title='${label_chiama_telefono}: ${record.metadata.destinationPhoneNumber.value}'><span class='fa-solid fa-phone' aria-hidden='true'></span> ${record.metadata.destinationPhoneNumber.value}</a>" />
574 </#if>
575 <#if record.metadata.destinationEmail?? && record.metadata.destinationEmail.value?has_content>
576 <#assign mapInfoJs += "<a href='mailto:${record.metadata.destinationEmail.value}' class='link sito d-inline-block mx-1' title='${label_invia_email_a}: ${record.metadata.destinationEmail.value}'><span class='fa-solid fa-envelope' aria-hidden='true'></span> ${label_e_mail}</a>" />
577 </#if>
578
579 <#-- leggi tutto -->
580 <#if record.detailUrl?has_content>
581 <a href="${record.detailUrl}" title="${label_vai_dettaglio} ${titoloScheda}">
582 <#else>
583 <a href="javascript:void(0);" title="${label_vai_dettaglio} ${titoloScheda}">
584 </#if>
585 <div class="sub-link">
586 ${label_leggi_tutto} <span class="fa fa-angle-right transition" aria-hidden="true"></span>
587 </div>
588 </a>
589
590 <#-- ******************************* CATEGORIE - COMMENTATO ******************************* -->
591 <#-- QUESTO CODICE È COMMENTATO, POICHÈ LE CATEGORIE NN SONO PREVISTE NEI MOCKUP, MA POTREBBE ESSERE SEMPRE UTILE -->
592
593 <#-- metodo tramite record (ricerca) -->
594 <#-- recupero l'elenco delle categorie dall'oggetto record anzichè passando dall'articolo -->
595 <#--
596 <#if record.categories?? && (record.categories?size > 0)>
597 <#list record.categories as key, value>
598 <#if (key?? && key != 0) && (value?? && value != "")>
599 <div class="chip chip-simple chip-outline-secondary chip-no-link">
600 <span class="chip-label">${value}</span>
601 </div>
602 </#if>
603 </#list>
604 </#if>
605 -->
606
607 <#-- categorie: metodo tramite api -->
608 <#--
609 <#assign categorie = []>
610 <#assign categorie = getListCategoryByArticlePrimKey(record.entryClassPk) />
611 <#if categorie?? && (categorie?size > 0)>
612 <#list categorie as cur_cat>
613 <#if validator.isNotNull(cur_cat) && cur_cat != "">
614 <div class="chip chip-simple chip-outline-secondary chip-no-link">
615 <span class="chip-label">${cur_cat.getTitle(locale)}</span>
616 </div>
617 </#if>
618 </#list>
619 </#if>
620 -->
621 <#-- ******************************* CATEGORIE - COMMENTATO ******************************* -->
622
623 </div>
624 </div>
625 <#-- fine testi -->
626
627 </div>
628 </div>
629 </div>
630 <#-- fine singolo elemento -->
631
632 <#-- valorizzo il marker sulla mappa, se esiste latitudine e longitudine -->
633 <#if (record.latitude?has_content && record.latitude != 0) && (record.longitude?has_content && record.longitude != 0)>
634 <script>
635 var marker = L.marker(L.latLng([${record.latitude},${record.longitude}]));
636
637 var infoBox = "";
638 // apertura contenitore infobox e card
639 infoBox += "<div class='info-box'><div class='card bg-white m-0 border-0 shadow-none'>";
640 // immagine
641 <#if mapImageUrlJs?? && mapImageUrlJs != "">
642 infoBox += "<div class='card-img-wrapper'><img src='${mapImageUrlJs}' class='card-img-top' alt='${titoloScheda}'></div>";
643 </#if>
644 // inizio body
645 infoBox += "<div class='card-body p-2'>"
646 //titolo
647 infoBox += "<h2 class='card-title mb-2'><a href='${record.detailUrl}' title='${label_vai_dettaglio} ${titoloScheda}'>${titoloScheda}</a></h2>"
648 // indirizzo
649 <#if mapAddressJs?? && mapAddressJs != "">
650 infoBox += "<p class='mt-0 mb-2'><span class='fa fa-map-marker mr-1'></span><strong>${mapAddressJs}</strong></p>"
651 </#if>
652 // info
653 <#if mapInfoJs?? && mapInfoJs != "">
654 infoBox += "<p class='mt-0 mb-2'>${mapInfoJs}</p>"
655 </#if>
656 // fine body
657 infoBox += "</div>"
658 // fine contenitore infobox e card
659 infoBox += "</div></div>"
660
661 var popup = marker.bindPopup(infoBox);
662 TglSearchMap.addMarker(marker);
663 </script>
664 </#if>
665
666 </#if>
667 </#list>
668 <#-- fine ciclo -->
669
670 </div>
671 </div>
672 </div>
673 <#-- FINE GRIGLIA -->
674 </#if>
675 <#-- fine curEntry -->
676
677 <#-- paginazione mediante taglib-->
678 <#-- aggiunta classe m-0 -->
679 <div class="row mb-0">
680 <div class="col-12 text-center">
681 <@ricerca_components["ricerca-pagination"]
682 currentPage=curEntry.paging.page?number
683 totalPages=curEntry.paging.totalPagesCount?number
684 paginationUrl="${portletURL}"></@>
685 </div>
686 </div>
687
688 </div>
689 </div>
690 </div>
691
692 </#list>
693 </#if>
694
695 </div>
696</div>
697
698<script>
699 $(document).ready(function(){
700 // carico la mappa
701 TglSearchMap.loadMap(true);
702
703 // scroll fino a ricerca
704 $('html, body').animate({
705 scrollTop: $(".search-template-localita").offset().top
706 }, 500);
707
708 // quando il container collapsed viene visualizzato, ricostruisco la mappa e applico il fitbounds, oltre che a visualizzare il popover, se non ancora visualizzato
709 $('#map-container-desktop').on('shown.bs.collapse', function () {
710 TglSearchMap.getMap().invalidateSize();
711 TglSearchMap.fitBounds();
712
713 // popover on draw circle function
714 if( $('.leaflet-draw-draw-circle').length === 1){
715 if (sessionStorage.getItem('showedPopoverMap') == undefined) {
716 showTooltipOnMap('.search-template-localita .leaflet-draw-draw-circle');
717 }
718 if(isShowedPopover){
719 hideTooltipOnMap('.search-template-localita .leaflet-draw-draw-circle','body');
720 }
721 }
722 });
723
724 // leggo i parametri dall'url: se esiste showMap ed è uguale a true, apro il collapse che contiene la mappa
725 // succede se arrivo dal template form_ricerca (form fittizia)
726 let searchParams = new URLSearchParams(window.location.search)
727 if (searchParams.has('showMap')){
728 let searchParamShowMap = searchParams.get('showMap');
729 if (searchParamShowMap == 'true'){
730 $('#map-container-desktop').collapse('show');
731 }
732 }
733
734 <#-- js per filtri categorie -->
735 <#if (ricercaPortletConfig.configSearchByCategories == true) && (categoriesAsKeyValue?size > 0)>
736 <#-- filtri categorie multiple -->
737 <#if ricercaPortletConfig.configSelectMultipleCategories == true>
738 /*bind checkbox category_*/
739 $('.search-template-localita input[id^="category_"]').click(function(){
740 var $currentElem = $( this );
741 if(!$currentElem.prop('checked')){
742 $(".search-template-localita #search-localita-form-desktop #form_"+$currentElem.attr('id')).remove();
743 }
744 else{
745 $(".search-template-localita #search-localita-form-desktop #form_"+$currentElem.attr('id')).remove();
746 var input = '<input class="mr-2 hide" style="display:none" type="checkbox" name="'+$currentElem.attr('name')+'" id="form_'+$currentElem.attr('id')+'" value="'+$currentElem.val()+'" checked="">';
747 $('.search-template-localita #search-localita-form-desktop .search-form').append(input);
748 }
749 $('.search-template-localita #search-localita-form-desktop').submit();
750 });
751 /*initialize checkbox category_*/
752 $('.search-template-localita input[id^="category_"]').each(function(){
753 var $currentElem = $( this );
754 if($currentElem.prop('checked')){
755 $(".search-template-localita #search-localita-form-desktop #form_"+$currentElem.attr('id')).remove();
756 var input = '<input class="mr-2 hide" style="display:none" type="checkbox" name="'+$currentElem.attr('name')+'" id="form_'+$currentElem.attr('id')+'" value="'+$currentElem.val()+'" checked="">';
757 $('.search-template-localita #search-localita-form-desktop .search-form').append(input);
758 }
759 });
760
761 <#else>
762
763 <#-- filtri categorie singola -->
764 /*bind checkbox category_*/
765 $('.search-template-localita #select-ricerca-categorie').on('change', function() {
766 var $currentElem = $(this);
767 var optionVal = $currentElem.val();
768
769 if(optionVal===undefined || optionVal==null || optionVal==''){
770 $(".search-template-localita #search-localita-form-desktop input[id^='form_']").remove();
771 }
772 else{
773 if ($('.search-template-localita #select-ricerca-categorie option[value=optionVal]').is(':selected')){
774 $(".search-template-localita #search-localita-form-desktop input[id^='form_']").remove();
775 }else{
776 $(".search-template-localita #search-localita-form-desktop input[id^='form_']").remove();
777 var input = '<input class="mr-2 hide" style="display:none;" type="checkbox" name="'+$currentElem.attr('name')+'" id="form_'+$currentElem.attr('id')+'" value="'+optionVal+'" checked="">';
778 $('.search-template-localita #search-localita-form-desktop .search-form').append(input);
779 }
780 }
781 $('.search-template-localita #search-localita-form-desktop').submit();
782 });
783 /*initialize checkbox category_*/
784 $('.search-template-localita #select-ricerca-categorie option').each(function(){
785 var $currentElem = $( this );
786 var optionVal = $currentElem.val();
787 if(optionVal!==undefined && optionVal!=null && optionVal!=''){
788 if($currentElem.is(':selected')){
789 $(".search-template-localita #search-localita-form-desktop input[id^='form_']").remove();
790 var input = '<input class="mr-2 hide" style="display:none;" type="checkbox" name="'+$currentElem.attr('name')+'" id="form_'+$currentElem.attr('id')+'" value="'+$currentElem.val()+'" checked="">';
791 $('.search-template-localita #search-localita-form-desktop .search-form').append(input);
792 }
793 }
794 });
795 </#if>
796 </#if>
797
798 });
799</script>
Explore like a true local
Here are some itineraries to discover the Marches