govuk_publishing_components 35.10.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/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] %>">
|