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.

Anhang

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">&lt;</button> 
156                                <div class="pdf-nav-index-div"></div> 
157                                <button class="pdf-nav next subtitle">&gt;</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">&lt;</button> 
156                                <div class="pdf-nav-index-div"></div> 
157                                <button class="pdf-nav next subtitle">&gt;</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">&lt;</button> 
156                                <div class="pdf-nav-index-div"></div> 
157                                <button class="pdf-nav next subtitle">&gt;</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">&lt;</button> 
156                                <div class="pdf-nav-index-div"></div> 
157                                <button class="pdf-nav next subtitle">&gt;</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>