Rakas lähiö: Kirjailija Tomi Kontio kasvoi Myllypurossa pojasta mieheksi
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ämä 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ää 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ää tekijältä:</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ää:</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ähköpostiosoite" name="userEmail" placeholder="Sähkö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äytä 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äyttää koska javascript on kytketty pois päältä 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äyttää koska javascript on kytketty pois päältä 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
Keskustele ja kommentoi Facebookissa
Uutiskirje
Tilaa Kirkko ja kaupungin viikoittainen juttukooste.
Tilaa Kirkko ja kaupungin viikoittainen juttukooste.