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

Position

4

Standort
Datum
Tätigkeitsfeld
8
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 68, column 55]

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

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

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

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