null Helsingissä kokeillaan maksukorttikolehtia

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

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 viikoittainen juttukooste.