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