From 0347d79552dc9a1e1aa6a6d4b5cb489b94feb4b4 Mon Sep 17 00:00:00 2001 From: Mikko Tapionlinna Date: Wed, 17 Apr 2024 14:16:44 +0300 Subject: [PATCH 1/8] UHF-9797: Fix cookie path --- src/js/hds-cc/hds-cc.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/js/hds-cc/hds-cc.js b/src/js/hds-cc/hds-cc.js index 71d67add6..c5c7812b3 100644 --- a/src/js/hds-cc/hds-cc.js +++ b/src/js/hds-cc/hds-cc.js @@ -230,7 +230,13 @@ class HdsCookieConsentClass { // console.log('#setCookie', cookieData); const expiryDate = new Date(); expiryDate.setDate(expiryDate.getDate() + this.#COOKIE_DAYS); - document.cookie = serialize(this.#cookie_name, JSON.stringify(cookieData), { expires: expiryDate }); + document.cookie = serialize( + this.#cookie_name, + JSON.stringify(cookieData), + { + expires: expiryDate, + path: '/', + }); } From 008c09234cc10a96dad2045c77e06693094dd32d Mon Sep 17 00:00:00 2001 From: Mikko Tapionlinna Date: Wed, 17 Apr 2024 14:17:54 +0300 Subject: [PATCH 2/8] UHF-9797: Remember to uncheck unaccepted groups too --- src/js/hds-cc/hds-cc.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/js/hds-cc/hds-cc.js b/src/js/hds-cc/hds-cc.js index c5c7812b3..484b6886b 100644 --- a/src/js/hds-cc/hds-cc.js +++ b/src/js/hds-cc/hds-cc.js @@ -275,9 +275,7 @@ class HdsCookieConsentClass { const formCheckboxes = form.querySelectorAll('input'); formCheckboxes.forEach(check => { - if (acceptedGroupNames.includes(check.dataset.group)) { - check.checked = true; - } + check.checked = acceptedGroupNames.includes(check.dataset.group); }); } } From 269f612b1e70cb3609e05af422f1c9399cab22ad Mon Sep 17 00:00:00 2001 From: Mikko Tapionlinna Date: Wed, 17 Apr 2024 14:21:30 +0300 Subject: [PATCH 3/8] UHF-9797: Move temporary css injection to separate function for clarity --- src/js/hds-cc/hds-cc.js | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/js/hds-cc/hds-cc.js b/src/js/hds-cc/hds-cc.js index 484b6886b..58e1e1d2e 100644 --- a/src/js/hds-cc/hds-cc.js +++ b/src/js/hds-cc/hds-cc.js @@ -573,6 +573,29 @@ class HdsCookieConsentClass { return groupsHtml; } + /** + * Temporary solition to inject CSS styles into the shadow root. + * @private + * @param {ShadowRoot} shadowRoot - The shadow root element to inject the styles into. + * @return {Promise} - A promise that resolves when the styles are injected successfully. + * @throws {Error} - If there is an error fetching or injecting the styles. + */ + async #injectCssStyles(shadowRoot) { + // TODO: Replace this temporary CSS file hack with proper preprocess CSS inlining + // Fetch the external CSS file + try { + const response = await fetch(this.#TEMP_CSS_PATH); + const cssText = await response.text(); + + // Create and inject the style + const style = document.createElement('style'); + style.textContent = cssText; + shadowRoot.appendChild(style); + } catch (error) { + throw new Error(`Cookie consent: Failed to load the temporary CSS file solution: '${error}'`); + } + } + /** * Renders the cookie consent banner. * @private @@ -604,19 +627,8 @@ class HdsCookieConsentClass { const shadowRoot = bannerContainer.attachShadow({ mode: 'open' }); this.#shadowRoot = shadowRoot; - // TODO: Replace this temporary CSS file hack with proper preprocess CSS inlining - // Fetch the external CSS file - try { - const response = await fetch(this.#TEMP_CSS_PATH); - const cssText = await response.text(); - - // Create and inject the style - const style = document.createElement('style'); - style.textContent = cssText; - shadowRoot.appendChild(style); - } catch (error) { - throw new Error(`Cookie consent: Failed to load the temporary CSS file solution: '${error}'`); - } + // Inject CSS styles + await this.#injectCssStyles(shadowRoot); const translations = {}; const translationKeys = getTranslationKeys(); From 1846b546f5bdf3d731388f0945596e565188cc84 Mon Sep 17 00:00:00 2001 From: Mikko Tapionlinna Date: Wed, 17 Apr 2024 14:23:15 +0300 Subject: [PATCH 4/8] UHF-9797: Move button event handling to a better location in code --- src/js/hds-cc/hds-cc.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/js/hds-cc/hds-cc.js b/src/js/hds-cc/hds-cc.js index 58e1e1d2e..54d7d7617 100644 --- a/src/js/hds-cc/hds-cc.js +++ b/src/js/hds-cc/hds-cc.js @@ -653,6 +653,13 @@ class HdsCookieConsentClass { // Create banner HTML shadowRoot.innerHTML += getCookieBannerHtml(translations, groupsHtml); + // Add button events + const cookieButtons = shadowRoot.querySelectorAll('button[type=submit]'); + const shadowRootForm = shadowRoot.querySelector('form'); + cookieButtons.forEach(button => button.addEventListener('click', e => { + this.#handleButtonEvents(e.target.dataset.approved, shadowRootForm, cookieSettings); + })); + // Add scroll-margin-bottom to all elements inside the contentSelector const style = document.createElement('style'); style.innerHTML = `${this.#PAGE_CONTENT_SELECTOR} * {scroll-margin-bottom: calc(var(--hds-cookie-consent-height, -8px) + 8px);}`; @@ -677,13 +684,6 @@ class HdsCookieConsentClass { this.#resizeReference.resizeObserver = resizeObserver; this.#resizeReference.bannerHeightElement = bannerHeightElement; - // Add button events - const cookieButtons = shadowRoot.querySelectorAll('button[type=submit]'); - const shadowRootForm = shadowRoot.querySelector('form'); - cookieButtons.forEach(button => button.addEventListener('click', e => { - this.#handleButtonEvents(e.target.dataset.approved, shadowRootForm, cookieSettings); - })); - shadowRoot.querySelector('.hds-cc').focus(); } From c5a8c3947b576636fdd1d453e891938c1553203a Mon Sep 17 00:00:00 2001 From: Mikko Tapionlinna Date: Wed, 17 Apr 2024 15:57:50 +0300 Subject: [PATCH 5/8] UHF-9797: Add support for rendering the banner contents on a page instead of banner --- src/js/hds-cc/hds-cc.js | 146 ++++++++++++++-------- src/js/hds-cc/template.js | 5 +- src/scss/cookie-consent.scss | 62 ++++++--- templates/misc/cookie-container.html.twig | 1 + 4 files changed, 138 insertions(+), 76 deletions(-) diff --git a/src/js/hds-cc/hds-cc.js b/src/js/hds-cc/hds-cc.js index 54d7d7617..2ee748904 100644 --- a/src/js/hds-cc/hds-cc.js +++ b/src/js/hds-cc/hds-cc.js @@ -28,6 +28,7 @@ class HdsCookieConsentClass { #SPACER_PARENT_SELECTOR; #PAGE_CONTENT_SELECTOR; #SUBMIT_EVENT = false; + #SETTINGS_PAGE_SELECTOR; #TEMP_CSS_PATH; #COOKIE_DAYS = 100; @@ -39,6 +40,8 @@ class HdsCookieConsentClass { spacer: null, }; + #settingsPageElement = null; + #resizeReference = { resizeObserver: null, bannerHeightElement: null, @@ -56,6 +59,7 @@ class HdsCookieConsentClass { * @param {string} [options.spacerParentSelector='body'] - The selector for where to inject the spacer. * @param {string} [options.pageContentSelector='body'] - The selector for where to add scroll-margin-bottom. * @param {boolean|string} [options.submitEvent=false] - If a string, do not reload the page, but submit the string as an event after consent. + * @param {string} [options.settingsPageSelector=null] - If this string is set and a matching element is found on the page, show cookie settings in a page replacing the matched element. * @param {string} [options.tempCssPath='/path/to/external.css'] - The temporary path to the external CSS file. * @throws {Error} Throws an error if siteSettingsJsonUrl is not provided. */ @@ -67,6 +71,7 @@ class HdsCookieConsentClass { spacerParentSelector = 'body', // Where to inject the spacer pageContentSelector = 'body', // Where to add scroll-margin-bottom submitEvent = false, // if string, do not reload page, but submit the string as event after consent + settingsPageSelector = null, // If this string is set and a matching element is found on the page, show cookie settings in a page replacing the matched element. tempCssPath = '/path/to/external.css', // TODO: Remove this tempoarry path to external CSS file } ) { @@ -79,6 +84,7 @@ class HdsCookieConsentClass { this.#SPACER_PARENT_SELECTOR = spacerParentSelector; this.#PAGE_CONTENT_SELECTOR = pageContentSelector; this.#SUBMIT_EVENT = submitEvent; + this.#SETTINGS_PAGE_SELECTOR = settingsPageSelector; this.#TEMP_CSS_PATH = tempCssPath; window.hds = window.hds || {}; @@ -359,11 +365,12 @@ class HdsCookieConsentClass { /** * Retrieves the cookie settings and performs necessary checks. * @private + * @param {boolean} [isBanner=true] - Optional parameter to bypass certain checks when settings page is being rendered. * @return {Promise} A promise that resolves to the result of removing invalid groups from the cookie settings. * @throws {Error} If the required group or cookie is missing in the cookie settings. * @throws {Error} If there are multiple cookie groups with identical names in the cookie settings. */ - async #getCookieSettings() { + async #getCookieSettings(isBanner = true) { const cookieSettings = await this.#getCookieSettingsFromJsonFile(); this.#cookie_name = cookieSettings.cookieName || this.#cookie_name; // Optional override for cookie name @@ -372,7 +379,7 @@ class HdsCookieConsentClass { const browserCookie = this.#getCookie(); if (browserCookie) { // Check if settings have not changed and browser cookie has 'showBanner' set to false - if (!browserCookie.showBanner && (cookieSettings.checksum === browserCookie.checksum)) { + if (isBanner && !browserCookie.showBanner && (cookieSettings.checksum === browserCookie.checksum)) { // console.log('Settings were unchanged'); return this.#UNCHANGED; } @@ -462,21 +469,30 @@ class HdsCookieConsentClass { window.location.reload(); } else { window.dispatchEvent(new CustomEvent(this.#SUBMIT_EVENT, { detail: { acceptedGroups } })); - this.#removeBanner(); + + // Handle selector and removal of banner depending on rendering mode: banner or page. + let ariaSelector = this.#TARGET_SELECTOR; + let ariaParentElement; + if (this.#settingsPageElement) { + ariaSelector = this.#SETTINGS_PAGE_SELECTOR; + ariaParentElement = this.#settingsPageElement; + } else { + ariaParentElement = document.querySelector(this.#TARGET_SELECTOR); + this.#removeBanner(); + } // Announce settings saved to screen readers const ARIA_LIVE_ID = 'hds-cc-aria-live'; const SHOW_ARIA_LIVE_FOR_MS = 5000; - const bannerTarget = document.querySelector(this.#TARGET_SELECTOR); - if (!bannerTarget) { - throw new Error(`Cookie consent: targetSelector element '${this.#TARGET_SELECTOR}' was not found`); + if (!ariaParentElement) { + throw new Error(`Cookie consent: Aria notification parent element '${ariaSelector}' was not found`); } const ariaLive = document.createElement('div'); ariaLive.id = ARIA_LIVE_ID; ariaLive.setAttribute('aria-live', 'polite'); ariaLive.style = 'position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;'; ariaLive.textContent = getTranslation('settingsSaved', this.#LANGUAGE); - bannerTarget.appendChild(ariaLive); + ariaParentElement.appendChild(ariaLive); // Remove ariaLive after 5 seconds setTimeout(() => { @@ -597,34 +613,39 @@ class HdsCookieConsentClass { } /** - * Renders the cookie consent banner. + * Renders the cookie consent banner or page element. * @private * @param {string} lang - The language for translations. * @param {Object} cookieSettings - The cookie settings object. + * @param {boolean} isBanner - Indicates if rendering banner or page element. + * @param {HTMLElement} renderTarget - The target element for rendering the page element, unset otherwise. * @throws {Error} If the targetSelector element is not found. * @throws {Error} If the spacerParentSelector element is not found. * @throws {Error} If the contentSelector element is not found. * @throws {Error} If failed to load the temporary CSS file solution. */ - async #renderBanner(lang, cookieSettings) { - const bannerTarget = document.querySelector(this.#TARGET_SELECTOR); - if (!bannerTarget) { - throw new Error(`Cookie consent: targetSelector element '${this.#TARGET_SELECTOR}' was not found`); - } - const spacerParent = document.querySelector(this.#SPACER_PARENT_SELECTOR); - if (!spacerParent) { - throw new Error(`Cookie consent: The spacerParentSelector element '${this.#SPACER_PARENT_SELECTOR}' was not found`); - } - if (!document.querySelector(this.#PAGE_CONTENT_SELECTOR)) { - throw new Error(`Cookie consent: contentSelector element '${this.#PAGE_CONTENT_SELECTOR}' was not found`); + async #render(lang, cookieSettings, isBanner, renderTarget = null) { + let spacerParent; + if (isBanner) { + const bannerTarget = document.querySelector(this.#TARGET_SELECTOR); + if (!bannerTarget) { + throw new Error(`Cookie consent: targetSelector element '${this.#TARGET_SELECTOR}' was not found`); + } + spacerParent = document.querySelector(this.#SPACER_PARENT_SELECTOR); + if (!spacerParent) { + throw new Error(`Cookie consent: The spacerParentSelector element '${this.#SPACER_PARENT_SELECTOR}' was not found`); + } + if (!document.querySelector(this.#PAGE_CONTENT_SELECTOR)) { + throw new Error(`Cookie consent: contentSelector element '${this.#PAGE_CONTENT_SELECTOR}' was not found`); + } + renderTarget = bannerTarget; } - const bannerContainer = document.createElement('div'); - bannerContainer.classList.add('hds-cc__target'); - bannerContainer.style.all = 'initial'; - bannerTarget.prepend(bannerContainer); - this.#bannerElements.bannerContainer = bannerContainer; - const shadowRoot = bannerContainer.attachShadow({ mode: 'open' }); + const container = document.createElement('div'); + container.classList.add('hds-cc__target'); + container.style.all = 'initial'; + renderTarget.prepend(container); + const shadowRoot = container.attachShadow({ mode: 'open' }); this.#shadowRoot = shadowRoot; // Inject CSS styles @@ -651,7 +672,7 @@ class HdsCookieConsentClass { groupsHtml += this.#getCookieGroupsHtml(cookieSettings.optionalCookies.groups, lang, translations, false, 'optional', listOfAcceptedGroups); // Create banner HTML - shadowRoot.innerHTML += getCookieBannerHtml(translations, groupsHtml); + shadowRoot.innerHTML += getCookieBannerHtml(translations, groupsHtml, isBanner); // Add button events const cookieButtons = shadowRoot.querySelectorAll('button[type=submit]'); @@ -660,31 +681,35 @@ class HdsCookieConsentClass { this.#handleButtonEvents(e.target.dataset.approved, shadowRootForm, cookieSettings); })); - // Add scroll-margin-bottom to all elements inside the contentSelector - const style = document.createElement('style'); - style.innerHTML = `${this.#PAGE_CONTENT_SELECTOR} * {scroll-margin-bottom: calc(var(--hds-cookie-consent-height, -8px) + 8px);}`; - document.head.appendChild(style); - - // Add spacer inside spacerParent (to the bottom of the page) - const spacer = document.createElement('div'); - this.#bannerElements.spacer = spacer; - spacer.id = 'hds-cc__spacer'; - spacerParent.appendChild(spacer); - spacer.style.height = 'var(--hds-cookie-consent-height, 0)'; - - // Update spacer and scroll-margin-bottom on banner resize - const resizeObserver = new ResizeObserver(entries => { - entries.forEach(entry => { - document.documentElement.style.setProperty('--hds-cookie-consent-height', `${parseInt(entry.contentRect.height, 10) + parseInt(getComputedStyle(entry.target).borderTopWidth, 10)}px`); - // spacer.style.height = `${entry.contentRect.height + parseInt(getComputedStyle(entry.target).borderTopWidth, 10)}px`; + if (isBanner) { + this.#bannerElements.bannerContainer = container; + + // Add scroll-margin-bottom to all elements inside the contentSelector + const style = document.createElement('style'); + style.innerHTML = `${this.#PAGE_CONTENT_SELECTOR} * {scroll-margin-bottom: calc(var(--hds-cookie-consent-height, -8px) + 8px);}`; + document.head.appendChild(style); + + // Add spacer inside spacerParent (to the bottom of the page) + const spacer = document.createElement('div'); + this.#bannerElements.spacer = spacer; + spacer.id = 'hds-cc__spacer'; + spacerParent.appendChild(spacer); + spacer.style.height = 'var(--hds-cookie-consent-height, 0)'; + + // Update spacer and scroll-margin-bottom on banner resize + const resizeObserver = new ResizeObserver(entries => { + entries.forEach(entry => { + document.documentElement.style.setProperty('--hds-cookie-consent-height', `${parseInt(entry.contentRect.height, 10) + parseInt(getComputedStyle(entry.target).borderTopWidth, 10)}px`); + // spacer.style.height = `${entry.contentRect.height + parseInt(getComputedStyle(entry.target).borderTopWidth, 10)}px`; + }); }); - }); - const bannerHeightElement = shadowRoot.querySelector('.hds-cc__container'); - resizeObserver.observe(bannerHeightElement); - this.#resizeReference.resizeObserver = resizeObserver; - this.#resizeReference.bannerHeightElement = bannerHeightElement; + const bannerHeightElement = shadowRoot.querySelector('.hds-cc__container'); + resizeObserver.observe(bannerHeightElement); + this.#resizeReference.resizeObserver = resizeObserver; + this.#resizeReference.bannerHeightElement = bannerHeightElement; - shadowRoot.querySelector('.hds-cc').focus(); + shadowRoot.querySelector('.hds-cc').focus(); + } } /** @@ -696,12 +721,25 @@ class HdsCookieConsentClass { */ async #init() { this.#removeBanner(); - const cookieSettings = await this.#getCookieSettings(); - // If cookie settings have not changed, do not show banner, otherwise, check - const shouldDisplayBanner = this.#shouldDisplayBanner(cookieSettings); - if (shouldDisplayBanner) { - await this.#renderBanner(this.#LANGUAGE, cookieSettings); + let settingsPageElement = null; + // If settings page selector is enabled, check if the element exists + if (this.#SETTINGS_PAGE_SELECTOR) { + settingsPageElement = document.querySelector(this.#SETTINGS_PAGE_SELECTOR); + } + + if (settingsPageElement) { + const cookieSettings = await this.#getCookieSettings(true); + this.#settingsPageElement = settingsPageElement; + // If settings page element is found, render cookie settings in page instead of banner + await this.#render(this.#LANGUAGE, cookieSettings, false, settingsPageElement); + } else { + const cookieSettings = await this.#getCookieSettings(); + // Check if banner is needed or not + const shouldDisplayBanner = this.#shouldDisplayBanner(cookieSettings); + if (shouldDisplayBanner) { + await this.#render(this.#LANGUAGE, cookieSettings, true); + } } }; } diff --git a/src/js/hds-cc/template.js b/src/js/hds-cc/template.js index 626df6b08..c3083a82e 100644 --- a/src/js/hds-cc/template.js +++ b/src/js/hds-cc/template.js @@ -13,11 +13,12 @@ * @param {string} translations.approveRequiredAndSelectedConsents - The text for the "Approve Required and Selected Consents" button. * @param {string} translations.approveOnlyRequiredConsents - The text for the "Approve Only Required Consents" button. * @param {string} groupsHtml - The HTML for the consent groups. + * @param {boolean} isBanner - Indicates if the code is rendered as banner or part of a page. * @return {string} The HTML for the cookie banner. */ -export function getCookieBannerHtml(translations, groupsHtml) { +export function getCookieBannerHtml(translations, groupsHtml, isBanner = true) { return ` -
+
diff --git a/src/scss/cookie-consent.scss b/src/scss/cookie-consent.scss index 5daa11780..bdccf8558 100644 --- a/src/scss/cookie-consent.scss +++ b/src/scss/cookie-consent.scss @@ -234,6 +234,10 @@ $base-font-size: 16px; // --hds-cc-border-color: #000000; } +.hds-cc--page { + margin-block: var(--spacing-layout-xs); +} + $font-path: '../fonts'; /* Webfont: HelsinkiGrotesk-Regular */ @@ -361,37 +365,51 @@ html { --common-spacing: var(--spacing-s); --focus-outline-color: var(--color-coat-of-arms); --outline-width: 3px; - // all: initial; - bottom: 0; color: var(--color-black-90); font-family: var(--font-default); font-size: var(--fontsize-body-m); - left: 0; - overscroll-behavior: contain; - position: fixed; - width: 100vw; - z-index: 999; + + &.hds-cc--banner { + bottom: 0; + left: 0; + overscroll-behavior: contain; + position: fixed; + width: 100vw; + z-index: 999; + } + + &.hds-cc--page { + padding-top: var(--spacing-layout-xs); + } } + .hds-cc__container { background: var(--color-white); - border-top: 8px solid var(--hds-cc-border-color, var(--color-bus)); - bottom: 0; - max-height: 80vh; - overflow-y: auto; - position: absolute; - width: 100%; - z-index: 2; + + .hds-cc--banner & { + border-top: 8px solid var(--hds-cc-border-color, var(--color-bus)); + bottom: 0; + max-height: 80vh; + overflow-y: auto; + position: absolute; + width: 100%; + z-index: 2; + } } + .hds-cc__aligner { margin-inline: auto; max-width: var(--container-width-xl); - padding: var(--spacing-layout-2-xs); - @media (min-width: 768px) { - padding: var(--spacing-layout-s) var(--spacing-layout-xs); + .hds-cc--banner & { + padding: var(--spacing-layout-2-xs); + + @media (min-width: 768px) { + padding: var(--spacing-layout-s) var(--spacing-layout-xs); + } } } @@ -466,7 +484,11 @@ html { } // Animate form open / close -@include animateheight( '.hds-cc__form', ':not([aria-expanded='true']) + .hds-cc__form', '.hds-cc__form__animator' ); +@include animateheight( '.hds-cc--banner .hds-cc__form', '.hds-cc--banner :not([aria-expanded='true']) + .hds-cc__form', '.hds-cc--banner .hds-cc__form__animator' ); + +.hds-cc--page .hds-cc__accordion-button--details { + display: none; +} .hds-cc__groups{ padding-bottom: var(--spacing-layout-xs); @@ -491,8 +513,8 @@ html { :not([aria-expanded='true']) > .hds-cc__accordion-button-hide, [aria-expanded='true'] > .hds-cc__accordion-button-show, [aria-controls='hds-cc-form'][aria-expanded='true'] ~ .hds-cc__buttons .hds-cc__all-cookies-button, -[aria-controls='hds-cc-form']:not([aria-expanded='true']) ~ .hds-cc__buttons .hds-cc__selected-cookies-button, -.temp { +.hds-cc--page .hds-cc__all-cookies-button, +.hds-cc--banner [aria-controls='hds-cc-form']:not([aria-expanded='true']) ~ .hds-cc__buttons .hds-cc__selected-cookies-button { display: none; } diff --git a/templates/misc/cookie-container.html.twig b/templates/misc/cookie-container.html.twig index 3add8ccb5..eedf83e3e 100644 --- a/templates/misc/cookie-container.html.twig +++ b/templates/misc/cookie-container.html.twig @@ -16,6 +16,7 @@ window.addEventListener('cookie-consent-changed', function(event) { //spacerParentSelector: 'body', // Defaults to 'body' //pageContentSelector: 'body', // Defaults to 'body' //submitEvent: 'cookie-consent-changed', // If this string is set, triggers a window level event with that string and detail.acceptedGroups before closing banner. If not set, reloads page instead + settingsPageSelector: '#hds-cookie-consent-full-page', // If this string is set and matching element is found on page, instead of banner, show a full page cookie settings replacing the matched element. tempCssPath: '{{ theme_path }}/dist/css/cookie-consent.min.css', // TODO: Remove this when the real build process can include css files } }; From 20d9d6e960e40702e22a1ebe0bc7891512918fb1 Mon Sep 17 00:00:00 2001 From: Mikko Tapionlinna Date: Thu, 18 Apr 2024 08:43:20 +0300 Subject: [PATCH 6/8] UHF-9797: Fix cookieShow functionality --- src/js/hds-cc/hds-cc.js | 56 ++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/src/js/hds-cc/hds-cc.js b/src/js/hds-cc/hds-cc.js index 2ee748904..0fafb196b 100644 --- a/src/js/hds-cc/hds-cc.js +++ b/src/js/hds-cc/hds-cc.js @@ -132,7 +132,8 @@ class HdsCookieConsentClass { */ async setGroupsStatusToAccepted(acceptedGroupsArray) { const browserCookie = this.#getCookie(); - const showBanner = browserCookie?.showBanner || false; + // If cookie is not set, or it has a showBanner set to true, we need to set the banner to be shown + const showBanner = !browserCookie || browserCookie.showBanner || false; // If cookie is set, get the accepted groups let currentlyAccepted = []; @@ -254,7 +255,7 @@ class HdsCookieConsentClass { * @param {boolean} showBanner - Whether to show the banner or not. */ #saveAcceptedGroups(cookieSettings, acceptedGroupNames = [], showBanner = false) { - // console.log('Saving accepted cookie groups:', acceptedGroupNames); + // console.log('Saving accepted cookie groups:', acceptedGroupNames, showBanner); const acceptedGroups = {}; @@ -298,35 +299,32 @@ class HdsCookieConsentClass { */ async #removeInvalidGroupsFromCookie(cookieSettingsGroups, browserCookieState, cookieSettings) { // console.log('#removeInvalidGroupsFromCookie', cookieSettingsGroups, browserCookieState, cookieSettings); - + let invalidGroupsFound = false; const newCookieGroups = []; - // If browser cookie has groups - if (browserCookieState.groups) { + // Loop through all groups in cookie settings and store each groups name and checksum + const cookieSettingsGroupsChecksums = {}; + cookieSettingsGroups.forEach(group => { + cookieSettingsGroupsChecksums[group.groupId] = group.checksum; + }); - // Loop through groups in cookie settings - cookieSettingsGroups.forEach(cookieSettingsGroup => { - const browserGroupName = cookieSettingsGroup.groupId; - const matchedBrowserGroup = browserCookieState.groups[browserGroupName]; - if (matchedBrowserGroup) { - - // If group names match - if (browserGroupName === cookieSettingsGroup.groupId) { - - // If checksums match, add to new cookie groups - if (browserCookieState.groups[browserGroupName] === cookieSettingsGroup.checksum) { - newCookieGroups.push(cookieSettingsGroup.groupId); - } else { - console.log(`Checksums do not match for group: '${cookieSettingsGroup.groupId}', removing from cookie accepted.`); - } - } + // Loop through browser cookie groups and check if they are in cookie settings, store valid groups to be saved + if (browserCookieState.groups) { + Object.keys(browserCookieState.groups).forEach(groupName => { + const group = browserCookieState.groups[groupName]; + if (cookieSettingsGroupsChecksums[groupName] && cookieSettingsGroupsChecksums[groupName] === group) { + newCookieGroups.push(group.groupId); + } else { + invalidGroupsFound = true; + console.log(`Invalid group found in browser cookie: '${group.groupId}', removing from cookie.`); } }); - }; + } - // Because global checksum did not match, group checksums were checked and non-matching groups were removed, save the cleaned cookie - const showBanner = true; - this.#saveAcceptedGroups(cookieSettings, newCookieGroups, showBanner); + if (invalidGroupsFound) { + const showBanner = true; + this.#saveAcceptedGroups(cookieSettings, newCookieGroups, showBanner); + } return cookieSettings; } @@ -448,17 +446,17 @@ class HdsCookieConsentClass { switch (selection) { case 'required': { acceptedGroups = [this.#ESSENTIAL_GROUP_NAME]; - this.#saveAcceptedGroups(cookieSettings, acceptedGroups); + this.#saveAcceptedGroups(cookieSettings, acceptedGroups, false); break; } case 'all': { acceptedGroups = this.#readGroupSelections(formReference, true); - this.#saveAcceptedGroups(cookieSettings, acceptedGroups); + this.#saveAcceptedGroups(cookieSettings, acceptedGroups, false); break; } case 'selected': { acceptedGroups = this.#readGroupSelections(formReference); - this.#saveAcceptedGroups(cookieSettings, acceptedGroups); + this.#saveAcceptedGroups(cookieSettings, acceptedGroups, false); break; } default: @@ -729,7 +727,7 @@ class HdsCookieConsentClass { } if (settingsPageElement) { - const cookieSettings = await this.#getCookieSettings(true); + const cookieSettings = await this.#getCookieSettings(false); this.#settingsPageElement = settingsPageElement; // If settings page element is found, render cookie settings in page instead of banner await this.#render(this.#LANGUAGE, cookieSettings, false, settingsPageElement); From 288f5e4d2e4238032a52d7fc7e457869263f2449 Mon Sep 17 00:00:00 2001 From: Mikko Tapionlinna Date: Thu, 18 Apr 2024 09:04:08 +0300 Subject: [PATCH 7/8] UHF-9797: Fix page rendering to replace the placeholder text --- src/js/hds-cc/hds-cc.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/js/hds-cc/hds-cc.js b/src/js/hds-cc/hds-cc.js index 0fafb196b..5f7a97316 100644 --- a/src/js/hds-cc/hds-cc.js +++ b/src/js/hds-cc/hds-cc.js @@ -642,6 +642,9 @@ class HdsCookieConsentClass { const container = document.createElement('div'); container.classList.add('hds-cc__target'); container.style.all = 'initial'; + if (!isBanner) { + renderTarget.innerHTML = ''; + } renderTarget.prepend(container); const shadowRoot = container.attachShadow({ mode: 'open' }); this.#shadowRoot = shadowRoot; From c6c28300ea8e9fc7db10c531bee3be98f0ac1ae0 Mon Sep 17 00:00:00 2001 From: Mikko Tapionlinna Date: Thu, 18 Apr 2024 09:17:37 +0300 Subject: [PATCH 8/8] UHF-9797: Move button order better for page version of banner --- src/js/hds-cc/template.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/js/hds-cc/template.js b/src/js/hds-cc/template.js index c3083a82e..0197e86b9 100644 --- a/src/js/hds-cc/template.js +++ b/src/js/hds-cc/template.js @@ -52,12 +52,12 @@ export function getCookieBannerHtml(translations, groupsHtml, isBanner = true) {
+ -