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