1 2<!doctype html> 3<html class="diks-no-js diks-site--vihdinuutiset 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 | Vihdin Uutiset</title> 8 <link id="diks-stylesheet" rel="stylesheet" href="https://a.vihdinuutiset.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.vihdinuutiset.fi/styles/e5576057/styles/diks-news-darkmode.css"; 16 const defaultStylesheet = "https://a.vihdinuutiset.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"> 76
76<script> 77 window.JankkoSSOConfig = { 78 accountOrigin: "VIHU" 79 }; 80 </script>
80 81 82 83
83<script id="jankko-sso-script" src="https://sso.vihdinuutiset.fi/assets/jankko-sso-client.modern.min.js"></script>
83 84 85 86 87 88 89
89<script> 90 // Hyphenopoly library initialization. The library will add soft-hyphen characters into the content if the 91 // browser doesn't support CSS hyphenation. For debugging on macOS Chrome: require: { 'fi': 'FORCEHYPHENOPOLY' } 92 const Hyphenopoly = { 93 require: { 'fi': 'yhdyssanahirviö' }, 94 setup: { 95 defaultLanguage: "fi", 96 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 } } 97 } 98 } 99 console.log('Hyphenopoly settings:', Hyphenopoly.setup) 100 101 // Helper function for hyphenating content that was added after pageload. We must query a nodelist and iterate 102 // each node because the library can't handle a nodelist. 103 // https://mnater.github.io/Hyphenopoly/Hyphenators.html 104 // https://github.com/mnater/Hyphenopoly/issues/92#issuecomment-597728300 105 const diksHyphenateContent = (containerSelector) => { 106 if (!Hyphenopoly.hyphenators) { 107 return 108 } 109 Hyphenopoly.hyphenators["HTML"].then((hyphenator) => { 110 for (const itemSelector in Hyphenopoly.setup.selectors) { 111 const containerNode = document.querySelector(containerSelector) 112 const itemNodeList = containerNode.querySelectorAll(itemSelector) 113 itemNodeList.forEach((itemNode) => { hyphenator(itemNode, itemSelector) }) 114 } 115 }) 116 } 117 </script>
117 118
118<script src="https://a.vihdinuutiset.fi/styles/e5576057/includes/hyphenopoly/Hyphenopoly_Loader.js"></script>
118 119
119<script src="/theme/css/includes/waypoints/lib/noframework.waypoints.min.js"></script>
119 120 <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)" /> 121 <meta name="theme-color" content="#121416" media="(prefers-color-scheme: dark)" /><link rel="alternate" type="application/rss+xml" title="Vihdin Uutiset" href="https://www.vihdinuutiset.fi/feed/rss"><meta name="robots" content="max-image-preview:large">
121<script> 122 var pageData = {}; 123 124 pageData.section = { 125 'name': 'Sovellus', 126 'uname': 'asenna', 127 'url': 'https\u003A\/\/www.vihdinuutiset.fi\/asenna\/' 128 } 129 pageData.publication = { 130 'name': 'vihdinuutiset', 131 'url': 'https\u003A\/\/www.vihdinuutiset.fi\/', 132 'engage': 'VIHU', 133 'paywallEnabled': false, 134 'registrationWallEnabled': true, 135 'env':'prod' 136 } 137 pageData.user = {} 138 pageData.companyUser = {} 139 140 function isPwa() { 141 // window.navigator.standalone = iOS 142 // window.matchMedia('(display-mode: standalone)').matches = Android/universal 143 return (window.navigator.standalone) || 144 (["fullscreen", "standalone", "minimal-ui"].some( 145 function(displayMode) { return window.matchMedia('(display-mode: ' + displayMode + ')') 146 .matches })); 147 } 148 149 pageData.general = { 150 'browseMode': (isPwa() ? 'pwa' : 'browser') 151 } 152</script>
152 153 <meta property="og:site_name" content="Vihdin Uutiset"> 154 <meta property="og:locale" content="fi_FI"><meta name='description' content=''> 155<meta property='og:title' content='Sovellus | Vihdin Uutiset'> 156<meta property='og:description' content=''> 157<meta property='og:url' content='https://www.vihdinuutiset.fi/asenna/'> 158<meta property='og:type' content='webpage'><meta property='og:image' content='https://a.vihdinuutiset.fi/styles/e5576057/images/default/og-image-vihdinuutiset.jpg'> 159<meta property='og:image:width' content='1200'> 160<meta property='og:image:height' content='630'> 161 <link rel="manifest" href="/manifest.webmanifest"> 162 <style>@media (max-width: 600px) { .gravitoCMP-footer { margin-top: 1.5em; } }</style> 163
163<script type="text/javascript">window.cX = window.cX || {};// Async load of cx.js 164 (function(d,s,e,t){e=d.createElement(s);e.type='text/java'+s;e.async='async'; 165 e.src='http'+('https:'===location.protocol?'s://s':'://')+'cdn.cxense.com/cx.js'; 166 t=d.getElementsByTagName(s)[0];t.parentNode.insertBefore(e,t);})(document,'script'); 167 </script>
167 168 169 170
170<script type='text/javascript'> 171 (function() { 172 /** CONFIGURATION START **/ 173 var _sf_async_config = window._sf_async_config = (window._sf_async_config || {}); 174 _sf_async_config.uid = 60754; 175 _sf_async_config.domain = location.host.replace("www.",""); 176 _sf_async_config.flickerControl = false; 177 _sf_async_config.useCanonical = true; 178 _sf_async_config.useCanonicalDomain = true; 179 /** CONFIGURATION END **/ 180 })(); 181 </script>
181<script> 182 function configureChartbeat(userType) { 183 /** CONFIGURATION START **/ 184 var _sf_async_config = window._sf_async_config = (window._sf_async_config || {}); 185 _sf_async_config.sections = pageData && pageData.section ? pageData.section.name : ''; 186 _sf_async_config.authors = pageData && pageData.article && Array.isArray(pageData.article.authors) ? pageData.article.authors.toString() : ''; 187 188 if (userType) { 189 var _cbq = window._cbq = (window._cbq || []); 190 _cbq.push(['_acct', userType]); 191 } 192 /** CONFIGURATION END **/ 193 function loadChartbeat() { 194 var e = document.createElement('script'); 195 var n = document.getElementsByTagName('script')[0]; 196 e.type = 'text/javascript'; 197 e.async = true; 198 e.src = 'https://static.chartbeat.com/js/chartbeat.js'; 199 n.parentNode.insertBefore(e, n); 200 } 201 loadChartbeat(); 202 }; 203 204 if (typeof JankkoSSOClient !== 'undefined') { 205 JankkoSSOClient.getSession().then(function(data) { 206 if (data && data.user && data.user.id) { 207 var userType = Array.isArray(data.permissions) && data.permissions.includes("paywall") ? 'paid' : 'lgdin'; 208 209 configureChartbeat(userType); 210 } else { 211 configureChartbeat('anon'); 212 } 213 }).catch(function(error) { 214 configureChartbeat('anon'); 215 }); 216 } else { 217 configureChartbeat('anon'); 218 } 219 </script>
219 220
220<script> 221 const gtmContainerId = 'GTM-KTJNB7R'; 222 const sendDatalayerPush = Boolean(1); 223 const context = 'sec'; 224 225 (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': 226 new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], 227 j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 228 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); 229 })(window,document,'script','dataLayer',gtmContainerId); 230 231 if (sendDatalayerPush) { 232 window.dataLayer.push({'event':'pageDataPush','pageData': window.pageData}); 233 } 234 235 (async function () { 236 const paywallEnabled = window?.pageData?.publication?.paywallEnabled ?? true; 237 const registrationWallEnabled = window?.pageData?.publication?.registrationWallEnabled ?? true; 238 239 const user = {}; 240 const companyUser = {}; 241 242 let articleState; 243 let articlePaywall = 'free'; // free is always the safer fallback 244 245 if (context === 'art') { 246 if (window?.pageData?.article?.effectivePaywall) { 247 articlePaywall = window.pageData.article.effectivePaywall; 248 } else if (window?.pageData?.article?.paywall){ 249 articlePaywall = window.pageData.article.paywall; 250 } 251 252 if ((articlePaywall === 'free' || !paywallEnabled) || (articlePaywall === "registered" && !registrationWallEnabled)) { 253 articleState = "full"; 254 } 255 else { 256 articleState = 'preview'; 257 } 258 } 259 260 function getCookie(name) { 261 name = name + '='; 262 const decodedCookie = decodeURIComponent(document.cookie); 263 const cookies = decodedCookie.split(';'); 264 for (let i = 0; i < cookies.length; i++) { 265 const cookie = cookies[i].trim(); 266 if (cookie.indexOf(name) === 0) { 267 return cookie.substring(name.length, cookie.length); 268 } 269 } 270 } 271 272 function pushDataLayerEvent() { 273 let segmentsCookie = getCookie('jankkosegments'); 274 275 if (segmentsCookie) { 276 let segmentsData = JSON.parse(segmentsCookie); 277 let segments = segmentsData.segments; 278 279 if (segments && typeof segments === 'object') { 280 user.segments = segments; 281 } 282 } 283 const pageData = { 284 'user': user,
285 'companyUser': companyUser 286 }; 287 if (context === 'art') { 288 pageData.article = { 'state': articleState }; 289 } 290 if (sendDatalayerPush) { 291 window.dataLayer.push({'event': 'userDataPush', 'pageData': pageData }); 292 } 293 } 294 295 async function modifyDatalayerData() { 296 const sessionData = await JankkoSSOClient.getSession(); 297 if (!sessionData) { 298 return; 299 } 300 301 user.id = sessionData?.personal?.personal_user_id; 302 user.products = sessionData?.personal?.personal_active_products; 303 user.permissions = sessionData?.personal?.personal_permissions; 304 305 companyUser.id = sessionData?.company?.company_user_id ?? null; 306 companyUser.products = sessionData?.company?.company_active_products ?? null; 307 companyUser.permissions = sessionData?.company?.company_permissions ?? null; 308 309 const permissions = sessionData?.permissions ?? []; 310 if (context === 'art') { 311 var userIsLoggedIn = false;if ((articlePaywall != "free" && permissions.includes("paywall") && articlePaywall != "registered") || (userIsLoggedIn === true && articlePaywall === "registered")) { 312 articleState = "full"; 313 } 314 } 315 } 316 317 try { 318 await modifyDatalayerData(); 319 } 320 catch (error) { 321 console.warn(error); 322 } 323 324 pushDataLayerEvent(); 325 }()); 326 327 </script>
327 328 329 </head> 330 <body class="diks-body diks-body--page-type-apps"> 331 <!-- Google Tag Manager (noscript) -->
vendor: 72 bytes, lines 331-332
331 332 <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=
332GTM-KTJNB7R
vendor: 95 bytes, lines 332-334
332" 333 height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> 334
334<!-- End Google Tag Manager (noscript) --> 335
335<script src='/gravito-cmp.js'></script>
335 336 337 338 339 340 <header id="main-header" class="diks-header diks-header diks-header--is-fixed"> 341 <div class="diks-skip-link-navigation diks-skip-link-navigation--top"> 342 <ul class="diks-navigation diks-navigation--skip-links"> 343 <li class="diks-navigation__item"> 344 <a class="diks-button diks-button--primary diks-a11y__screen-reader diks-a11y__screen-reader--focusable" href="#sisalto" >Siirry suoraan sisältöön</a> 345 </li> 346 </ul> 347 </div> 348 349 <div class="diks-header-wrapper"> 350 <div class="diks-container diks-container--header"> 351 <div class="diks-header-container"><div class="diks-header__navigation-container diks-header__navigation-container--left"> 352 <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"> 353 <path fill-rule="evenodd" d="M22 6H2V4H22V6ZM22 13H2V11H22V13ZM22 20H2V18H22V20Z" clip-rule="evenodd"/> 354</svg> 355</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"> 356 <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"/> 357</svg> 358</span></button> 359 360 <div class="diks-dropdown-navigation" id="diks-dropdown-navigation"> 361 <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"> 362 <img src="https://a.vihdinuutiset.fi/styles/e5576057/images/logos/keskisuomalainen-sign.svg" class="diks-logo diks-dropdown-navigation__sign" alt="Keskisuomalainen Oyj"> 363 </div><form id="dropdown-navigation-search" name="dropdownnavigationsearch" class="diks-form diks-form--fluid" action="/haku/" method="get"> 364 <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> 365 366 <div class="diks-form__field-wrapper diks-form__field-wrapper--submit-button-icon-only"> 367 <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"> 368 <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"/> 369</svg> 370</span>Hae 371 </button> 372 </div> 373 </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></ul> 374 </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/lehti/vihdin-uutiset/"><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"> 375 <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"/> 376</svg> 377</span>Asiakaspalvelu</a></li><li class="diks-navigation__item " ><a class="diks-navigation__link " href="https://oma.media.fi/lehti/vihdin-uutiset/yhteystiedot/laheta-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"> 378 <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"/> 379</svg> 380</span>Lähetä juttuvinkki</a></li></ul> 381 </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></ul> 382 </nav><!-- ESI start element "recommendedTopics" generated at 25-09-2026 02:57:30.398442 --><!-- ESI end element "recommendedTopics" --><!-- ESI start element "promotedAdvertisers" generated at 25-09-2026 03:00:11.456757 --><!-- 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/lehti/vihdin-uutiset/yhteystiedot/">Kaikki yhteystiedot</a></li></ul> 383 </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"> 384 <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"> 385 <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.7
385547 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"/> 386</svg> 387</span>Käytä tummaa tilaa</span> 388 <div class="diks-form__switch-wrapper"> 389 <input id="diks-darkmode-toggler" class="diks-form__switch-input" type="checkbox"> 390 <span class="diks-form__switch-slider"></span> 391 </div> 392 </label> 393 </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"> 394 <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"/> 395</svg> 396</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"> 397 <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"/> 398</svg> 399</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"> 400 <path fill-rule="evenodd" d="M4 2H20V22H4V2ZM6 4V20H18V4H6ZM8 6H16V12H8V6ZM10 8V10H14V8H10ZM16 15H8V13H16V15ZM16 18H8V16H16V18Z" clip-rule="evenodd"/> 401</svg> 402</span>Lehdet</a></li></ul> 403 </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.vihdinuutiset.fi/styles/e5576057/images/logos/vihdinuutiset.svg" class="diks-logo diks-logo--default diks-header__logo diks-header__main-logo" alt="Vihdin Uutiset"><img src="https://a.vihdinuutiset.fi/styles/e5576057/images/logos/vihdinuutiset-white.svg" class="diks-logo diks-logo--darkmode diks-header__logo diks-header__main-logo" alt="Vihdin Uutiset"></a> 404 </div><div class="diks-header__navigation-container diks-header__navigation-container--right"><div class="diks-user-navigation-wrapper"> 405 <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"> 406 <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"/> 407</svg> 408</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"> 409 <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
40918.364L10.5858 12Z" clip-rule="evenodd"/> 410</svg> 411</span></button> 412 413 <div class="diks-navigation diks-sub-navigation diks-user-navigation" id="diks-user-navigation"> 414 <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> 415 <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> 416 </div> 417</div> 418 </div> 419 </div> 420 </div> 421 </div><div class="diks-quicklinks-wrapper"> 422 <div class="diks-container diks-container--narrow-mobile"> 423 <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"> 424 <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"/> 425</svg> 426</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"> 427 <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"/> 428</svg> 429</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"> 430 <path fill-rule="evenodd" d="M4 2H20V22H4V2ZM6 4V20H18V4H6ZM8 6H16V12H8V6ZM10 8V10H14V8H10ZM16 15H8V13H16V15ZM16 18H8V16H16V18Z" clip-rule="evenodd"/> 431</svg> 432</span>Lehdet</a></li></ul> 433 </nav> 434 </div> 435 </div><div id="diks-dropdown-navigation-shade" class="diks-dropdown-navigation-shade"></div></header>
435<script src="/theme/css/includes/waypoints/lib/noframework.waypoints.min.js"></script>
435 436
436<script> 437 // Fix forEach for IE 438 if (window.NodeList && !NodeList.prototype.forEach) { 439 NodeList.prototype.forEach = Array.prototype.forEach; 440 } 441 442 // Element.closest() needs a polyfill for older browsers. 443 // While we only need the closest() functionality for mobile browsers, 444 // we don't want the code to fail even on old desktop browsers. 445 // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill 446 // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Browser_compatibility 447 if (!Element.prototype.matches) { 448 Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 449 } 450 451 if (!Element.prototype.closest) { 452 Element.prototype.closest = function(s) { 453 var el = this; 454 455 do { 456 if (el.matches(s)) return el; 457 el = el.parentElement || el.parentNode; 458 } while (el !== null && el.nodeType === 1); 459 return null; 460 }; 461 } 462 463 (function () { 464 if (typeof JankkoSSOClient !== 'undefined') { 465 var stringToHTML = function (htmlString) { 466 var div = document.createElement('div'); 467 div.innerHTML = htmlString.trim(); 468 return div.firstChild; 469 }; 470 471 var showUserRelatedItems = function(personalData) { 472 var usernameElement = document.querySelector('#diks-sso-username'); 473 if (usernameElement) { 474 usernameElement.innerHTML = personalData.full_name; 475 } 476 477 var linksElement = document.querySelector('#diks-sso-links'); 478 if (linksElement) { 479 var myAccountLink = stringToHTML('<li class="diks-navigation__item"><a class="diks-navigation__link" href="'+JankkoSSOClient.serviceUrls.myAccount+'">Omat tiedot</a></li>'); 480 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>'); 481 linksElement.insertBefore(myAccountLink, linksElement.childNodes[0]); 482 linksElement.appendChild(logoutForm); 483 } 484 485 var htmlElement = document.querySelector('.diks-user--is-not-logged-in'); // Class is set to main html element 486 if (htmlElement) { 487 htmlElement.classList.replace('diks-user--is-not-logged-in', 'diks-user--is-logged-in'); 488 } 489 } 490 491 var showMenuLinksForLoggedOutUser = function() { 492 const linksElement = document.querySelector('#diks-sso-links'); 493 if (!linksElement) { 494 return; 495 } 496 497 // Pidetään vain tietyt query-parametrit. Alunperin tässä poistettiin kaikki query-parametrit. 498 // @todo Selvitetään voisiko tässä sallia kaikki query-parametrit. 499 const currentUrlObject = new URL(window.location.href); 500 const returnUrlObject = new URL(`${currentUrlObject.origin}${currentUrlObject.pathname}`); 501 const allowedParams = ['limit-active-products']; 502 allowedParams.forEach(function(name) { 503 if (currentUrlObject.searchParams.get(name)) { 504 returnUrlObject.searchParams.set(name, currentUrlObject.searchParams.get(name)); 505 } 506 }); 507 508 const loginPageUrlObject = new URL(`${window.location.origin}/kirjaudu/`); 509 loginPageUrlObject.searchParams.set('returnUrl', returnUrlObject.toString()); 510 const loginLinkString = `<li class="diks-navigation__item"><a class="diks-navigation__link" href="${loginPageUrlObject.toString()}">Kirjaudu</a></li>`; 511 512 linksElement.insertBefore(stringToHTML(loginLinkString), linksElement.childNodes[0]); 513 } 514 515 var showCompanyUserRelatedItems = function(companyData) { 516 var htmlElement = document.querySelector('.diks-user--is-not-company-subscriber'); // Class is set to main html element 517 var permissions = companyData?.company_permissions || []; 518 if (htmlElement && permissions.length) { 519 htmlElement.classList.replace('diks-user--is-not-company-subscriber', 'diks-user--is-company-subscriber'); 520 } 521 } 522 523 document.addEventListener("DOMContentLoaded", async function() { 524 try { 525 const data = await JankkoSSOClient.getSession(); 526 if (data.company?.company_user_id) { 527 showCompanyUserRelatedItems(data.company); 528 }
529 if (data.personal?.personal_user_id) { 530 showUserRelatedItems(data.personal); 531 } else { 532 showMenuLinksForLoggedOutUser(); 533 } 534 } catch (error) { 535 showMenuLinksForLoggedOutUser(); 536 } 537 }); 538 } 539 }()); 540 541 542 ////////////////////////////////////////////////////////////////////////////////////////// 543 // NAVIGATIONS 544 ////////////////////////////////////////////////////////////////////////////////////////// 545 546 // Toggle icon inside a toggler 547 function toggleTogglerIcon(toggler) { 548 togglerIcons = toggler.querySelectorAll('.diks-icon'); 549 if ( togglerIcons.length > 1 ) { 550 for (var j= 0; j < togglerIcons.length; j++) { 551 togglerIcons[j].classList.toggle('diks-icon--hidden'); 552 } 553 } 554 } 555 556 // Function for closing all dropdown navigations 557 function closeAllDropdownNavigations() { 558 closeMainDropdownNavigation(); 559 closeUserDropdownNavigation(); 560 } 561 562 // Close main nav or user nav if hidden screen reader only close navigation button is clicked 563 let closeDropdownMainNav = document.getElementById('diks-close-dropdown-main-nav'); 564 let closeDropdownUserNav = document.getElementById('diks-close-dropdown-user-nav'); 565 if ( closeDropdownMainNav ) { 566 closeDropdownMainNav.addEventListener('click', function() { 567 closeMainDropdownNavigation(); 568 }); 569 } 570 if ( closeDropdownUserNav ) { 571 closeDropdownUserNav.addEventListener('click', function(e) { 572 e.stopPropagation(); 573 closeUserDropdownNavigation(); 574 }); 575 } 576 577 // Trap focus inside opened dropdown navigation 578 document.addEventListener('keydown', function(event) { 579 // Initialize variables 580 var ssoLinks = document.getElementById('diks-sso-links'); 581 var linksUserNav = ""; 582 var firstElUserNav = ""; 583 var lastElUserNav = ""; 584 var mainDropdownLastNavLinks = document.getElementById('dropdown-customer-nav'); // Last navigation element inside of main dropdown navigation 585 var linksMainDropdownNav = ""; 586 var firstElMainDropdownNav = "" 587 var lastElMainDropdownNav = ""; 588 589 // Set user nav variable values if SSO links exist 590 if (ssoLinks) { 591 linksUserNav = ssoLinks.querySelectorAll('.diks-navigation__link'); 592 firstElUserNav = document.getElementById('diks-close-dropdown-user-nav'); 593 lastElUserNav = linksUserNav[linksUserNav.length - 1]; 594 } 595 596 // Set main dropdown nav variable values if main dropdown last nav links exist 597 if (mainDropdownLastNavLinks) { 598 linksMainDropdownNav = mainDropdownLastNavLinks.querySelectorAll('.diks-navigation__link'); 599 firstElMainDropdownNav = document.getElementById('diks-close-dropdown-main-nav'); 600 lastElMainDropdownNav = linksMainDropdownNav[linksMainDropdownNav.length - 1]; 601 } 602 603 // If darkmode-toggler is found set it as the last element of main dropdown nav 604 if ( document.getElementById('diks-darkmode-toggler') ) { 605 lastElMainDropdownNav = document.getElementById('diks-darkmode-toggler'); 606 } 607 608 // Close all dropdown navigations & reposition fixed header when ESC key is pressed 609 if (event.key === "Escape" || event.key === "Esc") { 610 closeAllDropdownNavigations(); 611 } 612 // Trap focus inside user navigation and/or main dropdown navigation when they are open 613 if (event.keyCode === 9) { 614 if (event.shiftKey && (document.activeElement === firstElUserNav || document.activeElement === firstElMainDropdownNav)) { 615 event.preventDefault(); 616 if (document.activeElement === firstElUserNav) { 617 lastElUserNav.focus(); 618 } 619 else if ( document.activeElement === firstElMainDropdownNav ) { 620 lastElMainDropdownNav.focus(); 621 } 622 } 623 else if (!event.shiftKey && (document.activeElement === lastElUserNav || document.activeElement === lastElMainDropdownNav)) { 624 event.preventDefault(); 625 if (document.activeElement === lastElUserNav) { 626 firstElUserNav.focus(); 627 } 628 else if ( document.activeElement === lastElMainDropdownNav ) { 629 firstElMainDropdownNav.focus(); 630 } 631 } 632 } 633 }); 634 635 636 ////////////////////////////////////////////////////////////////////////////////////////// 637 // User navigation 638 ////////////////////////////////////////////////////////////////////////////////////////// 639 640 let userDropdownNavigation = document.getElementById('diks-user-navigation'); // user dropdown navigation 641 let userDropdownNavigationToggler = document.getElementById('diks-sso-user'); // user dropdown navigation toggler button (opens and closes user dropdown navigation) 642 let userDropdownNavigationCloseButton = document.getElementById('diks-close-dropdown-main-nav'); // Hidden screen-reader-only close button inside user dropdown navigation 643 644 // Close user dropdown navigation if hidden screen-reader-only close button is clicked 645 if ( userDropdownNavigationCloseButton ) { 646 userDropdownNavigationCloseButton.addEventListener('click', function() { 647 closeUserDropdownNavigation(); 648 }); 649 } 650 651 function closeUserDropdownNavigation() { 652 if (userDropdownNavigation) { 653 if (userDropdownNavigation.classList.contains('diks-user-navigation--is-open')) { 654 // Close user dropdown nav by removing --is-open class 655 userDropdownNavigation.classList.remove('diks-user-navigation--is-open'); 656 // Remove --is-open class from user dropdown navigation toggler 657 userDropdownNavigationToggler.classList.remove('diks-dropdown-toggle--is-open'); 658 // Toggle icon 659 toggleTogglerIcon(userDropdownNavigationToggler); 660
661 // Set aria-expanded to false for user dropdown toggler 662 userDropdownNavigationToggler.setAttribute('aria-expanded', 'false'); 663 } 664 } 665 } 666 667 // User Navigation Dropdown 668 if (userDropdownNavigation) { 669 let userDropdownNavigationAriaControls = userDropdownNavigationToggler.getAttribute('data-diks-toggle'); // aria-controls value for user dropown navigation toggler 670 userDropdownNavigationToggler.setAttribute('aria-controls', userDropdownNavigationAriaControls); 671 userDropdownNavigationToggler.addEventListener('click', function(e) { 672 e.preventDefault(); 673 // If the main dropdown navigation is already open (contains --is-open class) close it 674 if ( (userDropdownNavigation).classList.contains('diks-user-navigation--is-open') ) { 675 closeUserDropdownNavigation(); 676 } 677 // If the main dropdown navigation isn't open (doesn't contain --is-open class) open it 678 else { 679 // If other toggles are open, close them 680 document.querySelectorAll('.diks-user-navigation--is-open').forEach(function(item) { 681 item.classList.remove('diks-user-navigation--is-open'); 682 userDropdownNavigationToggler.classList.remove('diks-dropdown-toggler--is-open'); 683 }); 684 685 // Toggle icon 686 toggleTogglerIcon(userDropdownNavigationToggler); 687 688 // Set aria-expanded 689 userDropdownNavigationToggler.setAttribute('aria-expanded', 'true'); 690 691 // Open this toggle 692 userDropdownNavigation.classList.add('diks-user-navigation--is-open'); 693 694 // Close main dropdown navigation if it's open 695 closeMainDropdownNavigation(); 696 697 // Add event listener to window when user nav toggler is clicked and user nav is open 698 window.addEventListener('click', function(e){ 699 if (document.querySelector('.diks-user-navigation-wrapper').contains(e.target)){ 700 // Clicked inside user nav, do nothing 701 } 702 else { 703 // Clicked outside user nav, close user nav 704 closeUserDropdownNavigation(); 705 } 706 }); 707 708 } 709 }); 710 } 711 712 ////////////////////////////////////////////////////////////////////////////////////////// 713 // Main navigation 714 ////////////////////////////////////////////////////////////////////////////////////////// 715 716 let mainDropdownNavigation = document.getElementById('diks-dropdown-navigation'); // main dropdown navigation 717 let mainDropdownNavigationToggler = document.getElementById('diks-dropdown-toggle'); // main dropdown navigation toggler button (opens and closes main dropdown navigation) 718 let mainDropdownNavigationShade = document.querySelector('.diks-dropdown-navigation-shade'); // shade effect that is visible when main dropdown navigation is open 719 let mainDropdownNavigationCloseButton = document.getElementById('diks-close-dropdown-main-nav'); // Hidden screen-reader-only close button inside main dropdown navigation 720 721 // Close main dropdown navigation if hidden screen-reader-only close button is clicked 722 if ( mainDropdownNavigationCloseButton ) { 723 mainDropdownNavigationCloseButton.addEventListener('click', function() { 724 closeMainDropdownNavigation(); 725 }); 726 } 727 728 // Function for closing main dropdown navigation 729 function closeMainDropdownNavigation() { 730 // Main dropdown navigation 731 if (mainDropdownNavigation) { 732 if (mainDropdownNavigation.classList.contains('diks-dropdown-navigation--is-open')) { 733 // Close main dropdown nav by removing --is-open class 734 mainDropdownNavigation.classList.remove('diks-dropdown-navigation--is-open'); 735 // Remove --is-open class from main dropdown navigation toggler 736 mainDropdownNavigationToggler.classList.remove('diks-dropdown-toggle--is-open'); 737 // Toggle icon 738 toggleTogglerIcon(mainDropdownNavigationToggler); 739 740 // Set aria-expanded to false for main dropdown toggler 741 mainDropdownNavigationToggler.setAttribute('aria-expanded', 'false'); 742 743 // Remove --is-open class from body 744 document.body.classList.remove('diks-body--dropdown-navigation-is-open'); 745 746 // Turn off shade effect 747 mainDropdownNavigationShade.classList.remove('diks-dropdown-navigation-shade--is-visible'); 748 } 749 } 750 } 751 752 753 // Main Navigation Dropdown 754 if (mainDropdownNavigation) {
755 let mainDropdownNavigationAriaControls = mainDropdownNavigationToggler.getAttribute('data-toggle'); // aria-controls value for main dropown navigation toggler 756 mainDropdownNavigationToggler.setAttribute('aria-controls', mainDropdownNavigationAriaControls); 757 mainDropdownNavigationToggler.addEventListener('click', function(e) { 758 e.preventDefault(); 759 // If the main dropdown navigation is already open (contains --is-open class) close it 760 if ( (mainDropdownNavigation).classList.contains('diks-dropdown-navigation--is-open') ) { 761 closeMainDropdownNavigation(); 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-dropdown-navigation--is-open').forEach(function(item) { 767 item.classList.remove('diks-dropdown-navigation--is-open'); 768 mainDropdownNavigationToggler.classList.remove('diks-dropdown-toggler--is-open'); 769 }); 770 771 // Toggle icon 772 toggleTogglerIcon(mainDropdownNavigationToggler); 773 774 // Set aria-expanded 775 mainDropdownNavigationToggler.setAttribute('aria-expanded', 'true'); 776 777 // Open this toggle 778 mainDropdownNavigation.classList.add('diks-dropdown-navigation--is-open'); 779 // Add is-open class to body 780 document.body.classList.add('diks-body--dropdown-navigation-is-open'); 781 // Turn on shade effect 782 mainDropdownNavigationShade.classList.add('diks-dropdown-navigation-shade--is-visible'); 783 784 // Close main Dropdown Navigation when visible shade area is clicked 785 document.querySelector('.diks-dropdown-navigation-shade--is-visible').addEventListener('click', function() { 786 closeMainDropdownNavigation(); 787 }); 788 789 // Close user dropdown navigation if it's open 790 closeUserDropdownNavigation(); 791 792 } 793 }); 794 } 795 796 797</script>
797 798 799 800 801 802 803 804 805 <div class="diks-note-wrapper "><div class="diks-container diks-container--narrower-mobile"> 806 <div id="diks-segment-notes"></div></div></div>
806<script> 807 let segmentTeasersContainer = document.getElementById("diks-segment-notes"); 808 809 (function() { 810 function getCookie(name) { 811 name = name + '='; 812 const decodedCookie = decodeURIComponent(document.cookie); 813 const cookies = decodedCookie.split(';'); 814 815 for (let i = 0; i < cookies.length; i++) { 816 const cookie = cookies[i].trim(); 817 if (cookie.indexOf(name) == 0) { 818 return cookie.substring(name.length, cookie.length); 819 } 820 } 821 } 822 823 function injectSegmentTeasers(segmentsQueryString) { 824 var xhttp = new XMLHttpRequest(); 825 826 xhttp.onreadystatechange = function() { 827 if (this.readyState == 4 && this.status == 200) { 828 var segmentTeasers = this.responseText.trim(); 829 830 if (segmentTeasers) { 831 if (segmentTeasersContainer) { 832 segmentTeasersContainer.innerHTML = segmentTeasers; 833 } 834 } 835 else { 836 // Remove segment teaser container if there are no segment teasers 837 if (segmentTeasersContainer) { 838 segmentTeasersContainer.remove(); 839 } 840 } 841 } 842 }; 843 844 xhttp.open("GET", "/.ajax/segmentTeaser?" + segmentsQueryString, true); 845 xhttp.send(); 846 } 847 848 var segmentsCookie = getCookie('jankkosegments'); 849 850 if (segmentsCookie) { 851 var segmentsData = JSON.parse(segmentsCookie); 852 var segments = segmentsData.segments; 853 854 if (segments && typeof segments === 'object') { 855 var segmentsQueryString = ""; 856 857 Object.keys(segments).forEach(function(key, index) { 858 segmentsQueryString = index === 0 ? "" : segmentsQueryString + "&"; 859 var value = segments[key]; 860 861 if (Array.isArray(value)) { 862 value = value.join(','); 863 } 864 865 segmentsQueryString = segmentsQueryString + key + "=" + value; 866 }); 867 868 injectSegmentTeasers(segmentsQueryString); 869 } 870 } 871 else { 872 // Remove segment teaser container if there are no segment teasers 873 if (segmentTeasersContainer) { 874 segmentTeasersContainer.remove(); 875 } 876 } 877 })(); 878</script>
878 879 880 <div class="diks-custom-page diks-apps"> 881 <div class="diks-container"> 882 <div class="diks-grid"> 883 <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"> 884 <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> 885 </nav></div> 886 </div> 887 <main id="sisalto"> 888 <div class="diks-apps__content-wrapper"> 889 <div class="diks-grid"> 890 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-2"></div> 891 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-12"> 892 <h1 class="diks-title diks-title--size-3xl" >Sovellus</h1> 893 </div> 894 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-2"></div> 895 <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"> 896 <div class="diks-apps__icon-wrapper"> 897 <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"> 898 <path fill-rule="evenodd" d="M5 2H19V22H5V2ZM7 4V20H17V4H7ZM15 19H9V17H15V19Z" clip-rule="evenodd"/> 899</svg> 900</span> 901 <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"> 902 <path fill-rule="evenodd" d="M2 3H22V17H15.5138L15.8471 19H18V21H6V19H8.15287L8.48621 17H2V3ZM20 15V5H4V15H20ZM10.5138 17L10.1805 19H13.8195L13.4862 17H10.5138Z" clip-rule="evenodd"/> 903</svg> 904</span> 905 </div> <h2 class="diks-title diks-title--size-xl" >Uutissovellus</h2><div class="diks-hide-on-standalone"> 906 <div class="js-diks-apps-pwa-installation" style="display: none;"> 907 <p><strong>Uutissovellus</strong> sisältää tuoreet juttumme, joita ilmestyy ympäri vuorokauden vuoden jokaisena päivänä.</p> 908 <input class="diks-button js-diks-apps-pwa-installation-button" type="button" value="Asenna uutissovellus"> 909 </div> 910 911 <div class="js-diks-apps-pwa-instructions"> 912 <p><span class="diks-hide-on-android diks-hide-on-ios ">Valitettavasti emme tunnistaneet käyttämääsi laitetta ja selainta.<br><br>Uutissovelluksemme toimii Android-laitteilla Chrome-selaimella ja iPhoneilla ja iPadeilla Safari-selaimella. Tietokoneilla uutissovelluksemme toimii Chrome-selaimella.<br><br>Käynnistä laitteellasi jokin näistä selaimista ja palaa tälle sivulle asentamaan uutissovellus. Jos et silti näe tällä sivulla sovelluksen asennuspainiketta, kokeile päivittää selaimesi uusimpaan versioon.</span> <span class="diks-show-on-android">Uutissovelluksemme toimii Android-laitteilla vain Chrome-selaimella. Vaikuttaa siltä, että käytät jotain muuta selainta. Käynnistä laitteellasi Chrome ja palaa tälle sivulle asentamaan uutissovellus.</span> <span class="diks-show-on-ios">Uutissovelluksemme toimii iPhoneilla ja iPadeilla vain Safari-selaimella. Vaikuttaa siltä, että käytät jotain muuta selainta. Käynnistä laitteellasi Safari ja palaa tälle sivulle asentamaan uutissovellus.</span> </p> 913 </div> 914 915 <div class="diks-apps__pwa-ios-modal js-diks-apps-pwa-ios-instructions"> 916 <p> 917 Asenna uutissovellus painamalla 918 <span class="diks-icon " aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> 919 <path fill-rule="evenodd" d="m11 4.08-3.375 2.7-1.25-1.56L12 .72l5.625 4.5-1.25 1.56L13 4.08V14h-2V4.08ZM4 8h6v2H6v10h12V10h-4V8h6v14H4V8Z" clip-rule="evenodd"/> 920</svg> 921</span> 922 ja valitsemalla Lisää Koti-valikkoon. 923 </p> 924 </div>
925 </div><div class="diks-show-on-standalone"> 926 <p>Uutissovellus on asennettu. Löydät sovelluksen kotinäytöltäsi.</p><p><a class="diks-button" href="/">Siirry etusivulle</a></p></div></div> 927 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-12 diks-column--xl-span-2"></div> 928 </div> 929 </div> 930 </main> 931 </div> 932 </div> 933 934 <footer class="diks-footer"><div class="diks-container"><div class="diks-footer__main"> 935 <div class="diks-grid"> 936 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-4 diks-column--xl-span-4"> 937 <p><img src="https://a.vihdinuutiset.fi/styles/e5576057/images/logos/vihdinuutiset.svg" class="diks-logo diks-logo--default diks-footer__main-logo--wide" alt="Vihdin Uutiset"><img src="https://a.vihdinuutiset.fi/styles/e5576057/images/logos/vihdinuutiset-white.svg" class="diks-logo diks-logo--darkmode diks-footer__main-logo--wide" alt="Vihdin Uutiset"></p> 938 <p><strong>Postiosoite:</strong> Vihdin Uutiset, PL 60, 08101 Lohja<br><strong>Päätoimittaja:</strong> Päivi Kallo</p></div> 939 940 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-4 diks-column--xl-span-5"><div class="diks-footer__main-secondary-logos-container"><div class="diks-footer__main-secondary-logo"><a href="https://vastuullistajournalismia.fi/"><img src="https://a.vihdinuutiset.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"> 941 <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/">Tekoäly journalismissamme</a></div> 942 <div class="diks-column diks-column--span-2"><a class="diks-footer__main-link" href="https://oma.media.fi/lehti/vihdin-uutiset/">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/lehti/vihdin-uutiset/yhteystiedot/">Yhteystiedot</a></div> 943 </div></div> 944 945 <div class="diks-column diks-column--span-4 diks-column--m-span-8 diks-column--l-span-4 diks-column--xl-span-5"> 946 <h2 class="diks-footer__main-title">Sovellus</h2><p><strong>Uutissovellus</strong> sisältää tuoreet juttumme, joita ilmestyy ympäri vuorokauden vuoden jokaisena päivänä.</p><p><a class="diks-button diks-button--light" href="/asenna/" >Asenna uutissovellus</a></p> 947 948 949 </div> 950 </div> 951 </div><div class="diks-footer__bottom"> 952 <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.vihdinuutiset.fi/styles/e5576057/images/logos/keskisuomalainen-sign.svg" loading="lazy" alt="Keskisuomalainen Oyj"></a></div><span>Kuulumme Mediakonserni Keskisuomalaiseen</span></div> 953 <div class="diks-footer__bottom-link-farm-wrapper"> 954 <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/'>
954Viispiikkinen</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> 955 </div> 956 </div></div> 957</footer> 958 959 960
960<script> 961 if (!DOMTokenList.prototype.replace) { 962 // IE Polyfill 963 DOMTokenList.prototype.replace = function (a, b) { 964 if (this.contains(a)) { 965 this.add(b); 966 this.remove(a); 967 return true; 968 } 969 return false; 970 } 971 } 972 973 document.querySelector('.diks-no-js').classList.replace('diks-no-js', 'diks-js'); 974 975 // User agent sniffing is not reliable and it's going away. 976 // Use only to sprinkle a little bit of progressive enhancement on top. 977 // Dear Apple, stop lying, iPad on iOS 13 is not a Mac. You're turning into 90s Microsoft. 978 var userAgent = navigator.userAgent || navigator.vendor || window.opera; 979 if (/android/i.test(userAgent)) { 980 document.querySelector('html').classList.add('diks-user-agent--android'); 981 } else if (/iPad|iPhone|iPod/i.test(userAgent) && !window.MSStream) { 982 document.querySelector('html').classList.add('diks-user-agent--ios'); 983 } else if (/macintosh/i.test(userAgent) && navigator.maxTouchPoints > 1) { 984 document.querySelector('html').classList.add('diks-user-agent--ios'); 985 } 986</script>
986 987
988<script> 989 // Fix forEach for IE 990 if (window.NodeList && !NodeList.prototype.forEach) { 991 NodeList.prototype.forEach = Array.prototype.forEach; 992 } 993 994 // Element.closest() needs a polyfill for older browsers. 995 // While we only need the closest() functionality for mobile browsers, 996 // we don't want the code to fail even on old desktop browsers. 997 // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill 998 // https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Browser_compatibility 999 if (!Element.prototype.matches) { 1000 Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 1001 } 1002 1003 if (!Element.prototype.closest) { 1004 Element.prototype.closest = function(s) { 1005 var el = this; 1006 1007 do { 1008 if (el.matches(s)) return el; 1009 el = el.parentElement || el.parentNode; 1010 } while (el !== null && el.nodeType === 1); 1011 return null; 1012 }; 1013 } 1014 1015 function setAriaExpanded(toggler, ariaExpandedValue) { 1016 // Set aria-expanded attribute of dropdown toggler 1017 // If the toggler contains a button, set the aria-expanded attribute for the button instead 1018 if ( toggler.querySelector('button') != null ) { 1019 toggler.querySelector('button').setAttribute('aria-expanded', ariaExpandedValue); 1020 } 1021 else { 1022 toggler.setAttribute('aria-expanded', ariaExpandedValue); 1023 } 1024 } 1025 1026 function toggleElement(target, toggleClass, toggler) { 1027 if (toggleClass) { 1028 var isOpenClass = toggleClass + '--is-open'; 1029 var isClosedClass = toggleClass + '--is-closed'; 1030 1031 if (target.classList.contains(isOpenClass)) { 1032 // Close this toggle 1033 target.classList.remove(isOpenClass); 1034 target.classList.add(isClosedClass); 1035 1036 // Set aria-expanded to false for the toggler 1037 setAriaExpanded(toggler, 'false'); 1038 1039 } else if (target.classList.contains(isClosedClass)) { 1040 // Open this toggle 1041 target.classList.remove(isClosedClass); 1042 target.classList.add(isOpenClass); 1043 1044 // Set aria-expanded to true for the toggler 1045 setAriaExpanded(toggler, 'true'); 1046 } else { 1047 // Open this toggle as a fallback 1048 target.classList.add(isOpenClass); 1049 1050 // Set aria-expanded to true for the toggler 1051 setAriaExpanded(toggler, 'true'); 1052 } 1053 } else { 1054 if (window.getComputedStyle(target).display !== 'none') { 1055 target.style.display = 'none'; 1056 } else { 1057 target.style.display = 'block'; 1058 } 1059 } 1060 }; 1061 1062 document.querySelectorAll('.js-diks-toggler').forEach(function(toggler) { 1063 var toggleId = toggler.getAttribute('data-diks-toggle'); 1064 var target = document.getElementById(toggleId); 1065 var eventListenerAttached = toggler.getAttribute('data-diks-event-click'); 1066 1067 if (target && !eventListenerAttached) { 1068 1069 // Set aria-controls of toggler 1070 if ( toggler.querySelector('button') != null ) { 1071 toggler.querySelector('button').setAttribute('aria-controls', toggleId); 1072 } 1073 else { 1074 toggler.setAttribute('aria-controls', toggleId); 1075 } 1076 1077 toggler.addEventListener('click', function(e) { 1078 e.preventDefault(); 1079 1080 var toggleClass = toggler.getAttribute('data-diks-toggle-class'); 1081 1082 if (webShareAPIEnabled(toggleId)) { 1083 share(); 1084 } else { 1085 toggleElement(target, toggleClass, toggler); 1086 } 1087 }); 1088 1089 toggler.setAttribute('data-diks-event-click', true); 1090 } 1091 }); 1092 1093 // Web Share and Clipboard API capabilities 1094 1095 function webShareAPIEnabled(toggleId) { 1096 const webShareAPIEnabled = true; 1097 const webShareAPIDropdownShareIds = ["jaa","jakopainikkeet"]; 1098 const isMobileDevice = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); 1099 1100 return webShareAPIEnabled && webShareAPIDropdownShareIds.includes(toggleId) && isMobileDevice && navigator.share ? true : false; 1101 } 1102 1103 function share() { 1104 const metaTitleElement = document.querySelector('meta[property="og:title"]'); 1105 const metaDescriptionElement = document.querySelector('meta[name="description"]'); 1106 const metaUrlElement = document.querySelector('meta[property="og:url"]'); 1107 let title = ''; 1108 let description = ''; 1109 let url = document.location.href; 1110 1111 if (metaTitleElement && metaTitleElement.content) { 1112 title = metaTitleElement.content; 1113 } 1114 1115 if (metaDescriptionElement && metaDescriptionElement.content) { 1116 description = metaDescriptionElement.content; 1117 } 1118 1119 if (metaUrlElement && metaUrlElement.content) { 1120 url = metaUrlElement.content; 1121 } 1122 1123 navigator.share({ 1124 title: title, 1125 text: description, 1126 url: url 1127 }); 1128 } 1129 1130 document.querySelectorAll('.js-diks-share-clipboard').forEach(function(element) { 1131 element.addEventListener('click', function(e) { 1132 e.preventDefault(); 1133 1134 let url = document.location.href; 1135 const metaUrlElement = document.querySelector('meta[property="og:url"]'); 1136 1137 if (metaUrlElement && metaUrlElement.content) { 1138 url = metaUrlElement.content; 1139 } 1140 1141 // Copy URL to clipboard 1142 navigator.clipboard.writeText(url).then(function () { 1143 // Copying URL to clipboard succeeded 1144 const dropdownId = element.getAttribute('data-diks-dropdown-id'); 1145 // Find closest dropdown toggler 1146 let dropdownToggler = element.closest('.diks-dropdown').querySelector('.js-diks-toggler'); 1147 1148 if (dropdownId) { 1149 const dropdownElement = document.getElementById(dropdownId); 1150 1151 if (dropdownElement) { 1152 // Close currently open dropdown 1153 toggleElement(dropdownElement, 'diks-dropdown__content', dropdownToggler); 1154 } 1155 1156 // Show link copied notification text 1157 const notificationTextWrapperDiv = document.createElement('div'); 1158 const notificationTextDiv = document.createElement('div'); 1159 const notificationText = document.createTextNode('Linkki kopioitu leikepöydälle'); 1160 1161 notificationTextDiv.classList.add('diks-dropdown__notification-text'); 1162 notificationTextDiv.appendChild(notificationText); 1163 notificationTextWrapperDiv.classList.add('diks-dropdown__notification-text-wrapper'); 1164 notificationTextWrapperDiv.appendChild(notificationTextDiv); 1165 dropdownElement.parentNode.insertBefore(notificationTextWrapperDiv, null); 1166 1167 setTimeout(function () { 1168 notificationTextWrapperDiv.remove(); 1169 }, 5000); 1170 } 1171 }); 1172 }); 1173 }); 1174
1175 const initContentBlockToggleButtons = () => { 1176 const toggleContainers = document.querySelectorAll('[data-diks-init="toggle"]'); 1177 toggleContainers.forEach(container => { 1178 const toggleButton = container.querySelector('.diks-toggle-button'); 1179 const toggleContent = container.querySelector('.diks-toggle-content-container'); 1180 if (toggleButton && toggleContent) { 1181 toggleButton.addEventListener('click', () => { 1182 toggleElement(toggleContent, 'diks-toggle', toggleButton); 1183 }); 1184 } 1185 }); 1186 }; 1187 document.addEventListener('DOMContentLoaded', () => { 1188 initContentBlockToggleButtons(); 1189 }); 1190 1191</script>
1191 1192
1193<script> 1194 const useDragThreshold = true; 1195 1196 // Horizontally scrollable & draggable navigation 1197 class HorizontalScrollDragger { 1198 constructor(element) { 1199 this.slider = typeof element === 'string' ? document.querySelector(element) : element instanceof Element ? element : null; 1200 if (this.slider === null) return console.error('HorizontalScrollDragger: Element not found'); 1201 1202 this.isDown = false; 1203 this.preventClick = false; 1204 this.startX; 1205 this.scrollLeft; 1206 1207 this.dragThreshold = 5; 1208 this.dragSensitivity = 1; 1209 this.dragged = false; 1210 1211 this.init(); 1212 } 1213 1214 init() { 1215 this.slider.addEventListener('mousedown', (e) => this.handleMouseDown(e)); 1216 this.slider.addEventListener('mouseleave', () => this.handleMouseLeave()); 1217 this.slider.addEventListener('mouseup', () => this.handleMouseUp()); 1218 this.slider.addEventListener('mousemove', (e) => this.handleMouseMove(e)); 1219 this.slider.addEventListener('click', (e) => this.handleClick(e)); 1220 } 1221 1222 handleMouseDown(e) { 1223 this.isDown = true; 1224 this.slider.classList.add('diks-navigation--draggable-active'); 1225 this.startX = e.pageX - this.slider.offsetLeft; 1226 this.scrollLeft = this.slider.scrollLeft; 1227 this.preventClick = false; 1228 } 1229 1230 handleMouseLeave() { 1231 this.isDown = false; 1232 this.slider.classList.remove('diks-navigation--draggable-active'); 1233 } 1234 1235 handleMouseUp() { 1236 this.isDown = false; 1237 this.slider.classList.remove('diks-navigation--draggable-active'); 1238 } 1239 1240 handleMouseMove(e) { 1241 if (!this.isDown) return; 1242 1243 if ( useDragThreshold == true ) { 1244 const xWithThreshold = e.pageX - this.slider.offsetLeft; 1245 const delta = xWithThreshold - this.startX; 1246 1247 // If not yet dragging, check threshold 1248 if (!this.dragged && Math.abs(delta) > this.dragThreshold) { 1249 this.dragged = true; 1250 this.preventClick = true; 1251 1252 // Reset baseline so scrolling starts smoothly from here 1253 this.startX = xWithThreshold; 1254 this.scrollLeft = this.slider.scrollLeft; 1255 } 1256 1257 if (this.dragged) { 1258 e.preventDefault(); 1259 const walkWithThreshold = (xWithThreshold - this.startX) * this.dragSensitivity; // adjust sensitivity 1260 this.slider.scrollLeft = this.scrollLeft - walkWithThreshold; 1261 } 1262 } 1263 else { 1264 e.preventDefault(); 1265 const x = e.pageX - this.slider.offsetLeft; 1266 const walk = (x - this.startX) * this.dragSensitivity; // adjust sensitivity 1267 this.slider.scrollLeft = this.scrollLeft - walk; 1268 this.preventClick = true; 1269 } 1270 1271 } 1272 1273 handleClick(e) { 1274 if ( useDragThreshold == true && this.preventClick && this.dragged ) { 1275 e.preventDefault(); 1276 } 1277 else if ( useDragThreshold == false && this.preventClick) { 1278 e.preventDefault(); 1279 } 1280 } 1281 } 1282 1283 // Set the draggable navs (multiple) to handle their scrollbars 1284 let scrollableNavs = document.querySelectorAll('.diks-navigation--draggable'); 1285 1286 // Make draggable navigation draggable 1287 if ( scrollableNavs ) { 1288 scrollableNavs.forEach(function(element) { 1289 new HorizontalScrollDragger(element); 1290 }); 1291 } 1292 1293 1294 // Handle has-scrollbars class adding and removing 1295 function handleScrollableNavScrollbars(scrollableNavElement) { 1296 // If scrollable area is wider (scrollWidth) than what's visible (clientWidth) the element has scrollbars 1297 if ( scrollableNavElement.scrollWidth > scrollableNavElement.clientWidth ) { 1298 scrollableNavElement.classList.add('diks-navigation--draggable-has-scrollbars'); 1299 scrollableNavElement.parentElement.classList.add('diks-navigation-wrapper--has-scrollbars'); 1300 } 1301 // Remove the has-scrollbars class if it exists but shouldn't (element does not have scrollbars) 1302 else if ( scrollableNavElement.classList.contains('diks-navigation--draggable-has-scrollbars') ) { 1303 scrollableNavElement.classList.remove('diks-navigation--draggable-has-scrollbars'); 1304 scrollableNavElement.parentElement.classList.remove('diks-navigation-wrapper--has-scrollbars'); 1305 } 1306 } 1307 1308 // If scrollable nav exists add (or remove) necessary classes 1309 // "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 1310 window.addEventListener('load', (event) => { 1311 if ( scrollableNavs ) {
1312 scrollableNavs.forEach(function(element) { 1313 handleScrollableNavScrollbars(element); 1314 }); 1315 } 1316 }); 1317 1318 // Check if scrollable nav has scrollbar 1319 window.addEventListener('resize', function(event){ 1320 if ( scrollableNavs ) { 1321 scrollableNavs.forEach(function(element) { 1322 handleScrollableNavScrollbars(element); 1323 }); 1324 } 1325 }); 1326</script>
1326 1327
1328<script> 1329 // Back button handling 1330 document.querySelectorAll('a.js-diks-back-button').forEach(function(item) { 1331 var referrerIsSameDomain = false; 1332 // Check if referrer is found as referrer isn't always available (browser, tab, window, bookmark, privacy). 1333 if (typeof(document.referrer) === 'string' && document.referrer.length > 0) { 1334 // 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) 1335 if ( document.referrer.includes(document.location.hostname) && document.referrer != window.location.href ) { 1336 referrerIsSameDomain = true; 1337 } 1338 } 1339 1340 // Overwrite link with history.go, as it also remembers scroll position but only if referrer is the same domain as current location hostname 1341 if (history.length > 1 && referrerIsSameDomain == true) { 1342 // Set referrer as back button href to enable visual cue & opening to a new window 1343 item.setAttribute('href', document.referrer); 1344 1345 // Set back button text 1346 item.querySelector('.diks-header__cta-text').innerHTML = "Takaisin"; 1347 1348 var stepsToGoBack = -1; 1349 1350 item.addEventListener('click', function(e) { 1351 e.preventDefault(); 1352 history.go(stepsToGoBack); 1353 }); 1354 } 1355 }); 1356</script>
1356 1357 1358 <link rel="stylesheet" href="/theme/css/includes/lightgallery/css/lightgallery-bundle.min.css"> 1359 <style>.lg-sub-html { background-color: rgba(0,0,0, .6); }</style> 1360
1360<script src="/theme/css/includes/lightgallery/lightgallery.min.js"></script>
1360 1361
1361<script src="/theme/css/includes/lightgallery/plugins/autoplay/lg-autoplay.min.js"></script>
1361 1362
1362<script src="/theme/css/includes/lightgallery/plugins/fullscreen/lg-fullscreen.min.js"></script>
1362 1363
1363<script src="/theme/css/includes/lightgallery/plugins/thumbnail/lg-thumbnail.min.js"></script>
1363 1364
1364<script src="/theme/css/includes/lightgallery/plugins/zoom/lg-zoom.min.js"></script>
1364 1365
1365<script> 1366 // lightGallery 1367 // Separate gallery for every .js-lightgallery 1368 // Gallery items come from .js-lightgallery .js-lightgallery__link 1369 // https://www.lightgalleryjs.com/docs/getting-started/ 1370 document.querySelectorAll('.js-diks-lightgallery').forEach(function(gallery) { 1371 var galleryImageLinks = gallery.getElementsByClassName('diks-gallery__link'); 1372 1373 // Thumbnails come from img inside the links, unless links specify data-thumbnail 1374 var thumbnailSource = (galleryImageLinks[0].hasAttribute('data-thumbnail')) ? ('data-thumbnail') : (false); 1375 1376 // Adjust certain settings depending on whether the gallery has one or more images 1377 var galleryHasMultipleImages = (galleryImageLinks.length > 1 ? true : false); 1378 1379 // Initialize 1380 lightGallery(gallery, { 1381 autoplay: galleryHasMultipleImages, 1382 counter: galleryHasMultipleImages, 1383 download: false, 1384 exThumbImage: thumbnailSource, 1385 hideControlOnEnd: true, 1386 licenseKey: "96BAAD7E-3BF04397-BBB55AE3-6D5A2C0B", 1387 loop: false, 1388 plugins: [lgAutoplay, lgFullscreen, lgThumbnail, lgZoom], 1389 selector: '.diks-gallery__link', 1390 mobileSettings: { 1391 controls: true, 1392 showCloseIcon: true 1393 }, 1394 strings: { 1395 closeGallery: 'Sulje galleria', 1396 toggleMaximize: 'Maksimointi', 1397 previousSlide: 'Edellinen', 1398 nextSlide: 'Seuraava', 1399 download: 'Lataa', 1400 playVideo: 'Katso video', 1401 mediaLoadingFailed: 'Sisällön lataus epäonnistui', 1402 }, 1403 autoplayPluginStrings: { 1404 toggleAutoplay: 'Automaattinen toisto' 1405 }, 1406 fullscreenPluginStrings: { 1407 toggleFullscreen: 'Kokoruututila' 1408 }, 1409 thumbnailPluginStrings: { 1410 toggleThumbnails: 'Pikkukuvat' 1411 }, 1412 zoomPluginStrings: { 1413 zoomIn: 'Suurenna', 1414 zoomOut: 'Pienennä', 1415 viewActualSize: 'Näytä täysikokoisena' 1416 } 1417 }); 1418 1419 // After closing LightGallery return focus to the image link that opened the gallery 1420 gallery.addEventListener('lgAfterClose', () => { 1421 galleryImageLinks[0].focus(); 1422 }); 1423 1424 }); 1425 1426 </script>
1426 1427
1428<script> 1429 function loadScript(url, callback) { 1430 var script = document.createElement("script"); 1431 script.type = "text/javascript"; 1432 if (script.readyState) { // IE 1433 script.onreadystatechange = function() { 1434 if (script.readyState === "loaded" || script.readyState === "complete") { 1435 script.onreadystatechange = null; 1436 callback(); 1437 } 1438 }; 1439 } else { // Others 1440 script.onload = function() { 1441 callback(); 1442 }; 1443 } 1444 script.src = url; 1445 document.getElementsByTagName("head")[0].appendChild(script); 1446 } 1447 function checkAudioElements() { 1448 // load audioplayer script only when audio elements are found 1449 if (document.querySelector(".init-audio-player")) { 1450 loadScript("https://a.vihdinuutiset.fi/styles/e5576057/js/audioplayer/diks-audioplayer.min.js", function() { 1451 DiksAudioPlayer.init({ 1452 selector: '.init-audio-player', 1453 stopOthersOnPlay: true, 1454 enableKeystrokes: true 1455 }); 1456 }); 1457 } 1458 } 1459 window.onload = (event) => { 1460 checkAudioElements(); 1461 }; 1462</script>
1462<script> 1463 // Service Worker 1464 if ('serviceWorker' in navigator) { 1465 window.addEventListener('load', function() { 1466 navigator.serviceWorker.register('/sw.js').then( 1467 function(registration) { 1468 console.log('PWA: Service worker registered to scope: ', registration.scope); 1469 }, 1470 function(err) { 1471 console.error('PWA: Service worker failed to register with error: ', err); 1472 } 1473 ); 1474 }); 1475 } 1476 1477 // Show installation option, hide generic fallback instructions 1478 function pwaShowInstallationOption() { 1479 document.querySelectorAll('.js-diks-apps-pwa-installation').forEach(function(element) { 1480 element.style.display = 'block'; 1481 }); 1482 document.querySelectorAll('.js-diks-apps-pwa-instructions').forEach(function(element) { 1483 element.style.display = 'none'; 1484 }); 1485 } 1486 1487 let deferredPrompt; 1488 var dataLayer = window.dataLayer || []; 1489 1490 // Basic installation process 1491 window.addEventListener('beforeinstallprompt', (e) => { 1492 // Stash the event so it can be triggered later 1493 deferredPrompt = e; 1494 1495 const enablePrompt = 1; 1496 1497 if(!enablePrompt) { 1498 e.preventDefault(); 1499 } 1500 1501 // Update the UI to notify the user they can install PWA 1502 pwaShowInstallationOption(); 1503 1504 // Handle installation 1505 document.querySelectorAll('.js-diks-apps-pwa-installation-button').forEach(function(button) { 1506 button.addEventListener('click', (e) => { 1507 // Show the prompt 1508 deferredPrompt.prompt(); 1509 1510 // Wait for user to respond 1511 deferredPrompt.userChoice.then((choiceResult) => { 1512 if (choiceResult.outcome === 'accepted') { 1513 console.log('PWA: Installed (prompt)'); 1514 dataLayer.push({ 1515 'event': 'PWA.installation', 1516 'eventData': 'success' 1517 }); 1518 } else { 1519 console.log('PWA: User dismissed installation prompt'); 1520 dataLayer.push({ 1521 'event': 'PWA.installation', 1522 'eventData': 'canceled' 1523 }); 1524 } 1525 deferredPrompt = null; 1526 }); 1527 }); 1528 }); 1529 }); 1530 1531 // iOS installation process (show instructions modal) 1532 if (!navigator.standalone) { 1533 var userAgent = navigator.userAgent.toLowerCase(); 1534 var iPhoneUser = (/iphone/.test(userAgent)); 1535 var iPadUser = (/ipad/.test(userAgent) || (/macintosh/.test(userAgent) && navigator.maxTouchPoints > 1)); 1536 var safariUser = (/^(?!.*(brave|chrome|crios|duckduckgo|edgeios|firefox|fxios|opios|ucbrowser|yabrowser)).*safari.*$/.test(userAgent)); 1537 1538 if (safariUser && (iPhoneUser || iPadUser)) { 1539 // Update the UI to notify the user they can install PWA 1540 pwaShowInstallationOption(); 1541 1542 // Instructions 1543 var modals = document.querySelectorAll('.js-diks-apps-pwa-ios-instructions').forEach(function(element) { 1544 // Position on screen based on device 1545 if (iPhoneUser) { 1546 element.classList.add('diks-apps__pwa-ios-modal--bottom'); 1547 } else if (iPadUser) { 1548 element.classList.add('diks-apps__pwa-ios-modal--top'); 1549 } 1550 }); 1551 1552 // Handle modal instructions from installation button 1553 document.querySelectorAll('.js-diks-apps-pwa-installation-button').forEach(function(button) { 1554 button.addEventListener('click', (e) => { 1555 // Show first modal 1556 document.querySelector('.js-diks-apps-pwa-ios-instructions').classList.toggle('diks-apps__pwa-ios-modal--is-visible'); 1557 dataLayer.push({ 1558 'event': 'PWA.instructions.shown', 1559 'eventData': 'iOS' 1560 }); 1561 }); 1562 }); 1563 } 1564 } 1565</script>
1565 1566
1566<script class="coral-script" src="//coral.prod.diks.fi/assets/js/count.js?v=9.3.1.3" defer></script>
1566 1567 1568 </body> 1569</html> 1570
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.