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