Skip to content

Commit

Permalink
Amend explicit-cross-domain-links js code
Browse files Browse the repository at this point in the history
Amend explicit-cross-domain-links code to account for the possibility of
someone accepting/rejecting cookies on the page that the cross-domain
link is present. On detecting the cookie consent or rejection event, the
cross-domain link module should re-run and append the correct parameters
to any cross domain links present on the page.
  • Loading branch information
danacotoran committed Nov 25, 2021
1 parent c6f49c3 commit dba38bc
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 9 deletions.
Expand Up @@ -10,12 +10,18 @@

var cookieBannerEngaged = GOVUK.cookie('cookies_preferences_set')

// If not engaged, append only ?cookie-consent=not-engaged
// If engaged and rejected, append only ?cookie-consent=reject
// If engaged and accepted usage, append ?_ga=clientid if available and cookie-consent=accept
// If not engaged, append only ?cookie_consent=not-engaged
// If engaged and rejected, append only ?cookie_consent=reject
// If engaged and accepted usage, append ?_ga=clientid if available and cookie_consent=accept

if (cookieBannerEngaged !== 'true') {
this.decorate(element, 'cookie_consent=not-engaged')
this.start = this.start.bind(this, $module)

// if the user has not engaged with the cookie banner yet, listen for the cookie consent accept/reject events
// re-start the module if cookies are accepted or rejected on the current page – setting cookie preferences does not reload the page
window.addEventListener('cookie-consent', this.start)
window.addEventListener('cookie-reject', this.start)
return
}
var cookieConsent = GOVUK.getConsentCookie()
Expand Down Expand Up @@ -50,6 +56,8 @@
this.decorate = function (element, param) {
var attribute = 'href'
var attributeValue = element.getAttribute(attribute)
var cookieConsentParameterPattern = /cookie_consent=[^&]*/
var paramIsCookieConsent = param.match(cookieConsentParameterPattern)

if (!attributeValue) {
attribute = 'action'
Expand All @@ -58,13 +66,21 @@

if (!attributeValue) { return }

if (attributeValue.includes('?')) {
attributeValue += '&' + param
element.setAttribute(attribute, attributeValue)
var attributeHasCookieConsent = attributeValue.match(cookieConsentParameterPattern)

if (attributeHasCookieConsent && paramIsCookieConsent) {
// if the decorate function has received a cookie_consent parameter, but the target element already has a cookie_consent parameter, replace the existing parameter with the new value
attributeValue = attributeValue.replace(cookieConsentParameterPattern, param)
} else {
attributeValue += '?' + param
element.setAttribute(attribute, attributeValue)
// otherwise, simply append the parameter to the target element href query string
if (attributeValue.includes('?')) {
attributeValue += '&' + param
} else {
attributeValue += '?' + param
}
}

element.setAttribute(attribute, attributeValue)
}
}

Expand Down
Expand Up @@ -97,6 +97,7 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
this.$module.cookieBannerConfirmationMessage.focus()
window.GOVUK.cookie('cookies_preferences_set', 'true', { days: 365 })
window.GOVUK.setDefaultConsentCookie()
window.GOVUK.triggerEvent(window, 'cookie-reject')
}

