null Rakas lähiö: Kirjailija Virpi Hämeen-Anttila nauttii siitä, että Mikkolassa ei tapahdu liikaa

Virhe tapahtui prosessoidessa esitysmallia.
The following has evaluated to null or missing:
==> slot.videoFile  [in template "20116#20160#45930" at line 917, column 42]

----
Tip: It's the step after the last dot that caused this error, not those before it.
----
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 videoFile = slot.videoFile.ge...  [in template "20116#20160#45930" in macro "printRemainingVideoContents" at line 917, column 21]
	- Reached through: @printRemainingVideoContents articleV...  [in template "20116#20160#45930" at line 378, column 9]
----
1<#----------------------------------------------------------------------------- 
2    INIT (Single article template) 
3------------------------------------------------------------------------------> 
4<#setting time_zone="Europe/Helsinki"> 
5<#assign serviceContext = staticUtil["com.liferay.portal.kernel.service.ServiceContextThreadLocal"].getServiceContext()> 
6<#assign themeDisplay = serviceContext.getThemeDisplay() /> 
7<#assign javascript_folder = "/o/kirkkojakaupunki-site-theme/js" > 
8 
9 
10<#assign JournalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService")> 
11<#assign articleContentService = serviceLocator.findService("com.ch5finland.helsinginseurakuntayhtyma.kirkkojakaupunki.article.content.service.ArticleContentService")> 
12 
13<#assign currentArticle = JournalArticleLocalService.getArticle(groupId, .vars['reserved-article-id'].data) /> 
14<#setting url_escaping_charset="UTF-8"> 
15 
16<#-- 
17    Kirkkojakaupunki-site-theme-blank is used pages that are meant for mobile app  
18    Figure out if article is shown on mobile app based on theme id  
19     
20    It is also possible to show article with default kirkkojakaupunki-site-theme when request comes 
21    from mobile app. We can check this with x-prenly-client-type header 
22--> 
23<#assign mobileAppView = themeDisplay.getThemeId()?contains("kirkkojakaupunkisitethemeblank") ||  
24                         request.getHeader('x-prenly-client-type')?? && request.getHeader('x-prenly-client-type')?has_content 
25
26 
27 
28<#-- Helper variables --> 
29<#assign includeOwlScript = false> 
30 
31<#assign previewMode = false > 
32<#-- Check if article is viewed in preview mode --> 
33 
34<#if themeDisplay.getURLCurrent()?contains("preview_article_content.jsp") > 
35    <#-- this aplies if preview is selected via folder/list view. Site css is included  --> 
36    <#assign previewMode = true > 
37</#if> 
38<#if themeDisplay.getURLCurrent()?contains("preview_article_content_template.jsp") > 
39    <#-- this aplies if preview is selected via article edit. Site css is not included for some reason so here is little hack --> 
40    <#assign previewMode = true > 
41    <link rel="stylesheet" type="text/css"  href="/o/kirkkojakaupunki-site-theme/css/main.css" /> 
42    <script>$.getScript("/o/kirkkojakaupunki-site-theme/js/main.js");</script> 
43</#if> 
44 
45<#-- 
46    Counters for keeping track of now many elements 
47    have been placed with a tag. 
48--> 
49<#global tagReplaceCounter = 0 /> 
50<#assign kainaloTagCounter = 0 /> 
51<#assign infoTagCounter = 0 /> 
52<#assign faktaTagCounter = 0 /> 
53<#assign quoteTagCounter = 0 /> 
54<#assign videoTagCounter = 0 /> 
55<#assign audioTagCounter = 0 /> 
56<#assign imageComparisonTagCounter = 0 /> 
57 
58<#-- Article ID --> 
59<#assign articleId = .vars['reserved-article-id'].data> 
60<#assign articleCategories = getCategoryNames(articleId)> 
61 
62 
63<#-- Article --> 
64<#assign article = JournalArticleLocalService.getArticle(groupId, articleId) /> 
65 
66<#-- Article complete URL --> 
67<#assign urlTitle = article.urlTitle?trim /> 
68<#assign articleCompleteUrl = themeDisplay.getPortalURL() + "/-/" + urlTitle /> 
69 
70<#-- available author names : Those authors which have author card --> 
71<#assign authorCardFolderIds = [140767, 140764] /> <#-- Toimittjat, Kolumnistit --> 
72<#assign availableAuthorNames = getAvailableAuthorNames(authorCardFolderIds) /> 
73<#assign authorCardBaseUrl = "/toimittajat?author=" /> 
74 
75<#-- Article title --> 
76<#assign title = .vars['reserved-article-title'].data> 
77 
78<#-- Article lead --> 
79<#assign lead = .vars['reserved-article-description'].data> 
80 
81<#-- Get and format article publish date --> 
82<#assign displayDate = .vars['reserved-article-display-date'].data> 
83 
84    <#-- Save the original page locale for later --> 
85    <#assign originalLocale = locale> 
86 
87    <#-- Set the page locale to the portals default locale --> 
88    <#setting locale = localeUtil.getDefault()> 
89 
90    <#-- Parse the date to a date object --> 
91    <#assign displayDate = displayDate?datetime("EEE, d MMM yyyy HH:mm:ss Z")> 
92 
93    <#-- Set the page locale back to the original page locale --> 
94    <#assign locale = originalLocale> 
95 
96 
97<#-- Article body tags --> 
98<#assign tagKainalo = "[[kainalo]]"> 
99<#assign tagInfo = "[[info]]"> 
100<#assign tagFakta = "[[fakta]]"> 
101<#assign tagQuote = "[[sitaatti]]"> 
102<#assign tagImage = "[[kuva]]"> 
103<#assign tagVideo = "[[video]]"> 
104<#assign tagAudio = "[[audio]]"> 
105<#assign tagCarousel = "[[kuvakaruselli#]]"> <#-- # will be replaced with carousel number --> 
106<#assign tagImageComparison = "[[vaihtokuva]]"> 
107<#assign tagEmbeddedHTML = "[[upotus]]"> 
108 
109<#-- lisäksi käytössä  
110  [[mainos]] 
111  [[eimainosta]] 
112--> 
113 
114<#-- wrapper css classes --> 
115<#assign wrapperCSSKainalo = "article-section article-tail"> 
116<#assign wrapperCSSInfo = "article-box article-info"> 
117<#assign wrapperCSSFakta = "article-box article-fact"> 
118<#assign wrapperCSSQuote = "template-quote"> <#-- should not be changes. It is used in switch --> 
119 
120<#-- Article tags --> 
121<#assign articleTags = .vars['reserved-article-asset-tag-names'].data> 
122 
123<#-- Article raw body --> 
124<#assign articleBody = articleBody.getData()> 
125 
126<#-- Ad :  
127 https://tiketti.ch5.fi/issues/24425 
128  
129    Lähtökohta: Artikkelin sisäinen mainos näkyy aina neljän leipätekstin <p>-tagin jälkeen. 
130    Tarvittaessa artikkelin muokkaaja voi muuttaa mainoksen näyttöpaikkaa [[mainos]]-tagilla 
131    Tarvittaessa artikkelin muokkaaja voi estää mainoksen näkemisen yksittäisessä artikkelissa [[eimainosta]]-tagilla. 
132    Mainos ei näy ”erikoisartikkeleissa” eikä ”kuva-artikkeleissa”, ainoastaan ”Koko artikkeleissa”. 
133    Artikkelin sisäinen mainos ei näy koskaan artikkeleissa, joissa on tägi ”pääkirjoitus” tai ”hyvää pyhää” tai joiden leipäteksti on hyvin lyhyt (pituus alle 8 <p>) 
134    Mainos näytetään kaikissa palvelun vanhoissa artikkeleissa edellä mainituin rajoituksin. 
135    Artikkelin sisäisiä mainospaikkoja voidaan tehdä montakin, mutta ehkä lähdetään yhdellä liikkeelle… 
136    Pyritään testaamaan artikkelin sisäisen mainospaikan toimivuus kehitysympäristössä. 
137 
138     
139    --> 
140<#assign insertAdAfterNthParagraph = 4 /> 
141<#assign insertAdIfContainsMoreThanParagraphs = 8 /> 
142<#assign tagPreventsShowingAd = articleTags?contains("pääkirjoitus") || articleTags?contains("hyvää pyhää") /> 
143 
144<#if !articleBody?contains("[[eimainosta]]") && !tagPreventsShowingAd> 
145 
146    <#if !articleBody?contains("[[mainos]]")> 
147        <#-- no ad tag so inject --> 
148        <#assign articleBody = articleContentService.injectAdMarker(articleBody, insertAdAfterNthParagraph, insertAdIfContainsMoreThanParagraphs) /> 
149    </#if> 
150    <#assign articleBody = replaceAdTag(articleBody) /> 
151<#else> 
152 
153    <#-- Clean [[eimainosta]] and possible [[mainos]] tags -->  
154     
155    <#assign articleBody = articleBody?replace("<p>[[eimainosta]]</p>", "") /> 
156    <#assign articleBody = articleBody?replace("[[eimainosta]]", "") /> 
157    <#assign articleBody = articleBody?replace("<p>[[mainos]]</p>", "") /> 
158    <#assign articleBody = articleBody?replace("[[mainos]]", "") />     
159</#if> 
160 
161<#-- // END OF AD stuff --> 
162 
163<#if articleTail?has_content> 
164    <#assign articleBody = replaceTags(articleBody, tagKainalo, articleTail, wrapperCSSKainalo)> 
165    <#assign kainaloTagCounter = tagReplaceCounter /> 
166</#if> 
167<#if articleInfo?has_content> 
168    <#assign articleBody = replaceTags(articleBody, tagInfo, articleInfo, wrapperCSSInfo)> 
169    <#assign infoTagCounter = tagReplaceCounter /> 
170</#if> 
171<#if articleFacts?has_content> 
172    <#assign articleBody = replaceTags(articleBody, tagFakta, articleFacts, wrapperCSSFakta)> 
173    <#assign faktaTagCounter = tagReplaceCounter /> 
174</#if> 
175<#if articleQuotes?has_content> 
176    <#assign articleBody = replaceTags(articleBody, tagQuote, articleQuotes, wrapperCSSQuote)> 
177    <#assign quoteTagCounter = tagReplaceCounter /> 
178</#if> 
179<#if articleEmbeddedHTML?has_content> 
180    <#assign articleBody = replaceTags(articleBody, tagEmbeddedHTML, articleEmbeddedHTML, 'no-wrapper')> 
181</#if> 
182<#if articleImages?has_content> 
183    <#assign articleBody = replaceImageTags(articleBody, tagImage, articleImages)> 
184    <#assign articleBody = replaceCarouselTags(articleBody, tagCarousel, articleImages)> 
185</#if> 
186<#if articleVideos?has_content> 
187    <#assign articleBody = replaceVideoTags(articleBody, tagVideo, articleVideos)> 
188    <#assign videoTagCounter = tagReplaceCounter /> 
189</#if> 
190<#if articleAudio?has_content> 
191    <#assign articleBody = replaceAudioTags(articleBody, tagAudio, articleAudio)> 
192    <#assign audioTagCounter = tagReplaceCounter /> 
193</#if> 
194<#if imageComparisons?has_content> 
195    <#assign articleBody = replaceImageComparisonTags(articleBody, tagImageComparison, imageComparisons)> 
196</#if> 
197 
198<#-- 25209 - iframe is wrapped inside p-tags and for that reason gets extra text-indent. Replace p-tags. -->  
199<#assign articleBody = articleBody?replace("<p><iframe", "<iframe")?replace("</iframe></p>", "</iframe>") > 
200 
201<#----------------------------------------------------------------------------- 
202    OUTPUT ARTICLE 
203------------------------------------------------------------------------------> 
204 
205<#if previewMode> 
206    <script> 
207            inPreviewMode = true; 
208            var iframeContainer = jQuery('.modal-body-iframe', window.parent.document).parent().parent(); 
209            jQuery(iframeContainer).addClass("custom-preview-dialog"); 
210            jQuery(iframeContainer).css("width", "940px"); 
211            jQuery(iframeContainer).css("margin", "auto"); 
212            jQuery(iframeContainer).find("iframe").css("width", "900px"); 
213            jQuery('body', window.parent.document).addClass("custom-in-preview-mode"); 
214    </script> 
215</#if> 
216 
217<article class="voice-intuitive"> 
218     
219    <#-- Show article url in preview mode --> 
220    <#if previewMode?? && previewMode> 
221	    <div><span>${articleCompleteUrl}</span></div> 
222    </#if> 
223 
224    <#-- Article image(s) --> 
225 
226    <#if articleImages?has_content> 
227        <#assign headerImages = getHeaderImages(articleImages) > 
228        <#assign contentCarouselImages = getContentCarouselImages(articleImages) > 
229    </#if> 
230 
231    <#if contentCarouselImages?has_content> 
232        <#if (contentCarouselImages?size > 1) > 
233            <#assign includeOwlScript = true> 
234        </#if> 
235    </#if> 
236     
237     
238 
239    <#if headerImages?has_content> 
240 
241        <#-- Container with bottom margin --> 
242        <div class="article-header-img"> 
243 
244 
245 
246            <#-- More than one image > create owl-carousel --> 
247            <#if (headerImages?size > 1) > 
248 
249                    <#list headerImages as image> 
250 
251            		    <#if image.getData()?? && image.getData()?has_content> 
252 
253                            <#-- Open carousel container on first image --> 
254                            <#if image?is_first> 
255                                <div class="owl-carousel owl-theme"> 
256 
257                                <#-- Load carousel script at the end of display template --> 
258                                <#assign includeOwlScript = true> 
259                            </#if> 
260 
261                            <#-- Output carousel slides --> 
262                            <div class="item"> 
263                                <#if image.getAttribute("alt")?has_content> 
264                                    <div class="aspect-ratio aspect-ratio-middle aspect-ratio-xs"> 
265                                        <img  class="aspect-ratio-item-fluid" src="${getImageURLByTemplateModel(image, '1200')}" alt="${image.getAttribute("alt")}" /> 
266                                    </div> 
267                                    <span class="caption voice-no-read">${image.getAttribute("alt")}</span> 
268                                <#else> 
269                                    <div class="aspect-ratio aspect-ratio-middle aspect-ratio-xs"> 
270                                        <img class="aspect-ratio-item-fluid" src="${getImageURLByTemplateModel(image, '1200')}" alt="" /> 
271                                    </div> 
272                                </#if> 
273                            </div> 
274 
275                            <#-- Close carousel contaner after last item --> 
276                            <#if image?is_last> 
277                                </div> <#-- div.owl-carousel --> 
278                            </#if> 
279 
280            		    </#if> 
281            	    </#list> 
282 
283            <#else> 
284 
285            <#-- Display a single image without carousel --> 
286            <#list headerImages as image> 
287 
288    		    <#if image.getData()?? && image.getData()?has_content> 
289 
290                    <#-- <@adaptive_media_image["img"] fileVersion=dlAppServiceUtil.getFileEntry(.getFileVersion())/>  --> 
291         
292                    <#if image.getAttribute("alt")?has_content> 
293            	        <img  
294                            src="${getImageURLByTemplateModel(image, '1200')}"  
295                            alt="${image.getAttribute("alt")}" /> 
296                             
297                        <p class="caption voice-no-read">${image.getAttribute("alt")}</p> 
298                    <#else> 
299            	        <img  
300                            src="${getImageURLByTemplateModel(image, '1200')}" alt="" /> 
301                   </#if> 
302    		    </#if> 
303    	    </#list> 
304 
305            </#if> 
306 
307        </div> <#-- div.article-header-img --> 
308 
309    </#if> 
310 
311    <#if articleCategories?has_content> 
312        <div class="voice-no-read"> 
313            <#list articleCategories as cat> 
314                <span data-cat="${cat?lower_case}" class="category-item">${cat}</span> 
315            </#list> 
316        </div> 
317    </#if> 
318 
319    <h1>${title}</h1> 
320 
321    <#if lead?? && lead?has_content> 
322        <#-- Remove possible HTML-tags --> 
323        <#assign leadCleaned = htmlUtil.stripHtml(lead) /> 
324        <p class="lead">${leadCleaned}</p> 
325    </#if> 
326 
327    <ul class="list-inline article-meta voice-no-read""> 
328        <li class="list-inline-item"><span class="date">${displayDate?string["dd.MM.yyyy HH:mm"]}</span></li> 
329 
330        <#if articleAuthors.authors.getData()?? && articleAuthors.authors.getData()?has_content> 
331            <#assign articleAuthor = articleAuthors.authors.getData()> 
332            <li class="list-inline-item"> 
333                <span class="author authortext-no-margin author-text"></span> 
334                <span class="author author-name"> 
335                    <#if mobileAppView> 
336                        ${articleAuthor} 
337                    <#else> 
338                        ${makeAuthorLinks(articleAuthor,availableAuthorNames, authorCardBaseUrl)} 
339                    </#if> 
340                </span> 
341            </li> 
342        </#if> 
343 
344        <#if articleAuthors.photographers.getData()?? && articleAuthors.photographers.getData()?has_content> 
345            <li class="list-inline-item"> 
346                <span class="author author-name author-photo"> 
347                    <#if mobileAppView> 
348                        ${articleAuthors.photographers.getData()} 
349                    <#else> 
350                        ${makeAuthorLinks(articleAuthors.photographers.getData(),availableAuthorNames, authorCardBaseUrl)} 
351                    </#if> 
352                </span> 
353            </li> 
354        </#if> 
355    </ul> 
356 
357    <div id="voice-intuitive-root"></div> 
358     
359    ${articleBody} 
360 
361    <#-- Output article quotes --> 
362    <#if articleQuotes?has_content && articleQuotes.getSiblings()?has_content> 
363    <@printRemainingTagContents articleQuotes quoteTagCounter wrapperCSSQuote /> 
364    </#if> 
365 
366    <#-- Print article factbox(es) --> 
367    <#if articleFacts?has_content && articleFacts.getSiblings()?has_content> 
368        <@printRemainingTagContents articleFacts faktaTagCounter wrapperCSSFakta /> 
369    </#if> 
370 
371    <#-- Print article infobox(es) --> 
372    <#if articleInfo?has_content && articleInfo.getSiblings()?has_content> 
373        <@printRemainingTagContents articleInfo infoTagCounter wrapperCSSInfo/> 
374    </#if> 
375 
376    <#-- Print article video(s) --> 
377    <#if articleVideos?has_content && articleVideos.getSiblings()?has_content> 
378        <@printRemainingVideoContents articleVideos videoTagCounter  /> 
379    </#if> 
380 
381    <#-- Print remaining audio embeds --> 
382    <#if articleAudio?has_content && articleAudio.getSiblings()?has_content> 
383        <@printRemainingAudioContents articleAudio audioTagCounter  /> 
384    </#if> 
385     
386    <#-- Print article tail(s) --> 
387    <#if articleTail?has_content && articleTail.getSiblings()?has_content> 
388        <@printRemainingTagContents articleTail kainaloTagCounter wrapperCSSKainalo /> 
389    </#if> 
390 
391     
392    <div class="voice-no-read">  
393 
394     
395    <#--  NEWSLETTER SUBSCRIPTION BANNER  --> 
396    <@printNewsletterAd articleTags /> 
397 
398     <#-- R&S sharing buttons --> 
399        <div class="article-sharing"> 
400            <p class="sans text-uppercase">Jaa t&auml;m&auml; artikkeli:</p> 
401            <div class="rns-share-plugin"></div> 
402        </div> 
403         
404<#if !mobileAppView>         
405    <#-- City --> 
406        <#if articleTags?has_content> 
407 
408            <#assign cityTags = 0> 
409 
410            <#list articleTags?split(",") as tag> 
411                <#assign cities = ["Helsinki", "Espoo", "Vantaa", "Kauniainen", "helsinki", "espoo", "vantaa", "kauniainen"]>  
412                <#assign isCityTag = cities?seq_contains(tag)>  
413                <#if isCityTag == true> 
414                    <#assign cityTags = cityTags + 1> 
415                </#if> 
416            </#list> 
417 
418            <#if cityTags gt 0> 
419                <div class="article-section article-tags"> 
420                    <p class="sans text-uppercase d-inline">Lis&auml;&auml; aiheesta:</p> 
421                    <ul class="list-inline d-inline"> 
422                        <#list articleTags?split(",") as tag> 
423 
424                            <#assign cities = ["Helsinki", "Espoo", "Vantaa", "Kauniainen", "helsinki", "espoo", "vantaa", "kauniainen"]>  
425                            <#assign isCityTag = cities?seq_contains(tag)>  
426 
427                            <#if isCityTag> 
428                                <li class="list-inline-item"><a href="/artikkelit/-/tag/${htmlUtil.escapeURL(tag)}?article=${article.getResourcePrimKey()}" class="tag tag-map-icon">${tag}</a></li> 
429                            </#if> 
430                        </#list> 
431                    </ul> 
432                </div> 
433            </#if> 
434        </#if> 
435</#if> <#-- end of !mobileAppView -->         
436         
437        <#-- 
438            Output author card for the main author. 
439        --> 
440 
441        <#-- <#if articleAuthors.mainAuthor.getData()?? && articleAuthors.mainAuthor.getData()?has_content> 
442            <#assign authorCard = articleAuthors.mainAuthor.getData()?eval /> 
443            <@liferay_ui["asset-display"] 
444                className=authorCard.className 
445                classPK=getterUtil.getLong(authorCard.classPK, 0) 
446                template="full_content" 
447            /> 
448        </#if> --> 
449 
450        <#-- react&share buttons --> 
451         
452        <#-- Hide Kiinostavimmat nyt --> 
453        <#if mobileAppView>  
454        <style> 
455            #rns-post-recommender { display: none; } 
456        </style> 
457        </#if> <#-- end of mobileview --> 
458         
459         
460        <div class="rns"></div> 
461         
462        <script type="text/javascript"> 
463        (function() { 
464        'use strict'; 
465        var a=document.querySelector(".article-meta .date"), 
466            b=b?b.innerHTML:"", 
467            d=document.querySelector("article h1"), 
468            e=document.querySelector("a.author-name"); 
469        var rnsRecommend = function() { window.rnsRecommend() }; 
470        window.rnsData={ 
471            recommenderToggle: '.article-assets', 
472            apiKey:"oyrv5xd6dmwj3lkm", 
473            reactionCallback: rnsRecommend, 
474            maxRecommendations: 3, 
475            date:function(f){ 
476                try{ 
477                    var a=f.match(/(\d{1,2})\.(\d{1,2})\.(\d{4})(\s+(\d{1,2}):(\d{2}))*/), 
478            c=new Date(Date.UTC.apply(this,a[4]?[a[3],a[2]-1,a[1],a[5],a[6]]:[a[3],a[2]-1,a[1]]));return c.setHours(c.getHours()-2),c.toISOString()}catch(g){return""}}(b),title:d?d.innerHTML:"",author:e?e.innerHTML:"", 
479        canonicalUrl:"${articleCompleteUrl}"}; 
480        b=document.createElement("script"); 
481        b.src="https://cdn.reactandshare.com/plugin/rns.js";document.body.appendChild(b); 
482        b=document.createElement("script"); 
483        b.src="https://cdn.reactandshare.com/recommender/rnsrw.js"; 
484        document.body.appendChild(b); 
485 
486    })(); 
487        </script> 
488 
489 
490        <#-- MORE FROM AUTHOR --> 
491 
492        <#assign hasAuthor = articleAuthors.authors.getData()?? && articleAuthors.authors.getData()?has_content /> 
493        <#assign hasPhotographer = articleAuthors.photographers.getData()?? && articleAuthors.photographers.getData()?has_content /> 
494         
495        <#if hasAuthor || hasPhotographer> 
496            <#assign articleAuthor = articleAuthors.authors.getData()> 
497            <#assign articlePhotographer = articleAuthors.photographers.getData() /> 
498             
499            <#assign authorObjs = [] /> 
500 
501            <#-- Find which authors (author card titles) appears in author field and make list of those... 
502            We need no maintain order of appearance 
503            --> 
504            <#list availableAuthorNames as authorName> 
505                <#assign authorPos = articleAuthor?index_of(authorName) /> 
506                <#assign photographerPos = articlePhotographer?index_of(authorName) /> 
507                 
508                <#-- Keep the order... first authors then photographers --> 
509                <#if authorPos != -1 || photographerPos != -1> 
510                    <#assign pos = authorPos /> 
511                    <#if authorPos == -1 && photographerPos != -1> 
512                        <#assign pos = 1000 + photographerPos /> 
513                    </#if> 
514                    <#assign authorObj = {"pos" : pos, "name": authorName} /> 
515                    <#assign authorObjs = authorObjs + [authorObj] /> 
516                </#if> 
517            </#list> 
518 
519            <#if authorObjs?size gt 0> 
520                <#assign authorObjs = authorObjs?sort_by("pos") /> 
521 
522                <#-- <div class="article-tags"> 
523                    <p class="sans text-uppercase">Lis&auml;&auml; tekij&auml;lt&auml;:</p> 
524                    <ul class="list-inline"> 
525                        <#list authorObjs as authorObj> 
526                            <li class="list-inline-item"> 
527                                <#assign authorSearchURL = "/toimittajat?author=" /> 
528                                <a class="tag tag-default" href="${authorCardBaseUrl}${authorObj.name?url}">${authorObj.name}</a> 
529                            </li>		   
530                        </#list> 
531                    </ul> 
532                </div> --> 
533            </#if> 
534 
535        </#if> 
536 
537 
538        <#-- RELATED CONTENT  
539             
540            By default related content are ordered by publish date - newest first. 
541             
542            It is possible to prioritized content in article. Article must be added as related content AND  
543            it is selected into priotized content field. Editor can choose multiple prioritized content and then 
544            order is kept as it is organized in  
545         
546        -->  
547         
548        <#assign assetLinkLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetLinkLocalService") /> 
549        <#assign assetEntryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetEntryLocalService") /> 
550        <#assign currentArticleResourcePrimKey = currentArticle.getResourcePrimKey() /> 
551        <#assign currentArticleAssetEntry = assetEntryLocalService.getEntry("com.liferay.journal.model.JournalArticle", currentArticleResourcePrimKey) /> 
552        <#assign currentArticleAssetEntryId = currentArticleAssetEntry.getEntryId() /> 
553        <#assign currentArticleRelatedLinks = assetLinkLocalService.getDirectLinks(currentArticleAssetEntryId) /> 
554         
555 
556        <#if currentArticleRelatedLinks?has_content> 
557            <#assign relatedLinks = []> 
558            <#assign prioritizedLinks = []> 
559            <#assign alreadyHandledRelatedLinksAssetEntryIds = ""> 
560             
561            <#assign relatedLinksEntryIds = "" /> 
562            <#list currentArticleRelatedLinks as related_entry> 
563                <#assign relatedLinksEntryIds = relatedLinksEntryIds + related_entry.getEntryId2() + ", " /> 
564            </#list> 
565             
566            <#if prioritizedRelatedContent?? && prioritizedRelatedContent?has_content && prioritizedRelatedContent.getSiblings()?has_content> 
567                <#list prioritizedRelatedContent.getSiblings() as prioritizedContent> 
568                    <#assign prioritizedContentAsJSON = jsonFactoryUtil.createJSONObject(prioritizedContent.getData()) > 
569                    <#if prioritizedContentAsJSON.className??> 
570                        <#if prioritizedContentAsJSON.className == "com.liferay.journal.model.JournalArticle"> 
571                            <#assign assetEntry = assetEntryLocalService.fetchEntry(prioritizedContentAsJSON.className, prioritizedContentAsJSON.classPK?number)!"" > 
572                            <#if assetEntry?has_content && relatedLinksEntryIds?contains(assetEntry.entryId?string)> 
573                                <#assign prioritizedLinks += [getRelatedLinkObjectForAssetEntry(assetEntry.entryId)] /> 
574                                <#assign alreadyHandledRelatedLinksAssetEntryIds = alreadyHandledRelatedLinksAssetEntryIds + "," + assetEntry.entryId > 
575                            </#if> 
576                        </#if> 
577                    </#if> 
578                </#list> 
579            </#if>             
580            <#list currentArticleRelatedLinks as related_entry> 
581                <#if !alreadyHandledRelatedLinksAssetEntryIds?contains(related_entry.getEntryId2()?string)> 
582                    <#assign relatedLinks += [getRelatedLinkObjectForAssetEntry(related_entry.getEntryId2())] /> 
583                </#if> 
584            </#list> 
585            <#if relatedLinks?has_content> 
586 
587                <#-- <div class="article-assets"> 
588                    <h2 class="heading-decor-section">Lue lis&auml;&auml;:</h2> --> 
589 
590                <div class="blue-wrapper"> 
591                    <div class="container entry-columns"> 
592                        <div class="row"> 
593                            <div class="entry-column col-md-12"> 
594                                <h2 class="header--top-stripe">Toimitus suosittelee</h2> 
595                                <#assign relatedLinksSorted = prioritizedLinks + relatedLinks?sort_by("date")?reverse /> 
596                                <#list relatedLinksSorted as link> 
597 
598                                    <#-- Get entry categories --> 
599                                    <#-- <#assign categories = link.getCategories()> --> 
600                                     
601                                    <#-- Get article main images --> 
602                                    <#-- <#assign docXml = saxReaderUtil.read(link.getAssetRenderer().getArticle().getContent()) /> --> 
603                                    <#-- <#assign image = docXml.valueOf("//dynamic-element[@name='articleImages']/dynamic-content/text()") /> --> 
604 
605                                <#-- 25557 show maximum 7 related links --> 
606                                 
607                                <#if link?index gt 6> 
608                                    <#break /> 
609                                </#if> 
610                                 
611                                <div class="entry-card news-pick-list-cards"> 
612                                    <div class="row"> 
613 
614                                        <#if link?is_first> 
615                                            <div class="col col-xs-12 mb-3 col-md-4 mb-md-0"> 
616                                                <div class="xaspect-ratio xaspect-ratio-4-to-3"> 
617                                                    <#-- <img class="xaspect-ratio-item xaspect-ratio-item-center xaspect-ratio-item-middle" src="${getThumbnailUrl(image, 2) }" alt="" /> --> 
618                                                    <#if link.urlImage?? && link.urlImage?has_content > 
619                                                        <#assign imageJSON = jsonFactoryUtil.createJSONObject(link.urlImage)> 
620                                                        <#assign fileEntryId = imageJSON.getString("fileEntryId")> 
621                                                        <#assign fileName = imageJSON.getString("name")> 
622                                                        <img src="${getImageURL(imageJSON, '600')}" class="media-object"  alt=""  /> 
623                                                         
624                                                    <#else> 
625                                                        <div class="xaspect-ratio xaspect-ratio-top xaspect-ratio-3-to-2"> 
626                                                            <div class="placeholder placeholder-colored"></div>  
627                                                        </div> 
628                                                    </#if> 
629                                                </div> 
630                                            </div> 
631 
632                                        <#else> 
633                                            <div class="col col-sm-2 d-none d-md-block"> 
634                                                <div class="xaspect-ratio xaspect-ratio-4-to-3"> 
635                                                    <#-- <img class="xaspect-ratio-item xaspect-ratio-item-center xaspect-ratio-item-middle" src="${getThumbnailUrl(image, 2) }" alt="" /> --> 
636                                                    <#if link.urlImage?? && link.urlImage?has_content > 
637                                                        <#assign imageJSON = jsonFactoryUtil.createJSONObject(link.urlImage)> 
638                                                        <#assign fileEntryId = imageJSON.getString("fileEntryId")> 
639                                                        <#assign fileName = imageJSON.getString("name")> 
640                                                        <img src="${getImageURL(imageJSON, '600')}" class="media-object" /> 
641                                                         
642                                                    <#else> 
643                                                        <div class="xaspect-ratio xaspect-ratio-top xaspect-ratio-3-to-2"> 
644                                                            <div class="placeholder placeholder-colored"></div>  
645                                                        </div> 
646                                                    </#if> 
647                                                </div> 
648                                            </div> 
649                                        </#if> 
650 
651                                         
652                                        <div class="col"> 
653                                            <#if link?is_first> 
654                                                <h3 class="blue-wrapper--first-title"><a href="/-/${link.urlTitle}" class="media-content">${link.title}</a></h3> 
655                                            <#else> 
656                                                <h3><a href="/-/${link.urlTitle}" class="media-content">${link.title}</a></h3> 
657                                            </#if> 
658                                             
659                                            <#list link.categories as cat> 
660                                                <span data-cat="${cat?lower_case}" class="category-item">${cat}</span> 
661                                            </#list> 
662                                            <span class="entry-meta">${link.date}</span> 
663 
664                                            <#if link?is_first> 
665                                                <p>${link.lead}</p> 
666                                            </#if> 
667 
668                                        </div> 
669                                    </div> 
670                                    <hr> 
671                                </div> 
672 
673 
674 
675                                    <#-- VANHAT --> 
676 
677                                    <#-- <div class="media"> 
678                                        <div class="media-left"> 
679                                            <a href="/-/${link.urlTitle}" class="sans"> 
680 
681                                                <#if link.urlImage?? && link.urlImage?has_content > 
682                                                    <#assign imageJSON = jsonFactoryUtil.createJSONObject(link.urlImage)> 
683                                                    <#assign fileEntryId = imageJSON.getString("fileEntryId")> 
684                                                    <#assign fileName = imageJSON.getString("name")> 
685                                                    <img src="${getImageURL(imageJSON, '600')}" class="media-object" /> 
686                                                     
687                                                <#else> 
688                                                    <div class="aspect-ratio aspect-ratio-top aspect-ratio-3-to-2"> 
689                                                        <div class="placeholder placeholder-colored"></div>  
690                                                    </div> 
691                                                </#if> 
692 
693                                            </a> 
694                                        </div> 
695                                        <div class="media-body"> 
696                                            <a href="/-/${link.urlTitle}" class="sans">${link.title}</a> 
697                                            <span class="date">${link.date}</span> 
698                                        </div> 
699                                    </div> --> 
700                                </#list> 
701                            </div> 
702                        </div> 
703                    </div> 
704 
705                </div> 
706 
707            </#if> 
708        </#if> 
709 
710        <script src="${javascript_folder}/audioplayer.min.js?v=2"></script> 
711 
712        <#--  NEWSLETTER SUBSCRIPTION BANNER  --> 
713 
714        <#-- <div class="article-subscription"> 
715            <div class="visible-md visible-lg"> 
716                <div class="banner-category-d"><h2 class="no-top-margin" style="margin-bottom: 30px;">Tilaa Kirkko ja kaupungin viikoittainen juttukooste</h2> 
717                    <form class="form-inline" action="https://kirkkojakaupunki.creamailer.fi/tilaa/59d75acf78807" id="subForm" method="post"> 
718                        <input id="redirect" name="redirect" type="hidden" value="https://kirkkojakaupunki-dev.ch5finland.com/"> 
719                        <input class="form-control" id="S&auml;hk&ouml;postiosoite" name="userEmail" placeholder="S&auml;hk&ouml;postiosoite"> 
720                        <input id="newsletter-submit-article" class="btn btn-inverse" type="submit" value="Tilaa uutiskirje"> 
721                    </form>  
722                </div> 
723            </div> 
724        </div> --> 
725 
726        <#-- FACEBOOK COMMENTS --> 
727        <#-- <#if articleComments?? && getterUtil.getBoolean(articleComments.getData()) == true> 
728            <div id="fb-root"></div> 
729            <script>if ($.gdprcookie.preference("analytics")) { document.write(` 
730                <scri`+`pt> 
731                    (function(d, s, id) { 
732                        var js, fjs = d.getElementsByTagName(s)[0]; 
733                        if (d.getElementById(id)) return; 
734                        js = d.createElement(s); js.id = id; 
735                        js.src = "//connect.facebook.net/fi_FI/sdk.js#xfbml=1&version=v2.8&appId=206864833121117"; 
736                        fjs.parentNode.insertBefore(js, fjs); 
737                    }(document, 'script', 'facebook-jssdk')); 
738                </`+`script> 
739                 
740                <h2 class="heading-decor-section">Kommentoi</h2> 
741                <p>Kommentoidaksesi sinun täytyy olla kirjautuneena Facebookiin.</p> 
742                <div class="fb-comments" data-href="${articleCompleteUrl}" data-width="725" data-numposts="5"></div> 
743                 
744            `); } 
745        </script> 
746 
747        </#if> --> 
748  </div> 
749</article> 
750 
751 
752<#-- Include script only if owl carousel among content has been built --> 
753 
754<script src="${javascript_folder}/owl.carousel.min.js"></script> 
755 
756<#if includeOwlScript == true> 
757    <script> 
758    	$('.owl-carousel').owlCarousel({ 
759            items: 1, 
760    		loop: true, 
761    		rewind: false, 
762    		margin: 0, 
763    		nav: true, 
764            navText : ['<span class="owl-carousel-nav glyphicon glyphicon-chevron-left"></span>','<span class="owl-carousel-nav glyphicon glyphicon-chevron-right"></span>'], 
765            autoplay:true, 
766            autoplayTimeout:3000, 
767            smartSpeed:1400, 
768            autoplayHoverPause:true 
769    	}); 
770 
771    </script> 
772</#if> 
773 
774<#-- 
775    Convert Youtube links to embedded videos 
776--> 
777<script type="text/javascript"> 
778 
779    $(document).ready(function () { 
780        $(".js-video-embed" ).each(function() { 
781            // Creates an iframe if it's youtube video. Otherwise just shows the original link. 
782            if (getYoutubeVideoId($(this).attr("href"))) { 
783                var div = $("<div>", {"class": "responsive-video"}); 
784                var wrapper = $("<div>", {"class": "responsive-wrapper"}); 
785                wrapper.append('<iframe src="https://www.youtube.com/embed/'+getYoutubeVideoId($(this).attr("href"))+'?rel=0" frameborder="0" allowfullscreen=""></iframe>'); 
786                div.append(wrapper); 
787                $(this).parent().append(div); 
788                $(this).hide(); //iframe is shown, hide the original link 
789
790        }); 
791    }); 
792    function getYoutubeVideoId(url) { 
793        var videoid = url.match(/(?:https?:\/{2})?(?:w{3}\.)?youtu(?:be)?\.(?:com|be)(?:\/watch\?v=|\/)([^\s&]+)/); 
794        if(videoid != null) { 
795           return videoid[1]; 
796        } else { 
797            return ""; 
798
799
800</script> 
801 
802<#--   
803    Create image comparison slider   
804--> 
805<script src="/o/kirkkojakaupunki-site-theme/js/cocoen.min.js"></script> 
806 
807<script type="text/javascript"> 
808    $(document).ready(function () { 
809        document.querySelectorAll('.cocoen').forEach(function(element){ 
810            var imageComparison = new Cocoen(element); 
811                var sliderOffset = $(element).attr("slider-offset"); 
812                if ($(element).attr("slider-offset") >= 100 || !($(element).attr("slider-offset"))){ 
813                    sliderOffset = 98; 
814                } else if ($(element).attr("slider-offset") == 0) { 
815                    sliderOffset = 2; 
816
817                imageComparison.element.children[0].style.width = sliderOffset+"%"; 
818                imageComparison.dragElement.style.left = sliderOffset+"%"; 
819        }); 
820 
821        // depending on slider offset show either the caption of the first or the second image 
822        $('.cocoen').mousemove(function(event){ 
823            addCaption(this); 
824        }); 
825 
826        // same functionality for touch screens 
827        document.querySelectorAll('.cocoen').forEach(function(element){ 
828            element.addEventListener("touchmove", function() { 
829                addCaption(this); 
830            }); 
831        }); 
832 
833        function addCaption(element) { 
834            var index = $('.cocoen').index(element); 
835            var sliderOffset = parseInt(element.firstElementChild.style.width); 
836            if(sliderOffset < 50){ 
837                $('.caption1').eq(index).hide(); 
838                $('.caption2').eq(index).show(); 
839            } else { 
840                $('.caption2').eq(index).hide(); 
841                $('.caption1').eq(index).show(); 
842
843
844    });     
845     
846</script> 
847 
848 
849<#----------------------------------------------------------------------------- 
850    Helper functions 
851------------------------------------------------------------------------------> 
852<#function getRelatedLinkObjectForAssetEntry relatedAssetEntryId> 
853                <#local relatedAssetEntry = assetEntryLocalService.getEntry(relatedAssetEntryId) /> 
854                <#local relatedAssetEntryPrimKey = relatedAssetEntry.getClassPK() /> 
855                <#local relatedArticle = JournalArticleLocalService.getLatestArticle(relatedAssetEntryPrimKey) /> 
856                <#local relatedArticleId = relatedArticle.getArticleId() /> 
857                <#local docXml = saxReaderUtil.read(relatedArticle.getContent()) />	 
858                <#local image = docXml.valueOf("//dynamic-element[@name='articleImages']/dynamic-content/text()") /> 
859 
860                <#-- Get full description & shorten it --> 
861                <#local lead = htmlUtil.stripHtml(htmlUtil.extractText(relatedArticle.getDescription())) /> 
862         
863                <#local categories = getCategoryNames(relatedArticleId) /> 
864 
865                <#local linkObject = {"categories": categories, "title": relatedArticle.getTitleCurrentValue(),"urlTitle": relatedArticle.getUrlTitle(), "date": relatedArticle.getDisplayDate()?date, "urlImage": image, "lead": lead } /> 
866                 
867                <#if image?? && image?has_content> 
868 
869                <#else> 
870                    <#local nostokuva = docXml.valueOf("//dynamic-element[@name='nostokuva']/dynamic-content/text()") /> 
871                    <#if nostokuva?? && nostokuva?has_content> 
872                        <#local image = nostokuva /> 
873                        <#local linkObject = {"title": relatedArticle.getTitleCurrentValue(),"urlTitle": relatedArticle.getUrlTitle(), "date": relatedArticle.getDisplayDate()?date, "urlImage": image, "lead": lead, "categories": categories  } /> 
874                    </#if> 
875                </#if> 
876    <#return linkObject /> 
877</#function> 
878 
879<#macro printRemainingTagContents container startAt wrapperCSSClass> 
880    <#local contentSlots = container.getSiblings() /> 
881    <#if contentSlots?has_content && contentSlots?size gt 0> 
882        <#list contentSlots as slot> 
883            <#if slot?index gte startAt> 
884            <#if slot.getData()?? && slot.getData()?has_content> 
885            <#assign slotData = slot.getData()> 
886               <#if articleImages?has_content> 
887                <#assign slotData = replaceImageTags(slotData, tagImage, articleImages)> 
888                <#assign slotData = replaceCarouselTags(slotData, tagCarousel, articleImages)> 
889            </#if> 
890        	    <#switch wrapperCSSClass> 
891        	        <#case 'template-quote'> 
892        	            <div class="article-box article-quote voice-no-read"> 
893        	                <p class="quote-body">${slotData}</p> 
894        	            </div> 
895                	    <#break> 
896            	    <#default> 
897            	        <div class="${wrapperCSSClass}">${slotData}</div> 
898        	    </#switch> 
899            </#if> 
900            </#if> 
901        </#list> 
902    </#if> 
903</#macro> 
904 
905 
906<#-- 
907    Print remainging videos, if any 
908--> 
909<#macro printRemainingVideoContents container startAt> 
910    <#local contentSlots = container.getSiblings() /> 
911    <#if contentSlots?has_content && contentSlots?size gt 0> 
912        <#list contentSlots as slot> 
913            <#if slot?index gte startAt> 
914                <#if slot.URL.getData()?? && slot.URL.getData()?has_content> 
915 
916                    <#assign URL = slot.URL.getData()!"" /> 
917                    <#assign videoFile = slot.videoFile.getData()!"" /> 
918                    <#assign caption = slot.caption.getData()!"" /> 
919                    <#assign embed = videoEmbed(URL, caption, videoFile)!"" /> 
920                    ${embed} 
921 
922                </#if> 
923            </#if> 
924        </#list> 
925    </#if> 
926</#macro> 
927 
928<#macro printNewsletterAd articleTags> 
929 
930   <#-- 
931      hengellisyys, henkisyys, hiljentyminen, rukoukset laukaisemaan bannerin joka mainostaa hiljentymiskirjettä 
932 
933      Apply Order :  
934      Jos samassa artikkelissa on useampi mainittu tägi, niin yliajojärjestys voisi olla tämä: 
935      vantaa, espoo, helsinki, mainitut hiljentymiskirjeen tägit 
936      Eli jos artikkelissa on vantaa ja helsinki, näytetään helsinkikirjebanneri.  
937      Jos artikkelissa on helsinki ja vaikkapa hengellisyys, näytetään hiljentymiskirjebanneri. 
938   --> 
939 
940    <#local showNewsletterAd = ""> 
941    <#local showNewsletterAdImg = ""> 
942    <#local newsletterAdImgAlt = ""> 
943    <#local modified = "1766063977434"> 
944 
945    <#if articleTags?contains("vantaa")> 
946        <#local showNewsletterAd = "Vantaa"> 
947        <#local showNewsletterAdImg = "https://www.kirkkojakaupunki.fi/documents/20147/49696306/web_Vantaa-kirje+tooni.jpg/6fb76d3e-c16a-6143-4af1-7a776474a34b?t=" + modified> 
948    </#if> 
949 
950    <#if articleTags?contains("espoo")> 
951        <#local showNewsletterAd = "Espoo"> 
952        <#local showNewsletterAdImg = "https://www.kirkkojakaupunki.fi/documents/20147/49696306/web_Espoo-kirje+tooni.jpg/50bedfbc-552a-8239-6e25-f376aa76795b?t=" + modified> 
953    </#if> 
954     
955    <#if articleTags?contains("helsinki")> 
956        <#local showNewsletterAd = "Helsinki"> 
957        <#local showNewsletterAdImg = "https://www.kirkkojakaupunki.fi/documents/20147/49696306/web_Helsinki-kirje+tooni.jpg/a3f37d3b-fb3f-2728-0d48-bcc897a9186e?t=" + modified> 
958    </#if>     
959   <#if showNewsletterAd?has_content> 
960    <#local newsletterAdImgAlt = "Tilaa ${showNewsletterAd}-kirje"> 
961   </#if> 
962   <#-- 
963      Hiljentymiskirje 
964   --> 
965   <#if articleTags?contains("hengellisyys") ||  
966        articleTags?contains("henkisyys") || 
967        articleTags?contains("hiljentyminen") || 
968        articleTags?contains("rukoukset")   
969
970        <#local showNewsletterAd = "hiljentymiskirje"> 
971        <#local showNewsletterAdImg = "https://www.kirkkojakaupunki.fi/documents/20147/49696306/web_Hiljentymiskirje+tooni.jpg/e2fee3b7-1912-ba85-c08e-58754870b1ba?t=" + modified>    
972        <#local newsletterAdImgAlt = "Tilaa hiljentymiskirje"> 
973   </#if> 
974   <#-- // End of Hiljentymiskirje --> 
975 
976    <#if showNewsletterAd?has_content> 
977        <div class="subscribe-newsletter "> 
978            <a href="/uutiskirje?tilaa=${showNewsletterAd}"> 
979                <img alt="${newsletterAdImgAlt}" src="${showNewsletterAdImg}" /> 
980            </a> 
981        </div> 
982    </#if> 
983</#macro> 
984 
985<#-- 
986    Print remainging audio embeds, if any 
987--> 
988<#macro printRemainingAudioContents container startAt> 
989    <#local contentSlots = container.getSiblings() /> 
990    <#if contentSlots?has_content && contentSlots?size gt 0> 
991        <#list contentSlots as slot> 
992            <#if slot?index gte startAt> 
993                <#if slot.audioFile.getData()?? && slot.audioFile.getData()?has_content> 
994                    <#assign description = slot.audioDescription.getData() /> 
995                    <#assign files = slot.audioFile /> 
996                    <#assign embed = audioEmbed(description, files) /> 
997                    ${embed} 
998                </#if> 
999            </#if> 
1000        </#list> 
1001    </#if> 
1002</#macro> 
1003 
1004<#function replaceTags content tag replacementElement wrapperCSSClass> 
1005    <#global tagReplaceCounter = 0 /> 
1006    <#if replacementElement?has_content> 
1007        <#assign replacementList = replacementElement.getSiblings() > 
1008        <#if replacementList?has_content> 
1009 
1010        	<#list replacementList as cur_replacement> 
1011 
1012        	    <#switch wrapperCSSClass> 
1013        	        <#case 'template-quote'> 
1014                	    <#assign replacement> 
1015                	        <div class="article-box article-quote voice-no-read"> 
1016                	            <p class="quote-body">${cur_replacement.getData()}</p> 
1017            	            </div> 
1018                	    </#assign> 
1019                	    <#break> 
1020        	        <#case 'no-wrapper'> 
1021                	    <#assign replacement = cur_replacement.getData() > 
1022                	    <#break>                	     
1023            	    <#default> 
1024                	    <#assign replacement> 
1025                	        <div class="${wrapperCSSClass}">${cur_replacement.getData()}</div> 
1026                	    </#assign> 
1027        	    </#switch> 
1028 
1029        	    <#if content?index_of(tag) gt -1> 
1030            		<#local content = content?replace(tag, replacement, 'f') > 
1031            		<#global tagReplaceCounter++ /> 
1032        		</#if> 
1033        	</#list> 
1034        </#if> 
1035    </#if> 
1036 
1037  <#-- Remove "empty" tags--> 
1038  <#local content = content?replace(tag, '') > 
1039 
1040  <#return content > 
1041</#function> 
1042 
1043<#function replaceCarouselTags content tagBase replacementElement> 
1044    <#if replacementElement?has_content> 
1045        <#assign replacementList = replacementElement.getSiblings()> 
1046 
1047        <#if replacementList?has_content> 
1048            <#list 1..10 as i> 
1049                <#assign carouselArray = []> 
1050                <#list replacementList as cur_image> 
1051                    <#if cur_image.getData?? && cur_image.getData()?has_content> 
1052                        <#if cur_image.position.getData() == "article-image-carousel-${i}"> 
1053                            <#assign carouselArray = carouselArray + [createCarouselItem(cur_image)] /> 
1054                        </#if> 
1055                    </#if> 
1056                </#list> 
1057                 
1058                <#if carouselArray?has_content> 
1059                    <#assign replacement> 
1060                        <div class="owl-carousel owl-theme"> 
1061                            <#list carouselArray as carousel1> 
1062                            <div class="item"> 
1063                                ${carousel1} 
1064                            </div> 
1065                            </#list> 
1066                        </div> 
1067                    </#assign> 
1068                    <#local content = content?replace(tagBase?replace("#", i), replacement, 'f') > 
1069                </#if> 
1070            </#list> 
1071        </#if> 
1072    </#if> 
1073     
1074     
1075    <#-- clean image carousel tags --> 
1076    <#list 1..10 as i> 
1077        <#local content = content?replace(tagBase?replace("#", i), "") > 
1078    </#list> 
1079    <#return content /> 
1080</#function> 
1081 
1082<#function createCarouselItem cur_image> 
1083    <#assign result = "" /> 
1084    <#if cur_image.getAttribute("alt")?has_content> 
1085        <#assign result> 
1086            <div class="aspect-ratio aspect-ratio-middle aspect-ratio-xs"> 
1087                <img class="aspect-ratio-item-fluid" src="${getImageURLByTemplateModel(cur_image, '1200')}" alt="${cur_image.getAttribute("alt")}" /> 
1088            </div> 
1089            <p class="caption voice-no-read">${cur_image.getAttribute("alt")}</p> 
1090        </#assign> 
1091    <#else> 
1092        <#assign result> 
1093            <div class="aspect-ratio aspect-ratio-middle aspect-ratio-xs"> 
1094                <img class="aspect-ratio-item-fluid" src="${getImageURLByTemplateModel(cur_image, '1200')}" alt="" /> 
1095            </div> 
1096        </#assign> 
1097    </#if> 
1098    <#return result /> 
1099</#function> 
1100 
1101<#function replaceImageTags content tag replacementElement> 
1102    <#if replacementElement?has_content> 
1103        <#assign replacementList = replacementElement.getSiblings() > 
1104        <#if replacementList?has_content> 
1105        	<#list replacementList as cur_image> 
1106 
1107                <#if cur_image.getData?? && cur_image.getData()?has_content> 
1108 
1109                    <#-- Skip header images --> 
1110                    <#if cur_image.position.getData() != "article-image-header" && !cur_image.position.getData()?starts_with("article-image-carousel-")> 
1111                        <#assign thumbnailSize = 2 > 
1112                        <#if cur_image.position.getData() == "article-image-full"> 
1113                            <#assign thumbnailSize = 3 > 
1114                        </#if> 
1115                        <#assign replacement> 
1116 
1117                            <div class="article-box ${cur_image.position.getData()}"> 
1118                                <#if cur_image.getAttribute("alt")?has_content> 
1119                                    <img src="${getImageURLByTemplateModel(cur_image, '1200')}" alt="${cur_image.getAttribute("alt")}" /> 
1120                                    <p class="caption voice-no-read">${cur_image.getAttribute("alt")}</p> 
1121                                <#else> 
1122                                    <img src="${getImageURLByTemplateModel(cur_image, '1200')}" alt="" /> 
1123                                </#if> 
1124                            </div> 
1125                        </#assign> 
1126                        <#local content = content?replace(tag, replacement, 'f') > 
1127                    </#if> 
1128 
1129                </#if> 
1130 
1131        	</#list> 
1132        </#if> 
1133    </#if> 
1134 
1135  <#-- Remove "empty" tags--> 
1136  <#local content = content?replace(tag, '') > 
1137 
1138  <#return content > 
1139</#function> 
1140 
1141 
1142<#function replaceImageComparisonTags content tag replacementElement> 
1143    <#if replacementElement?has_content> 
1144        <#assign replacementList = replacementElement.getSiblings() > 
1145        <#if replacementList?has_content> 
1146            <#list replacementList as cur_imageComparison> 
1147                <#if cur_imageComparison.getData??> 
1148                    <#assign image1 = cur_imageComparison.image1 /> 
1149                    <#assign image2 = cur_imageComparison.image2 /> 
1150                    <#if cur_imageComparison.sliderOffset.getData() == "" > 
1151                        <#assign offset = 100 /> 
1152                    <#else> 
1153                        <#assign offset = cur_imageComparison.sliderOffset.getData() /> 
1154                    </#if> 
1155                    <#assign replacement> 
1156                        <#if image1.getData?? && image1.getData()?has_content && image2.getData?? && image2.getData()?has_content> 
1157                            <div class="cocoen-theme"> 
1158                                <div class="cocoen" slider-offset="${offset}"> 
1159                                    <#if image1.getAttribute("alt")?has_content> 
1160                                        <img src="${getThumbnailUrl(image1.getData(), 3) }" alt="${image1.getAttribute("alt")}" /> 
1161                                    <#else> 
1162                                        <img src="${getThumbnailUrl(image1.getData(), 3) }" alt="" /> 
1163                                    </#if> 
1164                                    <#if image2.getAttribute("alt")?has_content> 
1165                                        <img src="${getThumbnailUrl(image2.getData(), 3) }" alt="${image2.getAttribute("alt")}" /> 
1166                                    <#else> 
1167                                        <img src="${getThumbnailUrl(image2.getData(), 3) }" alt="" /> 
1168                                    </#if> 
1169                                </div> 
1170                                <#if image1.getAttribute("alt")?has_content && image2.getAttribute("alt")?has_content> 
1171                                    <#if offset?number lt 50> <!-- pienempi kuin 50, n&auml;yt&auml; kuvateksti 2 --> 
1172                                        <div class="caption2"> 
1173                                            <p class="caption voice-no-read"> 
1174                                                ${image2.getAttribute("alt")} 
1175                                            </p> 
1176                                        </div> 
1177                                        <div class="caption1" style="display:none"> 
1178                                            <p class="caption voice-no-read"> 
1179                                                ${image1.getAttribute("alt")} 
1180                                            </p> 
1181                                        </div> 
1182                                    <#else> 
1183                                        <div class="caption2" style="display:none"> 
1184                                            <p class="caption voice-no-read"> 
1185                                                ${image2.getAttribute("alt")} 
1186                                            </p> 
1187                                        </div> 
1188                                        <div class="caption1"> 
1189                                            <p class="caption voice-no-read"> 
1190                                                ${image1.getAttribute("alt")} 
1191                                            </p> 
1192                                        </div> 
1193                                    </#if> 
1194                                </#if> 
1195                            </div> 
1196                        </#if> 
1197                    </#assign> 
1198                    <#local content = content?replace(tag, replacement, 'f') > 
1199                </#if> 
1200            </#list> 
1201        </#if> 
1202    </#if> 
1203    <#-- Remove "empty" tags--> 
1204    <#local content = content?replace(tag, '') > 
1205 
1206    <#return content > 
1207</#function> 
1208 
1209 
1210<#function replaceVideoTags content tag replacementElement> 
1211    <#global tagReplaceCounter = 0 /> 
1212    <#if replacementElement?has_content> 
1213        <#assign replacementList = replacementElement.getSiblings() > 
1214        <#if replacementList?has_content> 
1215 
1216            <#global videoListSize = replacementList?size /> 
1217 
1218        	<#list replacementList as cur_video> 
1219                <#assign videoFile = "" /> 
1220                <#assign URL = cur_video.URL.getData()!"" /> 
1221                <#if (cur_video.videoFile)??> 
1222                    <#assign videoFile = cur_video.videoFile.getData()!"" /> 
1223                </#if> 
1224                <#assign caption = cur_video.caption.getData()!"" /> 
1225                 
1226                <#if (cur_video.videoFile)?? || URL?has_content> 
1227                    <#assign replacement = videoEmbed(URL, caption, videoFile)!"" /> 
1228                </#if> 
1229                
1230                <#if content?index_of(tag) gt -1> 
1231                    <#local content = content?replace(tag, replacement, 'f') > 
1232                    <#global tagReplaceCounter++ /> 
1233                </#if> 
1234 
1235                <#-- <#local content = content?replace(tag, replacement, 'f') > --> 
1236        	</#list> 
1237        </#if> 
1238    </#if> 
1239 
1240  <#-- Remove "empty" tags--> 
1241  <#local content = content?replace(tag, '') > 
1242 
1243  <#return content > 
1244</#function> 
1245 
1246 
1247<#function replaceAudioTags content tag replacementElement> 
1248    <#global tagReplaceCounter = 0 /> 
1249    <#if replacementElement?has_content> 
1250        <#assign replacementList = replacementElement.getSiblings() > 
1251        <#if replacementList?has_content> 
1252 
1253            <#global audioListSize = replacementList?size /> 
1254 
1255        	<#list replacementList as cur_audioEmbed> 
1256                <#assign description = cur_audioEmbed.audioDescription.getData() /> 
1257                <#assign files = cur_audioEmbed.audioFile /> 
1258                <#assign replacement = audioEmbed(description, files) /> 
1259 
1260                <#if content?index_of(tag) gt -1> 
1261                    <#local content = content?replace(tag, replacement, 'f') > 
1262                    <#global tagReplaceCounter++ /> 
1263                </#if> 
1264 
1265        	</#list> 
1266        </#if> 
1267    </#if> 
1268    <#local content = content?replace(tag, '') > 
1269    <#return content > 
1270</#function> 
1271 
1272<#function replaceAdTag content> 
1273    <#local adScript> 
1274    	<div class="ad-container"> 
1275            <div> 
1276                <script type="text/javascript"> 
1277                if (!$.gdprcookie || $.gdprcookie.preference("marketing")) { 
1278                    if((window.innerWidth > 1019) || (typeof inPreviewMode !== 'undefined' && inPreviewMode)) 
1279
1280                    // NM 468x400 
1281                    document.write('<scri'+'pt data-adfscript="adx.adform.net/adx/?mid=937873&mkv=" id="ar"></'+'script>'); 
1282                    document.write('<scri'+'pt src="//s1.adform.net/banners/scripts/adx.js" async defer ></'+'script>'); 
1283
1284                    else 
1285
1286                    // NM 300x300 3 
1287                    document.write('<scri'+'pt data-adfscript="adx.adform.net/adx/?mid=937882&mkv="></'+'script>'); 
1288                    document.write('<scri'+'pt src="//s1.adform.net/banners/scripts/adx.js" async defer></'+'script>'); 
1289
1290
1291                </script> 
1292            </div> 
1293        </div> 
1294    </#local> 
1295     
1296    <#return content?replace("[[mainos]]", adScript) /> 
1297</#function> 
1298 
1299<#function videoEmbed URL, caption, videoFile> 
1300    <#local embed = "" /> 
1301 
1302    <#if URL?contains("vimeo")> 
1303        <#local iframeSrc = "https://player.vimeo.com/video/" /> 
1304        <#local videoID = URL?split("/")?last /> 
1305		<#local embed> 
1306		    <div class="responsive-video"> 
1307    			<div class="responsive-wrapper vimeo" id="vimeo-${videoID}" data-embed="${videoID}"> 
1308    				<img class="decor-video" alt="Toista video" src="/o/kirkkojakaupunki-site-theme/images/icons/video-decor.svg"> 
1309    			</div> 
1310				<noscript><a href="${URL}" target="_blank" rel="noopener"Videota</a> ei voida n&auml;ytt&auml;&auml; koska javascript on kytketty pois p&auml;&auml;lt&auml; selaimesta.</noscript> 
1311    		</div> 
1312		</#local> 
1313    <#elseif URL?contains("youtube")> 
1314        <#local isVerticalVideo = URL?starts_with("https://www.youtube.com/shorts/")> 
1315         
1316        <#local iframeSrc = "https://www.youtube.com/embed/" /> 
1317        <#local videoID = URL?replace("^.*\\?v=([\\w-_]*).*", "$1", "r") /> 
1318        <#if URL?starts_with("https://www.youtube.com/shorts/")> 
1319            <#local videoID = URL?replace("https://www.youtube.com/shorts/","")> 
1320        </#if> 
1321         
1322		<#local embed> 
1323             
1324            <div class="responsive-video <#if isVerticalVideo>vertical-video</#if>">   
1325    			<div class="responsive-wrapper youtube" data-embed="${videoID}"> 
1326    				<img class="decor-video" alt="Toista video" src="/o/kirkkojakaupunki-site-theme/images/icons/video-decor.svg"> 
1327    			</div> 
1328                <noscript><a href="https://www.youtube.com/watch?v=${videoID}" target="_blank" rel="noopener">Videota</a> ei voida n&auml;ytt&auml;&auml; koska javascript on kytketty pois p&auml;&auml;lt&auml; selaimesta.</noscript> 
1329			</div> 
1330		</#local> 
1331    <#elseif videoFile?has_content> 
1332        <#local embed> 
1333            <div class="responsive-video"> 
1334                <video controls controlsList="nodownload" style="max-width:100%"> 
1335                <#-- #t=0.001 Safari hack - See ticket 25143 --> 
1336                <source src="${videoFile}#t=0.001" type="video/mp4"> 
1337                    Your browser does not support the video tag. 
1338                </video> 
1339            </div>  
1340        </#local> 
1341    <#else> 
1342        <#return embed> 
1343    </#if> 
1344 
1345    <#return embed> 
1346</#function> 
1347 
1348 
1349<#function audioEmbed description, files> 
1350    <#local embed = ""> 
1351    <#local audioFiles = [] /> 
1352     
1353    <#list files.getSiblings() as file>        
1354        <#local fileURL = file.getData()!""> 
1355        <#if fileURL?has_content> 
1356            <#local fileFormat = file.audioFormat.getData()> 
1357            <#local fileObject = {"format": fileFormat, "URL": fileURL}> 
1358            <#local audioFiles += [fileObject]> 
1359        </#if> 
1360    </#list> 
1361 
1362    <#if audioFiles?has_content> 
1363        <#local embed> 
1364            <div class="audio-player sans voice-no-read"> 
1365                <button class="btn btn-link flex-item-center"> 
1366                    <i class="glyphicon glyphicon-play" aria-hidden="true"></i> 
1367                </button> 
1368                <div class="audio-player-details flex-item-center"> 
1369                    <#if description?has_content> 
1370                        <p>${description}</p> 
1371                    </#if> 
1372                    <div class="audio-player-progress"> 
1373                        <span class="audio-player-time-display">-:- / -:-</span> 
1374                        <div class="audio-player-seekbar"> 
1375                            <div class="audio-player-bufferbar"></div> 
1376                            <div class="audio-player-progressbar"></div> 
1377                        </div> 
1378                    </div>                 
1379                </div> 
1380                <audio preload="metadata" loop> 
1381                    <#list audioFiles as file> 
1382                        <source src="${file.URL}" type="${file.format}" /> 
1383                    </#list> 
1384                </audio> 
1385            </div> 
1386        </#local> 
1387    </#if> 
1388 
1389    <#return embed> 
1390</#function> 
1391 
1392 
1393<#function getHeaderImages articleImages> 
1394    <#local headerImages = [] /> 
1395 
1396    <#if articleImages?has_content && articleImages.getSiblings()?has_content> 
1397        <#list articleImages.getSiblings() as cur_image> 
1398            <#if cur_image.position.getData() == 'article-image-header'> 
1399                <#local headerImages = headerImages + [cur_image] /> 
1400            </#if> 
1401        </#list> 
1402    </#if> 
1403 
1404    <#if !headerImages?has_content && articleImages?has_content && articleImages.getSiblings()?has_content > 
1405        <#local headerImages = headerImages + [articleImages.getSiblings()?first] /> 
1406    </#if> 
1407 
1408    <#return headerImages> 
1409</#function> 
1410 
1411<#function getContentCarouselImages articleImages> 
1412 
1413    <#local contentCarouselImages = [] /> 
1414 
1415    <#if articleImages?has_content && articleImages.getSiblings()?has_content> 
1416        <#list articleImages.getSiblings() as cur_image> 
1417            <#if cur_image.position.getData()?starts_with('article-image-carousel-')> 
1418                <#local contentCarouselImages = contentCarouselImages + [cur_image] /> 
1419            </#if> 
1420        </#list> 
1421    </#if> 
1422 
1423    <#if !contentCarouselImages?has_content && articleImages?has_content && articleImages.getSiblings()?has_content > 
1424        <#local contentCarouselImages = contentCarouselImages + [articleImages.getSiblings()?first] /> 
1425    </#if> 
1426 
1427    <#return contentCarouselImages> 
1428</#function> 
1429 
1430<#-- 
1431    Attempts to get mime type for a file in document library. 
1432 
1433    Parameters: 
1434        fileUrl: A string containig a url to the file. 
1435 
1436    Returns mime type as a string or an empty string. 
1437--> 
1438<#function getMimeType fileUrl> 
1439    <#if fileUrl?? && fileUrl?has_content> 
1440 
1441        <#-- Attempt to parse uuid & groupId from provided Url --> 
1442        <#assign splitUrl = fileUrl?split("/", "r") /> 
1443 
1444        <#if splitUrl?seq_contains("documents") && splitUrl?size gte 6> 
1445            <#attempt> 
1446 
1447                <#assign groupId = splitUrl[2] /> 
1448                <#assign uuid = splitUrl[5] /> 
1449                <#assign uuid = uuid?split("?")[0] /> 
1450 
1451                <#-- Get DLFileEntry --> 
1452                <#assign DLFileEntryLocalService = serviceLocator.findService("com.liferay.document.library.kernel.service.DLFileEntryLocalService") /> 
1453                <#assign fileEntry = DLFileEntryLocalService.fetchDLFileEntryByUuidAndGroupId(uuid, getterUtil.getLong(groupId)) /> 
1454                <#return fileEntry.getMimeType()> 
1455            <#recover> 
1456                <#-- Parsing mime type failed, return empty --> 
1457                <#return ""> 
1458            </#attempt> 
1459 
1460        <#elseif splitUrl?seq_contains("journal") && splitUrl?size gte 4> 
1461            <#attempt> 
1462                <#assign imageId = splitUrl[3]?split("?")[1]?split("=")[1]?split("&")[0] /> 
1463                <#assign ImageLocalService = serviceLocator.findService("com.liferay.portal.kernel.service.ImageLocalService") /> 
1464                <#assign imageType = ImageLocalService.getImage(getterUtil.getLong(imageId)).getType() /> 
1465                <#switch imageType> 
1466                    <#case "gif"> 
1467                        <#return "image/gif"> 
1468                    <#case "svg"> 
1469                        <#return "image/svg"> 
1470                    <#default> 
1471                        <#return imageType> 
1472                </#switch> 
1473            <#recover> 
1474                <#return ""> 
1475            </#attempt> 
1476 
1477        <#else> 
1478            <#-- Parsing image url failed, return empty --> 
1479            <#return ""> 
1480        </#if> 
1481 
1482    <#else> 
1483        <#-- parameter empty or missing, return empty --> 
1484        <#return ""> 
1485    </#if> 
1486</#function> 
1487 
1488<#-- 
1489    Returns thumbnail image url for given image. 
1490    Handles SVG & bitmap formats. 
1491 
1492    Parameters: 
1493        imageUrl: string containing relative url to an image in document library 
1494        thumbnailSize: value for Liferay's imageThumbnail parameter (0-3) 
1495 
1496    Returns image url with appended thumbnail info or an empty string. 
1497 --> 
1498<#function getThumbnailUrl imageUrl thumbnailSize> 
1499    <#if imageUrl?? && imageUrl?has_content> 
1500 
1501        <#-- Attempt to get mime type --> 
1502        <#assign mimeType = getMimeType(imageUrl) /> 
1503 
1504        <#if mimeType?has_content> 
1505 
1506            <#-- Check image mime type --> 
1507            <#switch mimeType> 
1508                <#case "image/svg+xml"> 
1509                    <#-- SVG image -> do not append thumbnail parameter --> 
1510                    <#return imageUrl> 
1511                <#case "image/gif"> 
1512                    <#return imageUrl> 
1513                <#default> 
1514                    <#-- Predume bitmap image -> append thumbnail parameter --> 
1515                    <#if imageUrl?contains("?")> 
1516                        <#assign paramChar = "&" /> 
1517                    <#else> 
1518                        <#assign paramChar = "?" /> 
1519                    </#if> 
1520<#-- 
1521    Liferay 7.3 thumbSize 3 on pienempi kuin aiemmin. Woodwingist tulevat kuvat nykyisin 1200 joten voidaan palauttaa suoraan kuvan url. Vaihtoehto hyodyntaa adaptive mediaa 
1522--> 
1523                    <#if thumbnailSize == 3> 
1524                        <#return imageUrl /> 
1525                    <#else> 
1526                        <#return imageUrl + paramChar + "imageThumbnail=" + thumbnailSize /> 
1527                    </#if> 
1528            </#switch> 
1529        <#else> 
1530            <#-- Embbedded journal article image (type: journal) mime recognizion fails for ie  
1531            /-/sini-mikkola-tutkii-lutherin-kasityksia 
1532            /-/kristinuskon-alkeita-ja-syventavia-keskusteluja 
1533            /-/mika-keisarin-on 
1534            --> 
1535            <#return imageUrl > 
1536        </#if> 
1537 
1538    </#if> 
1539</#function> 
1540 
1541<#-- 
1542    Return list of web content titles from given folder 
1543    parameter: 
1544        - authorCardFolderId 
1545--> 
1546<#function getAvailableAuthorNames authorCardFolderIds > 
1547 
1548  <#local authorNames = []>     
1549  <#local seenArticles = [] > 
1550  <#-- Multiple version exists so keep track which articles we have already checked --> 
1551 
1552  <#list authorCardFolderIds as authorCardFolderId> 
1553    <#assign authorCards = JournalArticleLocalService.getArticles(groupId, authorCardFolderId) /> 
1554 
1555    <#if authorCards?has_content> 
1556        <#list authorCards as authorCard> 
1557	    <#if !seenArticles?seq_contains(authorCard.articleId)> 
1558	      <#assign latest = JournalArticleLocalService.getLatestArticle(authorCard.resourcePrimKey) /> 
1559	      <#if latest.getStatus() == 0> 
1560		  <#local authorName = latest.getTitle(locale) /> 
1561		  <#if !authorNames?seq_contains(authorName) > 
1562		      <#local authorNames = authorNames + [authorName] /> 
1563		  </#if> 
1564	      </#if> 
1565	      <#local seenArticles = seenArticles + [authorCard.articleId] /> 
1566	    </#if> 
1567        </#list> 
1568         
1569    </#if> 
1570  </#list> 
1571  <#return authorNames /> 
1572</#function> 
1573 
1574<#-- 
1575    Replaces from given string author names with links to author page 
1576    parameters:  
1577    - authorNameStr : String where replacements is targeted 
1578    - authorNames : seq : list of author names 
1579    - baseUrl : url where author name is appended (as url escaped string) 
1580--> 
1581 
1582<#function makeAuthorLinks authorNameStr authorNames baseUrl > 
1583    <#list authorNames as authorName> 
1584        <#local authorNameInUrl = authorName?url("utf-8") /> 
1585        <#local authorNameStr = authorNameStr?replace(authorName, "<a class=\"author-name\" href=\""+baseUrl +authorNameInUrl + "\">"+authorName+"</a>") /> 
1586    </#list> 
1587    <#return authorNameStr /> 
1588</#function> 
1589 
1590<#function getImageURL imageJSON thumbId> 
1591    <#if imageJSON?? && imageJSON?has_content> 
1592        <#assign fileEntryId = imageJSON.getLong("fileEntryId")/> 
1593        <#assign fileName = imageJSON.getString("name")/> 
1594         
1595        <#if fileName?ends_with(".svg") || fileName?ends_with(".gif")> 
1596            <#assign imageGroupId = imageJSON.getLong("groupId")/> 
1597            <#assign imageUuid = imageJSON.getString("uuid")/> 
1598         
1599            <#return getFullImageUrL(imageGroupId, imageUuid) > 
1600        <#else> 
1601            <#return getAdaptiveImageURLByFileEntryId(fileEntryId, fileName, thumbId) > 
1602        </#if> 
1603    </#if> 
1604</#function> 
1605 
1606<#function getImageURLByTemplateModel imageTemplateModel thumbId> 
1607    <#local uuid = imageTemplateModel.getAttribute("uuid")/> 
1608    <#return getFullImageUrL(groupId, uuid)> 
1609</#function> 
1610 
1611<#function getAdaptiveImageURLByFileEntryId fileEntryId fileName thumbId> 
1612 
1613		<#local adaptiveMediaUrl = "/o/adaptive-media/image/${fileEntryId}/${thumbId}/${fileName}" > 
1614		 
1615        <#return adaptiveMediaUrl> 
1616</#function> 
1617 
1618<#function getFullImageUrL(groupId, uuid)> 
1619            <#assign imageURL = "/documents/" /> 
1620            <#assign imageURL += groupId /> 
1621            <#assign imageURL += "/" + uuid /> 
1622         
1623            <#return imageURL> 
1624</#function> 
1625 
1626<#function getCategoryNames( articleId, vocabularyId="" )> 
1627 
1628    <#local categoryNames = [] /> 
1629 
1630    <#-- Get all categories from journalArticle --> 
1631    <#local journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") /> 
1632    <#local primKey = journalArticleLocalService.getArticle(getterUtil.getLong(groupId), articleId).getResourcePrimKey() /> 
1633    <#local assetCategoryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetCategoryLocalService") /> 
1634    <#local categories = assetCategoryLocalService.getCategories('com.liferay.journal.model.JournalArticle', getterUtil.getLong(primKey)) /> 
1635 
1636    <#if categories?has_content> 
1637        <#list categories as cur_category> 
1638            <#if vocabularyId?has_content && vocabularyId == cur_category.getVocabularyId() > 
1639                <#-- get category names from given category --> 
1640                <#local categoryNames += [cur_category.getName()] /> 
1641            <#elseif !vocabularyId?has_content> 
1642                <#-- get all category names --> 
1643                <#local categoryNames += [cur_category.getName()] /> 
1644            </#if> 
1645 
1646        </#list> 
1647    </#if> 
1648 
1649    <#return categoryNames> 
1650</#function> 
1651 
1652<#if mobileAppView> 
1653    <script> 
1654        <#-- Replace article urls (contains /-/) with this asset publisher content url --> 
1655        let contentUrlIndex = window.location.pathname.indexOf('/content/'); 
1656         
1657        if (contentUrlIndex > 0) { 
1658            let assetPublisherContentURL = window.location.pathname.substring(0,contentUrlIndex) + "/content/"; 
1659         
1660            $('article a[href*="/-/"]').each(function(){ 
1661                let localAssetPublisherContentUrl  = $(this).attr("href").replace("/-/", assetPublisherContentURL); 
1662                $(this).attr("href", localAssetPublisherContentUrl); 
1663            }); 
1664
1665    </script> 
1666</#if> 

Löydä lisää näkökulmia


Keskustele Facebookissa
Keskustele ja kommentoi Facebookissa
Lähetä juttuvinkki
Lähetä juttuvinkki
Kirkko ja kaupunki -mediaan.

Tilaa Kirkko ja kaupungin ilmaisia uutiskirjeitä.