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