govuk_publishing_components 35.13.1 → 35.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1337364c8c59cc2f98de9c4919d17bbb17356257fcc90eb90f25e15db301a0ae
4
- data.tar.gz: 70b99e1a524455dc905f457addfb78aa46f0a4fa7be0a69c64a5e34952228be3
3
+ metadata.gz: cbe4c3f60d3220a9d2b715392ba0bdd2f6bce4f92153fff876e8a0b608361161
4
+ data.tar.gz: 94bd59d7a23b8e3cec4882814d7fb0140f81f0bd53bc23f0e475700ba8c489f8
5
5
  SHA512:
6
- metadata.gz: 9a85f01e30436be8cb8f2131f851353e28a8cbad3c0269758789991491ad5ed232ae1e2e9d782e2fa8349c4863c38faadb254a788abb416e3b4ba35f32d196d7
7
- data.tar.gz: 103018230befe8fca5796df4f9d2ebff20f255584253d37d5e3aa2c9cd997b7a17a6fdb719932c758f31647a84fb1c85329fc33082bf68ac1ca99fa48fcd7b36
6
+ metadata.gz: 47f46ab14ccabebf2a3a3c0da9bc03f9b8207d1e54b6a0c4eb8830eb87b5ce200dd606fd2de50c3804d61f222518c560b046ff77b0de87e635a84a653d77d758
7
+ data.tar.gz: c51c0a0407bfa84b24ba4d5dfb281f9c31657f1b18e5afe687198c401dbb0f05dc795d7c27ecdf9fbbfe8413cc82a18f28016d77f3d4248351780e0731a61e55
@@ -169,10 +169,10 @@ window.GOVUK.analyticsGa4 = window.GOVUK.analyticsGa4 || {};
169
169
  removeCrossDomainParams: function (href) {
170
170
  if (href.indexOf('_ga') !== -1 || href.indexOf('_gl') !== -1) {
171
171
  // _ga & _gl are values needed for cross domain tracking, but we don't want them included in our click tracking.
172
- href = href.replaceAll(/_g[al]=([^&]*)/g, '')
172
+ href = href.replace(/_g[al]=([^&]*)/g, '')
173
173
 
174
174
  // The following code cleans up inconsistencies such as gov.uk/&&, gov.uk/?&hello=world, gov.uk/?, and gov.uk/&.
175
- href = href.replaceAll(/(&&)+/g, '&')
175
+ href = href.replace(/(&&)+/g, '&')
176
176
  href = href.replace('?&', '?')
177
177
  if (this.stringEndsWith(href, '?') || this.stringEndsWith(href, '&')) {
178
178
  href = href.substring(0, href.length - 1)
@@ -241,7 +241,8 @@ window.GOVUK.analyticsGa4 = window.GOVUK.analyticsGa4 || {};
241
241
 
242
242
  try {
243
243
  var ga4LinkData = JSON.parse(module.getAttribute('data-ga4-link'))
244
- ga4LinkData.index_total = totalLinks
244
+ // use index_total if it already exists, otherwise calculate it and set it
245
+ ga4LinkData.index_total = ga4LinkData.index_total || totalLinks
245
246
  module.setAttribute('data-ga4-link', JSON.stringify(ga4LinkData))
246
247
  } catch (e) {
247
248
  // if there's a problem with the config, don't start the tracker
@@ -84,12 +84,13 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
84
84
  var labelText = input.label.innerText || input.label.textContent
85
85
  var inputType = elem.getAttribute('type')
86
86
  var inputNodename = elem.nodeName
87
+ var inputTypes = ['text', 'search', 'email', 'number']
87
88
 
88
89
  if (inputType === 'checkbox' && elem.checked) {
89
90
  input.answer = labelText
90
91
  } else if (inputNodename === 'SELECT' && elem.options[elem.selectedIndex].value) {
91
92
  input.answer = elem.options[elem.selectedIndex].text
92
- } else if ((inputType === 'text' || inputType === 'search') && elem.value) {
93
+ } else if (inputTypes.indexOf(inputType) !== -1 && elem.value) {
93
94
  if (this.includeTextInputValues) {
94
95
  var PIIRemover = new window.GOVUK.analyticsGa4.PIIRemover()
95
96
  input.answer = PIIRemover.stripPIIWithOverride(elem.value, true, true)
@@ -29,6 +29,9 @@ window.GOVUK.analyticsGa4.analyticsModules = window.GOVUK.analyticsGa4.analytics
29
29
  content_id: this.getMetaContent('content-id'),
30
30
 
31
31
  browse_topic: this.getMetaContent('section'),
32
+ navigation_page_type: this.getMetaContent('navigation-page-type'),
33
+ navigation_list_type: this.getMetaContent('navigation-list-type'),
34
+ step_navs: this.getMetaContent('stepnavs'),
32
35
  taxonomy_level1: this.getMetaContent('themes'),
33
36
  taxonomy_main: this.getMetaContent('taxon-slug'),
34
37
  taxonomy_main_id: this.getMetaContent('taxon-id'),
@@ -50,7 +53,9 @@ window.GOVUK.analyticsGa4.analyticsModules = window.GOVUK.analyticsGa4.analytics
50
53
  /* The existence of a referrer parameter indicates that the page has been dynamically updated via an AJAX request
51
54
  and therefore we can use it to set the dynamic property appropriately. This value is used by PA's to differentiate
52
55
  between fresh page loads and dynamic page updates. */
53
- dynamic: referrer ? 'true' : 'false'
56
+ dynamic: referrer ? 'true' : 'false',
57
+ emergency_banner: document.querySelector('[data-ga4-emergency-banner]') ? 'true' : undefined,
58
+ phase_banner: this.getElementAttribute('data-ga4-phase-banner') || undefined
54
59
  }
55
60
  }
56
61
  window.GOVUK.analyticsGa4.core.sendData(data)
@@ -88,6 +93,13 @@ window.GOVUK.analyticsGa4.analyticsModules = window.GOVUK.analyticsGa4.analytics
88
93
  }
89
94
  },
90
95
 
96
+ getElementAttribute: function (attributeName) {
97
+ var el = document.querySelector('[' + attributeName + ']')
98
+ if (el) {
99
+ return el.getAttribute(attributeName)
100
+ }
101
+ },
102
+
91
103
  getLanguage: function () {
92
104
  var content = document.getElementById('content')
93
105
  if (content) {
@@ -29,7 +29,10 @@
29
29
  link_domain: this.undefined,
30
30
  link_path_parts: this.undefined,
31
31
  tool_name: this.undefined,
32
- percent_scrolled: this.undefined
32
+ percent_scrolled: this.undefined,
33
+ video_current_time: this.undefined,
34
+ video_duration: this.undefined,
35
+ video_percent: this.undefined
33
36
  }
34
37
  }
35
38
  }
@@ -60,6 +60,8 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
60
60
  window.addEventListener('scroll', this.scrollEvent)
61
61
  this.resizeEvent = this.onResize.bind(this)
62
62
  window.addEventListener('resize', this.resizeEvent)
63
+ this.resetEvent = this.onReset.bind(this)
64
+ window.addEventListener('dynamic-page-update', this.resetEvent)
63
65
 
64
66
  // check if the page height changes e.g. accordion opened
65
67
  this.interval = window.setInterval(function () {
@@ -115,6 +117,7 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
115
117
  data.type = node.eventData.type
116
118
  // following will be undefined if tracking percentages
117
119
  data.text = node.eventData.text
120
+ data.section = node.eventData.text
118
121
  data.index = node.eventData.index
119
122
  // following will be undefined if tracking headings
120
123
  data.percent_scrolled = node.eventData.percent_scrolled
@@ -131,6 +134,14 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
131
134
  return scroll <= top && (scroll + this.windowHeight) >= bottom
132
135
  }
133
136
 
137
+ // if reset, we set all nodes 'alreadySeen' to false
138
+ // used when the page content is dynamically updated e.g. search
139
+ Ga4ScrollTracker.prototype.onReset = function () {
140
+ for (var i = 0; i < this.trackedNodes.length; i++) {
141
+ this.trackedNodes[i].alreadySeen = false
142
+ }
143
+ }
144
+
134
145
  Ga4ScrollTracker.Heading = function (config) {
135
146
  this.config = config
136
147
  }
@@ -0,0 +1,88 @@
1
+ window.GOVUK = window.GOVUK || {}
2
+ window.GOVUK.analyticsGa4 = window.GOVUK.analyticsGa4 || {}
3
+ window.GOVUK.analyticsGa4.analyticsModules = window.GOVUK.analyticsGa4.analyticsModules || {};
4
+
5
+ (function (analyticsModules) {
6
+ 'use strict'
7
+
8
+ var VideoTracker = {
9
+ init: function () {
10
+ this.handlers = {}
11
+ },
12
+
13
+ configureVideo: function (event) {
14
+ var player = event.target
15
+ var videoId = player.id
16
+ var duration = player.getDuration()
17
+ var percentages = [25, 50, 75]
18
+
19
+ for (var i = 0; i < percentages.length; i++) {
20
+ var percent = percentages[i]
21
+ var position = (duration / 100) * percent
22
+ this.handlers['video-' + videoId + '-' + percent + '-percent-begin'] = position
23
+ // interval is once a second, so end point must be at least one second beyond begin point
24
+ this.handlers['video-' + videoId + '-' + percent + '-percent-end'] = position + 2
25
+ }
26
+ },
27
+
28
+ trackVideo: function (event, state) {
29
+ var videoTracker = window.GOVUK.analyticsGa4.analyticsModules.VideoTracker
30
+ var player = event.target
31
+ var videoId = player.id
32
+ clearInterval(videoTracker.handlers['video-' + videoId])
33
+
34
+ if (state === 'VideoUnstarted') {
35
+ videoTracker.handlers['video-' + videoId] = setInterval(videoTracker.checkProgress, 1000, player)
36
+ videoTracker.sendData(player, 'start', 0) // VideoUnstarted seems to only happen the first time video is played
37
+ } else if (state === 'VideoPlaying') {
38
+ videoTracker.handlers['video-' + videoId] = setInterval(videoTracker.checkProgress, 1000, player)
39
+ } else if (state === 'VideoEnded') {
40
+ if (!videoTracker.handlers['video-' + videoId + '-100']) {
41
+ videoTracker.sendData(player, 'complete', 100)
42
+ videoTracker.handlers['video-' + videoId + '-100'] = true
43
+ }
44
+ }
45
+ },
46
+
47
+ checkProgress: function (player) {
48
+ var videoId = player.id
49
+ var videoTracker = window.GOVUK.analyticsGa4.analyticsModules.VideoTracker
50
+ var pos = player.getCurrentTime()
51
+ var percentages = [25, 50, 75]
52
+
53
+ // this looks really clunky and long hand
54
+ // but we have to do this once a second so doing the minimum before dropping out
55
+ // of an if statement is more efficient than combining all these statements into one
56
+ for (var i = 0; i < percentages.length; i++) {
57
+ if (pos >= videoTracker.handlers['video-' + videoId + '-' + percentages[i] + '-percent-begin']) {
58
+ if (pos < videoTracker.handlers['video-' + videoId + '-' + percentages[i] + '-percent-end']) {
59
+ if (!videoTracker.handlers['video-' + videoId + '-' + percentages[i]]) {
60
+ videoTracker.sendData(player, 'progress', percentages[i])
61
+ videoTracker.handlers['video-' + videoId + '-' + percentages[i]] = true
62
+ }
63
+ return
64
+ }
65
+ }
66
+ }
67
+ },
68
+
69
+ sendData: function (player, event, position) {
70
+ var data = {}
71
+ data.event_name = 'video_' + event
72
+ data.type = 'video'
73
+ data.url = player.getVideoUrl()
74
+ data.text = player.videoTitle
75
+ data.action = event
76
+ data.video_current_time = Math.round(player.getCurrentTime())
77
+ data.video_duration = Math.ceil(player.getDuration()) // number returned from the API varies, so round up
78
+ data.video_percent = position
79
+
80
+ var schemas = new window.GOVUK.analyticsGa4.Schemas()
81
+ var schema = schemas.mergeProperties(data, 'event_data')
82
+
83
+ window.GOVUK.analyticsGa4.core.sendData(schema)
84
+ }
85
+ }
86
+
87
+ analyticsModules.VideoTracker = VideoTracker
88
+ })(window.GOVUK.analyticsGa4.analyticsModules)
@@ -11,4 +11,5 @@
11
11
  //= require ./analytics-ga4/ga4-auto-tracker
12
12
  //= require ./analytics-ga4/ga4-smart-answer-results-tracker
13
13
  //= require ./analytics-ga4/ga4-scroll-tracker
14
+ //= require ./analytics-ga4/ga4-video-tracker
14
15
  //= require ./analytics-ga4/init-ga4
@@ -116,6 +116,9 @@
116
116
  // https://github.com/alphagov/govuk_publishing_components/pull/908#discussion_r302913995
117
117
  var videoTitle = options.title
118
118
  event.target.getIframe().title = videoTitle + ' (video)'
119
+ if (window.GOVUK.analyticsGa4.analyticsModules.VideoTracker) {
120
+ window.GOVUK.analyticsGa4.analyticsModules.VideoTracker.configureVideo(event)
121
+ }
119
122
  },
120
123
  onStateChange: function (event) {
121
124
  var eventData = event.data
@@ -140,6 +143,10 @@
140
143
 
141
144
  window.GOVUK.analytics.trackEvent(tracking.category, tracking.action, tracking.label)
142
145
  }
146
+
147
+ if (window.GOVUK.analyticsGa4.analyticsModules.VideoTracker) {
148
+ window.GOVUK.analyticsGa4.analyticsModules.VideoTracker.trackVideo(event, states[eventData])
149
+ }
143
150
  }
