VIVISOL Intensivservice vor Ort
Nähe schafft Vertrauen.
Unsere regionalen Teams in Bayern, Bremen, Nordrhein-Westfalen und Niedersachsen sind für Sie da, um eine schnelle und persönliche Versorgung zu gewährleisten. Finden Sie hier Ihren direkten Ansprechpartner.
Fehler bei der Verarbeitung der Vorlage.
The following has evaluated to null or missing:
==> assetVocabularyLocalService.fetchGroupVocabulary(themeDisplay.getScopeGroupId(), vocabularyName) [in template "37204#37246#42066452" at line 70, column 31]
----
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: #assign vocabulary = assetVocabularyL... [in template "37204#37246#42066452" at line 70, column 9]
----
1<#assign resourcePrimaryKey = .vars["reserved-article-resource-prim-key"].data />
2<#assign idArticle = .vars["reserved-article-id"].data />
3
4<#-- assetEntry-->
5<#assign assetEntryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetEntryLocalService") />
6<#assign assetTagLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetTagLocalService") />
7<#assign assetCategoryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetCategoryLocalService") />
8<#assign assetVocabularyLocalService= serviceLocator.findService("com.liferay.asset.kernel.service.AssetVocabularyLocalService") />
9<#assign assetEntry = assetEntryLocalService.fetchEntry("com.liferay.journal.model.JournalArticle", resourcePrimaryKey?number) />
10<#if !assetEntry?has_content>
11 <#stop "Error: Asset Entry with resourcePrimaryKey = ${resourcePrimaryKey} not found. Template execution stopped." />
12</#if>
13
14<#-- JournalArticle-->
15<#assign journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") />
16<#assign journalArticle = journalArticleLocalService.fetchLatestArticle(resourcePrimaryKey?number) />
17<#if !journalArticle?has_content>
18 <#stop "Error: Journal Article with resourcePrimaryKey = ${resourcePrimaryKey} not found. Template execution stopped." />
19</#if>
20
21<div class="thematic-area-page-content mt-5">
22 <div class="page-intro">
23
24 <!-- Publish Date -->
25 <#if assetEntry.getPublishDate()?has_content>
26 <div class="subtitle-div gap-3">
27 <h4 class="subtitle plain-text mb-0"> ${dateUtil.getDate(assetEntry.getPublishDate(), "d MMMM yyyy", locale, timeZone)?upper_case}</h4>
28 </div>
29 </#if>
30
31 <!-- Title -->
32 <h1 class="title">${journalArticle.getTitle(themeDisplay.getLocale())}</h1>
33
34 <!-- Subtitle -->
35 <div class="subtitle-div flex-wrap">
36 <h4 class="subtitle plain-text col-md-6 p-0">${languageUtil.get(locale, 'authors')}: ${authors.getData()}</h4>
37 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'document-language')}: ${documentLanguage.getData()!""}</h4>
38 <#if publishDateCustom?? && publishDateCustom.getData()?has_content>
39 <#assign dateObj = dateUtil.parseDate("yyyy-MM-dd", publishDateCustom.getData(), locale) />
40 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'publish-date')}: ${dateUtil.getDate(dateObj, "d MMMM yyyy", locale, timeZone)}</h4>
41 </#if>
42 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'citation')}: ${(citation.getData())!""}</h4>
43 <h4 class="subtitle plain-text col-md-6 col-12 p-0">DOI: ${(doi.getData())!""}</h4>
44 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'keywords-vivilibrary')}: ${(keywords.getData())!""}</h4>
45 </div>
46
47 <#assign distributionLevelChoice = distributionLevel.getData()!""/>
48 <div class="distribution-level mt-3 ${distributionLevelChoice}">
49 <b>${languageUtil.get(locale, distributionLevelChoice)}</b>
50 </div>
51
52 <!-- Main Image -->
53 <#assign mainImageUrl = ""/>
54 <#assign mainImageCss = ""/>
55 <#if uploadDocument.document.getData()?has_content>
56 <#assign mainImageUrl = uploadDocument.document.getData() + "&previewFileIndex=1">
57 <#assign mainImageCss = "main-image-crop"/>
58 <#elseif journalArticle.getArticleImageURL(themeDisplay)?has_content>
59 <#assign mainImageUrl = journalArticle.getArticleImageURL(themeDisplay)>
60 </#if>
61 <#if mainImageUrl?has_content>
62 <div class="main-image-div">
63 <img class="main-image ${(mainImageCss)!""}" src="${mainImageUrl}" alt="scientific article">
64 </div>
65 </#if>
66
67 <!-- Categories-->
68 <#assign vocabularyName = "Therapy" />
69 <#assign vocabularyId = 0 />
70 <#assign vocabulary = assetVocabularyLocalService.fetchGroupVocabulary(themeDisplay.getScopeGroupId(), vocabularyName)/>
71 <#if vocabulary??>
72 <#assign vocabularyId = vocabulary.getVocabularyId()/>
73 </#if>
74
75 <#assign cats = [] />
76 <#if assetEntry.getCategories()?has_content>
77 <#list assetEntry.getCategories() as c>
78 <#if c.getVocabularyId() == vocabularyId>
79 <#assign cats = cats + [c] />
80 </#if>
81 </#list>
82 </#if>
83
84 <#assign tags = [] />
85 <#if assetTagLocalService.getAssetEntryAssetTags(assetEntry.getEntryId())?has_content>
86 <#assign tags = assetTagLocalService.getAssetEntryAssetTags(assetEntry.getEntryId())>
87 </#if>
88
89 <#if tags?has_content || cats?has_content>
90 <div class="tags-container flex-wrap">
91 <#if cats?has_content>
92 <#list cats as cat>
93 <span class="tag tag-style">${languageUtil.get(locale, "account-treatment-"+cat.getTitle(themeDisplay.getLocale()))}</span>
94 </#list>
95 </#if>
96 <#if tags?has_content>
97 <#list tags as tag>
98 <span class="tag tag-style">${tag.getName()}</span>
99 </#list>
100 </#if>
101 </div>
102 </#if>
103 </div>
104
105 <!-- Wavy divider -->
106 <div class="wavy-divider">
107 <svg viewBox="0 0 1440 60" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none">
108 <path d="M0,20 Q360,60 720,20 T1440,20 V60 H0 Z" fill="#fff"/>
109 </svg>
110 </div>
111
112 <!-- 1. One column section -->
113 <#if shortAbstract.oneColumnSectionTitle.getData()?has_content && shortAbstract.oneColumnText.getData()?has_content>
114 <div class="sections-block">
115 <h4 class="section-title reading-time-parameter">${shortAbstract.oneColumnSectionTitle.getData()}</h4>
116 <div class="one-column-text p-0">
117 <div class="plain-text reading-time-parameter">${shortAbstract.oneColumnText.getData()}</div>
118 </div>
119 </div>
120 </#if>
121
122 <!-- 3. Two columns section -->
123 <#if abstract.title.getData()?has_content &&
124 abstract.text.getData()?has_content>
125 <div class="sections-block">
126 <h4 class="section-title reading-time-parameter">${abstract.title.getData()}</h4>
127 <div class="col-md-12 p-0">
128 <div class="plain-text reading-time-parameter multi-column-text">${abstract.text.getData()}</div>
129 </div>
130 </div>
131 </#if>
132
133 <!-- 5. Embedded document section -->
134 <#if uploadDocument.docSectionTitle.getData()?has_content && uploadDocument.document.getData()?has_content && uploadDocument.document.getData()?has_content>
135 <#assign totalPages = webContentUtil.getDocumentPreviewPageCount(themeDisplay, uploadDocument.document.getData()) />
136 <div class="sections-block">
137 <h4 class="section-title reading-time-parameter">${uploadDocument.docSectionTitle.getData()}</h4>
138 <div class="doc-container">
139 <div class="col-md-12 p-0">
140 <div class="doc-embed d-flex flex-column align-items-center">
141 <button class="pdf-open-doc" data-pdf-url="${uploadDocument.document.getData()}">
142 ${languageUtil.get(locale, "open-document")}
143 </button>
144 <div class="pdf-pages-container">
145 <#list 1..totalPages as page>
146 <img
147 src="${uploadDocument.document.getData()}&previewFileIndex=${page}"
148 class="pdf-page"
149 data-page="${page}"
150 />
151 </#list>
152 </div>
153 <div class="doc-index">
154 <div class="pdf-pagination">
155 <button class="pdf-nav prev subtitle"><</button>
156 <div class="pdf-nav-index-div"></div>
157 <button class="pdf-nav next subtitle">></button>
158 </div>
159 </div>
160 </div>
161 </div>
162 </div>
163 </div>
164 </#if>
165
166 <#assign linkTagIsNotEmpty = false>
167 <#list references.getSiblings() as field>
168 <#if field.getData()?? && field.linkTitle.getData()?trim != "" && field.linkUrl.getData()?trim != "">
169 <#assign linkTagIsNotEmpty = true>
170 <#break>
171 </#if>
172 </#list>
173
174 <!-- 6. Link section -->
175 <#if linkTagIsNotEmpty>
176 <div class="sections-block" style="border-bottom-right-radius:12px;border-bottom-left-radius:12px;">
177 <h4 class="section-title reading-time">${languageUtil.get(locale, "references")}</h4>
178 <div class="d-flex flex-column">
179 <#list references.getSiblings() as link>
180 <#if link.linkTitle.getData()?has_content && link.linkUrl.getData()?has_content>
181 <div class="link-card mb-4">
182 <div class="link-info">
183 <div class="link-title reading-time-parameter"><b>${link.linkTitle.getData()}</b></div>
184 <#if link.linkDesc.getData()?has_content>
185 <div class="link-description reading-time-parameter">${link.linkDesc.getData()}</div>
186 </#if>
187 </div>
188 <a href="${(link.linkUrl.getData())!'javascript:void(0);'}" class="download-btn"
189 title="Scarica" onclick="openLinkInNewTab(event, this)">
190 <i class="icom-vivimedical-link-icon">
191 </i>
192 </a>
193 </div>
194 </#if>
195 </#list>
196 </div>
197 </div>
198 </#if>
199
200</div>
201
202<script src="https://cdn.jsdelivr.net/npm/hammerjs@2.0.8/hammer.min.js"></script>
203
204<script>
205 function initializeOpenDocButton() {
206 const openDocBtn = document.querySelector('.pdf-open-doc');
207 if (openDocBtn) {
208 openDocBtn.addEventListener('click', () => {
209 const pdfUrl = openDocBtn.getAttribute('data-pdf-url');
210 if (!pdfUrl) {
211 alert('PDF not available');
212 return;
213 }
214 const newTab = window.open(pdfUrl, '_blank');
215 if (!newTab) {
216 alert('Unable to open the PDF. Please check your browser settings for pop-ups.');
217 }
218 });
219 }
220 }
221
222 function pdfPagination() {
223 const pages = document.querySelectorAll('.pdf-page');
224 const prevBtn = document.querySelector('.pdf-nav.prev');
225 const nextBtn = document.querySelector('.pdf-nav.next');
226 const pageNumbersContainer = document.querySelector('.pdf-nav-index-div');
227
228 // pdf-pagination struct: 1....lastPage
229 const totalPages = pages.length;
230 const firstPage = 1;
231 const lastPage = totalPages;
232 let currentPage = firstPage;
233 let indexStyleClass = 'subtitle';
234
235 function addStyle(elem, styleClass) {
236 elem.classList.add(styleClass);
237 }
238
239 function addPageButton(pageNumber) {
240 const btn = document.createElement('button');
241 btn.className = 'pdf-page-num';
242 btn.textContent = pageNumber;
243 addStyle(btn, indexStyleClass);
244 pageNumbersContainer.appendChild(btn);
245 }
246
247 function addEllipsis() {
248 const span = document.createElement('span');
249 span.className = 'pdf-page-num ellipsis';
250 span.textContent = '...';
251 addStyle(span, indexStyleClass);
252 pageNumbersContainer.appendChild(span);
253 }
254
255 // invalid currentPage sets value to default (firstPage)
256 function validateCurrentPage(currentPage, defaultValue) {
257 if (typeof currentPage !== 'number' || isNaN(currentPage) ||
258 currentPage < firstPage || currentPage > lastPage) {
259 return defaultValue;
260 }
261 return currentPage;
262 }
263
264 function renderPageNumbers(currentPage) {
265 pageNumbersContainer.innerHTML = '';
266 currentPage = validateCurrentPage(currentPage, firstPage);
267 console.log("totalPages " + totalPages);
268 if (totalPages >= 1 && totalPages <= 4) {
269 for (let i = firstPage; i < firstPage + totalPages; i++) {
270 addPageButton(i);
271 }
272 }
273 else if (currentPage == firstPage || currentPage == firstPage + 1) {
274 addPageButton(firstPage);
275 addPageButton(firstPage + 1);
276 addPageButton(firstPage + 2);
277 addEllipsis();
278 addPageButton(lastPage);
279 } else if (currentPage == lastPage - 1 || currentPage == lastPage) {
280 addPageButton(firstPage);
281 addEllipsis();
282 addPageButton(lastPage - 2);
283 addPageButton(lastPage - 1);
284 addPageButton(lastPage);
285 } else {
286 addPageButton(firstPage);
287 addEllipsis();
288 addPageButton(currentPage);
289 addEllipsis();
290 addPageButton(lastPage);
291 }
292 }
293
294 function setActivePage(currentPage) {
295 if (validateCurrentPage(currentPage, firstPage)) {
296 const buttons = document.querySelectorAll('.pdf-page-num');
297 buttons.forEach(btn => btn.classList.remove('active'));
298 buttons.forEach(btn => {
299 if (parseInt(btn.textContent, 10) === currentPage) {
300 btn.classList.add('active');
301 }
302 });
303 }
304 }
305
306 function showPage(page) {
307 currentPage = page;
308 // hides all images
309 document.querySelectorAll('.pdf-page').forEach(img => img.style.display = 'none');
310 // display currentPage image
311 const currentPageElement = document.querySelector('.pdf-page[data-page="' + page + '"]');
312 if (currentPageElement) {
313 currentPageElement.style.display = 'block';
314 }
315 prevBtn.disabled = currentPage === firstPage;
316 nextBtn.disabled = currentPage === lastPage;
317 renderPageNumbers(currentPage);
318 setActivePage(currentPage);
319 }
320
321 // prev btn listener
322 prevBtn.addEventListener('click', function () {
323 if (currentPage > firstPage) showPage(currentPage - 1);
324 });
325
326 // next btn listener
327 nextBtn.addEventListener('click', function () {
328 if (currentPage < lastPage) showPage(currentPage + 1);
329 });
330
331 // index btn listener
332 pageNumbersContainer.addEventListener('click', function (e) {
333 if (e.target.classList.contains('pdf-page-num') && !e.target.classList.contains('ellipsis')) {
334 const pageNumber = parseInt(e.target.textContent, 10);
335 if (!isNaN(pageNumber)) {
336 showPage(pageNumber);
337 }
338 }
339 });
340
341 //Hammer.js
342 function initializeHammer() {
343 const container = document.querySelector('.pdf-pages-container');
344
345 if (!container || typeof Hammer === 'undefined') {
346 console.warn('Container not found or Hammer.js not loaded');
347 return;
348 }
349
350 const hammer = new Hammer(container);
351
352 hammer.get('swipe').set({ direction: Hammer.DIRECTION_HORIZONTAL });
353
354 hammer.on('swipeleft', () => {
355 if (currentPage < totalPages) {
356 showPage(currentPage + 1);
357 }
358 });
359
360 hammer.on('swiperight', () => {
361 if (currentPage > 1) {
362 showPage(currentPage - 1);
363 }
364 });
365 }
366
367 // Initialize Hammer
368 initializeHammer();
369
370
371 showPage(firstPage);
372 }
373
374 function openLinkInNewTab(event, el) {
375 event.preventDefault();
376 event.stopPropagation();
377
378 const href = el.getAttribute('href');
379
380 if (!href || href.trim() === '' || href === 'javascript:void(0);') {
381 alert('Link non disponibile');
382 return;
383 }
384 try {
385 new URL(href, window.location.href);
386 } catch (e) {
387 alert('URL non valido');
388 return;
389 }
390
391 const newTab = window.open(href, '_blank');
392
393 if (!newTab || newTab.closed || typeof newTab.closed === 'undefined') {
394 alert('Unable to open the link. Please check your browser settings to allow pop-ups.');
395 }
396 }
397
398
399 function init() {
400 pdfPagination();
401 initializeOpenDocButton();
402 }
403 if (document.readyState === "loading") {
404 document.addEventListener('DOMContentLoaded', init);
405 document.addEventListener('DOMContentLoaded', function(){
406 let readingTime = calculateReadingTime();
407 $('#readingTime').text(readingTime);
408 });
409 } else {
410 init();
411 let readingTime = calculateReadingTime();
412 $('#readingTime').text(readingTime);
413 }
414
415 function calculateReadingTime(){
416 let wordCount = 0;
417 const wordsPerMinute = 200;
418 $('.reading-time-parameter').each(function(index, elem){
419 let text = $(elem).text();
420 wordCount += text.trim().split(/\s+/).length;
421 });
422 if(wordCount > 0){
423 return Math.ceil(wordCount / wordsPerMinute);
424 }else{
425 return 0;
426 }
427 }
428
429</script>
430
431<style>
432 * {
433 overflow-wrap: break-word;
434 }
435
436 .main-image-crop{
437 height: 300px;
438 object-position:top center;
439 @media(max-width: 576px){
440 height: 60px;
441 }
442 }
443 .multi-column-text{
444 column-count: 2;
445 column-gap: 2rem;
446 }
447 .distribution-level{
448 text-transform: uppercase;
449 &:before{
450 content: "";
451 display: inline-block;
452 width: 20px;
453 height: 20px;
454 margin-right: 6px;
455 border: 5px solid;
456 border-radius: 50%;
457 background: transparent;
458 vertical-align: sub;
459 }
460 &.disclosable{
461 &.before{
462 border-color: #23863F;
463 }
464 color: #23863F;
465 }
466 &.limited-disclosure{
467 &.before{
468 border-color: #F7B32B;
469 }
470 color: #F7B32B;
471 }
472 &.internal-use-only{
473 &.before{
474 border-color: #D24445;
475 }
476 color: #D24445;
477 }
478 }
479 .icom-vivimedical-link-icon:before{
480 color: #8ed300;
481 }
482 .thematic-area-page-content{
483 .download-btn:hover{
484 text-decoration: none;
485 }
486 }
487
488 .plain-text{
489 p{
490 line-height: 1.5;
491 }
492 }
493
494 .sections-block > .one-column-text > .plain-text img {
495 height: auto; !important;
496 max-width: 100%; !important;
497 }
498
499 @media (max-width: 768px) {
500 .multi-column-text {
501 column-count: 1;
502 }
503 }
504</style>
Fehler bei der Verarbeitung der Vorlage.
The following has evaluated to null or missing:
==> assetVocabularyLocalService.fetchGroupVocabulary(themeDisplay.getScopeGroupId(), vocabularyName) [in template "37204#37246#42066452" at line 70, column 31]
----
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: #assign vocabulary = assetVocabularyL... [in template "37204#37246#42066452" at line 70, column 9]
----
1<#assign resourcePrimaryKey = .vars["reserved-article-resource-prim-key"].data />
2<#assign idArticle = .vars["reserved-article-id"].data />
3
4<#-- assetEntry-->
5<#assign assetEntryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetEntryLocalService") />
6<#assign assetTagLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetTagLocalService") />
7<#assign assetCategoryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetCategoryLocalService") />
8<#assign assetVocabularyLocalService= serviceLocator.findService("com.liferay.asset.kernel.service.AssetVocabularyLocalService") />
9<#assign assetEntry = assetEntryLocalService.fetchEntry("com.liferay.journal.model.JournalArticle", resourcePrimaryKey?number) />
10<#if !assetEntry?has_content>
11 <#stop "Error: Asset Entry with resourcePrimaryKey = ${resourcePrimaryKey} not found. Template execution stopped." />
12</#if>
13
14<#-- JournalArticle-->
15<#assign journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") />
16<#assign journalArticle = journalArticleLocalService.fetchLatestArticle(resourcePrimaryKey?number) />
17<#if !journalArticle?has_content>
18 <#stop "Error: Journal Article with resourcePrimaryKey = ${resourcePrimaryKey} not found. Template execution stopped." />
19</#if>
20
21<div class="thematic-area-page-content mt-5">
22 <div class="page-intro">
23
24 <!-- Publish Date -->
25 <#if assetEntry.getPublishDate()?has_content>
26 <div class="subtitle-div gap-3">
27 <h4 class="subtitle plain-text mb-0"> ${dateUtil.getDate(assetEntry.getPublishDate(), "d MMMM yyyy", locale, timeZone)?upper_case}</h4>
28 </div>
29 </#if>
30
31 <!-- Title -->
32 <h1 class="title">${journalArticle.getTitle(themeDisplay.getLocale())}</h1>
33
34 <!-- Subtitle -->
35 <div class="subtitle-div flex-wrap">
36 <h4 class="subtitle plain-text col-md-6 p-0">${languageUtil.get(locale, 'authors')}: ${authors.getData()}</h4>
37 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'document-language')}: ${documentLanguage.getData()!""}</h4>
38 <#if publishDateCustom?? && publishDateCustom.getData()?has_content>
39 <#assign dateObj = dateUtil.parseDate("yyyy-MM-dd", publishDateCustom.getData(), locale) />
40 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'publish-date')}: ${dateUtil.getDate(dateObj, "d MMMM yyyy", locale, timeZone)}</h4>
41 </#if>
42 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'citation')}: ${(citation.getData())!""}</h4>
43 <h4 class="subtitle plain-text col-md-6 col-12 p-0">DOI: ${(doi.getData())!""}</h4>
44 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'keywords-vivilibrary')}: ${(keywords.getData())!""}</h4>
45 </div>
46
47 <#assign distributionLevelChoice = distributionLevel.getData()!""/>
48 <div class="distribution-level mt-3 ${distributionLevelChoice}">
49 <b>${languageUtil.get(locale, distributionLevelChoice)}</b>
50 </div>
51
52 <!-- Main Image -->
53 <#assign mainImageUrl = ""/>
54 <#assign mainImageCss = ""/>
55 <#if uploadDocument.document.getData()?has_content>
56 <#assign mainImageUrl = uploadDocument.document.getData() + "&previewFileIndex=1">
57 <#assign mainImageCss = "main-image-crop"/>
58 <#elseif journalArticle.getArticleImageURL(themeDisplay)?has_content>
59 <#assign mainImageUrl = journalArticle.getArticleImageURL(themeDisplay)>
60 </#if>
61 <#if mainImageUrl?has_content>
62 <div class="main-image-div">
63 <img class="main-image ${(mainImageCss)!""}" src="${mainImageUrl}" alt="scientific article">
64 </div>
65 </#if>
66
67 <!-- Categories-->
68 <#assign vocabularyName = "Therapy" />
69 <#assign vocabularyId = 0 />
70 <#assign vocabulary = assetVocabularyLocalService.fetchGroupVocabulary(themeDisplay.getScopeGroupId(), vocabularyName)/>
71 <#if vocabulary??>
72 <#assign vocabularyId = vocabulary.getVocabularyId()/>
73 </#if>
74
75 <#assign cats = [] />
76 <#if assetEntry.getCategories()?has_content>
77 <#list assetEntry.getCategories() as c>
78 <#if c.getVocabularyId() == vocabularyId>
79 <#assign cats = cats + [c] />
80 </#if>
81 </#list>
82 </#if>
83
84 <#assign tags = [] />
85 <#if assetTagLocalService.getAssetEntryAssetTags(assetEntry.getEntryId())?has_content>
86 <#assign tags = assetTagLocalService.getAssetEntryAssetTags(assetEntry.getEntryId())>
87 </#if>
88
89 <#if tags?has_content || cats?has_content>
90 <div class="tags-container flex-wrap">
91 <#if cats?has_content>
92 <#list cats as cat>
93 <span class="tag tag-style">${languageUtil.get(locale, "account-treatment-"+cat.getTitle(themeDisplay.getLocale()))}</span>
94 </#list>
95 </#if>
96 <#if tags?has_content>
97 <#list tags as tag>
98 <span class="tag tag-style">${tag.getName()}</span>
99 </#list>
100 </#if>
101 </div>
102 </#if>
103 </div>
104
105 <!-- Wavy divider -->
106 <div class="wavy-divider">
107 <svg viewBox="0 0 1440 60" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none">
108 <path d="M0,20 Q360,60 720,20 T1440,20 V60 H0 Z" fill="#fff"/>
109 </svg>
110 </div>
111
112 <!-- 1. One column section -->
113 <#if shortAbstract.oneColumnSectionTitle.getData()?has_content && shortAbstract.oneColumnText.getData()?has_content>
114 <div class="sections-block">
115 <h4 class="section-title reading-time-parameter">${shortAbstract.oneColumnSectionTitle.getData()}</h4>
116 <div class="one-column-text p-0">
117 <div class="plain-text reading-time-parameter">${shortAbstract.oneColumnText.getData()}</div>
118 </div>
119 </div>
120 </#if>
121
122 <!-- 3. Two columns section -->
123 <#if abstract.title.getData()?has_content &&
124 abstract.text.getData()?has_content>
125 <div class="sections-block">
126 <h4 class="section-title reading-time-parameter">${abstract.title.getData()}</h4>
127 <div class="col-md-12 p-0">
128 <div class="plain-text reading-time-parameter multi-column-text">${abstract.text.getData()}</div>
129 </div>
130 </div>
131 </#if>
132
133 <!-- 5. Embedded document section -->
134 <#if uploadDocument.docSectionTitle.getData()?has_content && uploadDocument.document.getData()?has_content && uploadDocument.document.getData()?has_content>
135 <#assign totalPages = webContentUtil.getDocumentPreviewPageCount(themeDisplay, uploadDocument.document.getData()) />
136 <div class="sections-block">
137 <h4 class="section-title reading-time-parameter">${uploadDocument.docSectionTitle.getData()}</h4>
138 <div class="doc-container">
139 <div class="col-md-12 p-0">
140 <div class="doc-embed d-flex flex-column align-items-center">
141 <button class="pdf-open-doc" data-pdf-url="${uploadDocument.document.getData()}">
142 ${languageUtil.get(locale, "open-document")}
143 </button>
144 <div class="pdf-pages-container">
145 <#list 1..totalPages as page>
146 <img
147 src="${uploadDocument.document.getData()}&previewFileIndex=${page}"
148 class="pdf-page"
149 data-page="${page}"
150 />
151 </#list>
152 </div>
153 <div class="doc-index">
154 <div class="pdf-pagination">
155 <button class="pdf-nav prev subtitle"><</button>
156 <div class="pdf-nav-index-div"></div>
157 <button class="pdf-nav next subtitle">></button>
158 </div>
159 </div>
160 </div>
161 </div>
162 </div>
163 </div>
164 </#if>
165
166 <#assign linkTagIsNotEmpty = false>
167 <#list references.getSiblings() as field>
168 <#if field.getData()?? && field.linkTitle.getData()?trim != "" && field.linkUrl.getData()?trim != "">
169 <#assign linkTagIsNotEmpty = true>
170 <#break>
171 </#if>
172 </#list>
173
174 <!-- 6. Link section -->
175 <#if linkTagIsNotEmpty>
176 <div class="sections-block" style="border-bottom-right-radius:12px;border-bottom-left-radius:12px;">
177 <h4 class="section-title reading-time">${languageUtil.get(locale, "references")}</h4>
178 <div class="d-flex flex-column">
179 <#list references.getSiblings() as link>
180 <#if link.linkTitle.getData()?has_content && link.linkUrl.getData()?has_content>
181 <div class="link-card mb-4">
182 <div class="link-info">
183 <div class="link-title reading-time-parameter"><b>${link.linkTitle.getData()}</b></div>
184 <#if link.linkDesc.getData()?has_content>
185 <div class="link-description reading-time-parameter">${link.linkDesc.getData()}</div>
186 </#if>
187 </div>
188 <a href="${(link.linkUrl.getData())!'javascript:void(0);'}" class="download-btn"
189 title="Scarica" onclick="openLinkInNewTab(event, this)">
190 <i class="icom-vivimedical-link-icon">
191 </i>
192 </a>
193 </div>
194 </#if>
195 </#list>
196 </div>
197 </div>
198 </#if>
199
200</div>
201
202<script src="https://cdn.jsdelivr.net/npm/hammerjs@2.0.8/hammer.min.js"></script>
203
204<script>
205 function initializeOpenDocButton() {
206 const openDocBtn = document.querySelector('.pdf-open-doc');
207 if (openDocBtn) {
208 openDocBtn.addEventListener('click', () => {
209 const pdfUrl = openDocBtn.getAttribute('data-pdf-url');
210 if (!pdfUrl) {
211 alert('PDF not available');
212 return;
213 }
214 const newTab = window.open(pdfUrl, '_blank');
215 if (!newTab) {
216 alert('Unable to open the PDF. Please check your browser settings for pop-ups.');
217 }
218 });
219 }
220 }
221
222 function pdfPagination() {
223 const pages = document.querySelectorAll('.pdf-page');
224 const prevBtn = document.querySelector('.pdf-nav.prev');
225 const nextBtn = document.querySelector('.pdf-nav.next');
226 const pageNumbersContainer = document.querySelector('.pdf-nav-index-div');
227
228 // pdf-pagination struct: 1....lastPage
229 const totalPages = pages.length;
230 const firstPage = 1;
231 const lastPage = totalPages;
232 let currentPage = firstPage;
233 let indexStyleClass = 'subtitle';
234
235 function addStyle(elem, styleClass) {
236 elem.classList.add(styleClass);
237 }
238
239 function addPageButton(pageNumber) {
240 const btn = document.createElement('button');
241 btn.className = 'pdf-page-num';
242 btn.textContent = pageNumber;
243 addStyle(btn, indexStyleClass);
244 pageNumbersContainer.appendChild(btn);
245 }
246
247 function addEllipsis() {
248 const span = document.createElement('span');
249 span.className = 'pdf-page-num ellipsis';
250 span.textContent = '...';
251 addStyle(span, indexStyleClass);
252 pageNumbersContainer.appendChild(span);
253 }
254
255 // invalid currentPage sets value to default (firstPage)
256 function validateCurrentPage(currentPage, defaultValue) {
257 if (typeof currentPage !== 'number' || isNaN(currentPage) ||
258 currentPage < firstPage || currentPage > lastPage) {
259 return defaultValue;
260 }
261 return currentPage;
262 }
263
264 function renderPageNumbers(currentPage) {
265 pageNumbersContainer.innerHTML = '';
266 currentPage = validateCurrentPage(currentPage, firstPage);
267 console.log("totalPages " + totalPages);
268 if (totalPages >= 1 && totalPages <= 4) {
269 for (let i = firstPage; i < firstPage + totalPages; i++) {
270 addPageButton(i);
271 }
272 }
273 else if (currentPage == firstPage || currentPage == firstPage + 1) {
274 addPageButton(firstPage);
275 addPageButton(firstPage + 1);
276 addPageButton(firstPage + 2);
277 addEllipsis();
278 addPageButton(lastPage);
279 } else if (currentPage == lastPage - 1 || currentPage == lastPage) {
280 addPageButton(firstPage);
281 addEllipsis();
282 addPageButton(lastPage - 2);
283 addPageButton(lastPage - 1);
284 addPageButton(lastPage);
285 } else {
286 addPageButton(firstPage);
287 addEllipsis();
288 addPageButton(currentPage);
289 addEllipsis();
290 addPageButton(lastPage);
291 }
292 }
293
294 function setActivePage(currentPage) {
295 if (validateCurrentPage(currentPage, firstPage)) {
296 const buttons = document.querySelectorAll('.pdf-page-num');
297 buttons.forEach(btn => btn.classList.remove('active'));
298 buttons.forEach(btn => {
299 if (parseInt(btn.textContent, 10) === currentPage) {
300 btn.classList.add('active');
301 }
302 });
303 }
304 }
305
306 function showPage(page) {
307 currentPage = page;
308 // hides all images
309 document.querySelectorAll('.pdf-page').forEach(img => img.style.display = 'none');
310 // display currentPage image
311 const currentPageElement = document.querySelector('.pdf-page[data-page="' + page + '"]');
312 if (currentPageElement) {
313 currentPageElement.style.display = 'block';
314 }
315 prevBtn.disabled = currentPage === firstPage;
316 nextBtn.disabled = currentPage === lastPage;
317 renderPageNumbers(currentPage);
318 setActivePage(currentPage);
319 }
320
321 // prev btn listener
322 prevBtn.addEventListener('click', function () {
323 if (currentPage > firstPage) showPage(currentPage - 1);
324 });
325
326 // next btn listener
327 nextBtn.addEventListener('click', function () {
328 if (currentPage < lastPage) showPage(currentPage + 1);
329 });
330
331 // index btn listener
332 pageNumbersContainer.addEventListener('click', function (e) {
333 if (e.target.classList.contains('pdf-page-num') && !e.target.classList.contains('ellipsis')) {
334 const pageNumber = parseInt(e.target.textContent, 10);
335 if (!isNaN(pageNumber)) {
336 showPage(pageNumber);
337 }
338 }
339 });
340
341 //Hammer.js
342 function initializeHammer() {
343 const container = document.querySelector('.pdf-pages-container');
344
345 if (!container || typeof Hammer === 'undefined') {
346 console.warn('Container not found or Hammer.js not loaded');
347 return;
348 }
349
350 const hammer = new Hammer(container);
351
352 hammer.get('swipe').set({ direction: Hammer.DIRECTION_HORIZONTAL });
353
354 hammer.on('swipeleft', () => {
355 if (currentPage < totalPages) {
356 showPage(currentPage + 1);
357 }
358 });
359
360 hammer.on('swiperight', () => {
361 if (currentPage > 1) {
362 showPage(currentPage - 1);
363 }
364 });
365 }
366
367 // Initialize Hammer
368 initializeHammer();
369
370
371 showPage(firstPage);
372 }
373
374 function openLinkInNewTab(event, el) {
375 event.preventDefault();
376 event.stopPropagation();
377
378 const href = el.getAttribute('href');
379
380 if (!href || href.trim() === '' || href === 'javascript:void(0);') {
381 alert('Link non disponibile');
382 return;
383 }
384 try {
385 new URL(href, window.location.href);
386 } catch (e) {
387 alert('URL non valido');
388 return;
389 }
390
391 const newTab = window.open(href, '_blank');
392
393 if (!newTab || newTab.closed || typeof newTab.closed === 'undefined') {
394 alert('Unable to open the link. Please check your browser settings to allow pop-ups.');
395 }
396 }
397
398
399 function init() {
400 pdfPagination();
401 initializeOpenDocButton();
402 }
403 if (document.readyState === "loading") {
404 document.addEventListener('DOMContentLoaded', init);
405 document.addEventListener('DOMContentLoaded', function(){
406 let readingTime = calculateReadingTime();
407 $('#readingTime').text(readingTime);
408 });
409 } else {
410 init();
411 let readingTime = calculateReadingTime();
412 $('#readingTime').text(readingTime);
413 }
414
415 function calculateReadingTime(){
416 let wordCount = 0;
417 const wordsPerMinute = 200;
418 $('.reading-time-parameter').each(function(index, elem){
419 let text = $(elem).text();
420 wordCount += text.trim().split(/\s+/).length;
421 });
422 if(wordCount > 0){
423 return Math.ceil(wordCount / wordsPerMinute);
424 }else{
425 return 0;
426 }
427 }
428
429</script>
430
431<style>
432 * {
433 overflow-wrap: break-word;
434 }
435
436 .main-image-crop{
437 height: 300px;
438 object-position:top center;
439 @media(max-width: 576px){
440 height: 60px;
441 }
442 }
443 .multi-column-text{
444 column-count: 2;
445 column-gap: 2rem;
446 }
447 .distribution-level{
448 text-transform: uppercase;
449 &:before{
450 content: "";
451 display: inline-block;
452 width: 20px;
453 height: 20px;
454 margin-right: 6px;
455 border: 5px solid;
456 border-radius: 50%;
457 background: transparent;
458 vertical-align: sub;
459 }
460 &.disclosable{
461 &.before{
462 border-color: #23863F;
463 }
464 color: #23863F;
465 }
466 &.limited-disclosure{
467 &.before{
468 border-color: #F7B32B;
469 }
470 color: #F7B32B;
471 }
472 &.internal-use-only{
473 &.before{
474 border-color: #D24445;
475 }
476 color: #D24445;
477 }
478 }
479 .icom-vivimedical-link-icon:before{
480 color: #8ed300;
481 }
482 .thematic-area-page-content{
483 .download-btn:hover{
484 text-decoration: none;
485 }
486 }
487
488 .plain-text{
489 p{
490 line-height: 1.5;
491 }
492 }
493
494 .sections-block > .one-column-text > .plain-text img {
495 height: auto; !important;
496 max-width: 100%; !important;
497 }
498
499 @media (max-width: 768px) {
500 .multi-column-text {
501 column-count: 1;
502 }
503 }
504</style>
Fehler bei der Verarbeitung der Vorlage.
The following has evaluated to null or missing:
==> assetVocabularyLocalService.fetchGroupVocabulary(themeDisplay.getScopeGroupId(), vocabularyName) [in template "37204#37246#42066452" at line 70, column 31]
----
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: #assign vocabulary = assetVocabularyL... [in template "37204#37246#42066452" at line 70, column 9]
----
1<#assign resourcePrimaryKey = .vars["reserved-article-resource-prim-key"].data />
2<#assign idArticle = .vars["reserved-article-id"].data />
3
4<#-- assetEntry-->
5<#assign assetEntryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetEntryLocalService") />
6<#assign assetTagLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetTagLocalService") />
7<#assign assetCategoryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetCategoryLocalService") />
8<#assign assetVocabularyLocalService= serviceLocator.findService("com.liferay.asset.kernel.service.AssetVocabularyLocalService") />
9<#assign assetEntry = assetEntryLocalService.fetchEntry("com.liferay.journal.model.JournalArticle", resourcePrimaryKey?number) />
10<#if !assetEntry?has_content>
11 <#stop "Error: Asset Entry with resourcePrimaryKey = ${resourcePrimaryKey} not found. Template execution stopped." />
12</#if>
13
14<#-- JournalArticle-->
15<#assign journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") />
16<#assign journalArticle = journalArticleLocalService.fetchLatestArticle(resourcePrimaryKey?number) />
17<#if !journalArticle?has_content>
18 <#stop "Error: Journal Article with resourcePrimaryKey = ${resourcePrimaryKey} not found. Template execution stopped." />
19</#if>
20
21<div class="thematic-area-page-content mt-5">
22 <div class="page-intro">
23
24 <!-- Publish Date -->
25 <#if assetEntry.getPublishDate()?has_content>
26 <div class="subtitle-div gap-3">
27 <h4 class="subtitle plain-text mb-0"> ${dateUtil.getDate(assetEntry.getPublishDate(), "d MMMM yyyy", locale, timeZone)?upper_case}</h4>
28 </div>
29 </#if>
30
31 <!-- Title -->
32 <h1 class="title">${journalArticle.getTitle(themeDisplay.getLocale())}</h1>
33
34 <!-- Subtitle -->
35 <div class="subtitle-div flex-wrap">
36 <h4 class="subtitle plain-text col-md-6 p-0">${languageUtil.get(locale, 'authors')}: ${authors.getData()}</h4>
37 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'document-language')}: ${documentLanguage.getData()!""}</h4>
38 <#if publishDateCustom?? && publishDateCustom.getData()?has_content>
39 <#assign dateObj = dateUtil.parseDate("yyyy-MM-dd", publishDateCustom.getData(), locale) />
40 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'publish-date')}: ${dateUtil.getDate(dateObj, "d MMMM yyyy", locale, timeZone)}</h4>
41 </#if>
42 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'citation')}: ${(citation.getData())!""}</h4>
43 <h4 class="subtitle plain-text col-md-6 col-12 p-0">DOI: ${(doi.getData())!""}</h4>
44 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'keywords-vivilibrary')}: ${(keywords.getData())!""}</h4>
45 </div>
46
47 <#assign distributionLevelChoice = distributionLevel.getData()!""/>
48 <div class="distribution-level mt-3 ${distributionLevelChoice}">
49 <b>${languageUtil.get(locale, distributionLevelChoice)}</b>
50 </div>
51
52 <!-- Main Image -->
53 <#assign mainImageUrl = ""/>
54 <#assign mainImageCss = ""/>
55 <#if uploadDocument.document.getData()?has_content>
56 <#assign mainImageUrl = uploadDocument.document.getData() + "&previewFileIndex=1">
57 <#assign mainImageCss = "main-image-crop"/>
58 <#elseif journalArticle.getArticleImageURL(themeDisplay)?has_content>
59 <#assign mainImageUrl = journalArticle.getArticleImageURL(themeDisplay)>
60 </#if>
61 <#if mainImageUrl?has_content>
62 <div class="main-image-div">
63 <img class="main-image ${(mainImageCss)!""}" src="${mainImageUrl}" alt="scientific article">
64 </div>
65 </#if>
66
67 <!-- Categories-->
68 <#assign vocabularyName = "Therapy" />
69 <#assign vocabularyId = 0 />
70 <#assign vocabulary = assetVocabularyLocalService.fetchGroupVocabulary(themeDisplay.getScopeGroupId(), vocabularyName)/>
71 <#if vocabulary??>
72 <#assign vocabularyId = vocabulary.getVocabularyId()/>
73 </#if>
74
75 <#assign cats = [] />
76 <#if assetEntry.getCategories()?has_content>
77 <#list assetEntry.getCategories() as c>
78 <#if c.getVocabularyId() == vocabularyId>
79 <#assign cats = cats + [c] />
80 </#if>
81 </#list>
82 </#if>
83
84 <#assign tags = [] />
85 <#if assetTagLocalService.getAssetEntryAssetTags(assetEntry.getEntryId())?has_content>
86 <#assign tags = assetTagLocalService.getAssetEntryAssetTags(assetEntry.getEntryId())>
87 </#if>
88
89 <#if tags?has_content || cats?has_content>
90 <div class="tags-container flex-wrap">
91 <#if cats?has_content>
92 <#list cats as cat>
93 <span class="tag tag-style">${languageUtil.get(locale, "account-treatment-"+cat.getTitle(themeDisplay.getLocale()))}</span>
94 </#list>
95 </#if>
96 <#if tags?has_content>
97 <#list tags as tag>
98 <span class="tag tag-style">${tag.getName()}</span>
99 </#list>
100 </#if>
101 </div>
102 </#if>
103 </div>
104
105 <!-- Wavy divider -->
106 <div class="wavy-divider">
107 <svg viewBox="0 0 1440 60" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none">
108 <path d="M0,20 Q360,60 720,20 T1440,20 V60 H0 Z" fill="#fff"/>
109 </svg>
110 </div>
111
112 <!-- 1. One column section -->
113 <#if shortAbstract.oneColumnSectionTitle.getData()?has_content && shortAbstract.oneColumnText.getData()?has_content>
114 <div class="sections-block">
115 <h4 class="section-title reading-time-parameter">${shortAbstract.oneColumnSectionTitle.getData()}</h4>
116 <div class="one-column-text p-0">
117 <div class="plain-text reading-time-parameter">${shortAbstract.oneColumnText.getData()}</div>
118 </div>
119 </div>
120 </#if>
121
122 <!-- 3. Two columns section -->
123 <#if abstract.title.getData()?has_content &&
124 abstract.text.getData()?has_content>
125 <div class="sections-block">
126 <h4 class="section-title reading-time-parameter">${abstract.title.getData()}</h4>
127 <div class="col-md-12 p-0">
128 <div class="plain-text reading-time-parameter multi-column-text">${abstract.text.getData()}</div>
129 </div>
130 </div>
131 </#if>
132
133 <!-- 5. Embedded document section -->
134 <#if uploadDocument.docSectionTitle.getData()?has_content && uploadDocument.document.getData()?has_content && uploadDocument.document.getData()?has_content>
135 <#assign totalPages = webContentUtil.getDocumentPreviewPageCount(themeDisplay, uploadDocument.document.getData()) />
136 <div class="sections-block">
137 <h4 class="section-title reading-time-parameter">${uploadDocument.docSectionTitle.getData()}</h4>
138 <div class="doc-container">
139 <div class="col-md-12 p-0">
140 <div class="doc-embed d-flex flex-column align-items-center">
141 <button class="pdf-open-doc" data-pdf-url="${uploadDocument.document.getData()}">
142 ${languageUtil.get(locale, "open-document")}
143 </button>
144 <div class="pdf-pages-container">
145 <#list 1..totalPages as page>
146 <img
147 src="${uploadDocument.document.getData()}&previewFileIndex=${page}"
148 class="pdf-page"
149 data-page="${page}"
150 />
151 </#list>
152 </div>
153 <div class="doc-index">
154 <div class="pdf-pagination">
155 <button class="pdf-nav prev subtitle"><</button>
156 <div class="pdf-nav-index-div"></div>
157 <button class="pdf-nav next subtitle">></button>
158 </div>
159 </div>
160 </div>
161 </div>
162 </div>
163 </div>
164 </#if>
165
166 <#assign linkTagIsNotEmpty = false>
167 <#list references.getSiblings() as field>
168 <#if field.getData()?? && field.linkTitle.getData()?trim != "" && field.linkUrl.getData()?trim != "">
169 <#assign linkTagIsNotEmpty = true>
170 <#break>
171 </#if>
172 </#list>
173
174 <!-- 6. Link section -->
175 <#if linkTagIsNotEmpty>
176 <div class="sections-block" style="border-bottom-right-radius:12px;border-bottom-left-radius:12px;">
177 <h4 class="section-title reading-time">${languageUtil.get(locale, "references")}</h4>
178 <div class="d-flex flex-column">
179 <#list references.getSiblings() as link>
180 <#if link.linkTitle.getData()?has_content && link.linkUrl.getData()?has_content>
181 <div class="link-card mb-4">
182 <div class="link-info">
183 <div class="link-title reading-time-parameter"><b>${link.linkTitle.getData()}</b></div>
184 <#if link.linkDesc.getData()?has_content>
185 <div class="link-description reading-time-parameter">${link.linkDesc.getData()}</div>
186 </#if>
187 </div>
188 <a href="${(link.linkUrl.getData())!'javascript:void(0);'}" class="download-btn"
189 title="Scarica" onclick="openLinkInNewTab(event, this)">
190 <i class="icom-vivimedical-link-icon">
191 </i>
192 </a>
193 </div>
194 </#if>
195 </#list>
196 </div>
197 </div>
198 </#if>
199
200</div>
201
202<script src="https://cdn.jsdelivr.net/npm/hammerjs@2.0.8/hammer.min.js"></script>
203
204<script>
205 function initializeOpenDocButton() {
206 const openDocBtn = document.querySelector('.pdf-open-doc');
207 if (openDocBtn) {
208 openDocBtn.addEventListener('click', () => {
209 const pdfUrl = openDocBtn.getAttribute('data-pdf-url');
210 if (!pdfUrl) {
211 alert('PDF not available');
212 return;
213 }
214 const newTab = window.open(pdfUrl, '_blank');
215 if (!newTab) {
216 alert('Unable to open the PDF. Please check your browser settings for pop-ups.');
217 }
218 });
219 }
220 }
221
222 function pdfPagination() {
223 const pages = document.querySelectorAll('.pdf-page');
224 const prevBtn = document.querySelector('.pdf-nav.prev');
225 const nextBtn = document.querySelector('.pdf-nav.next');
226 const pageNumbersContainer = document.querySelector('.pdf-nav-index-div');
227
228 // pdf-pagination struct: 1....lastPage
229 const totalPages = pages.length;
230 const firstPage = 1;
231 const lastPage = totalPages;
232 let currentPage = firstPage;
233 let indexStyleClass = 'subtitle';
234
235 function addStyle(elem, styleClass) {
236 elem.classList.add(styleClass);
237 }
238
239 function addPageButton(pageNumber) {
240 const btn = document.createElement('button');
241 btn.className = 'pdf-page-num';
242 btn.textContent = pageNumber;
243 addStyle(btn, indexStyleClass);
244 pageNumbersContainer.appendChild(btn);
245 }
246
247 function addEllipsis() {
248 const span = document.createElement('span');
249 span.className = 'pdf-page-num ellipsis';
250 span.textContent = '...';
251 addStyle(span, indexStyleClass);
252 pageNumbersContainer.appendChild(span);
253 }
254
255 // invalid currentPage sets value to default (firstPage)
256 function validateCurrentPage(currentPage, defaultValue) {
257 if (typeof currentPage !== 'number' || isNaN(currentPage) ||
258 currentPage < firstPage || currentPage > lastPage) {
259 return defaultValue;
260 }
261 return currentPage;
262 }
263
264 function renderPageNumbers(currentPage) {
265 pageNumbersContainer.innerHTML = '';
266 currentPage = validateCurrentPage(currentPage, firstPage);
267 console.log("totalPages " + totalPages);
268 if (totalPages >= 1 && totalPages <= 4) {
269 for (let i = firstPage; i < firstPage + totalPages; i++) {
270 addPageButton(i);
271 }
272 }
273 else if (currentPage == firstPage || currentPage == firstPage + 1) {
274 addPageButton(firstPage);
275 addPageButton(firstPage + 1);
276 addPageButton(firstPage + 2);
277 addEllipsis();
278 addPageButton(lastPage);
279 } else if (currentPage == lastPage - 1 || currentPage == lastPage) {
280 addPageButton(firstPage);
281 addEllipsis();
282 addPageButton(lastPage - 2);
283 addPageButton(lastPage - 1);
284 addPageButton(lastPage);
285 } else {
286 addPageButton(firstPage);
287 addEllipsis();
288 addPageButton(currentPage);
289 addEllipsis();
290 addPageButton(lastPage);
291 }
292 }
293
294 function setActivePage(currentPage) {
295 if (validateCurrentPage(currentPage, firstPage)) {
296 const buttons = document.querySelectorAll('.pdf-page-num');
297 buttons.forEach(btn => btn.classList.remove('active'));
298 buttons.forEach(btn => {
299 if (parseInt(btn.textContent, 10) === currentPage) {
300 btn.classList.add('active');
301 }
302 });
303 }
304 }
305
306 function showPage(page) {
307 currentPage = page;
308 // hides all images
309 document.querySelectorAll('.pdf-page').forEach(img => img.style.display = 'none');
310 // display currentPage image
311 const currentPageElement = document.querySelector('.pdf-page[data-page="' + page + '"]');
312 if (currentPageElement) {
313 currentPageElement.style.display = 'block';
314 }
315 prevBtn.disabled = currentPage === firstPage;
316 nextBtn.disabled = currentPage === lastPage;
317 renderPageNumbers(currentPage);
318 setActivePage(currentPage);
319 }
320
321 // prev btn listener
322 prevBtn.addEventListener('click', function () {
323 if (currentPage > firstPage) showPage(currentPage - 1);
324 });
325
326 // next btn listener
327 nextBtn.addEventListener('click', function () {
328 if (currentPage < lastPage) showPage(currentPage + 1);
329 });
330
331 // index btn listener
332 pageNumbersContainer.addEventListener('click', function (e) {
333 if (e.target.classList.contains('pdf-page-num') && !e.target.classList.contains('ellipsis')) {
334 const pageNumber = parseInt(e.target.textContent, 10);
335 if (!isNaN(pageNumber)) {
336 showPage(pageNumber);
337 }
338 }
339 });
340
341 //Hammer.js
342 function initializeHammer() {
343 const container = document.querySelector('.pdf-pages-container');
344
345 if (!container || typeof Hammer === 'undefined') {
346 console.warn('Container not found or Hammer.js not loaded');
347 return;
348 }
349
350 const hammer = new Hammer(container);
351
352 hammer.get('swipe').set({ direction: Hammer.DIRECTION_HORIZONTAL });
353
354 hammer.on('swipeleft', () => {
355 if (currentPage < totalPages) {
356 showPage(currentPage + 1);
357 }
358 });
359
360 hammer.on('swiperight', () => {
361 if (currentPage > 1) {
362 showPage(currentPage - 1);
363 }
364 });
365 }
366
367 // Initialize Hammer
368 initializeHammer();
369
370
371 showPage(firstPage);
372 }
373
374 function openLinkInNewTab(event, el) {
375 event.preventDefault();
376 event.stopPropagation();
377
378 const href = el.getAttribute('href');
379
380 if (!href || href.trim() === '' || href === 'javascript:void(0);') {
381 alert('Link non disponibile');
382 return;
383 }
384 try {
385 new URL(href, window.location.href);
386 } catch (e) {
387 alert('URL non valido');
388 return;
389 }
390
391 const newTab = window.open(href, '_blank');
392
393 if (!newTab || newTab.closed || typeof newTab.closed === 'undefined') {
394 alert('Unable to open the link. Please check your browser settings to allow pop-ups.');
395 }
396 }
397
398
399 function init() {
400 pdfPagination();
401 initializeOpenDocButton();
402 }
403 if (document.readyState === "loading") {
404 document.addEventListener('DOMContentLoaded', init);
405 document.addEventListener('DOMContentLoaded', function(){
406 let readingTime = calculateReadingTime();
407 $('#readingTime').text(readingTime);
408 });
409 } else {
410 init();
411 let readingTime = calculateReadingTime();
412 $('#readingTime').text(readingTime);
413 }
414
415 function calculateReadingTime(){
416 let wordCount = 0;
417 const wordsPerMinute = 200;
418 $('.reading-time-parameter').each(function(index, elem){
419 let text = $(elem).text();
420 wordCount += text.trim().split(/\s+/).length;
421 });
422 if(wordCount > 0){
423 return Math.ceil(wordCount / wordsPerMinute);
424 }else{
425 return 0;
426 }
427 }
428
429</script>
430
431<style>
432 * {
433 overflow-wrap: break-word;
434 }
435
436 .main-image-crop{
437 height: 300px;
438 object-position:top center;
439 @media(max-width: 576px){
440 height: 60px;
441 }
442 }
443 .multi-column-text{
444 column-count: 2;
445 column-gap: 2rem;
446 }
447 .distribution-level{
448 text-transform: uppercase;
449 &:before{
450 content: "";
451 display: inline-block;
452 width: 20px;
453 height: 20px;
454 margin-right: 6px;
455 border: 5px solid;
456 border-radius: 50%;
457 background: transparent;
458 vertical-align: sub;
459 }
460 &.disclosable{
461 &.before{
462 border-color: #23863F;
463 }
464 color: #23863F;
465 }
466 &.limited-disclosure{
467 &.before{
468 border-color: #F7B32B;
469 }
470 color: #F7B32B;
471 }
472 &.internal-use-only{
473 &.before{
474 border-color: #D24445;
475 }
476 color: #D24445;
477 }
478 }
479 .icom-vivimedical-link-icon:before{
480 color: #8ed300;
481 }
482 .thematic-area-page-content{
483 .download-btn:hover{
484 text-decoration: none;
485 }
486 }
487
488 .plain-text{
489 p{
490 line-height: 1.5;
491 }
492 }
493
494 .sections-block > .one-column-text > .plain-text img {
495 height: auto; !important;
496 max-width: 100%; !important;
497 }
498
499 @media (max-width: 768px) {
500 .multi-column-text {
501 column-count: 1;
502 }
503 }
504</style>
Fehler bei der Verarbeitung der Vorlage.
The following has evaluated to null or missing:
==> assetVocabularyLocalService.fetchGroupVocabulary(themeDisplay.getScopeGroupId(), vocabularyName) [in template "37204#37246#42066452" at line 70, column 31]
----
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: #assign vocabulary = assetVocabularyL... [in template "37204#37246#42066452" at line 70, column 9]
----
1<#assign resourcePrimaryKey = .vars["reserved-article-resource-prim-key"].data />
2<#assign idArticle = .vars["reserved-article-id"].data />
3
4<#-- assetEntry-->
5<#assign assetEntryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetEntryLocalService") />
6<#assign assetTagLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetTagLocalService") />
7<#assign assetCategoryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetCategoryLocalService") />
8<#assign assetVocabularyLocalService= serviceLocator.findService("com.liferay.asset.kernel.service.AssetVocabularyLocalService") />
9<#assign assetEntry = assetEntryLocalService.fetchEntry("com.liferay.journal.model.JournalArticle", resourcePrimaryKey?number) />
10<#if !assetEntry?has_content>
11 <#stop "Error: Asset Entry with resourcePrimaryKey = ${resourcePrimaryKey} not found. Template execution stopped." />
12</#if>
13
14<#-- JournalArticle-->
15<#assign journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") />
16<#assign journalArticle = journalArticleLocalService.fetchLatestArticle(resourcePrimaryKey?number) />
17<#if !journalArticle?has_content>
18 <#stop "Error: Journal Article with resourcePrimaryKey = ${resourcePrimaryKey} not found. Template execution stopped." />
19</#if>
20
21<div class="thematic-area-page-content mt-5">
22 <div class="page-intro">
23
24 <!-- Publish Date -->
25 <#if assetEntry.getPublishDate()?has_content>
26 <div class="subtitle-div gap-3">
27 <h4 class="subtitle plain-text mb-0"> ${dateUtil.getDate(assetEntry.getPublishDate(), "d MMMM yyyy", locale, timeZone)?upper_case}</h4>
28 </div>
29 </#if>
30
31 <!-- Title -->
32 <h1 class="title">${journalArticle.getTitle(themeDisplay.getLocale())}</h1>
33
34 <!-- Subtitle -->
35 <div class="subtitle-div flex-wrap">
36 <h4 class="subtitle plain-text col-md-6 p-0">${languageUtil.get(locale, 'authors')}: ${authors.getData()}</h4>
37 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'document-language')}: ${documentLanguage.getData()!""}</h4>
38 <#if publishDateCustom?? && publishDateCustom.getData()?has_content>
39 <#assign dateObj = dateUtil.parseDate("yyyy-MM-dd", publishDateCustom.getData(), locale) />
40 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'publish-date')}: ${dateUtil.getDate(dateObj, "d MMMM yyyy", locale, timeZone)}</h4>
41 </#if>
42 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'citation')}: ${(citation.getData())!""}</h4>
43 <h4 class="subtitle plain-text col-md-6 col-12 p-0">DOI: ${(doi.getData())!""}</h4>
44 <h4 class="subtitle plain-text col-md-6 col-12 p-0">${languageUtil.get(locale, 'keywords-vivilibrary')}: ${(keywords.getData())!""}</h4>
45 </div>
46
47 <#assign distributionLevelChoice = distributionLevel.getData()!""/>
48 <div class="distribution-level mt-3 ${distributionLevelChoice}">
49 <b>${languageUtil.get(locale, distributionLevelChoice)}</b>
50 </div>
51
52 <!-- Main Image -->
53 <#assign mainImageUrl = ""/>
54 <#assign mainImageCss = ""/>
55 <#if uploadDocument.document.getData()?has_content>
56 <#assign mainImageUrl = uploadDocument.document.getData() + "&previewFileIndex=1">
57 <#assign mainImageCss = "main-image-crop"/>
58 <#elseif journalArticle.getArticleImageURL(themeDisplay)?has_content>
59 <#assign mainImageUrl = journalArticle.getArticleImageURL(themeDisplay)>
60 </#if>
61 <#if mainImageUrl?has_content>
62 <div class="main-image-div">
63 <img class="main-image ${(mainImageCss)!""}" src="${mainImageUrl}" alt="scientific article">
64 </div>
65 </#if>
66
67 <!-- Categories-->
68 <#assign vocabularyName = "Therapy" />
69 <#assign vocabularyId = 0 />
70 <#assign vocabulary = assetVocabularyLocalService.fetchGroupVocabulary(themeDisplay.getScopeGroupId(), vocabularyName)/>
71 <#if vocabulary??>
72 <#assign vocabularyId = vocabulary.getVocabularyId()/>
73 </#if>
74
75 <#assign cats = [] />
76 <#if assetEntry.getCategories()?has_content>
77 <#list assetEntry.getCategories() as c>
78 <#if c.getVocabularyId() == vocabularyId>
79 <#assign cats = cats + [c] />
80 </#if>
81 </#list>
82 </#if>
83
84 <#assign tags = [] />
85 <#if assetTagLocalService.getAssetEntryAssetTags(assetEntry.getEntryId())?has_content>
86 <#assign tags = assetTagLocalService.getAssetEntryAssetTags(assetEntry.getEntryId())>
87 </#if>
88
89 <#if tags?has_content || cats?has_content>
90 <div class="tags-container flex-wrap">
91 <#if cats?has_content>
92 <#list cats as cat>
93 <span class="tag tag-style">${languageUtil.get(locale, "account-treatment-"+cat.getTitle(themeDisplay.getLocale()))}</span>
94 </#list>
95 </#if>
96 <#if tags?has_content>
97 <#list tags as tag>
98 <span class="tag tag-style">${tag.getName()}</span>
99 </#list>
100 </#if>
101 </div>
102 </#if>
103 </div>
104
105 <!-- Wavy divider -->
106 <div class="wavy-divider">
107 <svg viewBox="0 0 1440 60" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none">
108 <path d="M0,20 Q360,60 720,20 T1440,20 V60 H0 Z" fill="#fff"/>
109 </svg>
110 </div>
111
112 <!-- 1. One column section -->
113 <#if shortAbstract.oneColumnSectionTitle.getData()?has_content && shortAbstract.oneColumnText.getData()?has_content>
114 <div class="sections-block">
115 <h4 class="section-title reading-time-parameter">${shortAbstract.oneColumnSectionTitle.getData()}</h4>
116 <div class="one-column-text p-0">
117 <div class="plain-text reading-time-parameter">${shortAbstract.oneColumnText.getData()}</div>
118 </div>
119 </div>
120 </#if>
121
122 <!-- 3. Two columns section -->
123 <#if abstract.title.getData()?has_content &&
124 abstract.text.getData()?has_content>
125 <div class="sections-block">
126 <h4 class="section-title reading-time-parameter">${abstract.title.getData()}</h4>
127 <div class="col-md-12 p-0">
128 <div class="plain-text reading-time-parameter multi-column-text">${abstract.text.getData()}</div>
129 </div>
130 </div>
131 </#if>
132
133 <!-- 5. Embedded document section -->
134 <#if uploadDocument.docSectionTitle.getData()?has_content && uploadDocument.document.getData()?has_content && uploadDocument.document.getData()?has_content>
135 <#assign totalPages = webContentUtil.getDocumentPreviewPageCount(themeDisplay, uploadDocument.document.getData()) />
136 <div class="sections-block">
137 <h4 class="section-title reading-time-parameter">${uploadDocument.docSectionTitle.getData()}</h4>
138 <div class="doc-container">
139 <div class="col-md-12 p-0">
140 <div class="doc-embed d-flex flex-column align-items-center">
141 <button class="pdf-open-doc" data-pdf-url="${uploadDocument.document.getData()}">
142 ${languageUtil.get(locale, "open-document")}
143 </button>
144 <div class="pdf-pages-container">
145 <#list 1..totalPages as page>
146 <img
147 src="${uploadDocument.document.getData()}&previewFileIndex=${page}"
148 class="pdf-page"
149 data-page="${page}"
150 />
151 </#list>
152 </div>
153 <div class="doc-index">
154 <div class="pdf-pagination">
155 <button class="pdf-nav prev subtitle"><</button>
156 <div class="pdf-nav-index-div"></div>
157 <button class="pdf-nav next subtitle">></button>
158 </div>
159 </div>
160 </div>
161 </div>
162 </div>
163 </div>
164 </#if>
165
166 <#assign linkTagIsNotEmpty = false>
167 <#list references.getSiblings() as field>
168 <#if field.getData()?? && field.linkTitle.getData()?trim != "" && field.linkUrl.getData()?trim != "">
169 <#assign linkTagIsNotEmpty = true>
170 <#break>
171 </#if>
172 </#list>
173
174 <!-- 6. Link section -->
175 <#if linkTagIsNotEmpty>
176 <div class="sections-block" style="border-bottom-right-radius:12px;border-bottom-left-radius:12px;">
177 <h4 class="section-title reading-time">${languageUtil.get(locale, "references")}</h4>
178 <div class="d-flex flex-column">
179 <#list references.getSiblings() as link>
180 <#if link.linkTitle.getData()?has_content && link.linkUrl.getData()?has_content>
181 <div class="link-card mb-4">
182 <div class="link-info">
183 <div class="link-title reading-time-parameter"><b>${link.linkTitle.getData()}</b></div>
184 <#if link.linkDesc.getData()?has_content>
185 <div class="link-description reading-time-parameter">${link.linkDesc.getData()}</div>
186 </#if>
187 </div>
188 <a href="${(link.linkUrl.getData())!'javascript:void(0);'}" class="download-btn"
189 title="Scarica" onclick="openLinkInNewTab(event, this)">
190 <i class="icom-vivimedical-link-icon">
191 </i>
192 </a>
193 </div>
194 </#if>
195 </#list>
196 </div>
197 </div>
198 </#if>
199
200</div>
201
202<script src="https://cdn.jsdelivr.net/npm/hammerjs@2.0.8/hammer.min.js"></script>
203
204<script>
205 function initializeOpenDocButton() {
206 const openDocBtn = document.querySelector('.pdf-open-doc');
207 if (openDocBtn) {
208 openDocBtn.addEventListener('click', () => {
209 const pdfUrl = openDocBtn.getAttribute('data-pdf-url');
210 if (!pdfUrl) {
211 alert('PDF not available');
212 return;
213 }
214 const newTab = window.open(pdfUrl, '_blank');
215 if (!newTab) {
216 alert('Unable to open the PDF. Please check your browser settings for pop-ups.');
217 }
218 });
219 }
220 }
221
222 function pdfPagination() {
223 const pages = document.querySelectorAll('.pdf-page');
224 const prevBtn = document.querySelector('.pdf-nav.prev');
225 const nextBtn = document.querySelector('.pdf-nav.next');
226 const pageNumbersContainer = document.querySelector('.pdf-nav-index-div');
227
228 // pdf-pagination struct: 1....lastPage
229 const totalPages = pages.length;
230 const firstPage = 1;
231 const lastPage = totalPages;
232 let currentPage = firstPage;
233 let indexStyleClass = 'subtitle';
234
235 function addStyle(elem, styleClass) {
236 elem.classList.add(styleClass);
237 }
238
239 function addPageButton(pageNumber) {
240 const btn = document.createElement('button');
241 btn.className = 'pdf-page-num';
242 btn.textContent = pageNumber;
243 addStyle(btn, indexStyleClass);
244 pageNumbersContainer.appendChild(btn);
245 }
246
247 function addEllipsis() {
248 const span = document.createElement('span');
249 span.className = 'pdf-page-num ellipsis';
250 span.textContent = '...';
251 addStyle(span, indexStyleClass);
252 pageNumbersContainer.appendChild(span);
253 }
254
255 // invalid currentPage sets value to default (firstPage)
256 function validateCurrentPage(currentPage, defaultValue) {
257 if (typeof currentPage !== 'number' || isNaN(currentPage) ||
258 currentPage < firstPage || currentPage > lastPage) {
259 return defaultValue;
260 }
261 return currentPage;
262 }
263
264 function renderPageNumbers(currentPage) {
265 pageNumbersContainer.innerHTML = '';
266 currentPage = validateCurrentPage(currentPage, firstPage);
267 console.log("totalPages " + totalPages);
268 if (totalPages >= 1 && totalPages <= 4) {
269 for (let i = firstPage; i < firstPage + totalPages; i++) {
270 addPageButton(i);
271 }
272 }
273 else if (currentPage == firstPage || currentPage == firstPage + 1) {
274 addPageButton(firstPage);
275 addPageButton(firstPage + 1);
276 addPageButton(firstPage + 2);
277 addEllipsis();
278 addPageButton(lastPage);
279 } else if (currentPage == lastPage - 1 || currentPage == lastPage) {
280 addPageButton(firstPage);
281 addEllipsis();
282 addPageButton(lastPage - 2);
283 addPageButton(lastPage - 1);
284 addPageButton(lastPage);
285 } else {
286 addPageButton(firstPage);
287 addEllipsis();
288 addPageButton(currentPage);
289 addEllipsis();
290 addPageButton(lastPage);
291 }
292 }
293
294 function setActivePage(currentPage) {
295 if (validateCurrentPage(currentPage, firstPage)) {
296 const buttons = document.querySelectorAll('.pdf-page-num');
297 buttons.forEach(btn => btn.classList.remove('active'));
298 buttons.forEach(btn => {
299 if (parseInt(btn.textContent, 10) === currentPage) {
300 btn.classList.add('active');
301 }
302 });
303 }
304 }
305
306 function showPage(page) {
307 currentPage = page;
308 // hides all images
309 document.querySelectorAll('.pdf-page').forEach(img => img.style.display = 'none');
310 // display currentPage image
311 const currentPageElement = document.querySelector('.pdf-page[data-page="' + page + '"]');
312 if (currentPageElement) {
313 currentPageElement.style.display = 'block';
314 }
315 prevBtn.disabled = currentPage === firstPage;
316 nextBtn.disabled = currentPage === lastPage;
317 renderPageNumbers(currentPage);
318 setActivePage(currentPage);
319 }
320
321 // prev btn listener
322 prevBtn.addEventListener('click', function () {
323 if (currentPage > firstPage) showPage(currentPage - 1);
324 });
325
326 // next btn listener
327 nextBtn.addEventListener('click', function () {
328 if (currentPage < lastPage) showPage(currentPage + 1);
329 });
330
331 // index btn listener
332 pageNumbersContainer.addEventListener('click', function (e) {
333 if (e.target.classList.contains('pdf-page-num') && !e.target.classList.contains('ellipsis')) {
334 const pageNumber = parseInt(e.target.textContent, 10);
335 if (!isNaN(pageNumber)) {
336 showPage(pageNumber);
337 }
338 }
339 });
340
341 //Hammer.js
342 function initializeHammer() {
343 const container = document.querySelector('.pdf-pages-container');
344
345 if (!container || typeof Hammer === 'undefined') {
346 console.warn('Container not found or Hammer.js not loaded');
347 return;
348 }
349
350 const hammer = new Hammer(container);
351
352 hammer.get('swipe').set({ direction: Hammer.DIRECTION_HORIZONTAL });
353
354 hammer.on('swipeleft', () => {
355 if (currentPage < totalPages) {
356 showPage(currentPage + 1);
357 }
358 });
359
360 hammer.on('swiperight', () => {
361 if (currentPage > 1) {
362 showPage(currentPage - 1);
363 }
364 });
365 }
366
367 // Initialize Hammer
368 initializeHammer();
369
370
371 showPage(firstPage);
372 }
373
374 function openLinkInNewTab(event, el) {
375 event.preventDefault();
376 event.stopPropagation();
377
378 const href = el.getAttribute('href');
379
380 if (!href || href.trim() === '' || href === 'javascript:void(0);') {
381 alert('Link non disponibile');
382 return;
383 }
384 try {
385 new URL(href, window.location.href);
386 } catch (e) {
387 alert('URL non valido');
388 return;
389 }
390
391 const newTab = window.open(href, '_blank');
392
393 if (!newTab || newTab.closed || typeof newTab.closed === 'undefined') {
394 alert('Unable to open the link. Please check your browser settings to allow pop-ups.');
395 }
396 }
397
398
399 function init() {
400 pdfPagination();
401 initializeOpenDocButton();
402 }
403 if (document.readyState === "loading") {
404 document.addEventListener('DOMContentLoaded', init);
405 document.addEventListener('DOMContentLoaded', function(){
406 let readingTime = calculateReadingTime();
407 $('#readingTime').text(readingTime);
408 });
409 } else {
410 init();
411 let readingTime = calculateReadingTime();
412 $('#readingTime').text(readingTime);
413 }
414
415 function calculateReadingTime(){
416 let wordCount = 0;
417 const wordsPerMinute = 200;
418 $('.reading-time-parameter').each(function(index, elem){
419 let text = $(elem).text();
420 wordCount += text.trim().split(/\s+/).length;
421 });
422 if(wordCount > 0){
423 return Math.ceil(wordCount / wordsPerMinute);
424 }else{
425 return 0;
426 }
427 }
428
429</script>
430
431<style>
432 * {
433 overflow-wrap: break-word;
434 }
435
436 .main-image-crop{
437 height: 300px;
438 object-position:top center;
439 @media(max-width: 576px){
440 height: 60px;
441 }
442 }
443 .multi-column-text{
444 column-count: 2;
445 column-gap: 2rem;
446 }
447 .distribution-level{
448 text-transform: uppercase;
449 &:before{
450 content: "";
451 display: inline-block;
452 width: 20px;
453 height: 20px;
454 margin-right: 6px;
455 border: 5px solid;
456 border-radius: 50%;
457 background: transparent;
458 vertical-align: sub;
459 }
460 &.disclosable{
461 &.before{
462 border-color: #23863F;
463 }
464 color: #23863F;
465 }
466 &.limited-disclosure{
467 &.before{
468 border-color: #F7B32B;
469 }
470 color: #F7B32B;
471 }
472 &.internal-use-only{
473 &.before{
474 border-color: #D24445;
475 }
476 color: #D24445;
477 }
478 }
479 .icom-vivimedical-link-icon:before{
480 color: #8ed300;
481 }
482 .thematic-area-page-content{
483 .download-btn:hover{
484 text-decoration: none;
485 }
486 }
487
488 .plain-text{
489 p{
490 line-height: 1.5;
491 }
492 }
493
494 .sections-block > .one-column-text > .plain-text img {
495 height: auto; !important;
496 max-width: 100%; !important;
497 }
498
499 @media (max-width: 768px) {
500 .multi-column-text {
501 column-count: 1;
502 }
503 }
504</style>