null Rakas lähiö: Kirjailija Tomi Kontio kasvoi Myllypurossa pojasta mieheksi

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 408, 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    <#list articleCategories as cat> 
302        <span data-cat="${cat?lower_case}" class="category-item">${cat}</span> 
303    </#list> 
304 
305    <div class="voice-no-read"> 
306 
307        <#-- ${article.class}:: --> 
308        <#-- ${AssetCategoryLocalServiceUtil.getCategories(JournalArticle.class.getName(), articleId)} --> 
309 
310        <#-- ${AssetCategoryServiceUtil.getCategories(article.class.getName(), articleId);} --> 
311        <#-- <#assign categories = article.getCategories() /> 
312 
313                    <#if categories?has_content> 
314                        <#list categories as category> 
315                            <#if category.getName() == "Uutiset"> 
316                                <#assign cardColor = "card-category-d-light" /> 
317                                <#assign tagColor = "tag-inverse" /> 
318                                <#assign categoryTheme = "theme-news" /> 
319                                <#assign categoryTitle = "Ajankohtaista" /> 
320                                <#break> 
321                            <#elseif category.getName() == "Ihmiset ja elämä"> 
322                                <#assign cardColor = "card-category-a-light" /> 
323                                <#assign tagColor = "tag-inverse" /> 
324                                <#assign categoryTheme = "theme-people" /> 
325                                <#assign categoryTitle = "Ihmiset ja ilmiöt" /> 
326                                <#break> 
327                            <#elseif category.getName() == "Puheenvuorot"> 
328                                <#assign cardColor = "card-category-b-light" /> 
329                                <#assign tagColor = "tag-inverse" /> 
330                                <#assign categoryTheme = "theme-opinion" /> 
331                                <#assign categoryTitle = "Puheenvuoro" /> 
332                                <#break> 
333                            <#elseif category.getName() == "Menot"> 
334                                <#assign cardColor = "card-category-e-light" /> 
335                                <#assign tagColor = "tag-inverse" /> 
336                                <#assign categoryTheme = "theme-events" /> 
337                                <#assign categoryTitle = "Menot" /> 
338                                <#break> 
339                            <#elseif category.getName() == "Usko ja toivo"> 
340                                <#assign cardColor = "card-category-c-light" /> 
341                                <#assign tagColor = "tag-inverse" /> 
342                                <#assign categoryTheme = "theme-spirituality" /> 
343                                <#assign categoryTitle = "Usko ja toivo" /> 
344                                <#break> 
345                            </#if> 
346                        </#list> 
347                    </#if> 
348 
349        <@displayCategories categories=categories /> --> 
350    </div> 
351 
352    <#-- R&S sharing buttons --> 
353   <#--  <div class="voice-no-read"> 
354        <div class="article-sharing"> 
355            <div class="rns-share-plugin"></div> 
356        </div> 
357    </div> --> 
358 
359    <h1>${title}</h1> 
360 
361    <#if lead?? && lead?has_content> 
362        <#-- Remove possible HTML-tags --> 
363        <#assign leadCleaned = htmlUtil.stripHtml(lead) /> 
364        <p class="lead">${leadCleaned}</p> 
365    </#if> 
366 
367    <ul class="list-inline article-meta voice-no-read""> 
368        <li class="list-inline-item"><span class="date">${displayDate?string["dd.MM.yyyy HH:mm"]}</span></li> 
369 
370        <#if articleAuthors.authors.getData()?? && articleAuthors.authors.getData()?has_content> 
371            <#assign articleAuthor = articleAuthors.authors.getData()> 
372            <li class="list-inline-item"> 
373        <span class="author authortext-no-margin author-text"></span> 
374        <span class="author author-name">${makeAuthorLinks(articleAuthor,availableAuthorNames, authorCardBaseUrl)}</span> 
375            </li> 
376        </#if> 
377 
378        <#if articleAuthors.photographers.getData()?? && articleAuthors.photographers.getData()?has_content> 
379            <li class="list-inline-item"> 
380                <span class="author author-name author-photo"> 
381                    ${makeAuthorLinks(articleAuthors.photographers.getData(),availableAuthorNames, authorCardBaseUrl)} 
382                </span> 
383            </li> 
384        </#if> 
385    </ul> 
386 
387    <div id="voice-intuitive-root"></div> 
388     
389    ${articleBody} 
390 
391    <#-- Output article quotes --> 
392    <#if articleQuotes?has_content && articleQuotes.getSiblings()?has_content> 
393    <@printRemainingTagContents articleQuotes quoteTagCounter wrapperCSSQuote /> 
394    </#if> 
395 
396    <#-- Print article factbox(es) --> 
397    <#if articleFacts?has_content && articleFacts.getSiblings()?has_content> 
398        <@printRemainingTagContents articleFacts faktaTagCounter wrapperCSSFakta /> 
399    </#if> 
400 
401    <#-- Print article infobox(es) --> 
402    <#if articleInfo?has_content && articleInfo.getSiblings()?has_content> 
403        <@printRemainingTagContents articleInfo infoTagCounter wrapperCSSInfo/> 
404    </#if> 
405 
406    <#-- Print article video(s) --> 
407    <#if articleVideos?has_content && articleVideos.getSiblings()?has_content> 
408        <@printRemainingVideoContents articleVideos videoTagCounter  /> 
409    </#if> 
410 
411    <#-- Print remaining audio embeds --> 
412    <#if articleAudio?has_content && articleAudio.getSiblings()?has_content> 
413        <@printRemainingAudioContents articleAudio audioTagCounter  /> 
414    </#if> 
415     
416    <#-- Print article tail(s) --> 
417    <#if articleTail?has_content && articleTail.getSiblings()?has_content> 
418        <@printRemainingTagContents articleTail kainaloTagCounter wrapperCSSKainalo /> 
419    </#if> 
420 
421     <#-- R&S sharing buttons --> 
422        <div class="article-sharing"> 
423            <p class="sans text-uppercase">Jaa t&auml;m&auml; artikkeli:</p> 
424            <div class="rns-share-plugin"></div> 
425        </div> 
426 
427    <#-- City --> 
428        <#if articleTags?has_content> 
429 
430            <#assign cityTags = 0> 
431 
432            <#list articleTags?split(",") as tag> 
433                <#assign cities = ["Helsinki", "Espoo", "Vantaa", "Kauniainen", "helsinki", "espoo", "vantaa", "kauniainen"]>  
434                <#assign isCityTag = cities?seq_contains(tag)>  
435                <#if isCityTag == true> 
436                    <#assign cityTags = cityTags + 1> 
437                </#if> 
438            </#list> 
439 
440            <#if cityTags gt 0> 
441                <div class="article-section article-tags"> 
442                    <p class="sans text-uppercase d-inline">Lis&auml;&auml; aiheesta:</p> 
443                    <ul class="list-inline d-inline"> 
444                        <#list articleTags?split(",") as tag> 
445 
446                            <#assign cities = ["Helsinki", "Espoo", "Vantaa", "Kauniainen", "helsinki", "espoo", "vantaa", "kauniainen"]>  
447                            <#assign isCityTag = cities?seq_contains(tag)>  
448 
449                            <#if isCityTag> 
450                                <li class="list-inline-item"><a href="/artikkelit/-/tag/${htmlUtil.escapeURL(tag)}?article=${article.getResourcePrimKey()}" class="tag tag-map-icon">${tag}</a></li> 
451                            </#if> 
452                        </#list> 
453                    </ul> 
454                </div> 
455            </#if> 
456        </#if> 
457     
458    <div class="voice-no-read">  
459 
460        <#-- 
461            Output author card for the main author. 
462        --> 
463 
464        <#-- <#if articleAuthors.mainAuthor.getData()?? && articleAuthors.mainAuthor.getData()?has_content> 
465            <#assign authorCard = articleAuthors.mainAuthor.getData()?eval /> 
466            <@liferay_ui["asset-display"] 
467                className=authorCard.className 
468                classPK=getterUtil.getLong(authorCard.classPK, 0) 
469                template="full_content" 
470            /> 
471        </#if> --> 
472 
473        <#-- react&share buttons --> 
474        <div class="rns"></div> 
475         
476        <script type="text/javascript"> 
477        (function() { 
478        'use strict'; 
479        var a=document.querySelector(".article-meta .date"), 
480            b=b?b.innerHTML:"", 
481            d=document.querySelector("article h1"), 
482            e=document.querySelector("a.author-name"); 
483        var rnsRecommend = function() { window.rnsRecommend() }; 
484        window.rnsData={ 
485            recommenderToggle: '.article-assets', 
486            apiKey:"oyrv5xd6dmwj3lkm", 
487            reactionCallback: rnsRecommend, 
488            maxRecommendations: 3, 
489            date:function(f){ 
490                try{ 
491                    var a=f.match(/(\d{1,2})\.(\d{1,2})\.(\d{4})(\s+(\d{1,2}):(\d{2}))*/), 
492            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:"", 
493        canonicalUrl:window.location.protocol+"//"+window.location.hostname+window.location.pathname}; 
494        b=document.createElement("script"); 
495        b.src="https://cdn.reactandshare.com/plugin/rns.js";document.body.appendChild(b); 
496        b=document.createElement("script"); 
497        b.src="https://cdn.reactandshare.com/recommender/rnsrw.js"; 
498        document.body.appendChild(b); 
499 
500    })(); 
501        </script> 
502 
503        
504         
505         
506 
507         
508 
509        <#-- MORE FROM AUTHOR --> 
510 
511        <#assign hasAuthor = articleAuthors.authors.getData()?? && articleAuthors.authors.getData()?has_content /> 
512        <#assign hasPhotographer = articleAuthors.photographers.getData()?? && articleAuthors.photographers.getData()?has_content /> 
513         
514        <#if hasAuthor || hasPhotographer> 
515            <#assign articleAuthor = articleAuthors.authors.getData()> 
516            <#assign articlePhotographer = articleAuthors.photographers.getData() /> 
517             
518            <#assign authorObjs = [] /> 
519 
520            <#-- Find which authors (author card titles) appears in author field and make list of those... 
521            We need no maintain order of appearance 
522            --> 
523            <#list availableAuthorNames as authorName> 
524                <#assign authorPos = articleAuthor?index_of(authorName) /> 
525                <#assign photographerPos = articlePhotographer?index_of(authorName) /> 
526                 
527                <#-- Keep the order... first authors then photographers --> 
528                <#if authorPos != -1 || photographerPos != -1> 
529                    <#assign pos = authorPos /> 
530                    <#if authorPos == -1 && photographerPos != -1> 
531                        <#assign pos = 1000 + photographerPos /> 
532                    </#if> 
533                    <#assign authorObj = {"pos" : pos, "name": authorName} /> 
534                    <#assign authorObjs = authorObjs + [authorObj] /> 
535                </#if> 
536            </#list> 
537 
538            <#if authorObjs?size gt 0> 
539                <#assign authorObjs = authorObjs?sort_by("pos") /> 
540 
541                <#-- <div class="article-tags"> 
542                    <p class="sans text-uppercase">Lis&auml;&auml; tekij&auml;lt&auml;:</p> 
543                    <ul class="list-inline"> 
544                        <#list authorObjs as authorObj> 
545                            <li class="list-inline-item"> 
546                                <#assign authorSearchURL = "/toimittajat?author=" /> 
547                                <a class="tag tag-default" href="${authorCardBaseUrl}${authorObj.name?url}">${authorObj.name}</a> 
548                            </li>		   
549                        </#list> 
550                    </ul> 
551                </div> --> 
552            </#if> 
553 
554        </#if> 
555 
556 
557        <#-- RELATED CONTENT -->  
558        <#assign assetLinkLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetLinkLocalService") /> 
559        <#assign assetEntryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetEntryLocalService") /> 
560        <#assign currentArticleResourcePrimKey = currentArticle.getResourcePrimKey() /> 
561        <#assign currentArticleAssetEntry = assetEntryLocalService.getEntry("com.liferay.journal.model.JournalArticle", currentArticleResourcePrimKey) /> 
562        <#assign currentArticleAssetEntryId = currentArticleAssetEntry.getEntryId() /> 
563        <#assign currentArticleRelatedLinks = assetLinkLocalService.getDirectLinks(currentArticleAssetEntryId) /> 
564        <#if currentArticleRelatedLinks?has_content> 
565            <#assign relatedLinks = []> 
566            <#list currentArticleRelatedLinks as related_entry> 
567                <#assign relatedAssetEntryId = related_entry.getEntryId2() /> 
568                <#assign relatedAssetEntry = assetEntryLocalService.getEntry(relatedAssetEntryId) /> 
569                <#assign relatedAssetEntryPrimKey = relatedAssetEntry.getClassPK() /> 
570                <#assign relatedArticle = JournalArticleLocalService.getLatestArticle(relatedAssetEntryPrimKey) /> 
571                <#assign relatedArticleId = relatedArticle.getArticleId() /> 
572                <#assign docXml = saxReaderUtil.read(relatedArticle.getContent()) />	 
573                <#assign image = docXml.valueOf("//dynamic-element[@name='articleImages']/dynamic-content/text()") /> 
574 
575                <#-- Get full description & shorten it --> 
576                <#assign lead = htmlUtil.stripHtml(htmlUtil.extractText(relatedArticle.getDescription())) /> 
577         
578                <#assign categories = getCategoryNames(relatedArticleId) /> 
579 
580                <#assign linkObject = {"categories": categories, "title": relatedArticle.getTitleCurrentValue(),"urlTitle": relatedArticle.getUrlTitle(), "date": relatedArticle.getDisplayDate()?date, "urlImage": image, "lead": lead } /> 
581                 
582                <#if image?? && image?has_content> 
583 
584                <#else> 
585                    <#assign nostokuva = docXml.valueOf("//dynamic-element[@name='nostokuva']/dynamic-content/text()") /> 
586                    <#if nostokuva?? && nostokuva?has_content> 
587                        <#assign image = nostokuva /> 
588                        <#assign linkObject = {"title": relatedArticle.getTitleCurrentValue(),"urlTitle": relatedArticle.getUrlTitle(), "date": relatedArticle.getDisplayDate()?date, "urlImage": image, "lead": lead, "categories": categories  } /> 
589                    </#if> 
590                </#if> 
591 
592                <#-- ${relatedArticle} --> 
593                 
594                <#assign relatedLinks += [linkObject] /> 
595            </#list> 
596            <#if relatedLinks?has_content> 
597 
598                <#-- <div class="article-assets"> 
599                    <h2 class="heading-decor-section">Lue lis&auml;&auml;:</h2> --> 
600 
601                <div class="blue-wrapper"> 
602                    <div class="container entry-columns"> 
603                        <div class="row"> 
604                            <div class="entry-column col-md-12"> 
605                                <h2 class="header--top-stripe">Toimitus suosittelee</h2> 
606                                <#assign relatedLinksSorted = relatedLinks?sort_by("date") /> 
607                                <#list relatedLinksSorted?reverse as link> 
608 
609                                    <#-- Get entry categories --> 
610                                    <#-- <#assign categories = link.getCategories()> --> 
611                                     
612                                    <#-- Get article main images --> 
613                                    <#-- <#assign docXml = saxReaderUtil.read(link.getAssetRenderer().getArticle().getContent()) /> --> 
614                                    <#-- <#assign image = docXml.valueOf("//dynamic-element[@name='articleImages']/dynamic-content/text()") /> --> 
615 
616                                <div class="entry-card news-pick-list-cards"> 
617                                    <div class="row"> 
618 
619                                        <#if link?is_first> 
620                                            <div class="col col-xs-12 mb-3 col-md-4 mb-md-0"> 
621                                                <div class="xaspect-ratio xaspect-ratio-4-to-3"> 
622                                                    <#-- <img class="xaspect-ratio-item xaspect-ratio-item-center xaspect-ratio-item-middle" src="${getThumbnailUrl(image, 2) }" alt="" /> --> 
623                                                    <#if link.urlImage?? && link.urlImage?has_content > 
624                                                        <#assign imageJSON = jsonFactoryUtil.createJSONObject(link.urlImage)> 
625                                                        <#assign fileEntryId = imageJSON.getString("fileEntryId")> 
626                                                        <#assign fileName = imageJSON.getString("name")> 
627                                                        <img src="${getImageURL(imageJSON, '600')}" class="media-object" /> 
628                                                         
629                                                    <#else> 
630                                                        <div class="xaspect-ratio xaspect-ratio-top xaspect-ratio-3-to-2"> 
631                                                            <div class="placeholder placeholder-colored"></div>  
632                                                        </div> 
633                                                    </#if> 
634                                                </div> 
635                                            </div> 
636 
637                                        <#else> 
638                                            <div class="col col-sm-2 d-none d-md-block"> 
639                                                <div class="xaspect-ratio xaspect-ratio-4-to-3"> 
640                                                    <#-- <img class="xaspect-ratio-item xaspect-ratio-item-center xaspect-ratio-item-middle" src="${getThumbnailUrl(image, 2) }" alt="" /> --> 
641                                                    <#if link.urlImage?? && link.urlImage?has_content > 
642                                                        <#assign imageJSON = jsonFactoryUtil.createJSONObject(link.urlImage)> 
643                                                        <#assign fileEntryId = imageJSON.getString("fileEntryId")> 
644                                                        <#assign fileName = imageJSON.getString("name")> 
645                                                        <img src="${getImageURL(imageJSON, '600')}" class="media-object" /> 
646                                                         
647                                                    <#else> 
648                                                        <div class="xaspect-ratio xaspect-ratio-top xaspect-ratio-3-to-2"> 
649                                                            <div class="placeholder placeholder-colored"></div>  
650                                                        </div> 
651                                                    </#if> 
652                                                </div> 
653                                            </div> 
654                                        </#if> 
655 
656                                         
657                                        <div class="col"> 
658                                            <#if link?is_first> 
659                                                <h3 class="blue-wrapper--first-title"><a href="/-/${link.urlTitle}" class="media-content">${link.title}</a></h3> 
660                                            <#else> 
661                                                <h3><a href="/-/${link.urlTitle}" class="media-content">${link.title}</a></h3> 
662                                            </#if> 
663                                             
664                                            <#list link.categories as cat> 
665                                                <span data-cat="${cat?lower_case}" class="category-item">${cat}</span> 
666                                            </#list> 
667                                            <span class="entry-meta">${link.date}</span> 
668 
669                                            <#if link?is_first> 
670                                                <p>${link.lead}</p> 
671                                            </#if> 
672 
673                                        </div> 
674                                    </div> 
675                                    <hr> 
676                                </div> 
677 
678 
679 
680                                    <#-- VANHAT --> 
681 
682                                    <#-- <div class="media"> 
683                                        <div class="media-left"> 
684                                            <a href="/-/${link.urlTitle}" class="sans"> 
685 
686                                                <#if link.urlImage?? && link.urlImage?has_content > 
687                                                    <#assign imageJSON = jsonFactoryUtil.createJSONObject(link.urlImage)> 
688                                                    <#assign fileEntryId = imageJSON.getString("fileEntryId")> 
689                                                    <#assign fileName = imageJSON.getString("name")> 
690                                                    <img src="${getImageURL(imageJSON, '600')}" class="media-object" /> 
691                                                     
692                                                <#else> 
693                                                    <div class="aspect-ratio aspect-ratio-top aspect-ratio-3-to-2"> 
694                                                        <div class="placeholder placeholder-colored"></div>  
695                                                    </div> 
696                                                </#if> 
697 
698                                            </a> 
699                                        </div> 
700                                        <div class="media-body"> 
701                                            <a href="/-/${link.urlTitle}" class="sans">${link.title}</a> 
702                                            <span class="date">${link.date}</span> 
703                                        </div> 
704                                    </div> --> 
705                                </#list> 
706                            </div> 
707                        </div> 
708                    </div> 
709 
710                </div> 
711 
712            </#if> 
713        </#if> 
714 
715        <script src="${javascript_folder}/audioplayer.js"></script> 
716 
717        <#--  NEWSLETTER SUBSCRIPTION BANNER  --> 
718        <#-- <div class="article-subscription"> 
719            <div class="visible-md visible-lg"> 
720                <div class="banner-category-d"><h2 class="no-top-margin" style="margin-bottom: 30px;">Tilaa Kirkko ja kaupungin viikoittainen juttukooste</h2> 
721                    <form class="form-inline" action="https://kirkkojakaupunki.creamailer.fi/tilaa/59d75acf78807" id="subForm" method="post"> 
722                        <input id="redirect" name="redirect" type="hidden" value="https://kirkkojakaupunki-dev.ch5finland.com/"> 
723                        <input class="form-control" id="S&auml;hk&ouml;postiosoite" name="userEmail" placeholder="S&auml;hk&ouml;postiosoite"> 
724                        <input id="newsletter-submit-article" class="btn btn-inverse" type="submit" value="Tilaa uutiskirje"> 
725                    </form>  
726                </div> 
727            </div> 
728        </div> --> 
729 
730        <#-- FACEBOOK COMMENTS --> 
731        <#-- <#if articleComments?? && getterUtil.getBoolean(articleComments.getData()) == true> 
732            <div id="fb-root"></div> 
733            <script>if ($.gdprcookie.preference("analytics")) { document.write(` 
734                <scri`+`pt> 
735                    (function(d, s, id) { 
736                        var js, fjs = d.getElementsByTagName(s)[0]; 
737                        if (d.getElementById(id)) return; 
738                        js = d.createElement(s); js.id = id; 
739                        js.src = "//connect.facebook.net/fi_FI/sdk.js#xfbml=1&version=v2.8&appId=206864833121117"; 
740                        fjs.parentNode.insertBefore(js, fjs); 
741                    }(document, 'script', 'facebook-jssdk')); 
742                </`+`script> 
743                 
744                <h2 class="heading-decor-section">Kommentoi</h2> 
745                <p>Kommentoidaksesi sinun täytyy olla kirjautuneena Facebookiin.</p> 
746                <div class="fb-comments" data-href="${articleCompleteUrl}" data-width="725" data-numposts="5"></div> 
747                 
748            `); } 
749        </script> 
750 
751        </#if> --> 
752  </div> 
753</article> 
754 
755 
756<#-- Include script only if owl carousel among content has been built --> 
757 
758<script src="${javascript_folder}/owl.carousel.min.js"></script> 
759 
760<#if includeOwlScript == true> 
761    <script> 
762    	$('.owl-carousel').owlCarousel({ 
763            items: 1, 
764    		loop: true, 
765    		rewind: false, 
766    		margin: 0, 
767    		nav: true, 
768            navText : ['<span class="owl-carousel-nav glyphicon glyphicon-chevron-left"></span>','<span class="owl-carousel-nav glyphicon glyphicon-chevron-right"></span>'], 
769            autoplay:true, 
770            autoplayTimeout:3000, 
771            smartSpeed:1400, 
772            autoplayHoverPause:true 
773    	}); 
774 
775    </script> 
776</#if> 
777 
778<#-- 
779    Convert Youtube links to embedded videos 
780--> 
781<script type="text/javascript"> 
782 
783    $(document).ready(function () { 
784        $(".js-video-embed" ).each(function() { 
785            // Creates an iframe if it's youtube video. Otherwise just shows the original link. 
786            if (getYoutubeVideoId($(this).attr("href"))) { 
787                var div = $("<div>", {"class": "responsive-video"}); 
788                var wrapper = $("<div>", {"class": "responsive-wrapper"}); 
789                wrapper.append('<iframe src="https://www.youtube.com/embed/'+getYoutubeVideoId($(this).attr("href"))+'?rel=0" frameborder="0" allowfullscreen=""></iframe>'); 
790                div.append(wrapper); 
791                $(this).parent().append(div); 
792                $(this).hide(); //iframe is shown, hide the original link 
793
794        }); 
795    }); 
796    function getYoutubeVideoId(url) { 
797        var videoid = url.match(/(?:https?:\/{2})?(?:w{3}\.)?youtu(?:be)?\.(?:com|be)(?:\/watch\?v=|\/)([^\s&]+)/); 
798        if(videoid != null) { 
799           return videoid[1]; 
800        } else { 
801            return ""; 
802
803
804</script> 
805 
806<#--   
807    Create image comparison slider   
808--> 
809<script src="/o/kirkkojakaupunki-site-theme/js/cocoen.js"></script> 
810 
811<script type="text/javascript"> 
812    $(document).ready(function () { 
813        document.querySelectorAll('.cocoen').forEach(function(element){ 
814            var imageComparison = new Cocoen(element); 
815                var sliderOffset = $(element).attr("slider-offset"); 
816                if ($(element).attr("slider-offset") >= 100 || !($(element).attr("slider-offset"))){ 
817                    sliderOffset = 98; 
818                } else if ($(element).attr("slider-offset") == 0) { 
819                    sliderOffset = 2; 
820
821                imageComparison.element.children[0].style.width = sliderOffset+"%"; 
822                imageComparison.dragElement.style.left = sliderOffset+"%"; 
823        }); 
824 
825        // depending on slider offset show either the caption of the first or the second image 
826        $('.cocoen').mousemove(function(event){ 
827            addCaption(this); 
828        }); 
829 
830        // same functionality for touch screens 
831        document.querySelectorAll('.cocoen').forEach(function(element){ 
832            element.addEventListener("touchmove", function() { 
833                addCaption(this); 
834            }); 
835        }); 
836 
837        function addCaption(element) { 
838            var index = $('.cocoen').index(element); 
839            var sliderOffset = parseInt(element.firstElementChild.style.width); 
840            if(sliderOffset < 50){ 
841                $('.caption1').eq(index).hide(); 
842                $('.caption2').eq(index).show(); 
843            } else { 
844                $('.caption2').eq(index).hide(); 
845                $('.caption1').eq(index).show(); 
846
847
848    });     
849     
850</script> 
851 
852 
853<#----------------------------------------------------------------------------- 
854    Helper functions 
855------------------------------------------------------------------------------> 
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 iframeSrc = "https://www.youtube.com/embed/" /> 
1236        <#local videoID = URL?replace("^.*\\?v=([\\w-_]*).*", "$1", "r") /> 
1237        <#--<#local videoID = videoID + "?rel=0" />--> 
1238		<#local embed> 
1239		    <div class="responsive-video"> 
1240    			<div class="responsive-wrapper youtube" data-embed="${videoID}"> 
1241    				<img class="decor-video" alt="Toista video" src="/o/kirkkojakaupunki-site-theme/images/icons/video-decor.svg"> 
1242    			</div> 
1243    			<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> 
1244			</div> 
1245		</#local> 
1246    <#elseif videoFile?has_content> 
1247        <#local embed> 
1248            <div class="responsive-video"> 
1249                <video controls controlsList="nodownload" style="max-width:100%"> 
1250                <#-- #t=0.001 Safari hack - See ticket 25143 --> 
1251                <source src="${videoFile}#t=0.001" type="video/mp4"> 
1252                    Your browser does not support the video tag. 
1253                </video> 
1254            </div>  
1255        </#local> 
1256    <#else> 
1257        <#return embed> 
1258    </#if> 
1259 
1260    <#return embed> 
1261</#function> 
1262 
1263 
1264<#function audioEmbed description, files> 
1265    <#local embed = ""> 
1266    <#local audioFiles = [] /> 
1267     
1268    <#list files.getSiblings() as file>        
1269        <#local fileURL = file.getData()!""> 
1270        <#if fileURL?has_content> 
1271            <#local fileFormat = file.audioFormat.getData()> 
1272            <#local fileObject = {"format": fileFormat, "URL": fileURL}> 
1273            <#local audioFiles += [fileObject]> 
1274        </#if> 
1275    </#list> 
1276 
1277    <#if audioFiles?has_content> 
1278        <#local embed> 
1279            <div class="audio-player sans"> 
1280                <button class="btn btn-link flex-item-center"> 
1281                    <i class="icon-play" aria-hidden="true"></i> 
1282                </button> 
1283                <div class="audio-player-details flex-item-center"> 
1284                    <#if description?has_content> 
1285                        <p>${description}</p> 
1286                    </#if> 
1287                    <div class="audio-player-progress"> 
1288                        <span class="audio-player-time-display">-:- / -:-</span> 
1289                        <div class="audio-player-seekbar"> 
1290                            <div class="audio-player-bufferbar"></div> 
1291                            <div class="audio-player-progressbar"></div> 
1292                        </div> 
1293                    </div>                 
1294                </div> 
1295                <audio preload="metadata" loop> 
1296                    <#list audioFiles as file> 
1297                        <source src="${file.URL}" type="${file.format}" /> 
1298                    </#list> 
1299                </audio> 
1300            </div> 
1301        </#local> 
1302    </#if> 
1303 
1304    <#return embed> 
1305</#function> 
1306 
1307 
1308<#function getHeaderImages articleImages> 
1309    <#local headerImages = [] /> 
1310 
1311    <#if articleImages?has_content && articleImages.getSiblings()?has_content> 
1312        <#list articleImages.getSiblings() as cur_image> 
1313            <#if cur_image.position.getData() == 'article-image-header'> 
1314                <#local headerImages = headerImages + [cur_image] /> 
1315            </#if> 
1316        </#list> 
1317    </#if> 
1318 
1319    <#if !headerImages?has_content && articleImages?has_content && articleImages.getSiblings()?has_content > 
1320        <#local headerImages = headerImages + [articleImages.getSiblings()?first] /> 
1321    </#if> 
1322 
1323    <#return headerImages> 
1324</#function> 
1325 
1326<#function getContentCarouselImages articleImages> 
1327 
1328    <#local contentCarouselImages = [] /> 
1329 
1330    <#if articleImages?has_content && articleImages.getSiblings()?has_content> 
1331        <#list articleImages.getSiblings() as cur_image> 
1332            <#if cur_image.position.getData()?starts_with('article-image-carousel-')> 
1333                <#local contentCarouselImages = contentCarouselImages + [cur_image] /> 
1334            </#if> 
1335        </#list> 
1336    </#if> 
1337 
1338    <#if !contentCarouselImages?has_content && articleImages?has_content && articleImages.getSiblings()?has_content > 
1339        <#local contentCarouselImages = contentCarouselImages + [articleImages.getSiblings()?first] /> 
1340    </#if> 
1341 
1342    <#return contentCarouselImages> 
1343</#function> 
1344 
1345<#-- 
1346    Attempts to get mime type for a file in document library. 
1347 
1348    Parameters: 
1349        fileUrl: A string containig a url to the file. 
1350 
1351    Returns mime type as a string or an empty string. 
1352--> 
1353<#function getMimeType fileUrl> 
1354    <#if fileUrl?? && fileUrl?has_content> 
1355 
1356        <#-- Attempt to parse uuid & groupId from provided Url --> 
1357        <#assign splitUrl = fileUrl?split("/", "r") /> 
1358 
1359        <#if splitUrl?seq_contains("documents") && splitUrl?size gte 6> 
1360            <#attempt> 
1361 
1362                <#assign groupId = splitUrl[2] /> 
1363                <#assign uuid = splitUrl[5] /> 
1364                <#assign uuid = uuid?split("?")[0] /> 
1365 
1366                <#-- Get DLFileEntry --> 
1367                <#assign DLFileEntryLocalService = serviceLocator.findService("com.liferay.document.library.kernel.service.DLFileEntryLocalService") /> 
1368                <#assign fileEntry = DLFileEntryLocalService.fetchDLFileEntryByUuidAndGroupId(uuid, getterUtil.getLong(groupId)) /> 
1369                <#return fileEntry.getMimeType()> 
1370            <#recover> 
1371                <#-- Parsing mime type failed, return empty --> 
1372                <#return ""> 
1373            </#attempt> 
1374 
1375        <#elseif splitUrl?seq_contains("journal") && splitUrl?size gte 4> 
1376            <#attempt> 
1377                <#assign imageId = splitUrl[3]?split("?")[1]?split("=")[1]?split("&")[0] /> 
1378                <#assign ImageLocalService = serviceLocator.findService("com.liferay.portal.kernel.service.ImageLocalService") /> 
1379                <#assign imageType = ImageLocalService.getImage(getterUtil.getLong(imageId)).getType() /> 
1380                <#switch imageType> 
1381                    <#case "gif"> 
1382                        <#return "image/gif"> 
1383                    <#case "svg"> 
1384                        <#return "image/svg"> 
1385                    <#default> 
1386                        <#return imageType> 
1387                </#switch> 
1388            <#recover> 
1389                <#return ""> 
1390            </#attempt> 
1391 
1392        <#else> 
1393            <#-- Parsing image url failed, return empty --> 
1394            <#return ""> 
1395        </#if> 
1396 
1397    <#else> 
1398        <#-- parameter empty or missing, return empty --> 
1399        <#return ""> 
1400    </#if> 
1401</#function> 
1402 
1403<#-- 
1404    Returns thumbnail image url for given image. 
1405    Handles SVG & bitmap formats. 
1406 
1407    Parameters: 
1408        imageUrl: string containing relative url to an image in document library 
1409        thumbnailSize: value for Liferay's imageThumbnail parameter (0-3) 
1410 
1411    Returns image url with appended thumbnail info or an empty string. 
1412 --> 
1413<#function getThumbnailUrl imageUrl thumbnailSize> 
1414    <#if imageUrl?? && imageUrl?has_content> 
1415 
1416        <#-- Attempt to get mime type --> 
1417        <#assign mimeType = getMimeType(imageUrl) /> 
1418 
1419        <#if mimeType?has_content> 
1420 
1421            <#-- Check image mime type --> 
1422            <#switch mimeType> 
1423                <#case "image/svg+xml"> 
1424                    <#-- SVG image -> do not append thumbnail parameter --> 
1425                    <#return imageUrl> 
1426                <#case "image/gif"> 
1427                    <#return imageUrl> 
1428                <#default> 
1429                    <#-- Predume bitmap image -> append thumbnail parameter --> 
1430                    <#if imageUrl?contains("?")> 
1431                        <#assign paramChar = "&" /> 
1432                    <#else> 
1433                        <#assign paramChar = "?" /> 
1434                    </#if> 
1435<#-- 
1436    Liferay 7.3 thumbSize 3 on pienempi kuin aiemmin. Woodwingist tulevat kuvat nykyisin 1200 joten voidaan palauttaa suoraan kuvan url. Vaihtoehto hyodyntaa adaptive mediaa 
1437--> 
1438                    <#if thumbnailSize == 3> 
1439                        <#return imageUrl /> 
1440                    <#else> 
1441                        <#return imageUrl + paramChar + "imageThumbnail=" + thumbnailSize /> 
1442                    </#if> 
1443            </#switch> 
1444        <#else> 
1445            <#-- Embbedded journal article image (type: journal) mime recognizion fails for ie  
1446            /-/sini-mikkola-tutkii-lutherin-kasityksia 
1447            /-/kristinuskon-alkeita-ja-syventavia-keskusteluja 
1448            /-/mika-keisarin-on 
1449            --> 
1450            <#return imageUrl > 
1451        </#if> 
1452 
1453    </#if> 
1454</#function> 
1455 
1456<#-- 
1457    Return list of web content titles from given folder 
1458    parameter: 
1459        - authorCardFolderId 
1460--> 
1461<#function getAvailableAuthorNames authorCardFolderIds > 
1462 
1463  <#local authorNames = []>     
1464  <#local seenArticles = [] > 
1465  <#-- Multiple version exists so keep track which articles we have already checked --> 
1466 
1467  <#list authorCardFolderIds as authorCardFolderId> 
1468    <#assign authorCards = JournalArticleLocalService.getArticles(groupId, authorCardFolderId) /> 
1469 
1470    <#if authorCards?has_content> 
1471        <#list authorCards as authorCard> 
1472	    <#if !seenArticles?seq_contains(authorCard.articleId)> 
1473	      <#assign latest = JournalArticleLocalService.getLatestArticle(authorCard.resourcePrimKey) /> 
1474	      <#if latest.getStatus() == 0> 
1475		  <#local authorName = latest.getTitle(locale) /> 
1476		  <#if !authorNames?seq_contains(authorName) > 
1477		      <#local authorNames = authorNames + [authorName] /> 
1478		  </#if> 
1479	      </#if> 
1480	      <#local seenArticles = seenArticles + [authorCard.articleId] /> 
1481	    </#if> 
1482        </#list> 
1483         
1484    </#if> 
1485  </#list> 
1486  <#return authorNames /> 
1487</#function> 
1488 
1489<#-- 
1490    Replaces from given string author names with links to author page 
1491    parameters:  
1492    - authorNameStr : String where replacements is targeted 
1493    - authorNames : seq : list of author names 
1494    - baseUrl : url where author name is appended (as url escaped string) 
1495--> 
1496 
1497<#function makeAuthorLinks authorNameStr authorNames baseUrl > 
1498    <#list authorNames as authorName> 
1499        <#local authorNameInUrl = authorName?url("utf-8") /> 
1500        <#local authorNameStr = authorNameStr?replace(authorName, "<a class=\"author-name\" href=\""+baseUrl +authorNameInUrl + "\">"+authorName+"</a>") /> 
1501    </#list> 
1502    <#return authorNameStr /> 
1503</#function> 
1504 
1505<#function getImageURL imageJSON thumbId> 
1506    <#if imageJSON?? && imageJSON?has_content> 
1507        <#assign fileEntryId = imageJSON.getLong("fileEntryId")/> 
1508        <#assign fileName = imageJSON.getString("name")/> 
1509         
1510        <#if fileName?ends_with(".svg") || fileName?ends_with(".gif")> 
1511            <#assign imageGroupId = imageJSON.getLong("groupId")/> 
1512            <#assign imageUuid = imageJSON.getString("uuid")/> 
1513         
1514            <#return getFullImageUrL(imageGroupId, imageUuid) > 
1515        <#else> 
1516            <#return getAdaptiveImageURLByFileEntryId(fileEntryId, fileName, thumbId) > 
1517        </#if> 
1518    </#if> 
1519</#function> 
1520 
1521<#function getImageURLByTemplateModel imageTemplateModel thumbId> 
1522		<#local imageFileEntryId = imageTemplateModel.getAttribute("fileEntryId")/> 
1523		<#local fileName = imageTemplateModel.getAttribute("title")/> 
1524        <#local uuid = imageTemplateModel.getAttribute("uuid")/> 
1525		 <#if fileName?ends_with(".svg") || fileName?ends_with(".gif")> 
1526            <#return getFullImageUrL(groupId, uuid)> 
1527         <#else> 
1528            <#return getAdaptiveImageURLByFileEntryId(imageFileEntryId, fileName, thumbId)> 
1529		 </#if> 
1530</#function> 
1531 
1532<#function getAdaptiveImageURLByFileEntryId fileEntryId fileName thumbId> 
1533 
1534		<#local adaptiveMediaUrl = "/o/adaptive-media/image/${fileEntryId}/${thumbId}/${fileName}" > 
1535		 
1536        <#return adaptiveMediaUrl> 
1537</#function> 
1538 
1539<#function getFullImageUrL(groupId, uuid)> 
1540            <#assign imageURL = "/documents/" /> 
1541            <#assign imageURL += groupId /> 
1542            <#assign imageURL += "/" + uuid /> 
1543         
1544            <#return imageURL> 
1545</#function> 
1546 
1547<#-- 24944 - can't use data-fileentryid attribute when image is gif ... adaptive media breaks animated gifs --> 
1548<#function isGif(image)> 
1549    <#if image?? && image.getAttribute("name")?? && image.getAttribute("name")?has_content> 
1550        <#if image.getAttribute("name")?lower_case?contains(".gif")> 
1551            <#return true> 
1552        </#if> 
1553        <#return false> 
1554    </#if> 
1555    <#return false> 
1556</#function> 
1557 
1558<#function getCategoryNames( articleId, vocabularyId="" )> 
1559 
1560    <#local categoryNames = [] /> 
1561 
1562    <#-- Get all categories from journalArticle --> 
1563    <#local journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") /> 
1564    <#local primKey = journalArticleLocalService.getArticle(getterUtil.getLong(groupId), articleId).getResourcePrimKey() /> 
1565    <#local assetCategoryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetCategoryLocalService") /> 
1566    <#local categories = assetCategoryLocalService.getCategories('com.liferay.journal.model.JournalArticle', getterUtil.getLong(primKey)) /> 
1567 
1568    <#if categories?has_content> 
1569        <#list categories as cur_category> 
1570            <#if vocabularyId?has_content && vocabularyId == cur_category.getVocabularyId() > 
1571                <#-- get category names from given category --> 
1572                <#local categoryNames += [cur_category.getName()] /> 
1573            <#elseif !vocabularyId?has_content> 
1574                <#-- get all category names --> 
1575                <#local categoryNames += [cur_category.getName()] /> 
1576            </#if> 
1577 
1578        </#list> 
1579    </#if> 
1580 
1581    <#return categoryNames> 
1582</#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.