144
151
  }
145
152
  })
@@ -2,5 +2,6 @@
2
2
  @import "govuk/components/select/select";
3
3
 
4
4
  .gem-c-select__select--full-width {
5
- width: 100%;
5
+ min-width: 100%;
6
+ max-width: 100%;
6
7
  }
@@ -11,6 +11,7 @@
11
11
 
12
12
  container_class_names = %w[gem-c-attachment govuk-!-display-none-print]
13
13
  container_class_names << shared_helper.get_margin_bottom if local_assigns.key?(:margin_bottom)
14
+ ga4_link = { 'event_name': 'navigation', 'type': 'attachment' }
14
15
 
15
16
  case attachment.type
16
17
  when "file"
@@ -38,13 +39,14 @@
38
39
  class: "gem-c-attachment__attribute",
39
40
  )
40
41
  end
42
+
43
+ ga4_link[:event_name] = 'file_download'
44
+
41
45
  when "html"
42
46
  attributes << tag.span(
43
47
  "HTML",
44
48
  class: "gem-c-attachment__attribute",
45
49
  )
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
48
50
  when "external"
49
51
  attributes << tag.span(
50
52
  attachment.url,
@@ -53,7 +55,7 @@
53
55
  end
54
56
 
55
57
  %>
56
- <%= tag.section class: class_names(container_class_names) do %>
58
+ <%= tag.section class: class_names(container_class_names), data: { module: "ga4-link-tracker", ga4_track_links_only: "", ga4_link: ga4_link } do %>
57
59
  <%= tag.div class: "gem-c-attachment__thumbnail" do %>
58
60
  <%= link_to attachment.url,
59
61
  class: "govuk-link",
@@ -7,6 +7,7 @@
7
7
  link_text ||= "More information"
8
8
  campaign_class ||= nil
9
9
  homepage ||= false
10
+ ga4_tracking ||= false
10
11
 
11
12
  emergency_banner_helper = GovukPublishingComponents::Presenters::EmergencyBannerHelper.new()
12
13
 
@@ -28,9 +29,25 @@
28
29
  description_classes = %w[gem-c-emergency-banner__description]
29
30
  description_classes << "gem-c-emergency-banner__description--homepage" if homepage
30
31
 
32
+
33
+ data_attributes = {
34
+ "nosnippet": true,
35
+ }
36
+
37
+ if ga4_tracking
38
+ data_attributes[:ga4_emergency_banner] = ""
39
+ data_attributes[:module] = "ga4-link-tracker"
40
+ data_attributes[:ga4_track_links_only] = ""
41
+ data_attributes[:ga4_set_indexes] = ""
42
+ data_attributes[:ga4_link] = {
43
+ event_name: "navigation",
44
+ type: "emergency banner",
45
+ section: heading,
46
+ }.to_json
47
+ end
31
48
  %>
32
49
 
33
- <%= content_tag('section', class: banner_classes, "aria-labelledby": "emergency-banner-heading", "data-nosnippet": true ) do %>
50
+ <%= content_tag('section', class: banner_classes, "aria-labelledby": "emergency-banner-heading", data: data_attributes) do %>
34
51
  <div class="govuk-width-container">
35
52
  <div class="govuk-grid-row">
36
53
  <div class="govuk-grid-column-two-thirds">
@@ -5,6 +5,7 @@ app_name ||= nil
5
5
  phase ||= nil
6
6
  message ||= nil
7
7
  inverse ||= false
8
+ ga4_tracking ||= false
8
9
 
9
10
  unless message.present?
10
11
  if phase == "beta"
@@ -16,9 +17,24 @@ end
16
17
 
17
18
  container_css_classes = %w(gem-c-phase-banner govuk-phase-banner)
18
19
  container_css_classes << "gem-c-phase-banner--inverse" if inverse
20
+
21
+ data_attributes = {}
22
+
23
+ if ga4_tracking
24
+ data_attributes[:ga4_phase_banner] = phase
25
+ data_attributes[:module] = "ga4-link-tracker"
26
+ data_attributes[:ga4_track_links_only] = ""
27
+ data_attributes[:ga4_set_indexes] = ""
28
+ data_attributes[:ga4_link] = {
29
+ event_name: "navigation",
30
+ type: "phase banner",
31
+ section: Nokogiri::HTML(message).text,
32
+ }.to_json
33
+ end
34
+
19
35
  %>
20
36
 
21
- <%= tag.div class: container_css_classes do %>
37
+ <%= tag.div class: container_css_classes, data: data_attributes do %>
22
38
  <%= tag.p class: "govuk-phase-banner__content" do %>
23
39
  <%= tag.strong app_name, class: "govuk-phase-banner__content__app-name" if app_name %>
24
40
  <%= tag.strong phase, class: "govuk-tag govuk-phase-banner__content__tag" if phase %>
@@ -45,3 +45,13 @@ examples:
45
45
  short_description: "1491 to 1547"
46
46
  link: "https://www.gov.uk/"
47
47
  homepage: true
48
+ with_ga4_tracking:
49
+ description: |
50
+ Enables GA4 tracking on the banner. This includes link tracking on the component itself, and allows pageviews to record the presence of the banner on page load.
51
+ data:
52
+ campaign_class: "notable-death"
53
+ heading: "His Royal Highness Henry VIII"
54
+ short_description: "1491 to 1547"
55
+ link: "https://www.gov.uk/"
56
+ homepage: true
57
+ ga4_tracking: true
@@ -32,3 +32,11 @@ examples:
32
32
  app_name: Skittles Maker
33
33
  phase: beta
34
34
  inverse: true
35
+ with_ga4_tracking:
36
+ description: |
37
+ Enables GA4 tracking on the banner. This includes link tracking on the component itself, and allows pageviews to record the presence of the banner on page load.
38
+ data:
39
+ app_name: Skittles Maker
40
+ phase: beta
41
+ inverse: true
42
+ ga4_tracking: true
@@ -6,7 +6,7 @@
6
6
  <% else %>
7
7
  <%= render "govuk_publishing_components/components/layout_header", {
8
8
  environment: GovukPublishingComponents::AppHelpers::Environment.current_acceptance_environment,
9
- product_name: GovukPublishingComponents::Config.component_guide_title,
9
+ product_name: "#{GovukPublishingComponents::Config.component_guide_title} #{GovukPublishingComponents::VERSION}",
10
10
  href: component_guide_path
11
11
  } %>
12
12
  <div class="govuk-width-container app-width-container--wide">
@@ -1,3 +1,3 @@
1
1
  module GovukPublishingComponents
2
- VERSION = "35.13.1".freeze
2
+ VERSION = "35.14.0".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: govuk_publishing_components
3
3
  version: !ruby/object:Gem::Version
4
- version: 35.13.1
4
+ version: 35.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GOV.UK Dev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-01 00:00:00.000000000 Z
11
+ date: 2023-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: govuk_app_config
@@ -451,6 +451,7 @@ files:
451
451
  - app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-scroll-tracker.js
452
452
  - app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-smart-answer-results-tracker.js
453
453
  - app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-specialist-link-tracker.js
454
+ - app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-video-tracker.js
454
455
  - app/assets/javascripts/govuk_publishing_components/analytics-ga4/init-ga4.js
455
456
  - app/assets/javascripts/govuk_publishing_components/analytics-ga4/pii-remover.js
456
457
  - app/assets/javascripts/govuk_publishing_components/analytics.js
@@ -1467,7 +1468,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1467
1468
  - !ruby/object:Gem::Version
1468
1469
  version: '0'
1469
1470
  requirements: []
1470
- rubygems_version: 3.4.17
1471
+ rubygems_version: 3.4.18
1471
1472
  signing_key:
1472
1473
  specification_version: 4
1473
1474
  summary: A gem to document components in GOV.UK frontend applications