CookieBanner.prototype.showConfirmationMessage = function () {
Expand Down
2 changes: 2 additions & 0 deletions docs/javascript-modules.md
Expand Up @@ -69,6 +69,8 @@ This functionality runs like this:
- if cookies have been consented, the module calls the rest of its code and carries on as normal
- if cookies have not been consented, the listener is created and calls the rest of the module when the `cookie-consent` event is fired by the cookie banner

If a module has functionality which is dependent on rejecting cookies, that module should listen for the `cookie-reject` event. This event is fired by the cookie banner when the user rejects cookies.

### Module structure

A module must add its constructor to `GOVUK.Modules` and it must have an `init` method. The simplest module looks like:
Expand Down
Expand Up @@ -66,7 +66,7 @@ describe('Explicit cross-domain linker', function () {
expect(element.attr('href')).toEqual('/somewhere?cookie_consent=reject')
})

describe('user accepts cookies', function () {
describe('user has accepted cookies', function () {
it('modifies the link href to append cookie_consent parameter "accept" and adds _ga if trackers are present', function () {
GOVUK.cookie('cookies_preferences_set', 'true')
GOVUK.setConsentCookie({ usage: true })
Expand All @@ -93,6 +93,28 @@ describe('Explicit cross-domain linker', function () {
expect(element.attr('href')).toEqual('/somewhere?cookie_consent=accept')
})
})

describe('user has interacted with the cookie banner on the current page', function () {
beforeEach(function () {
GOVUK.cookie('cookies_preferences_set', null)
explicitCrossDomainLinks.start(element)
GOVUK.cookie('cookies_preferences_set', 'true')
})
it('modifies the link href to append cookie_consent parameter "accept" if the cookie-consent event was fired', function () {
GOVUK.setConsentCookie({ usage: true })
window.ga = undefined
window.GOVUK.triggerEvent(window, 'cookie-consent')

expect(element.attr('href')).toEqual('/somewhere?cookie_consent=accept')
})

it('modifies the link href to append cookie_consent parameter "reject" if the cookie-reject event was fired', function () {
GOVUK.setConsentCookie({ usage: false })
window.GOVUK.triggerEvent(window, 'cookie-reject')

expect(element.attr('href')).toEqual('/somewhere?cookie_consent=reject')
})
})
})

describe('forms', function () {
Expand Down Expand Up @@ -147,5 +169,27 @@ describe('Explicit cross-domain linker', function () {
expect(element.attr('action')).toEqual('/somewhere?cookie_consent=accept')
})
})

describe('user has interacted with the cookie banner on the current page', function () {
beforeEach(function () {
GOVUK.cookie('cookies_preferences_set', null)
explicitCrossDomainLinks.start(element)
GOVUK.cookie('cookies_preferences_set', 'true')
})
it('modifies the form action to append cookie_consent parameter "accept" if the cookie-consent event was fired', function () {
GOVUK.setConsentCookie({ usage: true })
window.ga = undefined
window.GOVUK.triggerEvent(window, 'cookie-consent')

expect(element.attr('action')).toEqual('/somewhere?cookie_consent=accept')
})

it('modifies the form action to append cookie_consent parameter "reject" if the cookie-reject event was fired', function () {
GOVUK.setConsentCookie({ usage: false })
window.GOVUK.triggerEvent(window, 'cookie-reject')

expect(element.attr('action')).toEqual('/somewhere?cookie_consent=reject')
})
})
})
})
26 changes: 26 additions & 0 deletions spec/javascripts/govuk_publishing_components/modules.spec.js
Expand Up @@ -140,6 +140,20 @@ describe('GOVUK Modules', function () {
}
GOVUK.Modules.TestCookieDependencyModule = TestCookieDependencyModule

// GOV.UK Frontend Module that depends on rejected cookies to start
function TestCookieRejectDependencyModule (element) {
this.element = element
}
TestCookieRejectDependencyModule.prototype.init = function () {
this.startModule = this.startModule.bind(this)
window.addEventListener('cookie-reject', this.startModule)
}
TestCookieRejectDependencyModule.prototype.startModule = function () {
window.removeEventListener('cookie-reject', this.startModule)
callbackFrontendModule(this.element)
}
GOVUK.Modules.TestCookieRejectDependencyModule = TestCookieRejectDependencyModule

container = $('<div></div>')
})

Expand All @@ -151,6 +165,7 @@ describe('GOVUK Modules', function () {
delete GOVUK.Modules.GovukTestAlertPublishingAndFrontendModule
delete GOVUK.Modules.TestAlertPublishingAndFrontendModule
delete GOVUK.Modules.TestCookieDependencyModule
delete GOVUK.Modules.TestCookieRejectDependencyModule

container.remove()
})
Expand Down Expand Up @@ -228,6 +243,17 @@ describe('GOVUK Modules', function () {
expect(callbackFrontendModule.calls.count()).toBe(1)
})

it('starts delayed modules once cookies have been rejected', function () {
var module = $('<div data-module="test-cookie-reject-dependency-module"></div>')
container.append(module)
$('body').append(container)

GOVUK.modules.start(container)
expect(callbackFrontendModule.calls.count()).toBe(0)
window.GOVUK.triggerEvent(window, 'cookie-reject')
expect(callbackFrontendModule.calls.count()).toBe(1)
})

it('starts multiple delayed modules once cookies have been consented', function () {
var module1 = $('<div data-module="test-cookie-dependency-module"></div>')
var module2 = $('<div data-module="test-cookie-dependency-module"></div>')
Expand Down

0 comments on commit dba38bc

Please sign in to comment.