govuk_publishing_components 35.11.0 → 35.12.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/views/govuk_publishing_components/components/_attachment.html.erb +3 -1
- data/app/views/govuk_publishing_components/components/_tabs.html.erb +30 -14
- 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 +14 -2
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
|
@@ -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 %>
|
@@ -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] %>">
|
@@ -30,6 +30,17 @@ examples:
|
|
30
30
|
label: "Second section"
|
31
31
|
content: |
|
32
32
|
<p class="govuk-body-m">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam congue elementum commodo. Vestibulum elit turpis, efficitur quis posuere vitae, commodo vitae augue. Donec ut pharetra ligula. Phasellus ac mauris eu felis bibendum dapibus rutrum sed quam. Pellentesque posuere ante id consequat pretium.</p>
|
33
|
+
as_links:
|
34
|
+
description: With this option the tabs operate as links, rather than switching between elements within a single page.
|
35
|
+
data:
|
36
|
+
as_links: true
|
37
|
+
tabs:
|
38
|
+
- href: "link1"
|
39
|
+
label: "Page one"
|
40
|
+
active: true
|
41
|
+
- href: "link2"
|
42
|
+
label: "Page two"
|
43
|
+
active: false
|
33
44
|
without_panel_border:
|
34
45
|
data:
|
35
46
|
panel_border: false
|
@@ -84,8 +95,8 @@ examples:
|
|
84
95
|
tracking: GTM-123AB
|
85
96
|
content: |
|
86
97
|
<p class="govuk-body-m">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam congue elementum commodo. Vestibulum elit turpis, efficitur quis posuere vitae, commodo vitae augue. Donec ut pharetra ligula. Phasellus ac mauris eu felis bibendum dapibus rutrum sed quam. Pellentesque posuere ante id consequat pretium.</p>
|
87
|
-
|
88
|
-
description: Enables GA4 tracking
|
98
|
+
with_ga4_tracking_on_tabs:
|
99
|
+
description: Enables GA4 tracking by adding the event tracker and required data attributes to the tabs. See the [ga4-event-tracker documentation](https://github.com/alphagov/govuk_publishing_components/blob/main/docs/analytics-ga4/ga4-event-tracker.md) for more information.
|
89
100
|
data:
|
90
101
|
ga4_tracking: true
|
91
102
|
tabs:
|
@@ -99,3 +110,15 @@ examples:
|
|
99
110
|
title: "Second section"
|
100
111
|
content: |
|
101
112
|
<p class="govuk-body-m">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam congue elementum commodo. Vestibulum elit turpis, efficitur quis posuere vitae, commodo vitae augue. Donec ut pharetra ligula. Phasellus ac mauris eu felis bibendum dapibus rutrum sed quam. Pellentesque posuere ante id consequat pretium.</p>
|
113
|
+
with_ga4_tracking_on_tabs_as_links:
|
114
|
+
description: Enables GA4 tracking by adding the link tracker and required data attributes to the tabs. See the [ga4-link-tracker documentation](https://github.com/alphagov/govuk_publishing_components/blob/main/docs/analytics-ga4/ga4-link-tracker.md) for more information.
|
115
|
+
data:
|
116
|
+
as_links: true
|
117
|
+
ga4_tracking: true
|
118
|
+
tabs:
|
119
|
+
- href: "/page1"
|
120
|
+
label: "Link 1"
|
121
|
+
active: true
|
122
|
+
- href: "/page2"
|
123
|
+
label: "Link 2"
|
124
|
+
active: false
|