Si è verificato un errore nell'elaborarazione del modello.
The following has evaluated to null or missing: ==> thisCardData [in template "20098#20124#1784553" at line 574, column 10] ---- 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 thisCardData?contains("journal-te... [in template "20098#20124#1784553" in macro "printCard" at line 574, column 5] - Reached through: @printCard curEntry, curEntry?index [in template "20098#20124#1784553" in function "generateHtmlData" at line 390, column 37] ----
1<!-- Tours listing UNI FTL -->
2<#assign counter = 0>
3<#assign journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") />
4<#assign assetCategoryService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetCategoryService") />
5<#assign thisFilterScope = "${randomNamespace}filter">
6
7<#-- instanceId with id parent layout to allow emebed differrent widget on different pages -->
8<#assign cur_time = .now>
9<#assign urlHelper = vtaLibrary.getUrlHelper()>
10<#assign cacheSufix = urlHelper + "_" + locale>
11<#assign cur_instanceId = "html_data_" + themeDisplay.getLayout().uuid + cacheSufix>
12
13<#-- tours common filters array: -->
14<#assign filter_tourType = []>
15<#assign filter_month = []>
16<#assign filter_destination = []>
17<#assign filter_price_from = []>
18<#assign filter_destinationCountry = []>
19<#assign filter_interests= []>
20<#assign filter_duration= []>
21<#assign filter_recommended= []>
22<#-- excursions specific filters array: -->
23<#assign filter_estartingpoint= []>
24<#assign filter_eduration= []>
25<#assign departureDates= []><#-- currently used only to count dates...-->
26
27<#assign data_set=[]>
28<#assign curYearYY = .now?string('yy')?number>
29<#assign curMonthMM = .now?string('MM')?number>
30
31<#assign envSettings = vtaLibrary.getEnvSettings()>
32<#assign vocDestTypenId = envSettings.vocDestTypenId?number>
33<#assign vocPopularityId = envSettings.vocPopularityId?number>
34<#assign embedTourCardUniId = envSettings.embedTourCardUniId>
35<#assign structureGuidedTourId = 975893>
36<#assign currency = "err">
37<#assign sectionLabelList = translationsUtils.getMessage(locale,'vta.webcontent.results')?lower_case?cap_first>
38<#assign sectionLabelFilters = translationsUtils.getMessage(locale,'vta.webcontent.filters')?lower_case?cap_first>
39<#if vtaUtil??>
40 <#assign currency = vtaUtil.getCurrencySymbol(request)>
41</#if>
42
43<#-- clear all cache by URL param (use ...url..."?cacheUpdate" ) -->
44<#assign curUrl = themeDisplay.getURLCurrent()?string>
45<#if curUrl?contains("?cacheUpdate")>
46 <#assign temp = freemarkerFilterCache.clearFreemarkerCache()>
47 <script>
48 console.log("Force cache update.");
49 </script>
50</#if>
51
52<#assign showFilerPanel = entries?size gte 5>
53
54<#-- check if are only Guided tours in list -->
55<#assign isGuidedListingOnly = false>
56<#if entries?has_content>
57 <#assign cur_guidesTypeCounter = 0>
58 <#list entries as curEntry>
59 <#assign cur_renderer=curEntry.getAssetRenderer() />
60 <#assign cur_journalArticle=cur_renderer.getArticle() />
61 <#assign cur_structureId = cur_journalArticle.getDDMStructureId()?string>
62 <#if vtaLibrary.getTemplateForStructure(cur_structureId?string,"name") = "guided">
63 <#assign cur_guidesTypeCounter = cur_guidesTypeCounter + 1>
64 </#if>
65 </#list>
66 <#assign isGuidedListingOnly = (cur_guidesTypeCounter == entries?size)>
67</#if>
68<!-- GUIDED ONLY: ${isGuidedListingOnly?string} -->
69<#if isGuidedListingOnly>
70 <#assign sortString = "gu_rec">
71<#else>
72 <#assign sortString = "rec">
73</#if>
74
75<#-- ################## -->
76<script src="${themeDisplay.getPathThemeJavaScript()}/vta-filter.js?t=${themeDisplay.getTheme().getTimestamp()}" type="text/javascript" data-senna-track="permanent"></script>
77
78
79<@generateData/>
80<#assign htmlData = generateHtmlData()>
81
82<!-- print html -->
83${htmlData}
84
85<#-- ******** generate data ********* -->
86<#macro generateData>
87 <#if entries?has_content>
88 <#list entries as curEntry>
89 <@generateCardData curEntry curEntry?index/>
90 </#list>
91 </#if>
92</#macro>
93
94
95<#function generateHtmlData>
96 <#-- HTML cachable data -->
97 <#local htmlData>
98
99 <#compress>
100 <style>
101 .d-tour.hidden,
102 .results-line .result,
103 #zeroBanner.hidden,
104 .results-line[data-results="1"] .results {
105 display:none;
106 }
107
108 .results-line[data-results="1"] .result {
109 display:inline;
110 }
111
112 /* default thumbs css */
113 .-Tour-swiperThumbs .swiper-slide {
114 width: 110px;
115 margin-right: 2px;
116 }
117 </style>
118
119 <div id="${thisFilterScope}" class="-sidebarLayout -Section -Section--verticalIndentLarge" data-sidewidth="3" data-space="2" <#--data-direction="row-reverse" data-sideright="true"--> data-switchxsmd="true" data-overflowvisible="true">
120 <div>
121 <#-- filter col -->
122 <section id="${thisFilterScope}-filter" class="-formElements js-f-col-filter" style="${showFilerPanel?then('','display:none;')}" aria-labelledby="filter-section-label">
123 <h2 class="sr-only" id="filter-section-label">${sectionLabelFilters}</h2>
124 <div class="-Collapse -Collapse--xsmdTypeDropdown -Collapse--xsmdExpandFullScreen -formElements">
125 <div class="-Collapse-contents">
126 <div class="-Collapse-content">
127 <div id="collapseFilters" class="-Collapse-collapse collapse" data-expanded-md="true">
128 <div class="-Panel -Panel--xsmdTypeModalFlyout -Collapse-panel -Collapse-panel--typeModalFlyout">
129 <div class="-Panel-inner">
130 <div class="-Panel-head">
131 <div class="-clusterLayout" data-space="05" data-align="center" data-justify="space-between">
132 <div>
133 <div>
134 <strong class="-clusterLayout" data-space="02" data-align="center" data-nowrap="true">
135 <span>
136 <i class="-Icon -Icon--filter" aria-hidden="true"></i><span>${translationsUtils.getMessage(locale,'vta.webcontent.filterBy')}</span>
137 </span>
138 </strong>
139 </div>
140 <div>
141 <button id="clearAllButton" type="button" class="-Button -Button--typeLinkSecondary">${translationsUtils.getMessage(locale,'vta.webcontent.clearAll')}</button>
142 </div>
143 </div>
144 </div>
145 </div>
146 <div class="-Panel-body">
147 <div class="-stackLayout" data-space="03">
148 <div></div>
149 <div class="-stackLayout" data-space="3" data-space-xsmd="0">
150
151
152 <#-- tour type -->
153 <#if getAllUniqueArray(filter_tourType)?size gt 1>
154 <#assign curFilterContent>
155 <@printFilterCheckBoxes filter_tourType "ttype"/>
156 </#assign>
157 <#assign curFilterTitle = translationsUtils.getMessage(locale,'vta.common.labels.tourType')>
158 <#assign curFilterStyle = "">
159 <@printFilterSection curFilterTitle curFilterContent curFilterStyle/>
160 </#if>
161
162 <#-- months -->
163 <#if filter_month?size gt 0>
164 <#assign curFilterContent>
165 <div class="-stackLayout" data-space="01">
166 <div class="-stackLayout" data-space="03">
167 <h4 class="-Heading -Heading--typeH6 -Heading--skinSharp">20${curYearYY}</h4>
168 <div><@printFilterDates filter_month "${curYearYY}"/></div>
169 </div>
170 <div class="-stackLayout" data-space="03">
171 <h4 class="-Heading -Heading--typeH6 -Heading--skinSharp">20${curYearYY+1}</h4>
172 <div><@printFilterDates filter_month "${curYearYY+1}"/></div>
173 </div>
174 </div>
175 </#assign>
176 <#assign curFilterTitle = translationsUtils.getMessage(locale,'vta.webcontent.departureMonth')>
177 <#assign curFilterStyle = "">
178 <@printFilterSection curFilterTitle curFilterContent curFilterStyle/>
179 </#if>
180
181 <#-- ex starting points -->
182 <#if filter_estartingpoint?size gt 0>
183 <#assign curFilterContent>
184 <@printFilterCheckBoxes filter_estartingpoint "estartingp"/>
185 </#assign>
186 <#assign curFilterTitle = translationsUtils.getMessage(locale,'vta.webcontent.starting.point')>
187 <#assign curFilterStyle = "">
188 <@printFilterSection curFilterTitle curFilterContent curFilterStyle/>
189 </#if>
190
191 <#-- ex duration -->
192 <#if filter_eduration?size gt 0>
193 <#assign curFilterContent>
194 <@printFilterCheckBoxes filter_eduration "eduration"/>
195 </#assign>
196 <#assign curFilterTitle = translationsUtils.getMessage(locale,'vta.webcontent.duration')>
197 <#assign curFilterStyle = "">
198 <@printFilterSection curFilterTitle curFilterContent curFilterStyle/>
199 </#if>
200
201
202 <#-- prices -->
203 <#if filter_price_from?size gt 0>
204 <#assign curFilterContent>
205 <div id="rangePrices" class="-Range -stackLayout js-frange" data-space="01">
206 <@printRangeCombo filter_price_from currency "Prices"/>
207 </div>
208 </#assign>
209 <#assign curFilterTitle = translationsUtils.getMessage(locale,'vta.webcontent.pricePerPerson')>
210 <#assign curFilterStyle = "${(isRangePrintable(filter_price_from))?then('','display:none;')}">
211 <@printFilterSection curFilterTitle curFilterContent curFilterStyle/>
212 </#if>
213
214 <#-- destinations -->
215 <#if filter_destination?size gt 0>
216 <#assign curFilterContent>
217 <div class="-CollapseGroup -stackLayout" data-space="03">
218 <#-- country -->
219 <div>
220 <div class="-Collapse -Collapse--typeChevron">
221 <div class="-Collapse-contents">
222 <div class="-Collapse-content">
223 <div class="-Collapse-head" id="destCollapseHead1">
224 <button class="-Button--expand -Button--typeBare -Collapse-toggle" data-toggle="collapse" href="#destCollapseItem1" role="button" aria-expanded="true" aria-controls="destCollapseItem1">
225 <strong class="-Collapse-toggleContents">
226 <span class="-Collapse-toggleContent">${translationsUtils.getMessage(locale,'vta.common.labels.country')}</span>
227 <span class="-Collapse-toggleIndicator" aria-hidden="true"></span>
228 </strong>
229 </a>
230 </div>
231 <div id="destCollapseItem1" class="-Collapse-collapse collapse show">
232 <div class="-Collapse-body">
233 <@printFilterCheckBoxes filter_destinationCountry "tcountry"/>
234 </div>
235 </div>
236 </div>
237 </div>
238 </div>
239 </div>
240
241 <#-- tem destinations -->
242 <@printDestinationsFilter filter_destination "tdest"/>
243
244 </div>
245 </#assign>
246 <#assign curFilterTitle = translationsUtils.getMessage(locale,'vta.webcontent.destinations')>
247 <#assign curFilterStyle = "">
248 <@printFilterSection curFilterTitle curFilterContent curFilterStyle/>
249 </#if>
250
251 <#-- interest -->
252 <#if filter_interests?size gt 0>
253 <#assign curFilterContent>
254 <@printFilterCheckBoxes filter_interests "tinterests"/>
255 </#assign>
256 <#assign curFilterTitle = translationsUtils.getMessage(locale,'vta.webcontent.interest')>
257 <#assign curFilterStyle = "">
258 <@printFilterSection curFilterTitle curFilterContent curFilterStyle/>
259 </#if>
260
261
262 <#-- days -->
263 <#if filter_duration?size gt 0>
264 <#assign curFilterContent>
265 <div id="rangeDurations" class="-Range -stackLayout js-frange" data-space="01">
266 <@printRangeCombo filter_duration "${translationsUtils.getMessage(locale,'vta.webcontent.days')}" "Durations"/>
267 </div>
268 </#assign>
269 <#assign curFilterTitle = translationsUtils.getMessage(locale,'vta.webcontent.tourLength')>
270 <#assign curFilterStyle = "${(isRangePrintable(filter_duration))?then('','display:none;')}">
271 <@printFilterSection curFilterTitle curFilterContent curFilterStyle/>
272 </#if>
273
274
275 </div>
276 </div>
277 </div>
278 <div class="-Panel-foot -mdHidden">
279 <div class="-clusterLayout" data-align="center" data-justify="space-between" data-nowrap="true">
280 <div>
281 <div>
282 <button type="button" data-toggle="collapse" data-target="#collapseFilters" aria-expanded="false" aria-controls="collapseFilters" class="-Button -Button--sizeMediumLarge -Button--typePrimary">
283 ${translationsUtils.getMessage(locale,'vta.common.labels.apply')}</button>
284 </div>
285 <div>
286 <button type="button" data-toggle="collapse" data-target="#collapseFilters" aria-expanded="false" aria-controls="collapseFilters" class="-Button -Button--sizeMediumLarge -Button--typeLinkSecondary">
287 ${translationsUtils.getMessage(locale,'vta.common.labels.cancel')}</button>
288 </div>
289 </div>
290 </div>
291 </div>
292 </div>
293 </div>
294 </div>
295 </div>
296 </div>
297 </div>
298 </section>
299
300 <#-- list col -->
301 <section aria-labelledby="list-section-label">
302 <h2 class="sr-only" id="list-section-label">${sectionLabelList}</h2>
303 <div class="-stackLayout" data-space="05">
304 <div class="-clusterLayout" data-space="05" data-align="center" data-justify="space-between">
305 <div>
306 <div>
307 <strong class="results-line" data-results="${entries?size}">
308 <span class="js-f-results">${entries?size}</span>
309 <span class="results">${translationsUtils.getMessage(locale,'vta.webcontent.results')}</span>
310 <span class="result">${translationsUtils.getMessage(locale,'vta.webcontent.result')}</span>
311 </strong>
312 </div>
313 <div>
314 <div class="-clusterLayout" data-space="1" data-align="center" data-justify="space-between" data-nowrap="true">
315 <div>
316
317 <#if showFilerPanel>
318 <div>
319 <button type="button" class="-Button -Button--typeBare -mdHidden" id="collapseFiltersToggle" data-toggle="collapse" data-target="#collapseFilters" aria-expanded="false" aria-controls="collapseFilters">
320 <span class="-clusterLayout" data-space="02" data-align="center" data-nowrap="true">
321 <span>
322 <i class="-Icon -Icon--filter" aria-hidden="true"></i><span> ${translationsUtils.getMessage(locale,'vta.webcontent.filters')} </span>
323 </span>
324 </span>
325 </button>
326 </div>
327 </#if>
328
329 <div>
330 <div class="-Collapse -Collapse--typeDropdown -Collapse--dropdownJustifyEnd">
331 <div class="-Collapse-contents">
332 <div class="-Collapse-content">
333 <div class="-Collapse-head">
334 <button id="collapseSortToggle" type="button" class="-Button -Button--typeBare collapsed" data-toggle="collapse" data-target="#collapseSort" aria-expanded="false" aria-controls="collapseSort" data-collapse-dropdown="true">
335 <span class="-clusterLayout" data-space="02" data-align="center" data-nowrap="true">
336 <span>
337 <i class="-Icon -Icon--sort" aria-hidden="true"></i><span> ${translationsUtils.getMessage(locale,'vta.webcontent.sortBy')} </span>
338 </span>
339 </span>
340 </button>
341 </div>
342 <div id="collapseSort" class="-Collapse-collapse collapse" aria-labelledby="collapseSortToggle" data-dropdown-justify="end" style="">
343 <div class="-Panel -Panel--typeFlyout -Collapse-panel -Collapse-panel--typeFlyout">
344 <div class="-Panel-inner">
345 <div class="-Panel-body -formElements">
346 <div class="-stackLayout js-sset" data-space="02">
347
348 <#assign sortListArray = [
349 {"id":"Recommended", "datasort":"${sortString}", "value":"Recommended", "checked":true, "label":"${translationsUtils.getMessage(locale,'vta.webcontent.recommended')}"},
350 {"id":"PriceLowToHigh", "datasort":"pr_lo", "value":"Price (low to high)", "checked":false, "label":"${translationsUtils.getMessage(locale,'vta.webcontent.priceLowToHigh')}"},
351 {"id":"PriceHighToLow", "datasort":"pr_hi", "value":"Price (high to low)", "checked":false, "label":"${translationsUtils.getMessage(locale,'vta.webcontent.priceHighToLow')}"},
352 {"id":"DepartureEarliestToLatest", "datasort":"de_er", "value":"Departure (earliest to latest)", "checked":false, "label":"${translationsUtils.getMessage(locale,'vta.webcontent.departureEarliestToLatest')}"},
353 {"id":"DepartureLatestToEarliest", "datasort":"de_lt", "value":"Departure (latest to earliest)", "checked":false, "label":"${translationsUtils.getMessage(locale,'vta.webcontent.departureLatestToEarliest')}"},
354 {"id":"DurationShortest", "datasort":"du_sh", "value":"Duration (shortest)", "checked":false, "label":"${translationsUtils.getMessage(locale,'vta.webcontent.durationShortest')}"},
355 {"id":"DurationLongest", "datasort":"du_ln", "value":"Duration (longest)", "checked":false, "label":"${translationsUtils.getMessage(locale,'vta.webcontent.durationLongest')}"}
356 ]>
357 <#list sortListArray as item>
358 <div class="-CustomControl -CustomControl--typeCheckMark js-sitem --focus-w">
359 <div class="custom-control custom-radio">
360 <label>
361 <input name="sortBy" data-sort="${item.datasort}" id="${item.id}" type="radio" class="-CustomControlInput custom-control-input js-sitem-input"
362 role="radio" value="${item.value}" ${item.checked?then('checked=""','')}>
363 <span class="custom-control-label">
364 <span class="custom-control-label-text">${item.label}</span>
365 </span>
366 </label>
367 </div>
368 </div>
369 </#list>
370
371 </div>
372 </div>
373 </div>
374 </div>
375 </div>
376 </div>
377 </div>
378 </div>
379 </div>
380
381 </div>
382 </div>
383 </div>
384 </div>
385 </div>
386
387 <div id="${thisFilterScope}-list" class="-stackLayout js-f-col-list" data-space="1">
388 <#if entries?has_content>
389 <#list entries as curEntry>
390 <@printCard curEntry curEntry?index/>
391 </#list>
392 </#if>
393
394 <#-- ********* don't remove - using for service prints -->
395 <#-- tourtype: ${filter_tourType?size} -->
396 <#-- month: ${filter_month?size} -->
397 <#-- destinations: ${filter_destination?size} -->
398 <#-- price: ${filter_price_from?size} -->
399 <#-- country: ${filter_destinationCountry?size} -->
400 <#-- interest: ${filter_interests?size} -->
401 <#-- duration: ${filter_duration?size} -->
402 <#-- recomended: ${filter_recommended?size} -->
403 <#-- ex starting point: ${filter_estartingpoint?size} -->
404 <#-- ex duration: ${filter_eduration?size} -->
405
406 <#-- loader -->
407 <#-- <div class="-LoaderContainer -LoaderContainer--variantSpinner -LoaderContainer--sizeMedium" data-state="active"></div> -->
408
409 <div id="banner" style="display:none;">
410 <#-- marketingBanner_${themeDisplay.getSiteGroupId()} -->
411 <#assign thisPrefs = freeMarkerPortletPreferences.getPreferences("portletSetupPortletDecoratorId", "barebone") />
412 <@liferay_portlet["runtime"]
413 defaultPreferences="${thisPrefs}"
414 portletProviderAction=portletProviderAction.VIEW
415 instanceId="marketingBanner_${themeDisplay.getSiteGroupId()}"
416 portletName="com_liferay_journal_content_web_portlet_JournalContentPortlet"
417 />
418 </div>
419
420 <div id="zeroBanner" class="hidden">
421 <#-- zeroBanner_${themeDisplay.getSiteGroupId()} -->
422 <#assign thisPrefs = freeMarkerPortletPreferences.getPreferences("portletSetupPortletDecoratorId", "barebone") />
423 <@liferay_portlet["runtime"]
424 defaultPreferences="${thisPrefs}"
425 portletProviderAction=portletProviderAction.VIEW
426 instanceId="zeroBanner_${themeDisplay.getSiteGroupId()}"
427 portletName="com_liferay_journal_content_web_portlet_JournalContentPortlet"
428 />
429 </div>
430
431 </div>
432
433 </div>
434 </section>
435
436
437 </div>
438 </div>
439
440 </#compress>
441 <@scripts/>
442 </#local>
443 <#-- /HTML cachable data -->
444
445<#return htmlData>
446</#function>
447
448
449<#-- ************************************** -->
450
451<#-- print filter section -->
452<#macro printFilterSection title content class="">
453 <#if filterSectionCounter??>
454 <#assign filterSectionCounter = filterSectionCounter + 1>
455 <#else>
456 <#assign filterSectionCounter = 1>
457 </#if>
458 <div class="-stackLayout" data-space="01" style="${class}" role="group" aria-labelledby="section-head_${filterSectionCounter}">
459 <div class="-stackLayout" data-space="04">
460 <h3 class="-Heading -Heading--typeH5Immutable -Heading--skinSharp" id="section-head_${filterSectionCounter}">${title}</h3>
461 <hr class="-Hr">
462 </div>
463 ${content}
464 </div>
465</#macro>
466
467
468
469
470<#-- get last modification date by structure type -->
471<#function getModDateForArticle article>
472 <#local ret = "00000">
473 <#if article.DDMStructureId?string = structureGuidedTourId?string>
474 <#-- get GuidedTour last modification datetime from BE -->
475 <#if !guidedToursModDatesMap??>
476 <#local guidedToursModDatesMap = guidedUtil.getLastModifiedMap(request)>
477 </#if>
478 <#if guidedToursModDatesMap[article.articleId]??>
479 <#local ret = guidedToursModDatesMap[article.articleId]>
480 <#else>
481 <#-- no data on BE -->
482 <#local ret = article.modifiedDate?datetime?string>
483 </#if>
484 <#else>
485 <#-- all tours except GuidedTours -->
486 <#local ret = article.modifiedDate?datetime?string>
487 </#if>
488 <#return ret>
489</#function>
490
491
492<#-- generate data and update/create cache -->
493<#macro generateCardData curEntry index>
494 <#local renderer=curEntry.getAssetRenderer() />
495 <#local cur_journalArticle=renderer.getArticle() />
496 <#local cur_journalArticle_Uuid = cur_journalArticle.uuid?string>
497 <#local cur_journalArticle_ModDate = getModDateForArticle(cur_journalArticle)>
498 <#-- articleID: ${cur_journalArticle.getArticleId()} -->
499 <#local card_id = "${randomNamespace}tc_${index}">
500 <#-- cache logic -->
501 <#if freemarkerFilterCache??>
502 <#local thisCacheItem = freemarkerFilterCache.getArticleItem(cur_journalArticle_Uuid + cacheSufix)!"null"><#-- read cache date modification date -->
503
504 <#if thisCacheItem = "null">
505 <#local cur_cacheMessage = "No cache record ...created">
506 <#local thisCardData = renderCardData(cur_journalArticle)>
507 <#elseif cur_journalArticle_ModDate == thisCacheItem.changeDate>
508 <#local thisCardData = thisCacheItem.content!"null"><#-- read cache data -->
509 <#if thisCardData != "null">
510 <#-- <#local cur_cacheMessage = "HIT actual"> -->
511 <#else>
512 <#local cur_cacheMessage = "HIT - record empty ...created">
513 <#local thisCardData = renderCardData(cur_journalArticle)>
514 </#if>
515 <#else>
516 <#local cur_cacheMessage = "HIT modified: ${thisCacheItem.changeDate} : ${cur_journalArticle_ModDate}<br>...updated">
517 <#local thisCardData = renderCardData(cur_journalArticle)>
518 </#if>
519 <#else>
520 <#local thisCardData = renderCardData(cur_journalArticle)>
521 <#local cur_cacheMessage = "Cache not installed">
522 </#if>
523 <#-- end cache logic -->
524
525 <#local thisCode = thisCardData>
526 <#assign data_map = thisCode?split("<-DATA-SPLIT->")>
527
528 <#if !thisCode?contains("journal-template-error") && data_map?size gt 1>
529 <#local currnetDataArray = data_map[1]?eval>
530 <#local dataString>
531 <@collectData currnetDataArray card_id/>
532 </#local>
533 <#list currnetDataArray as cur_dataArry>
534 <#local thisJsStringRecord = '{ "id":"${card_id}","inRanges":true,"inScope":true,"sort-date":"",${collectJsString(cur_dataArry)}}'>
535 <#assign data_set = data_set + [thisJsStringRecord]>
536 </#list>
537 </#if>
538 <#if cur_cacheMessage??>
539 <script>console.log("cache: ${card_id} ${cur_journalArticle.getTitle(locale)}, (${cur_journalArticle_ModDate}) : ${cur_cacheMessage}");</script>
540 </#if>
541</#macro>
542
543
544
545<#-- print a tour card from cache ONLY-->
546<#macro printCard curEntry index>
547 <#local renderer=curEntry.getAssetRenderer() />
548 <#local cur_journalArticle=renderer.getArticle() />
549 <#local cur_journalArticle_Uuid = cur_journalArticle.uuid?string>
550 <#local cur_journalArticle_ModDate = getModDateForArticle(cur_journalArticle)>
551 <#local card_id = "${randomNamespace}tc_${index}">
552
553 <#-- cache logic -->
554 <#if freemarkerFilterCache??>
555 <#local thisCacheItem = freemarkerFilterCache.getArticleItem(cur_journalArticle_Uuid + cacheSufix)!"null"><#-- read cache date modification date -->
556
557 <#if thisCacheItem = "null">
558 <#local cur_cacheMessage = "No cache record ...created">
559 <#elseif cur_journalArticle_ModDate == thisCacheItem.changeDate>
560 <#local thisCardData = thisCacheItem.content!"null"><#-- read cache data -->
561 <#if thisCardData != "null">
562 <#-- <#local cur_cacheMessage = "HIT actual"> -->
563 <#else>
564 <#local cur_cacheMessage = "HIT - record empty ERRRRRRRR!">
565 </#if>
566 <#else>
567 <#local cur_cacheMessage = "HIT modified: ${thisCacheItem.changeDate} : ${cur_journalArticle_ModDate}<br>...ERRRRRRRRRR!">
568 </#if>
569 <#else>
570 <#local cur_cacheMessage = "Cache not installed">
571 </#if>
572 <#-- end cache logic -->
573
574 <#if thisCardData?contains("journal-template-error")>
575 <div id="${card_id}" class="d-tour" >
576 <div style="background-color:black; color:white; padding:1em;">
577 <h2>*** card error ***</h2>
578 <h4>${cur_journalArticle.getTitle()}</h4>
579 <a href="${urlHelper}/w/${cur_journalArticle.getUrlTitle()}" target="_blank">OPEN TOUR</a>
580 <!-- ${cur_journalArticle} -->
581 </div>
582 <!-- ${thisCardData} -->
583 </div>
584 <#elseif thisCardData?contains("PAST TOUR")>
585 <!-- PAST TOUR: ${cur_journalArticle.getTitle()} -->
586 <#-- <div id="${card_id}" class="d-tour" >
587 <div style="background-color:lightskyblue; color:white; padding:1em;">
588 <h2>*** PAST TOUR ***</h2>
589 <h4>${cur_journalArticle.getTitle()}</h4>
590 <a href="${urlHelper}/w/${cur_journalArticle.getUrlTitle()}" target="_blank">OPEN TOUR</a>
591 </div>
592 </div> -->
593 <#elseif !thisCardData?contains("<-DATA-SPLIT->")>
594 <div id="${card_id}" class="d-tour" >
595 <div style="background-color:black; color:white; padding:1em;">
596 <h2>*** wrong template or webcontent ***</h2>
597 <h4>${cur_journalArticle.getTitle()}</h4>
598 <!-- ${cur_journalArticle} -->
599 </div>
600 </div>
601 <#else>
602 <#local data_map = thisCardData?split("<-DATA-SPLIT->")>
603 <#-- <p style="font-size: 0.6em;">${thisJsStringRecord?replace(":",": ")?replace(",",", ")} </p> -->
604 <div id="${card_id}" class="d-tour js-f-tour-card hidden"><#--${(index gte 2)?then('hidden','')}-->
605 <#if cur_cacheMessage??>
606 <script>console.log("*cache: ${card_id} ${cur_journalArticle.getTitle(locale)} : ${cur_cacheMessage}");</script>
607 </#if>
608 <#-- style="font-size: 0.6em;">${thisJsStringRecord?replace(":",": ")?replace(",",", ")} -->
609 <#-- ${thisCardData} -->
610 ${data_map[0]}${data_map[3]}
611 </div>
612
613
614
615 </#if>
616</#macro>
617
618<#-- render CARD data and write to cache -->
619<#function renderCardData cur_journalArticle>
620 <#local thisEntryData>
621 <@liferay_journal["journal-article"]
622 articleId=cur_journalArticle.getArticleId()
623 ddmTemplateKey="${embedTourCardUniId}"
624 groupId=cur_journalArticle.getGroupId()
625 />
626 </#local>
627 <#local thisEntryId = cur_journalArticle.uuid?string + cacheSufix>
628 <#local thisEntryDate = getModDateForArticle(cur_journalArticle)>
629 <#if freemarkerFilterCache??>
630 <#local writeMe = freemarkerFilterCache.putArticleItem(thisEntryId, thisEntryDate, thisEntryData)><#-- update cache -->
631 </#if>
632 <#return thisEntryData>
633</#function>
634
635<#function collectJsString hash>
636 <#local retString = "">
637 <#list hash as key,val>
638 <#local retString = retString + '"${key}": ' + (val?is_number)?then('${val}','"${val}"') + (key?is_last)?then('',', ')>
639 </#list>
640 <#return retString>
641</#function>
642
643
644<#-- data collect -->
645<#macro collectData hashArry id>
646 <#list hashArry as cur_hash>
647 <#list cur_hash as key,val>
648 <#if val?string="">
649 <#continue><#-- skip empty val -->
650 </#if>
651 ${key}="${val}"
652 <#if val?contains(",")>
653 <#assign value = val?split(",")>
654 <#else>
655 <#assign value = [val]>
656 </#if>
657 <#if key = "data-ttype">
658 <#assign filter_tourType = filter_tourType + value/>
659 <#elseif key = "data-tmonth">
660 <#assign filter_month = filter_month + value/>
661 <#elseif key = "data-tdest">
662 <#assign filter_destination = filter_destination + value/>
663 <#elseif key = "data-tprice">
664 <#assign filter_price_from = filter_price_from + value/>
665 <#elseif key = "data-tcountry">
666 <#assign filter_destinationCountry = filter_destinationCountry + value/>
667 <#elseif key = "data-tinterests">
668 <#assign filter_interests = filter_interests + value/>
669 <#elseif key = "data-tlength">
670 <#assign filter_duration = filter_duration + value/>
671 <#elseif key = "data-trec" && val?string != "">
672 <#assign filter_recommended = filter_recommended + value/>
673 <#elseif key = "data-estartingp" && val != "">
674 <#assign filter_estartingpoint = filter_estartingpoint + value/>
675 <#elseif key = "data-eduration">
676 <#assign filter_eduration = filter_eduration + value/>
677 </#if>
678 </#list>
679 </#list>
680</#macro>
681
682<#-- print a range inside combo -->
683<#macro printRangeCombo array units name>
684 <#local cur_array = []>
685 <#local minMaxStringsMapsArry = [{
686 "name":"Prices",
687 "min":translationsUtils.getMessage(locale,'vta.webcontent.rangePricesFrom'),
688 "max":translationsUtils.getMessage(locale,'vta.webcontent.rangePricesTo')
689 },{
690 "name":"Durations",
691 "min":translationsUtils.getMessage(locale,'vta.webcontent.rangeTourLengthMin'),
692 "max":translationsUtils.getMessage(locale,'vta.webcontent.rangeTourLengthMax')
693 }]>
694 <#if array?size != 0>
695 <#list array as item>
696 <#if item?is_number>
697 <#-- item is a valid number -->
698 <#local cur_array = cur_array + [item?number]>
699 <#else>
700 <#-- item is not a number! -->
701 <!-- array: ${array?join(", ")} -->
702 <!-- item: ${item} -->
703 <#local cur_array = [0,1]>
704 <#break>
705 </#if>
706 </#list>
707
708 <#local rangeMinLabel = (minMaxStringsMapsArry?filter(item -> item.name == name)?size == 1)?then((minMaxStringsMapsArry?filter(item -> item.name == name)[0].min),'Range Min')>
709 <#local rangeMaxLabel = (minMaxStringsMapsArry?filter(item -> item.name == name)?size == 1)?then((minMaxStringsMapsArry?filter(item -> item.name == name)[0].max),'Range Max')>
710
711 <#local cur_min = cur_array?min>
712 <#local cur_max = cur_array?max>
713 <#local cur_step = "1">
714 <div class="-Range-Value">
715 <span class="-Range-fromValue" data-from-value="">${cur_min}</span>
716 <span class="-Range-fromValueSuffix">${units}</span>
717 <span class="-Range-valueSeparator">-</span>
718 <span class="-Range-toValue" data-to-value="">${cur_max}</span>
719 <span class="-Range-toValueSuffix">${units}</span>
720 </div>
721 <div class="-Range-control">
722 <input type="range" id="from${name}" name="from${name}" data-from=""
723 value="${cur_min}" min="${cur_min}" max="${cur_max}" step="${cur_step}" aria-label="${rangeMinLabel}">
724 <input type="range" id="to${name}" name="to${name}" data-to=""
725 value="${cur_max}" min="${cur_min}" max="${cur_max}" step="${cur_step}" aria-label="${rangeMaxLabel}"
726 style="background: linear-gradient(to right,
727 var(--_range-control-secondary-color) 0%,
728 var(--_range-control-secondary-color) 20%,
729 var(--_range-control-primary-color) 20%,
730 var(--_range-control-primary-color) 66.66666666666666%,
731 var(--_range-control-secondary-color) 66.66666666666666%,
732 var(--_range-control-secondary-color) 100%); z-index: 0;">
733 </div>
734 </#if>
735
736</#macro>
737
738<#function isRangePrintable array>
739 <#local cur_array = []>
740 <#if array?size != 0>
741 <#list array as item>
742 <#attempt>
743 <#-- try -->
744 <#local cur_array = cur_array + [item?number]>
745 <#recover>
746 <#local cur_array = [0,1]>
747 <#break>
748 </#attempt>
749 </#list>
750 <#if cur_array?min != cur_array?max>
751 <#return true>
752 </#if>
753 </#if>
754 <#return false>
755</#function>
756
757
758<#macro printDestinationsFilter array type>
759 <#-- get array of destinations with types -->
760 <#local otherTypeName = translationsUtils.getMessage(locale,'vta.webcontent.other')>
761 <#local popularTypeName = "popular"><#-- default value if no popular tour... -->
762 <#local existPopulars = false>
763 <#local existOthers = false>
764 <#local destArray = []>
765 <#-- DEST : ${array?size} -->
766 <#-- DEST : ${array?join(", ")} -->
767
768 <#local allUniqueDestIds = getAllUniqueArray(array)>
769 <#-- UNIQ : ${allUniqueDestIds?size} -->
770 <#-- UNIQ : ${allUniqueDestIds?join(", ")} -->
771 <#list allUniqueDestIds as item>
772 <#local popular = readByClassPkAndVocIdWcCatName(item vocPopularityId "None")><#-- return name or "error" for missing classPk -->
773 <#if popular != "None" && popular != "error" >
774 <#local typeName = popular>
775 <#local popularTypeName = popular>
776 <#local existPopulars = true>
777 <#else>
778 <#local typeName = readByClassPkAndVocIdWcCatName(item vocDestTypenId "${otherTypeName}")>
779 <#local existOthers = true>
780 </#if>
781
782 <#local destArray = destArray + [{ "typeName":typeName, "destId":item }]>
783 </#list>
784
785 <#-- get array of unique types (labels of sections)-->
786 <#local allUniqueTypes = []>
787 <#if existPopulars><#-- add populars at start -->
788 <#local allUniqueTypes = allUniqueTypes + [popularTypeName]>
789 </#if>
790 <#list destArray?sort_by("typeName") as item>
791 <#if !(allUniqueTypes?seq_contains(item.typeName)) && item.typeName != popularTypeName && item.typeName != otherTypeName>
792 <#local allUniqueTypes = allUniqueTypes + [item.typeName]>
793 </#if>
794 </#list>
795 <#if existOthers><#-- add populars at end -->
796 <#local allUniqueTypes = allUniqueTypes + [otherTypeName]>
797 </#if>
798
799 <#-- iterate each type sets -->
800 <#list allUniqueTypes as cur_item>
801 <#-- types: ${cur_item} - ${popularTypeName} -->
802 <#local filteredDestNames = destArray?filter(item -> item.typeName == cur_item)?map(item -> item.destId)>
803 <#local collapseName = cur_item?replace("[^0-9a-zA-Z_]", "_", "r")>
804 <#local openDropDown = (cur_item == popularTypeName)>
805 <div>
806 <div class="-Collapse -Collapse--typeChevron">
807 <div class="-Collapse-contents">
808 <div class="-Collapse-content">
809 <div class="-Collapse-head">
810 <button class="-Button--expand -Button--typeBare -Collapse-toggle" data-toggle="collapse" role="button" aria-expanded="${openDropDown?c}"
811 href="#${collapseName}Item" aria-controls="${collapseName}Item">
812 <h4 class="-Collapse-toggleContents -Heading -Heading--typeH6 -Heading--skinSharp">
813 <span class="-Collapse-toggleContent">${cur_item}</span>
814 <span class="-Collapse-toggleIndicator" aria-hidden="true"></span>
815 </h4>
816 </button>
817 </div>
818 <div id="${collapseName}Item" class="-Collapse-collapse collapse ${openDropDown?then('show','')}">
819 <div class="-Collapse-body">
820
821 <@printFilterCheckBoxes filteredDestNames type/>
822
823 </div>
824 </div>
825 </div>
826 </div>
827 </div>
828 </div>
829
830 </#list>
831
832
833</#macro>
834
835
836<#function getAllUniqueArray array>
837 <#-- create array of unique items from array -->
838 <#local allUniqueItems = []>
839 <#list array as item>
840 <#if !(allUniqueItems?seq_contains(item))>
841 <#local allUniqueItems = allUniqueItems + [item]>
842 </#if>
843 </#list>
844
845 <#return allUniqueItems>
846</#function>
847
848
849
850<#-- filtr checkboxes -->
851<#macro printFilterCheckBoxes array type>
852
853 <#local allUniqueItems = getAllUniqueArray(array)>
854 <#local printArray = []>
855 <#list allUniqueItems?sort as item>
856 <#local screen_name = item>
857 <#if item?string = "">
858 <#continue>
859 <#elseif type = "tdest">
860 <#local screen_name = readByClassPkWebContentField(item,"ScreenName")>
861 <#elseif type = "ttype">
862 <#local langKey = vtaLibrary.getTemplateForStructure(screen_name,"lang")>
863 <#local screen_name = translationsUtils.getMessage(locale,langKey)>
864 <#elseif type = "tinterests" || type = "estartingp">
865 <#local screen_name = assetCategoryService.fetchCategory(screen_name?number).getTitle(locale)>
866 <#elseif type = "tcountry" && screen_name != "No country">
867 <#local screen_name = assetCategoryService.fetchCategory(screen_name?number).getTitle(locale)>
868 <#elseif type = "eduration">
869 <#switch item?string>
870 <#case "0">
871 <#local screen_name = translationsUtils.getMessage(locale,'vta.webcontent.short.up.2.hrs')>
872 <#break>
873 <#case "1">
874 <#local screen_name = translationsUtils.getMessage(locale,'vta.webcontent.medium')>
875 <#break>
876 <#case "2">
877 <#local screen_name = translationsUtils.getMessage(locale,'vta.webcontent.long.8plus.hrs')>
878 <#break>
879 <#default>
880 <#local screen_name = "Unknown">
881 </#switch>
882 </#if>
883 <#local count = array?filter(it -> it == item)?size >
884 <#local printArray = printArray + [{"screenName":screen_name, "item":item, "count":count}]>
885 <#-- ${item}, ${screen_name}, ${count} -->
886 </#list>
887
888 <div class="-stackLayout js-fset" data-ftype="${type}" data-space="04">
889 <#list printArray?sort_by("screenName") as item>
890 <@printFilterCheckboxItem item.item item.screenName item.count type/>
891 </#list>
892 </div>
893</#macro>
894
895 <#-- print one checkbox -->
896 <#macro printFilterCheckboxItem item screen_name count type>
897 <div class="custom-control custom-checkbox js-fitem">
898 <label>
899 <input type="checkbox"
900 class="-CustomControlInput custom-control-input js-fitem-input"
901 data-fname="${item}"
902 role="checkbox" value="${screen_name}">
903 <span class="custom-control-label">
904 <span class="custom-control-label-text filter-item">${screen_name} (<span class="-colorSecondaryPale js-fitem-count">${count}</span>)</span> <#-- to prevent orphan a number in the responsive design -->
905 </span>
906 </label>
907 </div>
908 </#macro>
909
910
911<#-- month list -->
912<#macro printFilterDates array year>
913 <div class="-gridLayout js-fset" data-fragment="1of4" data-space="02" data-overflowvisible="true" data-ftype="tmonth">
914 <div>
915 <#-- ${array?sort?join(", ")} -->
916 <#list 1..12 as cur_month>
917 <#local cur_fname = year + "-" + cur_month?left_pad(2, "00")>
918 <#local cur_is_enabled = array?seq_contains(cur_fname)>
919 <#if year?number == curYearYY?number && cur_month?number lt curMonthMM?number><#--disable past months-->
920 <#local cur_is_enabled = false>
921 </#if>
922 <#-- *${cur_fname}* -->
923 <#local cur_temp_date = dateUtil.parseDate("yyyy-MM-dd", "1999-" + cur_month?left_pad(2, "00") + "-01", locale)><#-- fake date 1999-MM-01 -->
924 <#local cur_month_string = dateUtil.getDate(cur_temp_date, "MMM", locale)>
925 <div>
926 <div class="-CustomControl -CustomControl--typeButton">
927 <div class="custom-control custom-checkbox ${cur_is_enabled?then('js-fitem','')}">
928 <label>
929 <input name="departureMonth"
930 type="checkbox"
931 class="-CustomControlInput custom-control-input ${cur_is_enabled?then('js-fitem-input','')}"
932 role="checkbox" value="${cur_month_string}"
933 ${cur_is_enabled?then('data-fname="${cur_fname}"','')}
934 ${cur_is_enabled?then("","disabled")}>
935 <span class="custom-control-label">
936 <span class="custom-control-label-text">${cur_month_string}</span>
937 </span>
938 </label>
939 </div>
940 </div>
941 </div>
942 </#list>
943 </div>
944 </div>
945</#macro>
946
947<#-- read a filed form webcontent -->
948<#function readByClassPkWebContentField classPK fieldReference>
949 <#local ret = "*****">
950 <#if classPK !="">
951 <#local journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService")>
952 <#local journalArticle = journalArticleLocalService.fetchLatestArticle(classPK?number)>
953 <#local docXML = saxReaderUtil.read(journalArticle.getDocument().asXML())>
954 <#local ret = docXML.selectSingleNode("/root/dynamic-element[@field-reference='${fieldReference}']/dynamic-content").getData()>
955 <#assign counter = counter + 1>
956 </#if>
957 <#return ret>
958</#function>
959
960<#-- read a category name form webcontent by classPK a vocabularyId-->
961<#function readByClassPkAndVocIdWcCatName classPK vocabularyId noCategorySetReturnString>
962 <#local ret = "error">
963 <#if classPK !="">
964 <#local assetCategoryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetCategoryLocalService") />
965 <#local categoryList=assetCategoryLocalService.getCategories("com.liferay.journal.model.JournalArticle",classPK?number) >
966
967 <#-- this category is NOT multioptional (if yes only first item will be returned -->
968 <#local name = noCategorySetReturnString>
969 <#list categoryList as category>
970 <#if category.vocabularyId = vocabularyId>
971 <#local name = category.getTitle(locale)>
972 </#if>
973 </#list>
974
975 <#local ret = name >
976 </#if>
977 <#return ret>
978</#function>
979
980<#macro scripts>
981 <#-- min/max price and length -->
982 <#assign priceArray = []>
983 <#list filter_price_from as item>
984 <#if item?string != "">
985 <#assign priceArray = priceArray + [item?number]>
986 </#if>
987 </#list>
988 <#if priceArray?size = 0>
989 <#assign priceArray = [0,1]>
990 </#if>
991
992
993 <#assign durationArray = []>
994 <#list filter_duration as item>
995 <#if item?string != "">
996 <#assign durationArray = durationArray + [item?number]>
997 </#if>
998 </#list>
999 <#if durationArray?size = 0>
1000 <#assign durationArray = [0,1]>
1001 </#if>
1002 <script>
1003
1004 ;AUI().ready(function() {
1005 // All data source
1006 var filterDataArray = [
1007 <#list data_set as item>
1008 ${item}<#sep>,</#sep>
1009 </#list>
1010 ];
1011
1012 var dataObject = {
1013 thisOrFilters: ["ttype","tmonth"],
1014 filterDataArray: filterDataArray,
1015 thisFilterCol: document.getElementById("${thisFilterScope}-filter"),
1016 thisResultsCol: document.getElementById("${thisFilterScope}-list"),
1017 rangePricesId: "rangePrices",
1018 rangeDurationsId: "rangeDurations",
1019 defaultRangePriceFrom: ${priceArray?min},
1020 defaultRangePriceTo: ${priceArray?max},
1021 defaultRangeLengthFrom: ${durationArray?min},
1022 defaultRangeLengthTo: ${durationArray?max},
1023 rangePriceFrom: ${priceArray?min},
1024 rangePriceTo: ${priceArray?max},
1025 rangeLengthFrom: ${durationArray?min},
1026 rangeLengthTo: ${durationArray?max},
1027 defaultSort: "${sortString}"
1028 };
1029
1030 handleRangeComponent(".-Range");
1031 startFilter(dataObject);
1032 });
1033
1034 </script>
1035
1036 <#-- <script> // DEBUG SCRIPT
1037
1038 var filterDataArray = [
1039 <#list data_set as item>
1040 ${item}<#sep>,</#sep>
1041 </#list>
1042 ];
1043
1044 var dataObject = {
1045 thisOrFilters: ["ttype","tmonth"],
1046 filterDataArray: filterDataArray,
1047 thisFilterCol: document.getElementById("${thisFilterScope}-filter"),
1048 thisResultsCol: document.getElementById("${thisFilterScope}-list"),
1049 rangePricesId: "rangePrices",
1050 rangeDurationsId: "rangeDurations",
1051 defaultRangePriceFrom: ${priceArray?min},
1052 defaultRangePriceTo: ${priceArray?max},
1053 defaultRangeLengthFrom: ${durationArray?min},
1054 defaultRangeLengthTo: ${durationArray?max},
1055 rangePriceFrom: ${priceArray?min},
1056 rangePriceTo: ${priceArray?max},
1057 rangeLengthFrom: ${durationArray?min},
1058 rangeLengthTo: ${durationArray?max},
1059 defaultSort: "${sortString}"
1060 };
1061
1062 //handleRangeComponent('.-Range');
1063 //startFilter(dataObject);
1064
1065
1066 </script> -->
1067
1068
1069
1070 <script>
1071
1072 ;function startSwipers(swiperContainers) {
1073 // + init swipers
1074 function setSwiper(container, index) {
1075 let thumbContainer = container.querySelector('.js-swiper-thumb');
1076 let mainContainer = container.querySelector('.js-swiper-main');
1077
1078 if (!thumbContainer.swiper) {
1079 var swiperThumb = new Swiper(thumbContainer, {
1080 spaceBetween: 2,
1081 speed: 500,
1082 grabCursor: true,
1083 keyboard: {
1084 enabled: true,
1085 },
1086 slidesPerView: 3,
1087 freeMode: {
1088 enabled: true,
1089 sticky: true,
1090 },
1091 watchSlidesProgress: false,
1092 });
1093
1094 var swiperMain = new Swiper(mainContainer, {
1095 spaceBetween: 2,
1096 speed: 500,
1097 grabCursor: true,
1098 keyboard: {
1099 enabled: true,
1100 },
1101 navigation: {
1102 nextEl: thumbContainer.querySelector('.swiper-button-next'),
1103 prevEl: thumbContainer.querySelector('.swiper-button-prev'),
1104 },
1105 thumbs: {
1106 swiper: swiperThumb,
1107 },
1108 });
1109
1110 // Uložit instance Swiperu, pokud je třeba s nimi dále pracovat
1111 thumbContainer.swiperInstance = swiperThumb;
1112 mainContainer.swiperInstance = swiperMain;
1113 }
1114 else {
1115 console.log(index, "uz existuje");
1116 }
1117 };
1118
1119 var observerOptions = {
1120 root: null, // Viewport jako kořen
1121 rootMargin: '0px',
1122 threshold: 0.1 // Spustí se, když je alespoň 10% prvku viditelné
1123 };
1124
1125 var observer = new IntersectionObserver((entries, observer) => {
1126 entries.forEach(entry => {
1127 if (entry.isIntersecting) {
1128 setSwiper(entry.target);
1129 observer.unobserve(entry.target); // Přestat sledovat prvek po inicializaci Swiperu
1130 }
1131 });
1132 }, observerOptions);
1133
1134 swiperContainers.forEach(container => {
1135 observer.observe(container); // Začít sledovat každý kontejner
1136 });
1137 };
1138
1139 ;AUI().ready(function() {
1140 var swContainer = document.querySelectorAll('.js-swipers-container');
1141 startSwipers(swContainer);
1142 });
1143
1144 </script>
1145</#macro>