diff --git a/CHANGELOG.md b/CHANGELOG.md
index 872baab325..00af4b45cf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@
## Unreleased
* Alter use of pseudo-underline mixin to allow for different button sizes ([#2501](https://github.com/alphagov/govuk_publishing_components/pull/2501))
+* Re-work explicit-cross-domain-links.js ([PR #2502](https://github.com/alphagov/govuk_publishing_components/pull/2502))
## 27.16.0
diff --git a/app/assets/javascripts/govuk_publishing_components/analytics/explicit-cross-domain-links.js b/app/assets/javascripts/govuk_publishing_components/analytics/explicit-cross-domain-links.js
index aed08fbf50..bea6137eeb 100644
--- a/app/assets/javascripts/govuk_publishing_components/analytics/explicit-cross-domain-links.js
+++ b/app/assets/javascripts/govuk_publishing_components/analytics/explicit-cross-domain-links.js
@@ -6,33 +6,57 @@
GOVUK.Modules.ExplicitCrossDomainLinks = function () {
this.start = function ($module) {
- var element = $module[0]
+ this.element = $module[0]
+ this.attribute = 'href'
+ this.attributeValue = this.element.getAttribute(this.attribute)
+ this.eventType = 'click'
+ if (!this.attributeValue) {
+ this.attribute = 'action'
+ this.attributeValue = this.element.getAttribute(this.attribute)
+ this.eventType = 'submit'
+ }
- var cookieBannerEngaged = GOVUK.cookie('cookies_preferences_set')
+ this.handleEvent = this.handleEvent.bind(this)
+ this.handleCookiesAccepted = this.handleCookiesAccepted.bind(this)
+ // Listens for the 'submit' event if the element is a form, and the 'click' event if it is a link
+ this.element.addEventListener(this.eventType, this.handleEvent)
+ }
- // 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
+ this.handleEvent = function (e) {
+ // prevent default: we want the link href and/or form action to be decorated before we navigate away
+ e.preventDefault()
+ var cookieBannerEngaged = GOVUK.cookie('cookies_preferences_set')
+ var cookieConsent = GOVUK.getConsentCookie()
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
+ // If not engaged, append only ?cookie_consent=not-engaged
+ this.decorate(this.element, 'cookie_consent=not-engaged', this.attribute)
+ } else if (cookieConsent && cookieConsent.usage === true) {
+ this.handleCookiesAccepted()
+ } else {
+ this.decorate(this.element, 'cookie_consent=reject', this.attribute)
}
- var cookieConsent = GOVUK.getConsentCookie()
- if (cookieConsent && cookieConsent.usage === false) {
- this.decorate(element, 'cookie_consent=reject')
- return
+
+ // remove the event listener to avoid an infinite loop
+ this.element.removeEventListener(this.eventType, this.handleEvent)
+
+ // if the element is a form, submit it. If it is a link, click it
+ if (this.eventType === 'submit') {
+ this.element.submit()
+ } else {
+ this.element.click()
}
+ }
- this.decorate(element, 'cookie_consent=accept')
+ this.handleCookiesAccepted = function () {
+ // If the cookie banner was engaged and usage cookie accepted, append ?_ga=clientid if available and cookie_consent=accept
+ var element = this.element
+ var attribute = this.attribute
+ this.decorate(element, 'cookie_consent=accept', attribute)
- if (!global.ga) { return }
+ if (!global.ga) {
+ return
+ }
global.ga(function () {
var trackers = global.ga.getAll()
@@ -40,44 +64,21 @@
if (!trackers.length) { return }
var linker = new global.gaplugins.Linker(trackers[0])
+ var attrValue = element.getAttribute(attribute)
- var attrAction = element.getAttribute('action')
- if (attrAction) {
- element.setAttribute('action', linker.decorate(attrAction))
- }
-
- var attrHref = element.getAttribute('href')
- if (attrHref) {
- element.href = linker.decorate(attrHref)
- }
+ element.setAttribute(attribute, linker.decorate(attrValue))
})
}
- this.decorate = function (element, param) {
- var attribute = 'href'
+ this.decorate = function (element, param, attribute) {
var attributeValue = element.getAttribute(attribute)
- var cookieConsentParameterPattern = /cookie_consent=[^&]*/
- var paramIsCookieConsent = param.match(cookieConsentParameterPattern)
-
- if (!attributeValue) {
- attribute = 'action'
- attributeValue = element.getAttribute(attribute)
- }
if (!attributeValue) { return }
- 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)
+ if (attributeValue.includes('?')) {
+ attributeValue += '&' + param
} else {
- // otherwise, simply append the parameter to the target element href query string
- if (attributeValue.includes('?')) {
- attributeValue += '&' + param
- } else {
- attributeValue += '?' + param
- }
+ attributeValue += '?' + param
}
element.setAttribute(attribute, attributeValue)
diff --git a/app/assets/javascripts/govuk_publishing_components/components/cookie-banner.js b/app/assets/javascripts/govuk_publishing_components/components/cookie-banner.js
index a8697eec4c..d3a833e723 100644
--- a/app/assets/javascripts/govuk_publishing_components/components/cookie-banner.js
+++ b/app/assets/javascripts/govuk_publishing_components/components/cookie-banner.js
@@ -97,7 +97,6 @@ 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 () {
diff --git a/docs/javascript-modules.md b/docs/javascript-modules.md
index 34ea5f6085..a36febbc30 100644
--- a/docs/javascript-modules.md
+++ b/docs/javascript-modules.md
@@ -69,8 +69,6 @@ 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:
diff --git a/spec/javascripts/govuk_publishing_components/analytics/explicit-cross-domain-links.spec.js b/spec/javascripts/govuk_publishing_components/analytics/explicit-cross-domain-links.spec.js
index 4afd22b15d..d7116b4c8e 100644
--- a/spec/javascripts/govuk_publishing_components/analytics/explicit-cross-domain-links.spec.js
+++ b/spec/javascripts/govuk_publishing_components/analytics/explicit-cross-domain-links.spec.js
@@ -42,28 +42,37 @@ describe('Explicit cross-domain linker', function () {
delete window.gaplugins
})
- describe('links', function () {
+ describe('when a cross-domain link is clicked', function () {
beforeEach(function () {
- element = $('')
+ element = $('')
})
it('modifies the link href to append cookie_consent parameter "not-engaged" if cookies_preferences_set cookie is "false"', function () {
GOVUK.cookie('cookies_preferences_set', 'false')
explicitCrossDomainLinks.start(element)
- expect(element.attr('href')).toEqual('/somewhere?cookie_consent=not-engaged')
+ expect(element.attr('href')).toEqual('#')
+ window.GOVUK.triggerEvent(element[0], 'click')
+ expect(element.attr('href')).toEqual('#?cookie_consent=not-engaged')
+ expect(window.location.href).toContain('?cookie_consent=not-engaged')
})
it('modifies the link href to append cookie_consent parameter "not-engaged" if cookies_preferences_set cookie is not set', function () {
GOVUK.cookie('cookies_preferences_set', null)
explicitCrossDomainLinks.start(element)
- expect(element.attr('href')).toEqual('/somewhere?cookie_consent=not-engaged')
+ expect(element.attr('href')).toEqual('#')
+ window.GOVUK.triggerEvent(element[0], 'click')
+ expect(element.attr('href')).toEqual('#?cookie_consent=not-engaged')
+ expect(window.location.href).toContain('?cookie_consent=not-engaged')
})
it('modifies the link href to append cookie_consent parameter "reject" if usage cookies have been rejected', function () {
GOVUK.cookie('cookies_preferences_set', 'true')
GOVUK.setConsentCookie({ usage: false })
explicitCrossDomainLinks.start(element)
- expect(element.attr('href')).toEqual('/somewhere?cookie_consent=reject')
+ expect(element.attr('href')).toEqual('#')
+ window.GOVUK.triggerEvent(element[0], 'click')
+ expect(element.attr('href')).toEqual('#?cookie_consent=reject')
+ expect(window.location.href).toContain('?cookie_consent=reject')
})
describe('user has accepted cookies', function () {
@@ -73,16 +82,23 @@ describe('Explicit cross-domain linker', function () {
trackers = [{ ga_mock: 'foobar' }]
explicitCrossDomainLinks.start(element)
+ expect(element.attr('href')).toEqual('#')
+ window.GOVUK.triggerEvent(element[0], 'click')
- expect(element.attr('href')).toEqual('/somewhere?cookie_consent=accept&_ga=abc123')
+ expect(element.attr('href')).toEqual('#?cookie_consent=accept&_ga=abc123')
+ expect(window.location.href).toContain('?cookie_consent=accept&_ga=abc123')
})
it('modifies the link href to only append cookie_consent "accept" if there are no trackers', function () {
GOVUK.cookie('cookies_preferences_set', 'true')
GOVUK.setConsentCookie({ usage: true })
trackers = []
+
explicitCrossDomainLinks.start(element)
- expect(element.attr('href')).toEqual('/somewhere?cookie_consent=accept')
+ expect(element.attr('href')).toEqual('#')
+ window.GOVUK.triggerEvent(element[0], 'click')
+ expect(element.attr('href')).toEqual('#?cookie_consent=accept')
+ expect(window.location.href).toContain('?cookie_consent=accept')
})
it('modifies the link href to only append cookie_consent "accept" if ga is not initalised on window', function () {
@@ -90,34 +106,15 @@ describe('Explicit cross-domain linker', function () {
GOVUK.setConsentCookie({ usage: true })
window.ga = undefined
explicitCrossDomainLinks.start(element)
- 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')
+ expect(element.attr('href')).toEqual('#')
+ window.GOVUK.triggerEvent(element[0], 'click')
+ expect(element.attr('href')).toEqual('#?cookie_consent=accept')
+ expect(window.location.href).toContain('?cookie_consent=accept')
})
})
})
- describe('forms', function () {
+ describe('when a cross-domain form is submitted', function () {
beforeEach(function () {
element = $('