1 2<!doctype html> 3<html class="diks-no-js diks-site--loviisansanomat diks-user--is-not-logged-in diks-user--is-not-subscriber diks-user--is-not-company-subscriber diks-site--layout-master diks-site--ads-disabled-from-page-level" lang="fi" prefix="og: http://ogp.me/ns#"> 4 <head> 5 <meta charset="utf-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1"> 7 <title>Sovellus | Loviisan Sanomat</title> 8 <link id="diks-stylesheet" rel="stylesheet" href="https://a.loviisansanomat.fi/styles/e5576057/styles/diks-news.css"> 9 <link rel="dns-prefetch" href="https://cdn.gravito.net"> 10 <link rel="dns-prefetch" href="https://cdn.gravito.network"> 11 <link rel="dns-prefetch" href="https://handshake.gravito.network"> 12
12<script> 13 14 const checkUserPreferenceEnabled = 1; 15 const darkmodeStylesheet = "https://a.loviisansanomat.fi/styles/e5576057/styles/diks-news-darkmode.css"; 16 const defaultStylesheet = "https://a.loviisansanomat.fi/styles/e5576057/styles/diks-news.css"; 17 const savedTheme = localStorage.getItem('theme'); 18 const stylesheet = document.getElementById("diks-stylesheet"); 19 20 // Check local storage for saved theme 21 if ( savedTheme == 'darkmode' ) { 22 stylesheet.href = darkmodeStylesheet; 23 document.documentElement.classList.add('diks-theme--darkmode'); 24 } 25 // Check user's theme preference through an OS setting or a user agent setting 26 else if ( checkUserPreferenceEnabled && savedTheme != 'default' && ( window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ) ) { 27 stylesheet.href = darkmodeStylesheet; 28 document.documentElement.classList.add('diks-theme--darkmode'); 29 } 30 else { 31 document.documentElement.classList.add('diks-theme--default'); 32 } 33 34 35 // Darkmode toggle switch 36 document.addEventListener('DOMContentLoaded', function () { 37 const darkmodeButton = document.getElementById("diks-darkmode-toggler"); 38 39 if (darkmodeButton) { 40 // Set darkmode button to checked if darkmode is already on 41 // Check local storage for saved theme 42 if (savedTheme == 'darkmode' ) { 43 darkmodeButton.checked = true; 44 } 45 // Check user's theme preference through an OS setting or a user agent setting 46 else if ( checkUserPreferenceEnabled && savedTheme != 'default' && ( window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ) ) { 47 darkmodeButton.checked = true; 48 } 49 50 // Change theme based on darkmode button checked/unchecked 51 darkmodeButton.addEventListener("click", function() { 52 // Swap out the URL for the different stylesheets 53 if ( stylesheet.getAttribute("href") == defaultStylesheet ) { 54 stylesheet.href = darkmodeStylesheet; 55 document.documentElement.classList.remove('diks-theme--default'); 56 document.documentElement.classList.add('diks-theme--darkmode'); 57 // Save theme to local storage 58 window.localStorage.setItem('theme', 'darkmode'); 59 } else { 60 stylesheet.href = defaultStylesheet; 61 document.documentElement.classList.remove('diks-theme--darkmode'); 62 document.documentElement.classList.add('diks-theme--default'); 63 // Save theme to local storage 64 window.localStorage.setItem('theme', 'default'); 65 } 66 // Dispatch event ThemeChanged when theme inside Local Storage changes 67 window.dispatchEvent(new Event("ThemeChanged")); 68 }); 69 } 70 }, false); 71 72 </script>
72 73 74 <link rel="preload" href="/gravito-cmp.js" as="script"> 75 <link rel="preload" href="https://cdn.gravito.net/sdk/v6/latest/sdk.js" as="script"><link rel="preload" href="https://k472.loviisansanomat.fi/script.js" as="script"> 76
76<script> 77 window.JankkoSSOConfig = { 78 accountOrigin: "LOSA" 79 }; 80 </script>
80 81 82 83
83<script id="jankko-sso-script" src="https://sso.loviisansanomat.fi/assets/jankko-sso-client.modern.min.js"></script>
83 84 85 86
86<script>window.ghdConfig = {autoInit: true, endpoint: 'https://ksml.detect.gravito.fi/api/v1/events', volume: 'sampling', samplingRatio: 0.1};</script>
86 87
87<script src='https://ksml.detect.gravito.fi/sdk.js'></script>
87 88 89 90
90<script> 91 // Hyphenopoly library initialization. The library will add soft-hyphen characters into the content if the 92 // browser doesn't support CSS hyphenation. For debugging on macOS Chrome: require: { 'fi': 'FORCEHYPHENOPOLY' } 93 const Hyphenopoly = { 94 require: { 'fi': 'yhdyssanahirviö' }, 95 setup: { 96 defaultLanguage: "fi", 97 selectors: { '.diks-card__title': { minWordLength: 11, leftmin: 4, rightmin: 4 }, '.diks-article__headline': { minWordLength: 11, leftmin: 4, rightmin: 4 }, '.diks-parallax-content .diks-article-box .diks-sub-headline': { minWordLength: 11, leftmin: 4, rightmin: 4 } } 98 } 99 } 100 console.log('Hyphenopoly settings:', Hyphenopoly.setup) 101 102 // Helper function for hyphenating content that was added after pageload. We must query a nodelist and iterate 103 // each node because the library can't handle a nodelist. 104 // https://mnater.github.io/Hyphenopoly/Hyphenators.html 105 // https://github.com/mnater/Hyphenopoly/issues/92#issuecomment-597728300 106 const diksHyphenateContent = (containerSelector) => { 107 if (!Hyphenopoly.hyphenators) { 108 return 109 } 110 Hyphenopoly.hyphenators["HTML"].then((hyphenator) => { 111 for (const itemSelector in Hyphenopoly.setup.selectors) { 112 const containerNode = document.querySelector(containerSelector) 113 const itemNodeList = containerNode.querySelectorAll(itemSelector) 114 itemNodeList.forEach((itemNode) => { hyphenator(itemNode, itemSelector) }) 115 } 116 }) 117 } 118 </script>
118 119
119<script src="https://a.loviisansanomat.fi/styles/e5576057/includes/hyphenopoly/Hyphenopoly_Loader.js"></script>
119 120
120<script src="/theme/css/includes/waypoints/lib/noframework.waypoints.min.js"></script>
120 121 <link rel="icon" type="image/png" href="/favicon.png" sizes="96x96" /><link rel="icon" href="/favicon.ico" sizes="48x48"><link rel="icon" href="/favicon.svg" sizes="any" type="image/svg+xml" /><link rel="apple-touch-icon" href="/icon-180.png"/><meta name="theme-color" content="#FFFFFF" media="(prefers-color-scheme: light)" /> 122 <meta name="theme-color" content="#121416" media="(prefers-color-scheme: dark)" /><link rel="alternate" type="application/rss+xml" title="Loviisan Sanomat" href="https://www.loviisansanomat.fi/feed/rss"><meta name="robots" content="max-image-preview:large"><meta name="facebook-domain-verification" content="8ys07wsobdaxlopzl7ncm1diobctmn">
122<script> 123 var pageData = {}; 124 125 pageData.section = { 126 'name': 'Sovellus', 127 'uname': 'asenna', 128 'url': 'https\u003A\/\/www.loviisansanomat.fi\/asenna\/' 129 } 130 pageData.publication = { 131 'name': 'loviisansanomat', 132 'url': 'https\u003A\/\/www.loviisansanomat.fi\/', 133 'engage': 'LOSA', 134 'paywallEnabled': true, 135 'registrationWallEnabled': true, 136 'env':'prod' 137 } 138 pageData.user = {} 139 pageData.companyUser = {} 140 141 function isPwa() { 142 // window.navigator.standalone = iOS 143 // window.matchMedia('(display-mode: standalone)').matches = Android/universal 144 return (window.navigator.standalone) || 145 (["fullscreen", "standalone", "minimal-ui"].some( 146 function(displayMode) { return window.matchMedia('(display-mode: ' + displayMode + ')') 147 .matches })); 148 } 149 150 pageData.general = { 151 'browseMode': (isPwa() ? 'pwa' : 'browser') 152 } 153</script>
153 154 <meta property="og:site_name" content="Loviisan Sanomat"> 155 <meta property="og:locale" content="fi_FI"><meta name='description' content='Sovellus sisältää tuoreet juttumme, joita ilmestyy ympäri vuorokauden vuoden jokaisena päivänä sekä näköislehtemme liitteineen sekä näköislehtien arkiston.'> 156<meta property='og:title' content='Sovellus | Loviisan Sanomat'> 157<meta property='og:description' content='Sovellus sisältää tuoreet juttumme, joita ilmestyy ympäri vuorokauden vuoden jokaisena päivänä sekä näköislehtemme liitteineen sekä näköislehtien arkiston.'> 158<meta property='og:url' content='https://www.loviisansanomat.fi/asenna/'> 159<meta property='og:type' content='webpage'><meta property='og:image' content='https://a.loviisansanomat.fi/styles/e5576057/images/default/og-image-loviisansanomat.jpg'> 160<meta property='og:image:width' content='1200'> 161<meta property='og:image:height' content='630'> 162 <link rel="manifest" href="/manifest.webmanifest"> 163 <style>@media (max-width: 600px) { .gravitoCMP-footer { margin-top: 1.5em; } }</style> 164
164<script type="text/javascript">window.cX = window.cX || {};// Async load of cx.js 165 (function(d,s,e,t){e=d.createElement(s);e.type='text/java'+s;e.async='async'; 166 e.src='http'+('https:'===location.protocol?'s://s':'://')+'cdn.cxense.com/cx.js'; 167 t=d.getElementsByTagName(s)[0];t.parentNode.insertBefore(e,t);})(document,'script'); 168 </script>
168 169
169<script src="https://a.loviisansanomat.fi/styles/e5576057/js/blueconic/dialog.min.js"></script>
169 170
170<script> 171 BCinst = 'blueconic'; 172 BCshortcode = 'LOSA'; 173 </script>
173<script src="https://a.loviisansanomat.fi/styles/e5576057/js/blueconic/events.min.js"></script>
173 174
174<script> 175 const BCPlatform = "web"; 176 const BCChannel = 'LOSA'; 177 178 const BCArticleViewProperties = {}; 179 const BCSessionStartProperties = {}; 180 181 BCArticleViewProperties["platform"] = BCPlatform; 182 BCArticleViewProperties["channel"] = BCChannel; 183 BCSessionStartProperties["platform"] = BCPlatform; 184 BCSessionStartProperties["channel"] = BCChannel; 185 186 const BCArticleID = pageData?.article?.id || ''; 187 const BCArticleMarketingCategories = pageData?.article?.marketingCategories || []; 188 const BCArticleTopics = pageData?.article?.topics || []; 189 190 if (BCArticleID) { 191 BCArticleViewProperties["articleID"] = BCArticleID; 192 } 193 194 if (Array.isArray(BCArticleMarketingCategories) && BCArticleMarketingCategories.length > 0) { 195 BCArticleViewProperties["marketing_categories"] = BCArticleMarketingCategories.join(', '); 196 } 197 198 if (Array.isArray(BCArticleTopics) && BCArticleTopics.length > 0) { 199 BCArticleViewProperties["tags"] = BCArticleTopics.join(', '); 200 } 201 202 const BCEventParams = { 203 currentPage: '/asenna/' || null, 204 pageType: 'section' || null, 205 dependenciesTimeout: 5000, 206 inHouseAdEnabled: true, 207 articleViewEventEnabled: true, 208 articleViewProperties: BCArticleViewProperties, 209 sessionStartEventEnabled: true, 210 sessionStartProperties: BCSessionStartProperties, 211 recommendationsEnabled: false, 212 recommendationsMaxItems: 3, 213 recommendationsTitle: 'Luitko\u0020jo\u0020n\u00E4m\u00E4\u003F' 214 }; 215 InitializeEventScript(BCEventParams); 216 </script>
216<script> 217 window.BCDatalayer = []; 218 </script>
218<script> 219 (function () { 220 window.BCscriptInjected = false; 221 var scriptSrc = ''; 222 223 scriptSrc = 'https://k472.loviisansanomat.fi/script.js'; 224 225 window.addEventListener( 226 "gravito:tcfv2:client", 227 function (event) { 228 let eventType = event.detail.eventType; 229 let consentUpdateEventsList = [ 230 "layer1:opt-out:all", 231 "layer2:opt-out:all", 232 "layer2:opt-in:selected", 233 "layer1:opt-in:all", 234 "layer2:opt-in:all", 235 "opt-in:previously", 236 ]; 237 if (consentUpdateEventsList.includes(eventType) && window.BCscriptInjected === false) { 238 window.BCscriptInjected = true; 239 240 var script = document.createElement("script"); 241 script.src = scriptSrc; 242 document.head.appendChild(script); 243 } 244 }, 245 true 246 ); 247 }()); 248 </script>
248 249 250
250<script type='text/javascript'> 251 (function() { 252 /** CONFIGURATION START **/ 253 var _sf_async_config = window._sf_async_config = (window._sf_async_config || {}); 254 _sf_async_config.uid = 60754; 255 _sf_async_config.domain = location.host.replace("www.",""); 256 _sf_async_config.flickerControl = false; 257 _sf_async_config.useCanonical = true; 258 _sf_async_config.useCanonicalDomain = true; 259 /** CONFIGURATION END **/ 260 })(); 261 </script>
261<script> 262 function configureChartbeat(userType) { 263 /** CONFIGURATION START **/ 264 var _sf_async_config = window._sf_async_config = (window._sf_async_config || {}); 265 _sf_async_config.sections = pageData && pageData.section ? pageData.section.name : ''; 266 _sf_async_config.authors = pageData && pageData.article && Array.isArray(pageData.article.authors) ? pageData.article.authors.toString() : ''; 267 268 if (userType) { 269 var _cbq = window._cbq = (window._cbq || []); 270 _cbq.push(['_acct', userType]); 271 } 272 /** CONFIGURATION END **/ 273 function loadChartbeat() { 274 var e = document.createElement('script'); 275 var n = document.getElementsByTagName('script')[0]; 276 e.type = 'text/javascript'; 277 e.async = true; 278 e.src = 'https://static.chartbeat.com/js/chartbeat.js'; 279 n.parentNode.insertBefore(e, n); 280 } 281 loadChartbeat(); 282 }; 283 284 if (typeof JankkoSSOClient !== 'undefined') { 285 JankkoSSOClient.getSession().then(function(data) { 286 if (data && data.user && data.user.id) { 287 var userType = Array.isArray(data.permissions) && data.permissions.includes("paywall") ? 'paid' : 'lgdin'; 288 289 configureChartbeat(userType); 290 } else { 291 configureChartbeat('anon'); 292 } 293 }).catch(function(error) { 294 configureChartbeat('anon'); 295 }); 296 } else { 297 configureChartbeat('anon'); 298 } 299 </script>
299 300
300<script> 301 const gtmContainerId = 'GTM-KTJNB7R'; 302 const sendDatalayerPush = Boolean(1); 303 const context = 'sec'; 304 305 (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': 306 new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], 307 j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 308 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); 309 })(window,document,'script','dataLayer',gtmContainerId); 310 311 if (sendDatalayerPush) { 312 window.dataLayer.push({'event':'pageDataPush','pageData': window.pageData}); 313 } 314 315 (async function () { 316 const paywallEnabled = window?.pageData?.publication?.paywallEnabled ?? true; 317 const registrationWallEnabled = window?.pageData?.publication?.registrationWallEnabled ?? true; 318 319 const user = {}; 320 const companyUser = {}; 321 322 let articleState; 323 let articlePaywall = 'free'; // free is always the safer fallback 324 325 if (context === 'art') { 326 if (window?.pageData?.article?.effectivePaywall) { 327 articlePaywall = window.pageData.article.effectivePaywall; 328 } else if (window?.pageData?.article?.paywall){ 329 articlePaywall = window.pageData.article.paywall; 330 } 331 332 if ((articlePaywall === 'free' || !paywallEnabled) || (articlePaywall === "registered" && !registrationWallEnabled)) { 333 articleState = "full"; 334 } 335 else { 336 articleState = 'preview'; 337 } 338 } 339 340 function getCookie(name) { 341 name = name + '='; 342 const decodedCookie = decodeURIComponent(document.cookie); 343 const cookies = decodedCookie.split(';'); 344 for (let i = 0; i < cookies.length; i++) { 345 const cookie = cookies[i].trim(); 346 if (cookie.indexOf(name) === 0) { 347 return cookie.substring(name.length, cookie.length); 348 } 349 } 350 } 351 352 function pushDataLayerEvent() { 353 let segmentsCookie = getCookie('jankkosegments'); 354 355 if (segmentsCookie) { 356 let segmentsData = JSON.parse(segmentsCookie); 357 let segments = segmentsData.segments; 358 359 if (segments && typeof segments === 'object') { 360 user.segments = segments; 361 } 362 } 363 const pageData = { 364 'user': user,
365 'companyUser': companyUser 366 }; 367 if (context === 'art') { 368 pageData.article = { 'state': articleState }; 369 } 370 if (sendDatalayerPush) { 371 window.dataLayer.push({'event': 'userDataPush', 'pageData': pageData }); 372 } 373 } 374 375 async function modifyDatalayerData() { 376 const sessionData = await JankkoSSOClient.getSession(); 377 if (!sessionData) { 378 return; 379 } 380 381 user.id = sessionData?.personal?.personal_user_id; 382 user.products = sessionData?.personal?.personal_active_products; 383 user.permissions = sessionData?.personal?.personal_permissions; 384 385 companyUser.id = sessionData?.company?.company_user_id ?? null; 386 companyUser.products = sessionData?.company?.company_active_products ?? null; 387 companyUser.permissions = sessionData?.company?.company_permissions ?? null; 388 389 const permissions = sessionData?.permissions ?? []; 390 if (context === 'art') { 391 var userIsLoggedIn = false;if ((articlePaywall != "free" && permissions.includes("paywall") && articlePaywall != "registered") || (userIsLoggedIn === true && articlePaywall === "registered")) { 392 articleState = "full"; 393 } 394 } 395 } 396 397 try { 398 await modifyDatalayerData(); 399 } 400 catch (error) { 401 console.warn(error); 402 } 403 404 pushDataLayerEvent(); 405 }()); 406 407 </script>
407 408 409 </head> 410 <body class="diks-body diks-body--page-type-apps"> 411 <!-- Google Tag Manager (noscript) -->
vendor: 72 bytes, lines 411-412
411 412 <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=
412GTM-KTJNB7R
vendor: 95 bytes, lines 412-414
412" 413 height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> 414
414<!-- End Google Tag Manager (noscript) --> 415
415<script src='/gravito-cmp.js'></script>
415 416 417 418 419 420 <header id="main-header" class="diks-header diks-header diks-header--is-fixed"> 421 <div class="diks-skip-link-navigation diks-skip-link-navigation--top"> 422 <ul class="diks-navigation diks-navigation--skip-links"> 423 <li class="diks-navigation__item"> 424 <a class="diks-button diks-button--primary diks-a11y__screen-reader diks-a11y__screen-reader--focusable" href="#sisalto" >Siirry suoraan sisältöön</a> 425 </li> 426 </ul> 427 </div> 428 429 <div class="diks-header-wrapper"> 430 <div class="diks-container diks-container--header"> 431 <div class="diks-header-container"><div class="diks-header__navigation-container diks-header__navigation-container--left"> 432 <button class="diks-button diks-button--icon-only diks-button--ghost diks-navigation__link js-diks-toggler diks-dropdown-toggler diks-dropdown-toggler--main" id="diks-dropdown-toggle" data-toggle="diks-dropdown-navigation" aria-expanded="false" aria-controls="diks-dropdown-navigation" aria-label="Valikko"><span class="diks-icon diks-icon--size-m" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 433 <path fill-rule="evenodd" d="M22 6H2V4H22V6ZM22 13H2V11H22V13ZM22 20H2V18H22V20Z" clip-rule="evenodd"/> 434</svg> 435</span><span class="diks-icon diks-icon--size-m diks-icon--hidden" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 436 <path fill-rule="evenodd" d="M10.5858 12L4.2218 5.63603L5.63602 4.22182L12 10.5858L18.3639 4.22183L19.7782 5.63605L13.4142 12L19.7782 18.364L18.3639 19.7782L12 13.4142L5.63602 19.7782L4.2218 18.364L10.5858 12Z" clip-rule="evenodd"/> 437</svg> 438</span></button> 439 440 <div class="diks-dropdown-navigation" id="diks-dropdown-navigation"> 441 <button id="diks-close-dropdown-main-nav" class="diks-button diks-button--outline diks-dropdown-navigation__close-button diks-a11y__screen-reader diks-a11y__screen-reader--focusable">Sulje valikko</button><div class="diks-dropdown-navigation__sign-container"> 442 <img src="https://a.loviisansanomat.fi/styles/e5576057/images/logos/keskisuomalainen-sign.svg" class="diks-logo diks-dropdown-navigation__sign" alt="Keskisuomalainen Oyj"> 443 </div><form id="dropdown-navigation-search" name="dropdownnavigationsearch" class="diks-form diks-form--fluid" action="/haku/" method="get"> 444 <div class="diks-form__field-wrapper diks-form__field-wrapper--padding-right diks-form__field-wrapper--required"><input class="diks-form__field" type="search" name="q" id="dropdown-navigation-searchSearch1" aria-label="Haku" placeholder="Hae sivustolta" required value=""></div> 445 446 <div class="diks-form__field-wrapper diks-form__field-wrapper--submit-button-icon-only"> 447 <button class="diks-form__submit" type="submit" id="dropdown-navigation-searchSubmitbutton2"><span class="diks-icon diks-icon--color-primary" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 448 <path fill-rule="evenodd" d="M9.5 4C6.46243 4 4 6.46243 4 9.5C4 12.5376 6.46243 15 9.5 15C12.5376 15 15 12.5376 15 9.5C15 6.46243 12.5376 4 9.5 4ZM2 9.5C2 5.35786 5.35786 2 9.5 2C13.6421 2 17 5.35786 17 9.5C17 11.2106 16.4273 12.7874 15.4632 14.0493L19.7782 18.3642L18.3639 19.7784L14.049 15.4634C12.7872 16.4274 11.2105 17 9.5 17C5.35786 17 2 13.6421 2 9.5Z" clip-rule="evenodd"/> 449</svg> 450</span>Hae 451 </button> 452 </div> 453 </form> <nav class="diks-navigation-wrapper diks-navigation-wrapper--border-bottom diks-navigation-wrapper--border-top" ><ul class="diks-navigation diks-navigation--row diks-navigation--mobile-row diks-navigation--no-active-links diks-navigation--size-s" id="dropdown-highlights-nav"><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/asenna/">Sovellus</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/nakoislehti/">Lehdet</a></li><li class="diks-navigation__item diks-navigation__item--button diks-navigation__item--align-right diks-hide-from-subscribers" ><a class="diks-navigation__link diks-bc-order-button" href="/jatka/">Tilaa</a></li></ul> 454 </nav> <nav class="diks-navigation-wrapper diks-navigation-wrapper--divider-bottom" ><ul class="diks-navigation diks-navigation--no-active-links diks-navigation--size-s" id="dropdown-customer-upper-nav"><li class="diks-navigation__item " ><a class="diks-navigation__link " href="https://oma.media.fi/loviisan-sanomat/"><span class="diks-icon diks-icon--size-m" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 455 <path d="M17 8H22V17H19.1875V20.8125L14.1045 17H9V13.4307L4.4375 17.0811V13H2V3H17V8ZM17 13H11V15H14.7705L17.1875 16.8125V15H20V10H17V13ZM4 11H6.4375V12.918L8.5625 11.2188L8.83691 11H15V5H4V11Z"/> 456</svg> 457</span>Asiakaspalvelu</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="https://oma.media.fi/loviisan-sanomat/yhteystiedot/juttuvinkki/"><span class="diks-icon diks-icon--size-m" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 458 <path fill-rule="evenodd" d="M7.38197 4H16.618L17.618 6H22V20H2V6H6.38197L7.38197 4ZM8.61803 6L7.61803 8H4V18H20V8H16.382L15.382 6H8.61803ZM12 11C10.8954 11 10 11.8954 10 13C10 14.1046 10.8954 15 12 15C13.1046 15 14 14.1046 14 13C14 11.8954 13.1046 11 12 11ZM8 13C8 10.7909 9.79086 9 12 9C14.2091 9 16 10.7909 16 13C16 15.2091 14.2091 17 12 17C9.79086 17 8 15.2091 8 13Z" clip-rule="evenodd"/> 459</svg> 460</span>Lähetä juttuvinkki</a></li></ul> 461 </nav> <nav class="diks-navigation-wrapper " ><ul class="diks-navigation diks-navigation--light" id="dropdown-section-nav"><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/">Etusivu</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/uusimmat/">Uusimmat</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/luetuimmat/">Luetuimmat</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/mysteerimaistaja">Mysteerimaistaja</a></li><li class="diks-navigation__item " >
461<a class="diks-navigation__link " href="/aihe/Hyv%C3%A4t_uutiset">Hyvät uutiset</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/maakunta-uusimaa">Uusimaa 360</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/paikalliset-yrittajat">Paikalliset yrittäjät</a></li></ul> 462 </nav><!-- ESI start element "recommendedTopics" generated at 25-09-2026 10:39:05.556220 --> <nav class="diks-navigation-wrapper diks-navigation-wrapper--divider-top" ><ul class="diks-navigation diks-navigation--light diks-navigation--size-s" ><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/Hyv%C3%A4t_uutiset">Hyvät uutiset</a></li></ul> 463 </nav><!-- ESI end element "recommendedTopics" --><!-- ESI start element "promotedAdvertisers" generated at 25-09-2026 10:36:51.650529 --><!-- ESI end element "promotedAdvertisers" --> <nav class="diks-navigation-wrapper diks-navigation-wrapper--divider-top" ><h2 class="diks-navigation__title">Yhteystiedot</h2><ul class="diks-navigation diks-navigation--light diks-navigation--size-s" id="dropdown-customer-nav"><li class="diks-navigation__item " ><a class="diks-navigation__link " href="https://meks.fi/mainonta/alueet/etela-suomen-media/">Mediamyynti</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="https://oma.media.fi/loviisan-sanomat/yhteystiedot/">Kaikki yhteystiedot</a></li></ul> 464 </nav><div class="diks-navigation-wrapper diks-navigation-wrapper--divider-top"><h2 class="diks-navigation__title">Ulkoasu</h2><label for="diks-darkmode-toggler" class="diks-form__switch"> 465 <span class="diks-form__switch-label"><span class="diks-icon diks-icon--size-m" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 466 <path fill-rule="evenodd" d="M13.7547 1.76065L11.7581 3.75666C10.6708 4.8436 10 6.34252 10 8C10 11.3137 12.6863 14 16 14C17.6575 14 19.1564 13.3292 20.2433 12.2419L22.2394 10.2453L21.9451 13.0531C21.4182 18.0815 17.1674 22 12 22C6.47715 22 2 17.5229 2 12C2 6.83263 5.91855 2.58178 10.9469 2.05488L13.7547 1.76065ZM8.70749 4.70657C5.93176 5.9617 4 8.75566 4 12C4 16.4183 7.58172 20 12 20C15.2443 20 18.0383 18.0682 19.2934 15.2925C18.289 15.7468 17.1738 16 16 16C11.5817 16 8 12.4183 8 8C8 6.82623 8.25316 5.71105 8.70749 4.70657Z" clip-rule="evenodd"/> 467</svg> 468</span>Käytä tummaa tilaa</span> 469 <div class="diks-form__switch-wrapper"> 470 <input id="diks-darkmode-toggler" class="diks-form__switch-input" type="checkbox"> 471 <span class="diks-form__switch-slider"></span> 472 </div> 473 </label> 474 </div></div> <nav class="diks-navigation-wrapper " ><ul class="diks-navigation diks-navigation--main diks-navigation--size-s diks-navigation--row diks-navigation--mobile-row diks-navigation--no-active-links diks-hide-below-large" ><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/uusimmat/"><span class="diks-icon diks-hide-above-large" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 475 <path fill-rule="evenodd" d="M12 4a8 8 0 100 16 8 8 0 000-16zM2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10S2 17.523 2 12zm9-6h2v5.586l2.707 2.707-1.414 1.414L11 12.414V6z" clip-rule="evenodd"/> 476</svg> 477</span>Uusimmat</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/luetuimmat/"><span class="diks-icon diks-hide-above-large" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 478 <path fill-rule="evenodd" d="M11.03 3.455c1.168-1.438 3.495-.652 3.55 1.2l.117 3.845h6a1.25 1.25 0 0 1 1.229 1.484l-1.905 10A1.25 1.25 0 0 1 18.793 21H9.06a1.25 1.25 0 0 1-.559-.132L6.764 20H3.25C2.56 20 2 19.44 2 18.75v-8.5C2 9.56 2.56 9 3.25 9h3.274l4.506-5.545ZM8 10.355v8.027L9.236 19h8.936l1.62-8.5h-5.58a1.5 1.5 0 0 1-1.499-1.455l-.131-4.33L8 10.356Zm10.056 9.255ZM4 11v7h2v-7H4Zm14.793 8.75.145.027Z" clip-rule="evenodd"/> 479</svg> 480</span>Luetuimmat</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/nakoislehti/"><span class="diks-icon diks-hide-above-large" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 481 <path fill-rule="evenodd" d="M4 2H20V22H4V2ZM6 4V20H18V4H6ZM8 6H16V12H8V6ZM10 8V10H14V8H10ZM16 15H8V13H16V15ZM16 18H8V16H16V18Z" clip-rule="evenodd"/> 482</svg> 483</span>Lehdet</a></li><li class="diks-navigation__item diks-navigation__item--button diks-navigation__item--align-right diks-hide-above-medium diks-hide-from-subscribers" ><a class="diks-navigation__link diks-bc-order-button" href="/jatka/">Tilaa</a></li></ul> 484 </nav></div><div class="diks-header__logo-container"><a class="diks-logo__link diks-header__logo-link diks-header__main-logo-link" href="/"><img src="https://a.loviisansanomat.fi/styles/e5576057/images/logos/loviisansanomat.svg" class="diks-logo diks-logo--default diks-header__logo diks-header__main-logo" alt="Loviisan Sanomat"><img src="https://a.loviisansanomat.fi/styles/e5576057/images/logos/loviisansanomat-white.svg" class="diks-logo diks-logo--darkmode diks-header__logo diks-header__main-logo" alt="Loviisan Sanomat"></a> 485 </div><div class="diks-header__navigation-container diks-header__navigation-container--right"><a class="diks-bc-order-button diks-button diks-button--primary diks-button--size-m diks-hide-from-subscribers diks-hide-below-medium " href="/jatka/">Tilaa</a><div class="diks-user-navigation-wrapper"> 486 <button class="diks-button diks-button--icon-only diks-button--ghost diks-navigation__link diks-dropdown-toggler diks-dropdown-toggler--user" aria-expanded="false" id="diks-sso-user" data-diks-toggle="diks-user-navigation" data-diks-toggle-class="diks-user-navigation" aria-controls="diks-user-navigation"><span class="diks-icon diks-icon--size-m" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 487 <path fill-rule="evenodd" d="M4 12a8 8 0 1 1 13.496 5.814c-1.216-1.593-3.262-2.602-5.491-2.602-2.231 0-4.28 1.011-5.495 2.607A7.978 7.978 0 0 1 4 12Zm4.04 6.953A7.963 7.963 0 0 0 12 20a7.964 7.964 0 0 0 3.966-1.05c-.83-1.087-2.254-1.84-3.961-1.84-1.71 0-3.135.754-3.965 1.843ZM12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2Zm.005 5.898c-1.247 0-2.305 1.049-2.305 2.4 0 1.353 1.058 2.402 2.305 2.402s2.305-1.05 2.305-2.401c0-1.352-1.058-2.4-2.305-2.4Zm-4.203 2.4C7.802 7.952 9.658 6 12.005 6c2.347 0 4.203 1.95 4.203 4.299 0 2.348-1.856 4.299-4.203 4.299-2.347 0-4.203-1.951-4.203-4.3Z" clip-rule="evenodd"/> 488</svg> 489</span><span class="diks-icon diks-icon--size-m diks-icon--hidden" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 490 <path fill-rule="evenodd" d="M10.5858 12L4.2218 5.63603L5.63602 4.22182L12 10.5858L18.3639 4.22183L19.7782 5.63605L13.4142 12L19.7782 18.364L18.3639 19.7782L12 13.4142L5.63602 19.7782L4.2218
49018.364L10.5858 12Z" clip-rule="evenodd"/> 491</svg> 492</span></button> 493 494 <div class="diks-navigation diks-sub-navigation diks-user-navigation" id="diks-user-navigation"> 495 <button id="diks-close-dropdown-user-nav" class="diks-button diks-button--outline diks-dropdown-navigation__close-button diks-a11y__screen-reader diks-a11y__screen-reader--focusable">Sulje valikko</button> 496 <p id="diks-sso-username" class="diks-user-navigation__username diks-hide-from-company-subscribers"></p><p class="diks-user-navigation__username diks-show-for-company-subscribers">Yritystilaus tunnistettu</p><div class="diks-show-for-company-subscribers"><p>Voit käyttää palvelun kaikkia sisältöjä vapaasti. Jos haluat kommentoida, kirjaudu sisään henkilökohtaisella Mediatunnuksella.</p></div> <ul class="diks-navigation diks-navigation--size-m" id="diks-sso-links"><li class="diks-navigation__item " ><a class="diks-navigation__link " href="javascript:window.gravito.cmp.openPreferences();">Evästevalinnat</a></li></ul> 497 </div> 498</div> 499 </div> 500 </div> 501 </div> 502 </div><div class="diks-section-navigation-wrapper"> 503 <div class="diks-container diks-container--narrow-mobile diks-container--full-width-before-l"> 504 <nav class="diks-navigation-wrapper diks-navigation-wrapper--border-bottom" aria-label="Osastovalikko"><ul class="diks-navigation diks-navigation--row diks-navigation--light diks-navigation--centered diks-navigation--mobile-row diks-navigation--draggable diks-navigation--size-xs diks-navigation--active-subtle" id="osastovalikko"><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/mysteerimaistaja"draggable="false">Mysteerimaistaja</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/Hyv%C3%A4t_uutiset"draggable="false">Hyvät uutiset</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/maakunta-uusimaa"draggable="false">Uusimaa 360</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/paikalliset-yrittajat"draggable="false">Paikalliset yrittäjät</a></li></ul> 505 </nav> 506 </div> 507 </div><div class="diks-quicklinks-wrapper"> 508 <div class="diks-container diks-container--narrow-mobile"> 509 <nav class="diks-navigation-wrapper " ><ul class="diks-navigation diks-navigation--main diks-navigation--size-s diks-navigation--row diks-navigation--mobile-row diks-navigation--no-active-links diks-navigation--centered diks-hide-above-large" ><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/uusimmat/"><span class="diks-icon diks-hide-above-large" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 510 <path fill-rule="evenodd" d="M12 4a8 8 0 100 16 8 8 0 000-16zM2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10S2 17.523 2 12zm9-6h2v5.586l2.707 2.707-1.414 1.414L11 12.414V6z" clip-rule="evenodd"/> 511</svg> 512</span>Uusimmat</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/luetuimmat/"><span class="diks-icon diks-hide-above-large" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 513 <path fill-rule="evenodd" d="M11.03 3.455c1.168-1.438 3.495-.652 3.55 1.2l.117 3.845h6a1.25 1.25 0 0 1 1.229 1.484l-1.905 10A1.25 1.25 0 0 1 18.793 21H9.06a1.25 1.25 0 0 1-.559-.132L6.764 20H3.25C2.56 20 2 19.44 2 18.75v-8.5C2 9.56 2.56 9 3.25 9h3.274l4.506-5.545ZM8 10.355v8.027L9.236 19h8.936l1.62-8.5h-5.58a1.5 1.5 0 0 1-1.499-1.455l-.131-4.33L8 10.356Zm10.056 9.255ZM4 11v7h2v-7H4Zm14.793 8.75.145.027Z" clip-rule="evenodd"/> 514</svg> 515</span>Luetuimmat</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/nakoislehti/"><span class="diks-icon diks-hide-above-large" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 516 <path fill-rule="evenodd" d="M4 2H20V22H4V2ZM6 4V20H18V4H6ZM8 6H16V12H8V6ZM10 8V10H14V8H10ZM16 15H8V13H16V15ZM16 18H8V16H16V18Z" clip-rule="evenodd"/> 517</svg> 518</span>Lehdet</a></li><li class="diks-navigation__item diks-navigation__item--button diks-navigation__item--align-right diks-hide-above-medium diks-hide-from-subscribers" ><a class="diks-navigation__link diks-bc-order-button" href="/jatka/">Tilaa</a></li></ul> 519 </nav> 520 </div> 521 </div><div id="diks-dropdown-navigation-shade" class="diks-dropdown-navigation-shade"></div></header>
521<script src="/theme/css/includes/waypoints/lib/noframework.waypoints.min.js"></script>
521 522
522<script> 523 // Fix forEach for IE 524 if (window.NodeList && !NodeList.prototype.forEach) { 525 NodeList.prototype.forEach = Array.prototype.forEach; 526 } 527 528 // Element.closest() needs a polyfill for older browsers. 529 // While we only need the closest() functionality for mobile browsers, 530 // we don't want the code to fail even on old desktop browsers. 531 // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill 532 // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Browser_compatibility 533 if (!Element.prototype.matches) { 534 Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 535 } 536 537 if (!Element.prototype.closest) { 538 Element.prototype.closest = function(s) { 539 var el = this; 540 541 do { 542 if (el.matches(s)) return el; 543 el = el.parentElement || el.parentNode; 544 } while (el !== null && el.nodeType === 1); 545 return null; 546 }; 547 } 548 549 (function () { 550 if (typeof JankkoSSOClient !== 'undefined') { 551 var stringToHTML = function (htmlString) { 552 var div = document.createElement('div'); 553 div.innerHTML = htmlString.trim(); 554 return div.firstChild; 555 }; 556 557 var showUserRelatedItems = function(personalData) { 558 var usernameElement = document.querySelector('#diks-sso-username'); 559 if (usernameElement) { 560 usernameElement.innerHTML = personalData.full_name; 561 } 562 563 var linksElement = document.querySelector('#diks-sso-links'); 564 if (linksElement) { 565 var myAccountLink = stringToHTML('<li class="diks-navigation__item"><a class="diks-navigation__link" href="'+JankkoSSOClient.serviceUrls.myAccount+'">Omat tiedot</a></li>'); 566 var logoutForm = stringToHTML('<li class="diks-navigation__item diks-navigation__item--logout"><form id="logout-form" action="'+JankkoSSOClient.serviceUrls.logout+'" method="post"><input class="diks-navigation__link" type="submit" value="Kirjaudu ulos"></form></li>'); 567 linksElement.insertBefore(myAccountLink, linksElement.childNodes[0]); 568 linksElement.appendChild(logoutForm); 569 } 570 571 var htmlElement = document.querySelector('.diks-user--is-not-logged-in'); // Class is set to main html element 572 if (htmlElement) { 573 htmlElement.classList.replace('diks-user--is-not-logged-in', 'diks-user--is-logged-in'); 574 } 575 } 576 577 var showMenuLinksForLoggedOutUser = function() { 578 const linksElement = document.querySelector('#diks-sso-links'); 579 if (!linksElement) { 580 return; 581 } 582 583 // Pidetään vain tietyt query-parametrit. Alunperin tässä poistettiin kaikki query-parametrit. 584 // @todo Selvitetään voisiko tässä sallia kaikki query-parametrit. 585 const currentUrlObject = new URL(window.location.href); 586 const returnUrlObject = new URL(`${currentUrlObject.origin}${currentUrlObject.pathname}`); 587 const allowedParams = ['limit-active-products']; 588 allowedParams.forEach(function(name) { 589 if (currentUrlObject.searchParams.get(name)) { 590 returnUrlObject.searchParams.set(name, currentUrlObject.searchParams.get(name)); 591 } 592 }); 593 594 const loginPageUrlObject = new URL(`${window.location.origin}/kirjaudu/`); 595 loginPageUrlObject.searchParams.set('returnUrl', returnUrlObject.toString()); 596 const loginLinkString = `<li class="diks-navigation__item"><a class="diks-navigation__link" href="${loginPageUrlObject.toString()}">Kirjaudu</a></li>`; 597 598 linksElement.insertBefore(stringToHTML(loginLinkString), linksElement.childNodes[0]); 599 } 600 601 var showCompanyUserRelatedItems = function(companyData) { 602 var htmlElement = document.querySelector('.diks-user--is-not-company-subscriber'); // Class is set to main html element 603 var permissions = companyData?.company_permissions || []; 604 if (htmlElement && permissions.length) { 605 htmlElement.classList.replace('diks-user--is-not-company-subscriber', 'diks-user--is-company-subscriber'); 606 } 607 } 608 609 document.addEventListener("DOMContentLoaded", async function() { 610 try { 611 const data = await JankkoSSOClient.getSession(); 612 if (data.company?.company_user_id) { 613 showCompanyUserRelatedItems(data.company); 614 }
615 if (data.personal?.personal_user_id) { 616 showUserRelatedItems(data.personal); 617 } else { 618 showMenuLinksForLoggedOutUser(); 619 } 620 } catch (error) { 621 showMenuLinksForLoggedOutUser(); 622 } 623 }); 624 } 625 }()); 626 627 628 ////////////////////////////////////////////////////////////////////////////////////////// 629 // NAVIGATIONS 630 ////////////////////////////////////////////////////////////////////////////////////////// 631 632 // Toggle icon inside a toggler 633 function toggleTogglerIcon(toggler) { 634 togglerIcons = toggler.querySelectorAll('.diks-icon'); 635 if ( togglerIcons.length > 1 ) { 636 for (var j= 0; j < togglerIcons.length; j++) { 637 togglerIcons[j].classList.toggle('diks-icon--hidden'); 638 } 639 } 640 } 641 642 // Function for closing all dropdown navigations 643 function closeAllDropdownNavigations() { 644 closeMainDropdownNavigation(); 645 closeUserDropdownNavigation(); 646 } 647 648 // Close main nav or user nav if hidden screen reader only close navigation button is clicked 649 let closeDropdownMainNav = document.getElementById('diks-close-dropdown-main-nav'); 650 let closeDropdownUserNav = document.getElementById('diks-close-dropdown-user-nav'); 651 if ( closeDropdownMainNav ) { 652 closeDropdownMainNav.addEventListener('click', function() { 653 closeMainDropdownNavigation(); 654 }); 655 } 656 if ( closeDropdownUserNav ) { 657 closeDropdownUserNav.addEventListener('click', function(e) { 658 e.stopPropagation(); 659 closeUserDropdownNavigation(); 660 }); 661 } 662 663 // Trap focus inside opened dropdown navigation 664 document.addEventListener('keydown', function(event) { 665 // Initialize variables 666 var ssoLinks = document.getElementById('diks-sso-links'); 667 var linksUserNav = ""; 668 var firstElUserNav = ""; 669 var lastElUserNav = ""; 670 var mainDropdownLastNavLinks = document.getElementById('dropdown-customer-nav'); // Last navigation element inside of main dropdown navigation 671 var linksMainDropdownNav = ""; 672 var firstElMainDropdownNav = "" 673 var lastElMainDropdownNav = ""; 674 675 // Set user nav variable values if SSO links exist 676 if (ssoLinks) { 677 linksUserNav = ssoLinks.querySelectorAll('.diks-navigation__link'); 678 firstElUserNav = document.getElementById('diks-close-dropdown-user-nav'); 679 lastElUserNav = linksUserNav[linksUserNav.length - 1]; 680 } 681 682 // Set main dropdown nav variable values if main dropdown last nav links exist 683 if (mainDropdownLastNavLinks) { 684 linksMainDropdownNav = mainDropdownLastNavLinks.querySelectorAll('.diks-navigation__link'); 685 firstElMainDropdownNav = document.getElementById('diks-close-dropdown-main-nav'); 686 lastElMainDropdownNav = linksMainDropdownNav[linksMainDropdownNav.length - 1]; 687 } 688 689 // If darkmode-toggler is found set it as the last element of main dropdown nav 690 if ( document.getElementById('diks-darkmode-toggler') ) { 691 lastElMainDropdownNav = document.getElementById('diks-darkmode-toggler'); 692 } 693 694 // Close all dropdown navigations & reposition fixed header when ESC key is pressed 695 if (event.key === "Escape" || event.key === "Esc") { 696 closeAllDropdownNavigations(); 697 } 698 // Trap focus inside user navigation and/or main dropdown navigation when they are open 699 if (event.keyCode === 9) { 700 if (event.shiftKey && (document.activeElement === firstElUserNav || document.activeElement === firstElMainDropdownNav)) { 701 event.preventDefault(); 702 if (document.activeElement === firstElUserNav) { 703 lastElUserNav.focus(); 704 } 705 else if ( document.activeElement === firstElMainDropdownNav ) { 706 lastElMainDropdownNav.focus(); 707 } 708 } 709 else if (!event.shiftKey && (document.activeElement === lastElUserNav || document.activeElement === lastElMainDropdownNav)) { 710 event.preventDefault(); 711 if (document.activeElement === lastElUserNav) { 712 firstElUserNav.focus(); 713 } 714 else if ( document.activeElement === lastElMainDropdownNav ) { 715 firstElMainDropdownNav.focus(); 716 } 717 } 718 } 719 }); 720 721 722 ////////////////////////////////////////////////////////////////////////////////////////// 723 // User navigation 724 ////////////////////////////////////////////////////////////////////////////////////////// 725 726 let userDropdownNavigation = document.getElementById('diks-user-navigation'); // user dropdown navigation 727 let userDropdownNavigationToggler = document.getElementById('diks-sso-user'); // user dropdown navigation toggler button (opens and closes user dropdown navigation) 728 let userDropdownNavigationCloseButton = document.getElementById('diks-close-dropdown-main-nav'); // Hidden screen-reader-only close button inside user dropdown navigation 729 730 // Close user dropdown navigation if hidden screen-reader-only close button is clicked 731 if ( userDropdownNavigationCloseButton ) { 732 userDropdownNavigationCloseButton.addEventListener('click', function() { 733 closeUserDropdownNavigation(); 734 }); 735 } 736 737 function closeUserDropdownNavigation() { 738 if (userDropdownNavigation) { 739 if (userDropdownNavigation.classList.contains('diks-user-navigation--is-open')) { 740 // Close user dropdown nav by removing --is-open class 741 userDropdownNavigation.classList.remove('diks-user-navigation--is-open'); 742 // Remove --is-open class from user dropdown navigation toggler 743 userDropdownNavigationToggler.classList.remove('diks-dropdown-toggle--is-open'); 744 // Toggle icon 745 toggleTogglerIcon(userDropdownNavigationToggler); 746
747 // Set aria-expanded to false for user dropdown toggler 748 userDropdownNavigationToggler.setAttribute('aria-expanded', 'false'); 749 } 750 } 751 } 752 753 // User Navigation Dropdown 754 if (userDropdownNavigation) { 755 let userDropdownNavigationAriaControls = userDropdownNavigationToggler.getAttribute('data-diks-toggle'); // aria-controls value for user dropown navigation toggler 756 userDropdownNavigationToggler.setAttribute('aria-controls', userDropdownNavigationAriaControls); 757 userDropdownNavigationToggler.addEventListener('click', function(e) { 758 e.preventDefault(); 759 // If the main dropdown navigation is already open (contains --is-open class) close it 760 if ( (userDropdownNavigation).classList.contains('diks-user-navigation--is-open') ) { 761 closeUserDropdownNavigation(); 762 } 763 // If the main dropdown navigation isn't open (doesn't contain --is-open class) open it 764 else { 765 // If other toggles are open, close them 766 document.querySelectorAll('.diks-user-navigation--is-open').forEach(function(item) { 767 item.classList.remove('diks-user-navigation--is-open'); 768 userDropdownNavigationToggler.classList.remove('diks-dropdown-toggler--is-open'); 769 }); 770 771 // Toggle icon 772 toggleTogglerIcon(userDropdownNavigationToggler); 773 774 // Set aria-expanded 775 userDropdownNavigationToggler.setAttribute('aria-expanded', 'true'); 776 777 // Open this toggle 778 userDropdownNavigation.classList.add('diks-user-navigation--is-open'); 779 780 // Close main dropdown navigation if it's open 781 closeMainDropdownNavigation(); 782 783 // Add event listener to window when user nav toggler is clicked and user nav is open 784 window.addEventListener('click', function(e){ 785 if (document.querySelector('.diks-user-navigation-wrapper').contains(e.target)){ 786 // Clicked inside user nav, do nothing 787 } 788 else { 789 // Clicked outside user nav, close user nav 790 closeUserDropdownNavigation(); 791 } 792 }); 793 794 } 795 }); 796 } 797 798 ////////////////////////////////////////////////////////////////////////////////////////// 799 // Main navigation 800 ////////////////////////////////////////////////////////////////////////////////////////// 801 802 let mainDropdownNavigation = document.getElementById('diks-dropdown-navigation'); // main dropdown navigation 803 let mainDropdownNavigationToggler = document.getElementById('diks-dropdown-toggle'); // main dropdown navigation toggler button (opens and closes main dropdown navigation) 804 let mainDropdownNavigationShade = document.querySelector('.diks-dropdown-navigation-shade'); // shade effect that is visible when main dropdown navigation is open 805 let mainDropdownNavigationCloseButton = document.getElementById('diks-close-dropdown-main-nav'); // Hidden screen-reader-only close button inside main dropdown navigation 806 807 // Close main dropdown navigation if hidden screen-reader-only close button is clicked 808 if ( mainDropdownNavigationCloseButton ) { 809 mainDropdownNavigationCloseButton.addEventListener('click', function() { 810 closeMainDropdownNavigation(); 811 }); 812 } 813 814 // Function for closing main dropdown navigation 815 function closeMainDropdownNavigation() { 816 // Main dropdown navigation 817 if (mainDropdownNavigation) { 818 if (mainDropdownNavigation.classList.contains('diks-dropdown-navigation--is-open')) { 819 // Close main dropdown nav by removing --is-open class 820 mainDropdownNavigation.classList.remove('diks-dropdown-navigation--is-open'); 821 // Remove --is-open class from main dropdown navigation toggler 822 mainDropdownNavigationToggler.classList.remove('diks-dropdown-toggle--is-open'); 823 // Toggle icon 824 toggleTogglerIcon(mainDropdownNavigationToggler); 825 826 // Set aria-expanded to false for main dropdown toggler 827 mainDropdownNavigationToggler.setAttribute('aria-expanded', 'false'); 828 829 // Remove --is-open class from body 830 document.body.classList.remove('diks-body--dropdown-navigation-is-open'); 831 832 // Turn off shade effect 833 mainDropdownNavigationShade.classList.remove('diks-dropdown-navigation-shade--is-visible'); 834 } 835 } 836 } 837 838 839 // Main Navigation Dropdown 840 if (mainDropdownNavigation) {
841 let mainDropdownNavigationAriaControls = mainDropdownNavigationToggler.getAttribute('data-toggle'); // aria-controls value for main dropown navigation toggler 842 mainDropdownNavigationToggler.setAttribute('aria-controls', mainDropdownNavigationAriaControls); 843 mainDropdownNavigationToggler.addEventListener('click', function(e) { 844 e.preventDefault(); 845 // If the main dropdown navigation is already open (contains --is-open class) close it 846 if ( (mainDropdownNavigation).classList.contains('diks-dropdown-navigation--is-open') ) { 847 closeMainDropdownNavigation(); 848 } 849 // If the main dropdown navigation isn't open (doesn't contain --is-open class) open it 850 else { 851 // If other toggles are open, close them 852 document.querySelectorAll('.diks-dropdown-navigation--is-open').forEach(function(item) { 853 item.classList.remove('diks-dropdown-navigation--is-open'); 854 mainDropdownNavigationToggler.classList.remove('diks-dropdown-toggler--is-open'); 855 }); 856 857 // Toggle icon 858 toggleTogglerIcon(mainDropdownNavigationToggler); 859 860 // Set aria-expanded 861 mainDropdownNavigationToggler.setAttribute('aria-expanded', 'true'); 862 863 // Open this toggle 864 mainDropdownNavigation.classList.add('diks-dropdown-navigation--is-open'); 865 // Add is-open class to body 866 document.body.classList.add('diks-body--dropdown-navigation-is-open'); 867 // Turn on shade effect 868 mainDropdownNavigationShade.classList.add('diks-dropdown-navigation-shade--is-visible'); 869 870 // Close main Dropdown Navigation when visible shade area is clicked 871 document.querySelector('.diks-dropdown-navigation-shade--is-visible').addEventListener('click', function() { 872 closeMainDropdownNavigation(); 873 }); 874 875 // Close user dropdown navigation if it's open 876 closeUserDropdownNavigation(); 877 878 } 879 }); 880 } 881 882 883</script>
883 884 885 886 887 888 889 890 891 <div class="diks-note-wrapper "><div class="diks-container diks-container--narrower-mobile"> 892 <div id="diks-segment-notes"></div><div id="diks-bc-notes"></div></div></div>
892<script> 893 let segmentTeasersContainer = document.getElementById("diks-segment-notes"); 894 895 (function() { 896 function getCookie(name) { 897 name = name + '='; 898 const decodedCookie = decodeURIComponent(document.cookie); 899 const cookies = decodedCookie.split(';'); 900 901 for (let i = 0; i < cookies.length; i++) { 902 const cookie = cookies[i].trim(); 903 if (cookie.indexOf(name) == 0) { 904 return cookie.substring(name.length, cookie.length); 905 } 906 } 907 } 908 909 function injectSegmentTeasers(segmentsQueryString) { 910 var xhttp = new XMLHttpRequest(); 911 912 xhttp.onreadystatechange = function() { 913 if (this.readyState == 4 && this.status == 200) { 914 var segmentTeasers = this.responseText.trim(); 915 916 if (segmentTeasers) { 917 if (segmentTeasersContainer) { 918 segmentTeasersContainer.innerHTML = segmentTeasers; 919 } 920 } 921 else { 922 // Remove segment teaser container if there are no segment teasers 923 if (segmentTeasersContainer) { 924 segmentTeasersContainer.remove(); 925 } 926 } 927 } 928 }; 929 930 xhttp.open("GET", "/.ajax/segmentTeaser?" + segmentsQueryString, true); 931 xhttp.send(); 932 } 933 934 var segmentsCookie = getCookie('jankkosegments'); 935 936 if (segmentsCookie) { 937 var segmentsData = JSON.parse(segmentsCookie); 938 var segments = segmentsData.segments; 939 940 if (segments && typeof segments === 'object') { 941 var segmentsQueryString = ""; 942 943 Object.keys(segments).forEach(function(key, index) { 944 segmentsQueryString = index === 0 ? "" : segmentsQueryString + "&"; 945 var value = segments[key]; 946 947 if (Array.isArray(value)) { 948 value = value.join(','); 949 } 950 951 segmentsQueryString = segmentsQueryString + key + "=" + value; 952 }); 953 954 injectSegmentTeasers(segmentsQueryString); 955 } 956 } 957 else { 958 // Remove segment teaser container if there are no segment teasers 959 if (segmentTeasersContainer) { 960 segmentTeasersContainer.remove(); 961 } 962 } 963 })(); 964</script>
964 965 966 <div class="diks-custom-page diks-apps"> 967 <div class="diks-container"> 968 <div class="diks-grid"> 969 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-16"><nav aria-label="Murupolku"> 970 <ul class="diks-breadcrumb"><li class="diks-breadcrumb__item"><a class="diks-breadcrumb__link" href="/">Etusivu</a></li><li class="diks-breadcrumb__item"><span class="diks-breadcrumb__sub-item">Sovellus</span></li></ul> 971 </nav></div> 972 </div> 973 <main id="sisalto"> 974 <div class="diks-apps__content-wrapper"> 975 <div class="diks-grid"> 976 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-2"></div> 977 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-12"> 978 <h1 class="diks-title diks-title--size-3xl" >Sovellus</h1> 979 </div> 980 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-2"></div> 981 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-2"></div><div class="diks-apps-installation-wrapper diks-column diks-column--span-4 diks-column--m-span-4 diks-column--l-span-6 diks-column--xl-span-6"> 982 <div class="diks-apps__icon-wrapper"> 983 <span class="diks-icon diks-icon--size-l diks-icon--color-primary" aria-hidden="true"><svg role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 984 <path fill-rule="evenodd" d="M5 2H19V22H5V2ZM7 4V20H17V4H7ZM15 19H9V17H15V19Z" clip-rule="evenodd"/> 985</svg> 986</span> 987 </div> <h2 class="diks-title diks-title--size-xl" >Sovellus</h2><p>Sovellus sisältää tuoreet juttumme, joita ilmestyy ympäri vuorokauden vuoden jokaisena päivänä sekä näköislehtemme liitteineen sekä näköislehtien arkiston. Asenna sovellus laitteesi sovelluskaupasta.</p><div class="diks-apps-image-wrapper"> 988 <a class="diks-apps__app-link diks-hide-on-android" href="https://apps.apple.com/fi/app/loviisan-sanomat/id6740268457"><img class="diks-apps__app-image" src="https://a.loviisansanomat.fi/styles/e5576057/images/default/appstore-badge.svg" alt="Lataa sovellus App Storesta"></a> 989 <a class="diks-apps__app-link diks-hide-on-ios" href="https://play.google.com/store/apps/details?id=fi.media.loviisansanomat"><img class="diks-apps__app-image" src="https://a.loviisansanomat.fi/styles/e5576057/images/default/google-play-badge.svg" alt="Lataa sovellus Google Play -kaupasta"></a> 990 </div></div> 991 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-2"></div> 992 </div> 993 </div> 994 </main> 995 </div> 996 </div> 997 998 <footer class="diks-footer"><div class="diks-container diks-container--narrow-mobile diks-container--full-width-before-l"> 999 <div class="diks-footer__top"> <nav class="diks-navigation-wrapper " aria-label="Osastovalikko"><ul class="diks-navigation diks-navigation--row diks-navigation--light diks-navigation--centered diks-navigation--mobile-row diks-navigation--draggable diks-navigation--size-xs diks-navigation--active-subtle" ><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/mysteerimaistaja"draggable="false">Mysteerimaistaja</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/Hyv%C3%A4t_uutiset"draggable="false">Hyvät uutiset</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/maakunta-uusimaa"draggable="false">Uusimaa 360</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="/aihe/paikalliset-yrittajat"draggable="false">Paikalliset yrittäjät</a></li></ul> 1000 </nav></div> 1001 </div><div class="diks-container"><div class="diks-footer__main"> 1002 <div class="diks-grid"> 1003 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-4 diks-column--xl-span-4"> 1004 <p><img src="https://a.loviisansanomat.fi/styles/e5576057/images/logos/loviisansanomat.svg" class="diks-logo diks-logo--default diks-footer__main-logo--wide" alt="Loviisan Sanomat"><img src="https://a.loviisansanomat.fi/styles/e5576057/images/logos/loviisansanomat-white.svg" class="diks-logo diks-logo--darkmode diks-footer__main-logo--wide" alt="Loviisan Sanomat"></p> 1005 <p><strong>Postiosoite:</strong> Lundinkatu 8, 06100 Porvoo<br><strong>Käyntiosoite:</strong> Lundinkatu 8, 06100 Porvoo (käynti Runeberginkatu 31)<br><strong>Vt. päätoimittaja:</strong> Marko Enberg</p><div class="diks-footer__main-secondary-logos-container"><div class="diks-footer__main-secondary-logo"><a href="https://vastuullistajournalismia.fi/"><img src="https://a.loviisansanomat.fi/styles/e5576057/images/logos/vastuullista-journalismia.png" loading="lazy" alt="Vastuullisen journalismin merkki kertoo, että sitä käyttävä media on sitoutunut noudattamaan Julkisen sanan neuvoston laatimia Journalistin ohjeita."></a></div></div><div class="diks-footer__main-links-wrapper"> 1006 <div class="diks-column diks-column--span-2"><a class="diks-footer__main-link" href="https://www.keskisuomalainen.com/tietosuojalauseke/">Tietosuojalauseke</a><a class="diks-footer__main-link" href="javascript:window.gravito.cmp.openPreferences();">Evästevalinnat</a><a class="diks-footer__main-link" href="https://www.keskisuomalainen.com/kayttoehdot/">Käyttöehdot</a><a class="diks-footer__main-link" href="https://keskisuomalainen.com/medianvapausasetus/">Medianvapausasetus</a><a class="diks-footer__main-link" href="https://oma.media.fi/tekoaly-journalismissamme/">
1006Tekoäly journalismissamme</a></div> 1007 <div class="diks-column diks-column--span-2"><a class="diks-footer__main-link" href="https://oma.media.fi/loviisan-sanomat/">Asiakaspalvelu</a><a class="diks-footer__main-link" href="https://meks.fi/mainonta/alueet/etela-suomen-media/">Mediamyynti</a><a class="diks-footer__main-link" href="https://oma.media.fi/loviisan-sanomat/yhteystiedot/">Yhteystiedot</a></div> 1008 </div></div> 1009 1010 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-4 diks-column--xl-span-5"><h2 class="diks-footer__main-title">Mistä tänään puhutaan?</h2><form id="lianamailer-footer" class="diks-newsletter-form js-diks-recaptcha-newsletter-form" action="https://sisaltokirjeet.media.fi/account" method="post"> 1011 <input type="hidden" name="join" value="781861"><input type="hidden" name="consent[]" value="2963-1-fi"><div class="diks-form__field-wrapper"> 1012 <label class="diks-form__label" for="email">Sähköpostiosoite</label> 1013 <input class="diks-form__field" type="email" name="email" id="lianamailer-footer-email" size="30" value=""> 1014 </div> 1015 <div class="diks-form__field-wrapper"> 1016 <input class="diks-form__submit g-recaptcha" type="submit" data-sitekey="6Lfmg9UZAAAAAORf4dzYH7iNb-xFbjh-D45PEgqq" data-callback="onSubmitFooter" value="Tilaa uutiskirje"> 1017 </div> 1018 </form></div> 1019 1020 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-4 diks-column--xl-span-5"> 1021 <h2 class="diks-footer__main-title">Sovellus</h2><p>Sovellus sisältää tuoreet juttumme, joita ilmestyy ympäri vuorokauden vuoden jokaisena päivänä sekä näköislehtemme liitteineen sekä näköislehtien arkiston. Asenna sovellus laitteesi sovelluskaupasta.</p><div class="diks-footer__main-app-image-wrapper"> 1022 <a class="diks-apps__app-link diks-hide-on-android" href="https://apps.apple.com/fi/app/loviisan-sanomat/id6740268457"><img class="diks-apps__app-image" src="https://a.loviisansanomat.fi/styles/e5576057/images/default/appstore-badge.svg" loading="lazy" alt="Lataa sovellus App Storesta"></a> 1023 <a class="diks-apps__app-link diks-hide-on-ios" href="https://play.google.com/store/apps/details?id=fi.media.loviisansanomat"><img class="diks-apps__app-image" src="https://a.loviisansanomat.fi/styles/e5576057/images/default/google-play-badge.svg" loading="lazy" alt="Lataa sovellus Google Play -kaupasta"></a> 1024 </div> 1025 1026 1027 </div> 1028 </div> 1029 </div><div class="diks-footer__bottom"> 1030 <div class="diks-footer__bottom-row"><div class="diks-footer__bottom-logo-wrapper"><a href="https://www.keskisuomalainen.com/"><img class="diks-footer__bottom-logo" src="https://a.loviisansanomat.fi/styles/e5576057/images/logos/keskisuomalainen-sign.svg" loading="lazy" alt="Keskisuomalainen Oyj"></a></div><span>Kuulumme Mediakonserni Keskisuomalaiseen</span></div> 1031 <div class="diks-footer__bottom-link-farm-wrapper"> 1032 <p><a class='diks-footer__bottom-link-farm-item' href='https://www.aamuposti.fi/'>Aamuposti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.avecmedia.fi/'>Avec</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.esaimaa.fi/'>Etelä-Saimaa</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.ess.fi/'>Etelä-Suomen Sanomat</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.forssanlehti.fi/'>Forssan Lehti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.hankasalmensanomat.fi/'>Hankasalmen Sanomat </a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.heinavedenlehti.fi/'>Heinäveden Lehti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.helsinginuutiset.fi/'>Helsingin Uutiset</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.hameensanomat.fi/'>Hämeen Sanomat</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.hameenlinnankaupunkiuutiset.fi/'>Hämeenlinnan Kaupunkiuutiset</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.iisalmensanomat.fi/'>Iisalmen Sanomat</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.itahame.fi/'>Itä-Häme</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.ita-savo.fi/'>Itä-Savo</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.joroistenlehti.fi/'>Joroisten Lehti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.juvanlehti.fi/'>Juvan Lehti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.kaakonkulma.fi/'>Kaakonkulma</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.kangasniemenlehti.fi/'>Kangasniemen Kunnallislehti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.karjalainen.fi/'>Karjalainen</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.heili.fi/'>Karjalan Heili</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.karkkilalainen.fi/'>Karkkilalainen</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.keski-hame.fi/'>Keski-Häme</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.keski-uusimaa.fi/'>Keski-Uusimaa</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.keskilaakso.fi/'>Keskilaakso</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.ksml.fi/'>Keskisuomalainen</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.koillis-savo.fi/'>Koillis-Savo</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.kouvolansanomat.fi/'>Kouvolan Sanomat</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.kymensanomat.fi/'>Kymen Sanomat</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.lappeenrannanuutiset.fi/'>Lappeenrannan Uutiset</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.laukaa-konnevesi.fi/'>Laukaa-Konnevesi</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.lieksanlehti.fi/'>Lieksan Lehti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.lopenlehti.fi/'>Lopen Lehti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.loviisansanomat.fi/'>Loviisan Sanomat</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.luumaenlehti.fi/'>Luumäen Lehti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.lansisaimaa.fi/'>Länsi-Saimaan Sanomat</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.lansi-savo.fi/'>Länsi-Savo</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.lansi-uusimaa.fi/'>Länsi-Uusimaa</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.lansivayla.fi/'>Länsiväylä</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.mattijaliisa.fi/'>Matti ja Liisa</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.meksi.fi/'>Meksi Urheilumedia</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.miilu.fi/'>Miilu</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.mikkelinkaupunkilehti.fi/'>Mikkelin Kaupunkilehti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.mantsalanuutiset.fi/'>Mäntsälän Uutiset</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.aamuposti.fi/aihe/Nurmij%C3%A4rvi'>Nurmijärven Uutiset</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.outokummunseutu.fi/'>Outokummun Seutu</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.joutsenolehti.fi/'>Paikallislehti Joutseno</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.prsanomat.fi/'>Parikkalan-Rautjärven Sanomat</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.pernionseudunlehti.fi/'>Perniönseudun Lehti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.pieksamaenlehti.fi/'>Pieksämäen Lehti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.pielavesi-keitele.fi/'>Pielavesi-Keitele</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.pielisjokiseutu.fi/'>Pielisjokiseutu</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.pitajalainen.fi/'>Pitäjäläinen</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.pitajanuutiset.fi/'>Pitäjänuutiset</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.pogostansanomat.fi/'>Pogostan Sanomat</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.puruvesi.net/'>Puruvesi</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.pyhtaanlehti.fi/'>Pyhtäänlehti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.salonjokilaakso.fi/'>Salonjokilaakso</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.sampolehti.fi/'>Sampo</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.savonsanomat.fi/'>Savon Sanomat</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.sinunsavo.fi/'>Sinun Savo</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.sisa-savolehti.fi/'>Sisä-Savo</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.sisasuomenlehti.fi/'>Sisä-Suomen Lehti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.soisalonseutu.fi/'>Soisalon Seutu</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.sjl.fi/'>Suur-Jyväskylän Lehti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.tamperelainen.fi/'>Tamperelainen</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.tollotin.fi/'>Töllötin</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.uusimaa.fi/'>Uusimaa</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.uutis-jousi.fi/'>Uutis-Jousi</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.uutisvuoksi.fi/'>Uutisvuoksi</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.vantaansanomat.fi/'>Vantaan Sanomat</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.vihdinuutiset.fi/'>Vihdin Uutiset</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.viikkosavo.fi/'>Viikkosavo</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.viispiikkinen.fi/'>
1032Viispiikkinen</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.viitasaarenseutu.fi/'>Viitasaaren Seutu</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.warkaudenlehti.fi/'>Warkauden Lehti</a> • <a class='diks-footer__bottom-link-farm-item' href='https://www.ylakarjala.fi/'>Ylä-Karjala</a></p><p>Kaikki sisällöt voidaan julkaista kaikissa Mediakonserni Keskisuomalaisen medioissa.</p> 1033 </div> 1034 </div></div> 1035</footer> 1036 1037 1038
1038<script> 1039 if (!DOMTokenList.prototype.replace) { 1040 // IE Polyfill 1041 DOMTokenList.prototype.replace = function (a, b) { 1042 if (this.contains(a)) { 1043 this.add(b); 1044 this.remove(a); 1045 return true; 1046 } 1047 return false; 1048 } 1049 } 1050 1051 document.querySelector('.diks-no-js').classList.replace('diks-no-js', 'diks-js'); 1052 1053 // User agent sniffing is not reliable and it's going away. 1054 // Use only to sprinkle a little bit of progressive enhancement on top. 1055 // Dear Apple, stop lying, iPad on iOS 13 is not a Mac. You're turning into 90s Microsoft. 1056 var userAgent = navigator.userAgent || navigator.vendor || window.opera; 1057 if (/android/i.test(userAgent)) { 1058 document.querySelector('html').classList.add('diks-user-agent--android'); 1059 } else if (/iPad|iPhone|iPod/i.test(userAgent) && !window.MSStream) { 1060 document.querySelector('html').classList.add('diks-user-agent--ios'); 1061 } else if (/macintosh/i.test(userAgent) && navigator.maxTouchPoints > 1) { 1062 document.querySelector('html').classList.add('diks-user-agent--ios'); 1063 } 1064</script>
1064 1065
1066<script> 1067 // Fix forEach for IE 1068 if (window.NodeList && !NodeList.prototype.forEach) { 1069 NodeList.prototype.forEach = Array.prototype.forEach; 1070 } 1071 1072 // Element.closest() needs a polyfill for older browsers. 1073 // While we only need the closest() functionality for mobile browsers, 1074 // we don't want the code to fail even on old desktop browsers. 1075 // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill 1076 // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Browser_compatibility 1077 if (!Element.prototype.matches) { 1078 Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 1079 } 1080 1081 if (!Element.prototype.closest) { 1082 Element.prototype.closest = function(s) { 1083 var el = this; 1084 1085 do { 1086 if (el.matches(s)) return el; 1087 el = el.parentElement || el.parentNode; 1088 } while (el !== null && el.nodeType === 1); 1089 return null; 1090 }; 1091 } 1092 1093 function setAriaExpanded(toggler, ariaExpandedValue) { 1094 // Set aria-expanded attribute of dropdown toggler 1095 // If the toggler contains a button, set the aria-expanded attribute for the button instead 1096 if ( toggler.querySelector('button') != null ) { 1097 toggler.querySelector('button').setAttribute('aria-expanded', ariaExpandedValue); 1098 } 1099 else { 1100 toggler.setAttribute('aria-expanded', ariaExpandedValue); 1101 } 1102 } 1103 1104 function toggleElement(target, toggleClass, toggler) { 1105 if (toggleClass) { 1106 var isOpenClass = toggleClass + '--is-open'; 1107 var isClosedClass = toggleClass + '--is-closed'; 1108 1109 if (target.classList.contains(isOpenClass)) { 1110 // Close this toggle 1111 target.classList.remove(isOpenClass); 1112 target.classList.add(isClosedClass); 1113 1114 // Set aria-expanded to false for the toggler 1115 setAriaExpanded(toggler, 'false'); 1116 1117 } else if (target.classList.contains(isClosedClass)) { 1118 // Open this toggle 1119 target.classList.remove(isClosedClass); 1120 target.classList.add(isOpenClass); 1121 1122 // Set aria-expanded to true for the toggler 1123 setAriaExpanded(toggler, 'true'); 1124 } else { 1125 // Open this toggle as a fallback 1126 target.classList.add(isOpenClass); 1127 1128 // Set aria-expanded to true for the toggler 1129 setAriaExpanded(toggler, 'true'); 1130 } 1131 } else { 1132 if (window.getComputedStyle(target).display !== 'none') { 1133 target.style.display = 'none'; 1134 } else { 1135 target.style.display = 'block'; 1136 } 1137 } 1138 }; 1139 1140 document.querySelectorAll('.js-diks-toggler').forEach(function(toggler) { 1141 var toggleId = toggler.getAttribute('data-diks-toggle'); 1142 var target = document.getElementById(toggleId); 1143 var eventListenerAttached = toggler.getAttribute('data-diks-event-click'); 1144 1145 if (target && !eventListenerAttached) { 1146 1147 // Set aria-controls of toggler 1148 if ( toggler.querySelector('button') != null ) { 1149 toggler.querySelector('button').setAttribute('aria-controls', toggleId); 1150 } 1151 else { 1152 toggler.setAttribute('aria-controls', toggleId); 1153 } 1154 1155 toggler.addEventListener('click', function(e) { 1156 e.preventDefault(); 1157 1158 var toggleClass = toggler.getAttribute('data-diks-toggle-class'); 1159 1160 if (webShareAPIEnabled(toggleId)) { 1161 share(); 1162 } else { 1163 toggleElement(target, toggleClass, toggler); 1164 } 1165 }); 1166 1167 toggler.setAttribute('data-diks-event-click', true); 1168 } 1169 }); 1170 1171 // Web Share and Clipboard API capabilities 1172 1173 function webShareAPIEnabled(toggleId) { 1174 const webShareAPIEnabled = true; 1175 const webShareAPIDropdownShareIds = ["jaa","jakopainikkeet"]; 1176 const isMobileDevice = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); 1177 1178 return webShareAPIEnabled && webShareAPIDropdownShareIds.includes(toggleId) && isMobileDevice && navigator.share ? true : false; 1179 } 1180 1181 function share() { 1182 const metaTitleElement = document.querySelector('meta[property="og:title"]'); 1183 const metaDescriptionElement = document.querySelector('meta[name="description"]'); 1184 const metaUrlElement = document.querySelector('meta[property="og:url"]'); 1185 let title = ''; 1186 let description = ''; 1187 let url = document.location.href; 1188 1189 if (metaTitleElement && metaTitleElement.content) { 1190 title = metaTitleElement.content; 1191 } 1192 1193 if (metaDescriptionElement && metaDescriptionElement.content) { 1194 description = metaDescriptionElement.content; 1195 } 1196 1197 if (metaUrlElement && metaUrlElement.content) { 1198 url = metaUrlElement.content; 1199 } 1200 1201 navigator.share({ 1202 title: title, 1203 text: description, 1204 url: url 1205 }); 1206 } 1207 1208 document.querySelectorAll('.js-diks-share-clipboard').forEach(function(element) { 1209 element.addEventListener('click', function(e) { 1210 e.preventDefault(); 1211 1212 let url = document.location.href; 1213 const metaUrlElement = document.querySelector('meta[property="og:url"]'); 1214 1215 if (metaUrlElement && metaUrlElement.content) { 1216 url = metaUrlElement.content; 1217 } 1218 1219 // Copy URL to clipboard 1220 navigator.clipboard.writeText(url).then(function () { 1221 // Copying URL to clipboard succeeded 1222 const dropdownId = element.getAttribute('data-diks-dropdown-id'); 1223 // Find closest dropdown toggler 1224 let dropdownToggler = element.closest('.diks-dropdown').querySelector('.js-diks-toggler'); 1225 1226 if (dropdownId) { 1227 const dropdownElement = document.getElementById(dropdownId); 1228 1229 if (dropdownElement) { 1230 // Close currently open dropdown 1231 toggleElement(dropdownElement, 'diks-dropdown__content', dropdownToggler); 1232 } 1233 1234 // Show link copied notification text 1235 const notificationTextWrapperDiv = document.createElement('div'); 1236 const notificationTextDiv = document.createElement('div'); 1237 const notificationText = document.createTextNode('Linkki kopioitu leikepöydälle'); 1238 1239 notificationTextDiv.classList.add('diks-dropdown__notification-text'); 1240 notificationTextDiv.appendChild(notificationText); 1241 notificationTextWrapperDiv.classList.add('diks-dropdown__notification-text-wrapper'); 1242 notificationTextWrapperDiv.appendChild(notificationTextDiv); 1243 dropdownElement.parentNode.insertBefore(notificationTextWrapperDiv, null); 1244 1245 setTimeout(function () { 1246 notificationTextWrapperDiv.remove(); 1247 }, 5000); 1248 } 1249 }); 1250 }); 1251 }); 1252
1253 const initContentBlockToggleButtons = () => { 1254 const toggleContainers = document.querySelectorAll('[data-diks-init="toggle"]'); 1255 toggleContainers.forEach(container => { 1256 const toggleButton = container.querySelector('.diks-toggle-button'); 1257 const toggleContent = container.querySelector('.diks-toggle-content-container'); 1258 if (toggleButton && toggleContent) { 1259 toggleButton.addEventListener('click', () => { 1260 toggleElement(toggleContent, 'diks-toggle', toggleButton); 1261 }); 1262 } 1263 }); 1264 }; 1265 document.addEventListener('DOMContentLoaded', () => { 1266 initContentBlockToggleButtons(); 1267 }); 1268 1269</script>
1269 1270
1271<script> 1272 const useDragThreshold = true; 1273 1274 // Horizontally scrollable & draggable navigation 1275 class HorizontalScrollDragger { 1276 constructor(element) { 1277 this.slider = typeof element === 'string' ? document.querySelector(element) : element instanceof Element ? element : null; 1278 if (this.slider === null) return console.error('HorizontalScrollDragger: Element not found'); 1279 1280 this.isDown = false; 1281 this.preventClick = false; 1282 this.startX; 1283 this.scrollLeft; 1284 1285 this.dragThreshold = 5; 1286 this.dragSensitivity = 1; 1287 this.dragged = false; 1288 1289 this.init(); 1290 } 1291 1292 init() { 1293 this.slider.addEventListener('mousedown', (e) => this.handleMouseDown(e)); 1294 this.slider.addEventListener('mouseleave', () => this.handleMouseLeave()); 1295 this.slider.addEventListener('mouseup', () => this.handleMouseUp()); 1296 this.slider.addEventListener('mousemove', (e) => this.handleMouseMove(e)); 1297 this.slider.addEventListener('click', (e) => this.handleClick(e)); 1298 } 1299 1300 handleMouseDown(e) { 1301 this.isDown = true; 1302 this.slider.classList.add('diks-navigation--draggable-active'); 1303 this.startX = e.pageX - this.slider.offsetLeft; 1304 this.scrollLeft = this.slider.scrollLeft; 1305 this.preventClick = false; 1306 } 1307 1308 handleMouseLeave() { 1309 this.isDown = false; 1310 this.slider.classList.remove('diks-navigation--draggable-active'); 1311 } 1312 1313 handleMouseUp() { 1314 this.isDown = false; 1315 this.slider.classList.remove('diks-navigation--draggable-active'); 1316 } 1317 1318 handleMouseMove(e) { 1319 if (!this.isDown) return; 1320 1321 if ( useDragThreshold == true ) { 1322 const xWithThreshold = e.pageX - this.slider.offsetLeft; 1323 const delta = xWithThreshold - this.startX; 1324 1325 // If not yet dragging, check threshold 1326 if (!this.dragged && Math.abs(delta) > this.dragThreshold) { 1327 this.dragged = true; 1328 this.preventClick = true; 1329 1330 // Reset baseline so scrolling starts smoothly from here 1331 this.startX = xWithThreshold; 1332 this.scrollLeft = this.slider.scrollLeft; 1333 } 1334 1335 if (this.dragged) { 1336 e.preventDefault(); 1337 const walkWithThreshold = (xWithThreshold - this.startX) * this.dragSensitivity; // adjust sensitivity 1338 this.slider.scrollLeft = this.scrollLeft - walkWithThreshold; 1339 } 1340 } 1341 else { 1342 e.preventDefault(); 1343 const x = e.pageX - this.slider.offsetLeft; 1344 const walk = (x - this.startX) * this.dragSensitivity; // adjust sensitivity 1345 this.slider.scrollLeft = this.scrollLeft - walk; 1346 this.preventClick = true; 1347 } 1348 1349 } 1350 1351 handleClick(e) { 1352 if ( useDragThreshold == true && this.preventClick && this.dragged ) { 1353 e.preventDefault(); 1354 } 1355 else if ( useDragThreshold == false && this.preventClick) { 1356 e.preventDefault(); 1357 } 1358 } 1359 } 1360 1361 // Set the draggable navs (multiple) to handle their scrollbars 1362 let scrollableNavs = document.querySelectorAll('.diks-navigation--draggable'); 1363 1364 // Make draggable navigation draggable 1365 if ( scrollableNavs ) { 1366 scrollableNavs.forEach(function(element) { 1367 new HorizontalScrollDragger(element); 1368 }); 1369 } 1370 1371 1372 // Handle has-scrollbars class adding and removing 1373 function handleScrollableNavScrollbars(scrollableNavElement) { 1374 // If scrollable area is wider (scrollWidth) than what's visible (clientWidth) the element has scrollbars 1375 if ( scrollableNavElement.scrollWidth > scrollableNavElement.clientWidth ) { 1376 scrollableNavElement.classList.add('diks-navigation--draggable-has-scrollbars'); 1377 scrollableNavElement.parentElement.classList.add('diks-navigation-wrapper--has-scrollbars'); 1378 } 1379 // Remove the has-scrollbars class if it exists but shouldn't (element does not have scrollbars) 1380 else if ( scrollableNavElement.classList.contains('diks-navigation--draggable-has-scrollbars') ) { 1381 scrollableNavElement.classList.remove('diks-navigation--draggable-has-scrollbars'); 1382 scrollableNavElement.parentElement.classList.remove('diks-navigation-wrapper--has-scrollbars'); 1383 } 1384 } 1385 1386 // If scrollable nav exists add (or remove) necessary classes 1387 // "DOMContentLoaded" does not wait for styles to load and styles affect the size of the scrollable nav directly so we have to use "load" instead 1388 window.addEventListener('load', (event) => { 1389 if ( scrollableNavs ) {
1390 scrollableNavs.forEach(function(element) { 1391 handleScrollableNavScrollbars(element); 1392 }); 1393 } 1394 }); 1395 1396 // Check if scrollable nav has scrollbar 1397 window.addEventListener('resize', function(event){ 1398 if ( scrollableNavs ) { 1399 scrollableNavs.forEach(function(element) { 1400 handleScrollableNavScrollbars(element); 1401 }); 1402 } 1403 }); 1404</script>
1404 1405
1406<script> 1407 // Back button handling 1408 document.querySelectorAll('a.js-diks-back-button').forEach(function(item) { 1409 var referrerIsSameDomain = false; 1410 // Check if referrer is found as referrer isn't always available (browser, tab, window, bookmark, privacy). 1411 if (typeof(document.referrer) === 'string' && document.referrer.length > 0) { 1412 // Set referrerIsSameDomain to true if referrer is in the same domain as current location hostname and referrer is not the same page as current page (window.location.href) 1413 if ( document.referrer.includes(document.location.hostname) && document.referrer != window.location.href ) { 1414 referrerIsSameDomain = true; 1415 } 1416 } 1417 1418 // Overwrite link with history.go, as it also remembers scroll position but only if referrer is the same domain as current location hostname 1419 if (history.length > 1 && referrerIsSameDomain == true) { 1420 // Set referrer as back button href to enable visual cue & opening to a new window 1421 item.setAttribute('href', document.referrer); 1422 1423 // Set back button text 1424 item.querySelector('.diks-header__cta-text').innerHTML = "Takaisin"; 1425 1426 var stepsToGoBack = -1; 1427 1428 item.addEventListener('click', function(e) { 1429 e.preventDefault(); 1430 history.go(stepsToGoBack); 1431 }); 1432 } 1433 }); 1434</script>
1434 1435 1436 <link rel="stylesheet" href="/theme/css/includes/lightgallery/css/lightgallery-bundle.min.css"> 1437 <style>.lg-sub-html { background-color: rgba(0,0,0, .6); }</style> 1438
1438<script src="/theme/css/includes/lightgallery/lightgallery.min.js"></script>
1438 1439
1439<script src="/theme/css/includes/lightgallery/plugins/autoplay/lg-autoplay.min.js"></script>
1439 1440
1440<script src="/theme/css/includes/lightgallery/plugins/fullscreen/lg-fullscreen.min.js"></script>
1440 1441
1441<script src="/theme/css/includes/lightgallery/plugins/thumbnail/lg-thumbnail.min.js"></script>
1441 1442
1442<script src="/theme/css/includes/lightgallery/plugins/zoom/lg-zoom.min.js"></script>
1442 1443
1443<script> 1444 // lightGallery 1445 // Separate gallery for every .js-lightgallery 1446 // Gallery items come from .js-lightgallery .js-lightgallery__link 1447 // https://www.lightgalleryjs.com/docs/getting-started/ 1448 document.querySelectorAll('.js-diks-lightgallery').forEach(function(gallery) { 1449 var galleryImageLinks = gallery.getElementsByClassName('diks-gallery__link'); 1450 1451 // Thumbnails come from img inside the links, unless links specify data-thumbnail 1452 var thumbnailSource = (galleryImageLinks[0].hasAttribute('data-thumbnail')) ? ('data-thumbnail') : (false); 1453 1454 // Adjust certain settings depending on whether the gallery has one or more images 1455 var galleryHasMultipleImages = (galleryImageLinks.length > 1 ? true : false); 1456 1457 // Initialize 1458 lightGallery(gallery, { 1459 autoplay: galleryHasMultipleImages, 1460 counter: galleryHasMultipleImages, 1461 download: false, 1462 exThumbImage: thumbnailSource, 1463 hideControlOnEnd: true, 1464 licenseKey: "96BAAD7E-3BF04397-BBB55AE3-6D5A2C0B", 1465 loop: false, 1466 plugins: [lgAutoplay, lgFullscreen, lgThumbnail, lgZoom], 1467 selector: '.diks-gallery__link', 1468 mobileSettings: { 1469 controls: true, 1470 showCloseIcon: true 1471 }, 1472 strings: { 1473 closeGallery: 'Sulje galleria', 1474 toggleMaximize: 'Maksimointi', 1475 previousSlide: 'Edellinen', 1476 nextSlide: 'Seuraava', 1477 download: 'Lataa', 1478 playVideo: 'Katso video', 1479 mediaLoadingFailed: 'Sisällön lataus epäonnistui', 1480 }, 1481 autoplayPluginStrings: { 1482 toggleAutoplay: 'Automaattinen toisto' 1483 }, 1484 fullscreenPluginStrings: { 1485 toggleFullscreen: 'Kokoruututila' 1486 }, 1487 thumbnailPluginStrings: { 1488 toggleThumbnails: 'Pikkukuvat' 1489 }, 1490 zoomPluginStrings: { 1491 zoomIn: 'Suurenna', 1492 zoomOut: 'Pienennä', 1493 viewActualSize: 'Näytä täysikokoisena' 1494 } 1495 }); 1496 1497 // After closing LightGallery return focus to the image link that opened the gallery 1498 gallery.addEventListener('lgAfterClose', () => { 1499 galleryImageLinks[0].focus(); 1500 }); 1501 1502 }); 1503 1504 </script>
1504 1505
1506<script> 1507 function loadScript(url, callback) { 1508 var script = document.createElement("script"); 1509 script.type = "text/javascript"; 1510 if (script.readyState) { // IE 1511 script.onreadystatechange = function() { 1512 if (script.readyState === "loaded" || script.readyState === "complete") { 1513 script.onreadystatechange = null; 1514 callback(); 1515 } 1516 }; 1517 } else { // Others 1518 script.onload = function() { 1519 callback(); 1520 }; 1521 } 1522 script.src = url; 1523 document.getElementsByTagName("head")[0].appendChild(script); 1524 } 1525 function checkAudioElements() { 1526 // load audioplayer script only when audio elements are found 1527 if (document.querySelector(".init-audio-player")) { 1528 loadScript("https://a.loviisansanomat.fi/styles/e5576057/js/audioplayer/diks-audioplayer.min.js", function() { 1529 DiksAudioPlayer.init({ 1530 selector: '.init-audio-player', 1531 stopOthersOnPlay: true, 1532 enableKeystrokes: true 1533 }); 1534 }); 1535 } 1536 } 1537 window.onload = (event) => { 1538 checkAudioElements(); 1539 }; 1540</script>
1540<script> 1541 // Service Worker 1542 if ('serviceWorker' in navigator) { 1543 window.addEventListener('load', function() { 1544 navigator.serviceWorker.register('/sw.js').then( 1545 function(registration) { 1546 console.log('PWA: Service worker registered to scope: ', registration.scope); 1547 }, 1548 function(err) { 1549 console.error('PWA: Service worker failed to register with error: ', err); 1550 } 1551 ); 1552 }); 1553 } 1554 1555 // Show installation option, hide generic fallback instructions 1556 function pwaShowInstallationOption() { 1557 document.querySelectorAll('.js-diks-apps-pwa-installation').forEach(function(element) { 1558 element.style.display = 'block'; 1559 }); 1560 document.querySelectorAll('.js-diks-apps-pwa-instructions').forEach(function(element) { 1561 element.style.display = 'none'; 1562 }); 1563 } 1564 1565 let deferredPrompt; 1566 var dataLayer = window.dataLayer || []; 1567 1568 // Basic installation process 1569 window.addEventListener('beforeinstallprompt', (e) => { 1570 // Stash the event so it can be triggered later 1571 deferredPrompt = e; 1572 1573 const enablePrompt = 0; 1574 1575 if(!enablePrompt) { 1576 e.preventDefault(); 1577 } 1578 1579 // Update the UI to notify the user they can install PWA 1580 pwaShowInstallationOption(); 1581 1582 // Handle installation 1583 document.querySelectorAll('.js-diks-apps-pwa-installation-button').forEach(function(button) { 1584 button.addEventListener('click', (e) => { 1585 // Show the prompt 1586 deferredPrompt.prompt(); 1587 1588 // Wait for user to respond 1589 deferredPrompt.userChoice.then((choiceResult) => { 1590 if (choiceResult.outcome === 'accepted') { 1591 console.log('PWA: Installed (prompt)'); 1592 dataLayer.push({ 1593 'event': 'PWA.installation', 1594 'eventData': 'success' 1595 }); 1596 } else { 1597 console.log('PWA: User dismissed installation prompt'); 1598 dataLayer.push({ 1599 'event': 'PWA.installation', 1600 'eventData': 'canceled' 1601 }); 1602 } 1603 deferredPrompt = null; 1604 }); 1605 }); 1606 }); 1607 }); 1608 1609 // iOS installation process (show instructions modal) 1610 if (!navigator.standalone) { 1611 var userAgent = navigator.userAgent.toLowerCase(); 1612 var iPhoneUser = (/iphone/.test(userAgent)); 1613 var iPadUser = (/ipad/.test(userAgent) || (/macintosh/.test(userAgent) && navigator.maxTouchPoints > 1)); 1614 var safariUser = (/^(?!.*(brave|chrome|crios|duckduckgo|edgeios|firefox|fxios|opios|ucbrowser|yabrowser)).*safari.*$/.test(userAgent)); 1615 1616 if (safariUser && (iPhoneUser || iPadUser)) { 1617 // Update the UI to notify the user they can install PWA 1618 pwaShowInstallationOption(); 1619 1620 // Instructions 1621 var modals = document.querySelectorAll('.js-diks-apps-pwa-ios-instructions').forEach(function(element) { 1622 // Position on screen based on device 1623 if (iPhoneUser) { 1624 element.classList.add('diks-apps__pwa-ios-modal--bottom'); 1625 } else if (iPadUser) { 1626 element.classList.add('diks-apps__pwa-ios-modal--top'); 1627 } 1628 }); 1629 1630 // Handle modal instructions from installation button 1631 document.querySelectorAll('.js-diks-apps-pwa-installation-button').forEach(function(button) { 1632 button.addEventListener('click', (e) => { 1633 // Show first modal 1634 document.querySelector('.js-diks-apps-pwa-ios-instructions').classList.toggle('diks-apps__pwa-ios-modal--is-visible'); 1635 dataLayer.push({ 1636 'event': 'PWA.instructions.shown', 1637 'eventData': 'iOS' 1638 }); 1639 }); 1640 }); 1641 } 1642 } 1643</script>
1643 1644
1644<script class="coral-script" src="//coral.prod.diks.fi/assets/js/count.js?v=9.3.1.3" defer></script>
vendor: 78 bytes, lines 1644-1645
1644<script src="https://www.google.com/recaptcha/api.js" async defer></script> 1645
1645<script> 1646 function onSubmitSidebar(token) { 1647 document.getElementById("lianamailer-sidebar").submit(); 1648 } 1649 function onSubmitFooter(token) { 1650 document.getElementById("lianamailer-footer").submit(); 1651 } 1652 </script>
1652 1653 <style>.grecaptcha-badge { visibility: hidden; }</style> 1654<div id="diks-bc-order-button" style="display: none;"></div> 1655 </body> 1656</html> 1657
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.