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.
Leggi tutto
Riduci
Si è verificato un errore nell'elaborarazione del modello.
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>
Esplora come un vero local
Ecco alcuni itinerari per scoprire le Marche