govuk_publishing_components 35.10.0 → 35.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-core.js +2 -48
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-form-tracker.js +5 -0
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-link-tracker.js +2 -2
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-schemas.js +51 -5
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-scroll-tracker.js +225 -0
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/init-ga4.js +0 -5
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4.js +1 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/_attachment.scss +7 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/_feedback.scss +8 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_tables.scss +41 -0
- data/app/views/govuk_publishing_components/components/_attachment.html.erb +3 -1
- data/app/views/govuk_publishing_components/components/_contents_list.html.erb +9 -9
- data/app/views/govuk_publishing_components/components/_metadata.html.erb +2 -1
- data/app/views/govuk_publishing_components/components/_tabs.html.erb +30 -14
- data/app/views/govuk_publishing_components/components/docs/govspeak.yml +22 -0
- data/app/views/govuk_publishing_components/components/docs/tabs.yml +25 -2
- data/lib/govuk_publishing_components/version.rb +1 -1
- data/node_modules/govuk-frontend/govuk/all.js +406 -1
- data/node_modules/govuk-frontend/govuk/all.js.map +1 -1
- data/node_modules/govuk-frontend/govuk/common/govuk-frontend-version.js +1 -1
- data/node_modules/govuk-frontend/govuk/components/_all.scss +2 -1
- data/node_modules/govuk-frontend/govuk/components/back-link/_index.scss +8 -0
- data/node_modules/govuk-frontend/govuk/components/back-link/fixtures.json +9 -0
- data/node_modules/govuk-frontend/govuk/components/breadcrumbs/_index.scss +12 -0
- data/node_modules/govuk-frontend/govuk/components/breadcrumbs/fixtures.json +21 -0
- data/node_modules/govuk-frontend/govuk/components/button/_index.scss +41 -3
- data/node_modules/govuk-frontend/govuk/components/button/fixtures.json +44 -0
- data/node_modules/govuk-frontend/govuk/components/checkboxes/macro-options.json +9 -8
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/README.md +15 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/_exit-this-page.scss +2 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/_index.scss +97 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/exit-this-page.js +2120 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/exit-this-page.js.map +1 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/fixtures.json +50 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/macro-options.json +62 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/macro.njk +3 -0
- data/node_modules/govuk-frontend/govuk/components/exit-this-page/template.njk +16 -0
- data/node_modules/govuk-frontend/govuk/components/radios/macro-options.json +9 -8
- data/node_modules/govuk-frontend/govuk/core/_govuk-frontend-version.scss +1 -1
- data/node_modules/govuk-frontend/govuk/helpers/_visually-hidden.scss +12 -0
- data/node_modules/govuk-frontend/govuk/objects/_template.scss +20 -0
- data/node_modules/govuk-frontend/govuk-esm/all.mjs +8 -0
- data/node_modules/govuk-frontend/govuk-esm/all.mjs.map +1 -1
- data/node_modules/govuk-frontend/govuk-esm/common/govuk-frontend-version.mjs +1 -1
- data/node_modules/govuk-frontend/govuk-esm/components/exit-this-page/exit-this-page.mjs +406 -0
- data/node_modules/govuk-frontend/govuk-esm/components/exit-this-page/exit-this-page.mjs.map +1 -0
- data/node_modules/govuk-frontend/govuk-prototype-kit.config.json +4 -0
- data/node_modules/govuk-frontend/package.json +4 -2
- metadata +15 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d923b79189269417363dd2c12781e9ee9644a03bf2c514b21e24d71efe0c07c7
|
|
4
|
+
data.tar.gz: ce1f69cdb8ef0eaf3fcf836e359311e8b38a0f401bb931a3e8bfc27c1b568f56
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bffc7c115facd8c323182b04f089ecae6b5b2a6991ebed42aea17fc748b1a95bcbf1093f75e238291819bb9d821152b7f4ef3f2b95f0a4b2b1b14021ccbb5a14
|
|
7
|
+
data.tar.gz: 03c818b7b4f9731f3075020ad5273256a30c3cdef0862f92892edea1dd6cd19e0e65ea781d8c9bb7fb2c87403c5478503442453c68ff80a2deea73ba820e3721
|
|
@@ -30,32 +30,7 @@ window.GOVUK.analyticsGa4 = window.GOVUK.analyticsGa4 || {};
|
|
|
30
30
|
firstScript.parentNode.insertBefore(newScript, firstScript)
|
|
31
31
|
},
|
|
32
32
|
|
|
33
|
-
ensureIndexesArePopulated: function (data) {
|
|
34
|
-
if (!data.event_data) {
|
|
35
|
-
return data
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (!data.event_data.index) {
|
|
39
|
-
return data
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
var indexKeys = ['index_link', 'index_section', 'index_section_count']
|
|
43
|
-
|
|
44
|
-
for (var i = 0; i < indexKeys.length; i++) {
|
|
45
|
-
var indexKey = indexKeys[i]
|
|
46
|
-
|
|
47
|
-
// If the index key isn't in the object, populate it. However if it's set to 0, leave it as 0. 0 is falsy so we have to add this extra check.
|
|
48
|
-
if (!data.event_data.index[indexKey] && data.event_data.index[indexKey] !== 0) {
|
|
49
|
-
data.event_data.index[indexKey] = undefined
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return data
|
|
54
|
-
},
|
|
55
|
-
|
|
56
33
|
sendData: function (data) {
|
|
57
|
-
data = this.ensureIndexesArePopulated(data)
|
|
58
|
-
|
|
59
34
|
data.govuk_gem_version = this.getGemVersion()
|
|
60
35
|
// set this in the console as a debugging aid
|
|
61
36
|
if (window.GOVUK.analyticsGa4.showDebug) {
|
|
@@ -274,29 +249,8 @@ window.GOVUK.analyticsGa4 = window.GOVUK.analyticsGa4 || {};
|
|
|
274
249
|
}
|
|
275
250
|
},
|
|
276
251
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
for (var i = 0; i < targetElements.length; i++) {
|
|
281
|
-
var element = targetElements[i]
|
|
282
|
-
|
|
283
|
-
for (var j = 0; j < dataAttributes.length; j++) {
|
|
284
|
-
var key = dataAttributes[j].key
|
|
285
|
-
var value = dataAttributes[j].value
|
|
286
|
-
|
|
287
|
-
// value must check for undefined only as it would return false on an empty string, the number 0, etc.
|
|
288
|
-
if (key && value !== undefined) {
|
|
289
|
-
var existingAttributeValue = element.getAttribute(key)
|
|
290
|
-
|
|
291
|
-
if (key === 'data-module' && existingAttributeValue) {
|
|
292
|
-
// Combines values to prevent replacing any existing data-module values.
|
|
293
|
-
element.setAttribute(key, existingAttributeValue + ' ' + value)
|
|
294
|
-
} else {
|
|
295
|
-
element.setAttribute(key, value)
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
252
|
+
applyRedactionIfRequired: function (PIIRemover, element, data) {
|
|
253
|
+
return element.closest('[data-ga4-do-not-redact]') ? data : PIIRemover.stripPIIWithOverride(data, true, true)
|
|
300
254
|
}
|
|
301
255
|
},
|
|
302
256
|
|
|
@@ -45,6 +45,11 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
|
|
|
45
45
|
var formData = this.getInputValues(formInputs)
|
|
46
46
|
data.text = data.text || (this.combineGivenAnswers(formData) || 'No answer given')
|
|
47
47
|
|
|
48
|
+
if (data.action === 'search') {
|
|
49
|
+
data.text = data.text.toLowerCase()
|
|
50
|
+
data.text = window.GOVUK.analyticsGa4.core.trackFunctions.removeLinesAndExtraSpaces(data.text)
|
|
51
|
+
}
|
|
52
|
+
|
|
48
53
|
var schemas = new window.GOVUK.analyticsGa4.Schemas()
|
|
49
54
|
var schema = schemas.mergeProperties(data, 'event_data')
|
|
50
55
|
window.GOVUK.analyticsGa4.core.sendData(schema)
|
|
@@ -81,12 +81,12 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
|
|
|
81
81
|
|
|
82
82
|
var text = data.text || event.target.textContent
|
|
83
83
|
data.text = window.GOVUK.analyticsGa4.core.trackFunctions.removeLinesAndExtraSpaces(text)
|
|
84
|
-
data.text =
|
|
84
|
+
data.text = window.GOVUK.analyticsGa4.core.trackFunctions.applyRedactionIfRequired(this.PIIRemover, element, data.text)
|
|
85
85
|
if (!data.text && (element.querySelector('img') || element.querySelector('svg') || element.tagName === 'IMG' || element.closest('svg'))) {
|
|
86
86
|
data.text = 'image'
|
|
87
87
|
}
|
|
88
88
|
var url = data.url || this.findLink(event.target).getAttribute('href')
|
|
89
|
-
data.url = window.GOVUK.analyticsGa4.core.trackFunctions.
|
|
89
|
+
data.url = window.GOVUK.analyticsGa4.core.trackFunctions.applyRedactionIfRequired(this.PIIRemover, element, window.GOVUK.analyticsGa4.core.trackFunctions.removeCrossDomainParams(url))
|
|
90
90
|
data.link_domain = window.GOVUK.analyticsGa4.core.trackFunctions.populateLinkDomain(data.url)
|
|
91
91
|
data.link_path_parts = window.GOVUK.analyticsGa4.core.trackFunctions.populateLinkPathParts(data.url)
|
|
92
92
|
data.method = window.GOVUK.analyticsGa4.core.trackFunctions.getClickType(event)
|
|
@@ -16,7 +16,11 @@
|
|
|
16
16
|
type: this.undefined,
|
|
17
17
|
url: this.undefined,
|
|
18
18
|
text: this.undefined,
|
|
19
|
-
index:
|
|
19
|
+
index: {
|
|
20
|
+
index_link: this.undefined,
|
|
21
|
+
index_section: this.undefined,
|
|
22
|
+
index_section_count: this.undefined
|
|
23
|
+
},
|
|
20
24
|
index_total: this.undefined,
|
|
21
25
|
section: this.undefined,
|
|
22
26
|
action: this.undefined,
|
|
@@ -24,7 +28,8 @@
|
|
|
24
28
|
method: this.undefined,
|
|
25
29
|
link_domain: this.undefined,
|
|
26
30
|
link_path_parts: this.undefined,
|
|
27
|
-
tool_name: this.undefined
|
|
31
|
+
tool_name: this.undefined,
|
|
32
|
+
percent_scrolled: this.undefined
|
|
28
33
|
}
|
|
29
34
|
}
|
|
30
35
|
}
|
|
@@ -45,19 +50,60 @@
|
|
|
45
50
|
}
|
|
46
51
|
}
|
|
47
52
|
|
|
48
|
-
//
|
|
53
|
+
// merge data attributes data into the event schema
|
|
49
54
|
// only allow it if it already exists in the schema
|
|
50
55
|
Schemas.prototype.mergeProperties = function (data, eventAttribute) {
|
|
51
56
|
var schema = this.eventSchema()
|
|
52
57
|
schema.event = eventAttribute
|
|
58
|
+
// exceptions should be inserted without checking for sub parameters
|
|
59
|
+
// exceptions should only come from code, not directly from data attributes
|
|
60
|
+
// e.g. link_path_parts is generated by JS and contains potentially non-unique
|
|
61
|
+
// sub parameter names i.e. '1', '2'
|
|
62
|
+
var exceptions = ['link_path_parts']
|
|
63
|
+
|
|
53
64
|
for (var property in data) {
|
|
54
|
-
|
|
55
|
-
|
|
65
|
+
// some passed data might be undefined, don't want it to overwrite e.g. the index sub parameters
|
|
66
|
+
if (data[property] !== undefined) {
|
|
67
|
+
if (exceptions.indexOf(property) >= 0 || !this.isAnObject(data[property])) {
|
|
68
|
+
schema.event_data = this.addToObject(schema.event_data, property, data[property])
|
|
69
|
+
} else {
|
|
70
|
+
// we check for one level of nesting in the data attributes data
|
|
71
|
+
// this check can be removed once nesting is removed from all data attributes
|
|
72
|
+
for (var subproperty in data[property]) {
|
|
73
|
+
schema.event_data = this.addToObject(schema.event_data, subproperty, data[property][subproperty])
|
|
74
|
+
}
|
|
75
|
+
}
|
|
56
76
|
}
|
|
57
77
|
}
|
|
58
78
|
return schema
|
|
59
79
|
}
|
|
60
80
|
|
|
81
|
+
// might be easier to check if it's not a string or a number?
|
|
82
|
+
Schemas.prototype.isAnObject = function (item) {
|
|
83
|
+
if (typeof item === 'object' && !Array.isArray(item) && item !== null) {
|
|
84
|
+
return true
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// given an object and a key, insert a value into that object for that key
|
|
89
|
+
// we check for one level of nesting in the object
|
|
90
|
+
Schemas.prototype.addToObject = function (obj, key, value) {
|
|
91
|
+
if (key in obj) {
|
|
92
|
+
obj[key] = value
|
|
93
|
+
return obj
|
|
94
|
+
} else {
|
|
95
|
+
for (var property in obj) {
|
|
96
|
+
if (this.isAnObject(obj[property])) {
|
|
97
|
+
if (key in obj[property]) {
|
|
98
|
+
obj[property][key] = value
|
|
99
|
+
return obj
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return obj
|
|
105
|
+
}
|
|
106
|
+
|
|
61
107
|
GOVUK.analyticsGa4 = GOVUK.analyticsGa4 || {}
|
|
62
108
|
GOVUK.analyticsGa4.Schemas = Schemas
|
|
63
109
|
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
window.GOVUK = window.GOVUK || {}
|
|
2
|
+
window.GOVUK.Modules = window.GOVUK.Modules || {};
|
|
3
|
+
|
|
4
|
+
(function (Modules) {
|
|
5
|
+
function Ga4ScrollTracker ($module) {
|
|
6
|
+
this.$module = $module
|
|
7
|
+
this.pageHeight = document.querySelector('body').clientHeight
|
|
8
|
+
this.trackedNodes = []
|
|
9
|
+
this.config = {
|
|
10
|
+
allowHeadingsInside: ['main'],
|
|
11
|
+
percentages: [20, 40, 60, 80, 100],
|
|
12
|
+
scrollTimeoutDelay: 20,
|
|
13
|
+
resizeTimeoutDelay: 100,
|
|
14
|
+
pageHeightTimeoutDelay: 500,
|
|
15
|
+
markerAttribute: 'data-ga4-scroll-marker'
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
Ga4ScrollTracker.prototype.init = function () {
|
|
20
|
+
var consentCookie = window.GOVUK.getConsentCookie()
|
|
21
|
+
|
|
22
|
+
if (consentCookie && consentCookie.settings) {
|
|
23
|
+
this.startModule()
|
|
24
|
+
} else {
|
|
25
|
+
this.startModule = this.startModule.bind(this)
|
|
26
|
+
window.addEventListener('cookie-consent', this.startModule)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
Ga4ScrollTracker.prototype.startModule = function () {
|
|
31
|
+
if (window.GOVUK.analyticsGa4.vars.scrollTrackerStarted) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this.trackType = this.$module.getAttribute('data-ga4-track-type')
|
|
36
|
+
window.GOVUK.analyticsGa4.vars.scrollTrackerStarted = true
|
|
37
|
+
|
|
38
|
+
if (this.trackType === 'headings') {
|
|
39
|
+
this.track = new Ga4ScrollTracker.Heading(this.config)
|
|
40
|
+
} else if (this.trackType === 'markers') {
|
|
41
|
+
this.config.trackMarkers = true
|
|
42
|
+
this.track = new Ga4ScrollTracker.Heading(this.config)
|
|
43
|
+
} else {
|
|
44
|
+
this.track = new Ga4ScrollTracker.Percentage(this.config)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
this.getWindowDetails()
|
|
48
|
+
// if the URL has a hash we want to prevent tracking on initial page load
|
|
49
|
+
// until the browser jumps down the page, at which point a scroll event
|
|
50
|
+
// will happen and tracking will continue normally
|
|
51
|
+
var windowHash = window.location.hash
|
|
52
|
+
var dontTrackOnLoad = windowHash && document.getElementById(windowHash.substring(1))
|
|
53
|
+
if (!dontTrackOnLoad) {
|
|
54
|
+
this.trackVisibleNodes()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (this.trackedNodes.length) {
|
|
58
|
+
// store event listener functions as variables so they can be removed if needed
|
|
59
|
+
this.scrollEvent = this.onScroll.bind(this)
|
|
60
|
+
window.addEventListener('scroll', this.scrollEvent)
|
|
61
|
+
this.resizeEvent = this.onResize.bind(this)
|
|
62
|
+
window.addEventListener('resize', this.resizeEvent)
|
|
63
|
+
|
|
64
|
+
// check if the page height changes e.g. accordion opened
|
|
65
|
+
this.interval = window.setInterval(function () {
|
|
66
|
+
var pageHeight = document.querySelector('body').clientHeight
|
|
67
|
+
if (pageHeight !== this.pageHeight) {
|
|
68
|
+
this.pageHeight = pageHeight
|
|
69
|
+
this.getWindowDetails()
|
|
70
|
+
this.trackVisibleNodes()
|
|
71
|
+
}
|
|
72
|
+
}.bind(this), this.config.pageHeightTimeoutDelay)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
Ga4ScrollTracker.prototype.onScroll = function () {
|
|
77
|
+
clearTimeout(this.scrollTimeout)
|
|
78
|
+
this.scrollTimeout = setTimeout(function () {
|
|
79
|
+
this.trackVisibleNodes()
|
|
80
|
+
}.bind(this), this.config.scrollTimeoutDelay)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
Ga4ScrollTracker.prototype.onResize = function () {
|
|
84
|
+
clearTimeout(this.resizeTimeout)
|
|
85
|
+
this.resizeTimeout = setTimeout(function () {
|
|
86
|
+
this.getWindowDetails()
|
|
87
|
+
this.trackVisibleNodes()
|
|
88
|
+
}.bind(this), this.config.resizeTimeoutDelay)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
Ga4ScrollTracker.prototype.getWindowDetails = function () {
|
|
92
|
+
this.pageHeight = document.querySelector('body').clientHeight
|
|
93
|
+
this.windowHeight = window.innerHeight
|
|
94
|
+
this.trackedNodes = this.track.getTrackingNodes(this.trackedNodes)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
Ga4ScrollTracker.prototype.trackVisibleNodes = function () {
|
|
98
|
+
var data = {
|
|
99
|
+
event_name: 'scroll',
|
|
100
|
+
action: 'scroll',
|
|
101
|
+
type: this.config.type
|
|
102
|
+
}
|
|
103
|
+
for (var i = 0; i < this.trackedNodes.length; i++) {
|
|
104
|
+
var node = this.trackedNodes[i]
|
|
105
|
+
if (this.isVisible(node.top, node.bottom) && !node.alreadySeen) {
|
|
106
|
+
node.alreadySeen = true
|
|
107
|
+
// we store whether a heading has been tracked or not on the heading
|
|
108
|
+
// because if headings appear/disappear (e.g. inside an accordion)
|
|
109
|
+
// the order changes, so we can't refer to the previous trackedNodes
|
|
110
|
+
// as we do with percentages
|
|
111
|
+
if (node.element) {
|
|
112
|
+
node.element.setAttribute('data-ga4-scrolltracker-already-seen', true)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
data.type = node.eventData.type
|
|
116
|
+
// following will be undefined if tracking percentages
|
|
117
|
+
data.text = node.eventData.text
|
|
118
|
+
data.index = node.eventData.index
|
|
119
|
+
// following will be undefined if tracking headings
|
|
120
|
+
data.percent_scrolled = node.eventData.percent_scrolled
|
|
121
|
+
|
|
122
|
+
var schemas = new window.GOVUK.analyticsGa4.Schemas()
|
|
123
|
+
var schema = schemas.mergeProperties(data, 'event_data')
|
|
124
|
+
window.GOVUK.analyticsGa4.core.sendData(schema)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
Ga4ScrollTracker.prototype.isVisible = function (top, bottom) {
|
|
130
|
+
var scroll = window.scrollY || document.documentElement.scrollTop // IE fallback
|
|
131
|
+
return scroll <= top && (scroll + this.windowHeight) >= bottom
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
Ga4ScrollTracker.Heading = function (config) {
|
|
135
|
+
this.config = config
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
Ga4ScrollTracker.Heading.prototype.getTrackingNodes = function () {
|
|
139
|
+
var headingsDetails = []
|
|
140
|
+
var headingsFound = this.findAllowedHeadings()
|
|
141
|
+
var totalHeadings = headingsFound.length
|
|
142
|
+
|
|
143
|
+
for (var i = 0; i < totalHeadings; i++) {
|
|
144
|
+
var heading = headingsFound[i]
|
|
145
|
+
var type = this.config.trackMarkers ? 'marker' : 'heading'
|
|
146
|
+
// only track headings that are visible i.e. not inside display: none
|
|
147
|
+
if (this.visible(heading)) {
|
|
148
|
+
var pos = heading.getBoundingClientRect()
|
|
149
|
+
headingsDetails.push({
|
|
150
|
+
element: heading,
|
|
151
|
+
alreadySeen: heading.getAttribute('data-ga4-scrolltracker-already-seen'),
|
|
152
|
+
top: pos.top + document.documentElement.scrollTop,
|
|
153
|
+
bottom: pos.bottom + document.documentElement.scrollTop,
|
|
154
|
+
eventData: {
|
|
155
|
+
type: type,
|
|
156
|
+
text: heading.textContent.replace(/\s+/g, ' ').trim(),
|
|
157
|
+
index: {
|
|
158
|
+
index_section: i + 1,
|
|
159
|
+
index_section_count: totalHeadings
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return headingsDetails
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// check heading is inside allowed elements, generally ignores everything outside of page content
|
|
169
|
+
Ga4ScrollTracker.Heading.prototype.findAllowedHeadings = function () {
|
|
170
|
+
var headingsFound = []
|
|
171
|
+
var headings = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
|
|
172
|
+
if (this.config.trackMarkers) {
|
|
173
|
+
headings = ['[' + this.config.markerAttribute + ']']
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// this is a loop that only happens once as we currently only have one
|
|
177
|
+
// allowed element for headings to be in - 'main'
|
|
178
|
+
for (var h = 0; h < this.config.allowHeadingsInside.length; h++) {
|
|
179
|
+
var insideElements = document.querySelectorAll(this.config.allowHeadingsInside[h])
|
|
180
|
+
for (var e = 0; e < insideElements.length; e++) {
|
|
181
|
+
var found = insideElements[e].querySelectorAll(headings)
|
|
182
|
+
for (var f = 0; f < found.length; f++) {
|
|
183
|
+
headingsFound.push(found[f])
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return headingsFound
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// this is bit more verbose than checking offsetParent !== null but more reliable for IE10+
|
|
191
|
+
Ga4ScrollTracker.Heading.prototype.visible = function (el) {
|
|
192
|
+
return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
Ga4ScrollTracker.Percentage = function (config) {
|
|
196
|
+
this.config = config
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
Ga4ScrollTracker.Percentage.prototype.getTrackingNodes = function (trackedNodes) {
|
|
200
|
+
var body = document.body
|
|
201
|
+
var html = document.documentElement
|
|
202
|
+
var pageHeight = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight)
|
|
203
|
+
|
|
204
|
+
var percentDetails = []
|
|
205
|
+
|
|
206
|
+
for (var i = 0; i < this.config.percentages.length; i++) {
|
|
207
|
+
var percent = this.config.percentages[i]
|
|
208
|
+
// subtract 1 pixel to solve a bug where 100% can't be reached in some cases
|
|
209
|
+
var pos = ((pageHeight / 100) * percent) - 1
|
|
210
|
+
var alreadySeen = false
|
|
211
|
+
if (trackedNodes.length) {
|
|
212
|
+
alreadySeen = trackedNodes[i].alreadySeen
|
|
213
|
+
}
|
|
214
|
+
percentDetails.push({
|
|
215
|
+
alreadySeen: alreadySeen,
|
|
216
|
+
top: pos,
|
|
217
|
+
bottom: pos,
|
|
218
|
+
eventData: { type: 'percent', percent_scrolled: String(percent) }
|
|
219
|
+
})
|
|
220
|
+
}
|
|
221
|
+
return percentDetails
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
Modules.Ga4ScrollTracker = Ga4ScrollTracker
|
|
225
|
+
})(window.GOVUK.Modules)
|
|
@@ -8,11 +8,6 @@ var initFunction = function () {
|
|
|
8
8
|
window.GOVUK.analyticsGa4.vars.internalDomains = []
|
|
9
9
|
window.GOVUK.analyticsGa4.vars.internalDomains.push(window.GOVUK.analyticsGa4.core.trackFunctions.getHostname())
|
|
10
10
|
window.GOVUK.analyticsGa4.core.trackFunctions.appendDomainsWithoutWWW(window.GOVUK.analyticsGa4.vars.internalDomains)
|
|
11
|
-
var attachmentLinkData = [
|
|
12
|
-
{ key: 'data-module', value: 'ga4-link-tracker' },
|
|
13
|
-
{ key: 'data-ga4-track-links-only', value: '' },
|
|
14
|
-
{ key: 'data-ga4-link', value: JSON.stringify({ event_name: 'navigation', type: 'attachment' }) }]
|
|
15
|
-
window.GOVUK.analyticsGa4.core.trackFunctions.addAttributesToElements('[data-ga4-attachment-link]', attachmentLinkData)
|
|
16
11
|
window.GOVUK.analyticsGa4.core.load()
|
|
17
12
|
|
|
18
13
|
var analyticsModules = window.GOVUK.analyticsGa4.analyticsModules
|
|
@@ -67,6 +67,13 @@ $thumbnail-icon-border-colour: govuk-colour("mid-grey", $legacy: "grey-3");
|
|
|
67
67
|
&:last-of-type {
|
|
68
68
|
margin-bottom: 0;
|
|
69
69
|
}
|
|
70
|
+
|
|
71
|
+
.gem-c-attachment__attribute {
|
|
72
|
+
// From the Design System
|
|
73
|
+
// Automatic wrapping for unbreakable text (e.g. URLs)
|
|
74
|
+
word-wrap: break-word; // Fallback for older browsers only
|
|
75
|
+
overflow-wrap: break-word;
|
|
76
|
+
}
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
.gem-c-attachment__metadata--compact {
|
|
@@ -86,6 +86,10 @@
|
|
|
86
86
|
padding-bottom: 0;
|
|
87
87
|
margin-right: govuk-spacing(2);
|
|
88
88
|
}
|
|
89
|
+
|
|
90
|
+
@include govuk-media-query($from: desktop) {
|
|
91
|
+
margin-right: govuk-spacing(4);
|
|
92
|
+
}
|
|
89
93
|
}
|
|
90
94
|
|
|
91
95
|
.gem-c-feedback__prompt-link {
|
|
@@ -138,6 +142,10 @@
|
|
|
138
142
|
.gem-c-feedback__option-list-item {
|
|
139
143
|
&:last-child {
|
|
140
144
|
margin-left: govuk-spacing(2);
|
|
145
|
+
|
|
146
|
+
@include govuk-media-query($from: desktop) {
|
|
147
|
+
margin-left: govuk-spacing(4);
|
|
148
|
+
}
|
|
141
149
|
}
|
|
142
150
|
}
|
|
143
151
|
|
|
@@ -55,3 +55,44 @@
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
// Add rtl table styling when `direction: "rtl"` is set
|
|
60
|
+
.govuk-govspeak.direction-rtl,
|
|
61
|
+
.gem-c-govspeak.direction-rtl {
|
|
62
|
+
table {
|
|
63
|
+
caption {
|
|
64
|
+
text-align: right;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
th {
|
|
68
|
+
text-align: right;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
th,
|
|
72
|
+
td {
|
|
73
|
+
padding: govuk-spacing(2) 0 govuk-spacing(2) govuk-spacing(4);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Add rtl table styling when `.direction-rtl` is set on a parent element
|
|
79
|
+
// stylelint-disable max-nesting-depth
|
|
80
|
+
.direction-rtl {
|
|
81
|
+
.govspeak,
|
|
82
|
+
.gem-c-govspeak {
|
|
83
|
+
table {
|
|
84
|
+
caption {
|
|
85
|
+
text-align: right;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
th {
|
|
89
|
+
text-align: right;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
th,
|
|
93
|
+
td {
|
|
94
|
+
padding: govuk-spacing(2) 0 govuk-spacing(2) govuk-spacing(4);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -43,13 +43,15 @@
|
|
|
43
43
|
"HTML",
|
|
44
44
|
class: "gem-c-attachment__attribute",
|
|
45
45
|
)
|
|
46
|
+
data_attributes[:module] ? data_attributes[:module] << " ga4-link-tracker" : data_attributes[:module] = "ga4-link-tracker"
|
|
47
|
+
data_attributes[:ga4_link] = { "event_name": "navigation", "type": "attachment" }.to_json
|
|
46
48
|
when "external"
|
|
47
49
|
attributes << tag.span(
|
|
48
50
|
attachment.url,
|
|
49
51
|
class: "gem-c-attachment__attribute",
|
|
50
52
|
)
|
|
51
53
|
end
|
|
52
|
-
|
|
54
|
+
|
|
53
55
|
%>
|
|
54
56
|
<%= tag.section class: class_names(container_class_names) do %>
|
|
55
57
|
<%= tag.div class: "gem-c-attachment__thumbnail" do %>
|
|
@@ -13,20 +13,16 @@
|
|
|
13
13
|
link_classes << "govuk-link--no-underline" unless underline_links
|
|
14
14
|
|
|
15
15
|
ga4_tracking ||= false
|
|
16
|
-
ga4_data =
|
|
17
|
-
if ga4_tracking
|
|
18
|
-
ga4_data = {
|
|
16
|
+
ga4_data = {
|
|
19
17
|
event_name: "navigation",
|
|
20
18
|
type: "content",
|
|
21
19
|
section: t("components.contents_list.contents", locale: :en) || ""
|
|
22
|
-
|
|
23
|
-
end
|
|
20
|
+
} if ga4_tracking
|
|
24
21
|
local_assigns[:aria] ||= {}
|
|
25
22
|
component_helper = GovukPublishingComponents::Presenters::ComponentWrapperHelper.new(local_assigns)
|
|
26
23
|
component_helper.add_class("gem-c-contents-list #{brand_helper.brand_class}")
|
|
27
24
|
component_helper.add_data_attribute({ module: "gem-track-click" })
|
|
28
25
|
component_helper.add_data_attribute({ module: "ga4-link-tracker" }) if ga4_tracking
|
|
29
|
-
component_helper.add_data_attribute({ ga4_link: ga4_data, ga4_track_links_only: "" }) if ga4_tracking
|
|
30
26
|
component_helper.add_aria_attribute({ label: t("components.contents_list.contents") }) unless local_assigns[:aria][:label]
|
|
31
27
|
component_helper.add_role("navigation")
|
|
32
28
|
-%>
|
|
@@ -44,8 +40,12 @@
|
|
|
44
40
|
<% contents.each.with_index(1) do |contents_item, position| %>
|
|
45
41
|
<li class="<%= cl_helper.list_item_classes(contents_item, false) %>" <%= "aria-current=true" if contents_item[:active] %>>
|
|
46
42
|
<% link_text = format_numbers ? cl_helper.wrap_numbers_with_spans(contents_item[:text]) : contents_item[:text]
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
if ga4_tracking
|
|
44
|
+
ga4_data[:index] = {
|
|
45
|
+
"index_link": position,
|
|
46
|
+
}
|
|
47
|
+
ga4_data[:index_total] = contents.length
|
|
48
|
+
end
|
|
49
49
|
%>
|
|
50
50
|
<%= link_to_if !contents_item[:active], link_text, contents_item[:href],
|
|
51
51
|
class: link_classes,
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
track_options: {
|
|
57
57
|
dimension29: contents_item[:text]
|
|
58
58
|
},
|
|
59
|
-
ga4_link:
|
|
59
|
+
ga4_link: (ga4_tracking ? ga4_data.to_json : nil)
|
|
60
60
|
}
|
|
61
61
|
%>
|
|
62
62
|
|
|
@@ -7,22 +7,30 @@
|
|
|
7
7
|
panel_css_classes << "gem-c-tabs__panel--no-border" if panel_border == false
|
|
8
8
|
panel_css_classes = panel_css_classes.join(" ")
|
|
9
9
|
|
|
10
|
+
as_links ||= false
|
|
10
11
|
ga4_tracking ||= false
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
component_helper = GovukPublishingComponents::Presenters::ComponentWrapperHelper.new(local_assigns)
|
|
14
|
+
component_helper.add_class("govuk-tabs gem-c-tabs")
|
|
15
|
+
component_helper.add_data_attribute({ module: "govuk-tabs" }) unless as_links
|
|
16
|
+
|
|
17
|
+
if ga4_tracking
|
|
18
|
+
component_helper.add_data_attribute({ module: "ga4-event-tracker" }) unless as_links
|
|
19
|
+
component_helper.add_data_attribute({ module: "ga4-link-tracker" }) if as_links
|
|
20
|
+
end
|
|
13
21
|
%>
|
|
14
22
|
<% if tabs.count > 1 %>
|
|
15
|
-
|
|
23
|
+
<%= tag.div(**component_helper.all_attributes) do %>
|
|
16
24
|
<h2 class="govuk-tabs__title">
|
|
17
25
|
<%= t("components.tabs.contents") %>
|
|
18
26
|
</h2>
|
|
19
27
|
<ul class="govuk-tabs__list">
|
|
20
28
|
<% tabs.each_with_index do |tab, index| %>
|
|
21
|
-
<li class="govuk-tabs__list-item">
|
|
29
|
+
<li class="govuk-tabs__list-item <%= "govuk-tabs__list-item--selected" if tab[:active] %>">
|
|
22
30
|
<%
|
|
23
31
|
tab[:tab_data_attributes] ||= {}
|
|
24
32
|
if ga4_tracking
|
|
25
|
-
|
|
33
|
+
ga4_attributes = {
|
|
26
34
|
event_name: "select_content",
|
|
27
35
|
type: "tabs",
|
|
28
36
|
text: tab[:label],
|
|
@@ -31,24 +39,32 @@
|
|
|
31
39
|
index_section_count: tabs.length,
|
|
32
40
|
},
|
|
33
41
|
}
|
|
42
|
+
ga4_attributes[:event_name] = "navigation" if as_links
|
|
43
|
+
tab[:tab_data_attributes][:ga4_link] = ga4_attributes if as_links
|
|
44
|
+
tab[:tab_data_attributes][:ga4_event] = ga4_attributes unless as_links
|
|
34
45
|
end
|
|
46
|
+
|
|
47
|
+
tab_link = "##{tab[:id]}"
|
|
48
|
+
tab_link = tab[:href] if as_links
|
|
35
49
|
%>
|
|
36
50
|
<%= link_to(tab[:label],
|
|
37
|
-
|
|
51
|
+
tab_link,
|
|
38
52
|
class: "govuk-tabs__tab",
|
|
39
53
|
data: tab[:tab_data_attributes]) %>
|
|
40
54
|
</li>
|
|
41
55
|
<% end %>
|
|
42
56
|
</ul>
|
|
43
|
-
<%
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
<% unless as_links %>
|
|
58
|
+
<% tabs.each do |tab| %>
|
|
59
|
+
<section class="<%= panel_css_classes %>" id="<%= tab[:id] %>">
|
|
60
|
+
<% if tab[:title] %>
|
|
61
|
+
<h2 class="govuk-heading-l"><%= tab[:title] %></h2>
|
|
62
|
+
<% end %>
|
|
63
|
+
<%= tab[:content] %>
|
|
64
|
+
</section>
|
|
65
|
+
<% end %>
|
|
50
66
|
<% end %>
|
|
51
|
-
|
|
67
|
+
<% end %>
|
|
52
68
|
<% end %>
|
|
53
69
|
<% if tabs.count == 1 %>
|
|
54
70
|
<section id="<%= tabs[0][:id] %>">
|