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