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