govuk_publishing_components 30.1.0 → 30.2.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: 98ffd65de2a6ab2a76338534b51c8a25a9c45bbf7c15ea2eb59363067929846f
4
- data.tar.gz: 7b0e8e36604bd2666bfe8171b1e06334af902135028115afdbc59838d36ebb94
3
+ metadata.gz: 4aee02160c93679a75c8418c7b1f0da2ed3908a6016f4437f06dfa0091b61096
4
+ data.tar.gz: 629859a537593a4f5547cbfa45e866bde739b616ef0598f2428ea07bc0f0af26
5
5
  SHA512:
6
- metadata.gz: cbd879810fbb5845aeb9ad610b1afe41dd4324ed9148895bfe5da773599e87f593c606ffd364fb54623cde60f6e340689eab3168aebf229e210e8fc4612c0b49
7
- data.tar.gz: 4c179f7d646a332d7ea36c6383bd8d808a001590280ba40c747e248a62ed29ece82580331ab6b0f509c99835ef3fcfd72d31ccb1cccf91fc1d39fa688b328172
6
+ metadata.gz: 043a2bed5b586217a53aea43f53b9a43219b6f8947aaa90776d00a86ebb1f78c410131085401a2b0802a450426d85be2e22f986447e9e99c4d2afee76f95cbbb
7
+ data.tar.gz: a52358d241fd9539a21fd7cb47c4d54fd2e402e0441758ec7348eb9b14c64444cfeaca9c54e03c34e8051c10bcac4c7c0f00999898f3586b5007f320ba9a5d86
@@ -5,16 +5,16 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
5
5
  (function (Modules) {
6
6
  'use strict'
7
7
 
8
- function GtmClickTracking (module) {
8
+ function GA4EventTracker (module) {
9
9
  this.module = module
10
10
  this.trackingTrigger = 'data-ga4' // elements with this attribute get tracked
11
11
  }
12
12
 
13
- GtmClickTracking.prototype.init = function () {
13
+ GA4EventTracker.prototype.init = function () {
14
14
  this.module.addEventListener('click', this.trackClick.bind(this), true) // useCapture must be true
15
15
  }
16
16
 
17
- GtmClickTracking.prototype.trackClick = function (event) {
17
+ GA4EventTracker.prototype.trackClick = function (event) {
18
18
  if (window.dataLayer) {
19
19
  var target = this.findTrackingAttributes(event.target)
20
20
  if (target) {
@@ -58,12 +58,25 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
58
58
  var openAttribute = detailsElement.getAttribute('open')
59
59
  schema.event_data.action = (openAttribute == null) ? 'opened' : 'closed'
60
60
  }
61
+
62
+ /* If a tab was clicked, grab the href of the clicked tab (usually an anchor # link) */
63
+ var tabElement = event.target.closest('.gem-c-tabs')
64
+ if (tabElement) {
65
+ var aTag = event.target.closest('a')
66
+ if (aTag) {
67
+ var href = aTag.getAttribute('href')
68
+ if (href) {
69
+ schema.event_data.url = href
70
+ }
71
+ }
72
+ }
73
+
61
74
  window.dataLayer.push(schema)
62
75
  }
63
76
  }
64
77
  }
65
78
 
66
- GtmClickTracking.prototype.findTrackingAttributes = function (clicked) {
79
+ GA4EventTracker.prototype.findTrackingAttributes = function (clicked) {
67
80
  if (clicked.hasAttribute('[' + this.trackingTrigger + ']')) {
68
81
  return clicked
69
82
  } else {
@@ -72,7 +85,7 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
72
85
  }
73
86
 
74
87
  // check if an attribute exists or contains the attribute
75
- GtmClickTracking.prototype.getClosestAttribute = function (clicked, attribute) {
88
+ GA4EventTracker.prototype.getClosestAttribute = function (clicked, attribute) {
76
89
  var isAttributeOnElement = clicked.getAttribute(attribute)
77
90
  var containsAttribute = clicked.querySelector('[' + attribute + ']')
78
91
 
@@ -83,5 +96,5 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
83
96
  }
84
97
  }
85
98
 
86
- Modules.GtmClickTracking = GtmClickTracking
99
+ Modules.GA4EventTracker = GA4EventTracker
87
100
  })(window.GOVUK.Modules)
@@ -0,0 +1,153 @@
1
+ // = require govuk/vendor/polyfills/Element/prototype/closest.js
2
+
3
+ ;(function (global) {
4
+ 'use strict'
5
+
6
+ var GOVUK = global.GOVUK || {}
7
+ GOVUK.analyticsGA4 = GOVUK.analyticsGA4 || {}
8
+
9
+ GOVUK.analyticsGA4.linkTracker = {
10
+ trackLinkClicks: function () {
11
+ if (window.dataLayer) {
12
+ this.internalLinksDomain = 'www.gov.uk/'
13
+ this.internalLinksDomainWithoutWww = 'gov.uk/'
14
+ this.handleClick = this.handleClick.bind(this)
15
+ this.handleMousedown = this.handleMousedown.bind(this)
16
+ document.querySelector('body').addEventListener('click', this.handleClick)
17
+ document.querySelector('body').addEventListener('contextmenu', this.handleClick)
18
+ document.querySelector('body').addEventListener('mousedown', this.handleMousedown)
19
+ }
20
+ },
21
+
22
+ stopTracking: function () {
23
+ document.querySelector('body').removeEventListener('click', this.handleClick)
24
+ document.querySelector('body').removeEventListener('contextmenu', this.handleClick)
25
+ document.querySelector('body').removeEventListener('mousedown', this.handleMousedown)
26
+ },
27
+
28
+ handleClick: function (event) {
29
+ var element = event.target
30
+
31
+ if (element.tagName !== 'A') {
32
+ element = element.closest('a')
33
+ }
34
+
35
+ if (!element) {
36
+ return
37
+ }
38
+
39
+ var clickData = {}
40
+ var href = element.getAttribute('href')
41
+
42
+ if (!href) {
43
+ return
44
+ }
45
+
46
+ if (this.isMailToLink(href)) {
47
+ clickData.type = 'email'
48
+ clickData.external = 'true'
49
+ } else if (this.isDownloadLink(href)) {
50
+ clickData.type = 'download'
51
+ clickData.external = 'false'
52
+ } else if (this.isExternalLink(href)) {
53
+ clickData.type = 'generic link'
54
+ clickData.external = 'true'
55
+ }
56
+
57
+ if (Object.keys(clickData).length > 0) {
58
+ clickData.event_name = 'navigation'
59
+ clickData.text = element.textContent.trim()
60
+ clickData.url = href
61
+ clickData.link_method = this.getClickType(event)
62
+
63
+ var schema = new window.GOVUK.analyticsGA4.Schemas().eventSchema()
64
+ schema.event = 'analytics'
65
+
66
+ // get attributes from the clickData object to send to GA
67
+ // only allow it if it already exists in the schema
68
+ for (var property in clickData) {
69
+ if (property in schema.event_data) {
70
+ schema.event_data[property] = clickData[property]
71
+ }
72
+ }
73
+
74
+ window.dataLayer.push(schema)
75
+ }
76
+ },
77
+
78
+ getClickType: function (event) {
79
+ switch (event.type) {
80
+ case 'click':
81
+ if (event.ctrlKey) {
82
+ return 'ctrl click'
83
+ } else if (event.metaKey) {
84
+ return 'command/win click'
85
+ } else {
86
+ return 'primary click'
87
+ }
88
+ case 'mousedown':
89
+ return 'middle click'
90
+ case 'contextmenu':
91
+ return 'secondary click'
92
+ }
93
+ },
94
+
95
+ handleMousedown: function (event) {
96
+ // 1 = middle mouse button
97
+ if (event.button === 1) {
98
+ this.handleClick(event)
99
+ }
100
+ },
101
+
102
+ isMailToLink: function (href) {
103
+ return href.substring(0, 7) === 'mailto:'
104
+ },
105
+
106
+ isDownloadLink: function (href) {
107
+ var assetsDomain = 'assets.publishing.service.gov.uk/'
108
+ var uploadsPath = '/government/uploads/'
109
+
110
+ if (this.hrefPointsToDomain(href, assetsDomain)) {
111
+ return true
112
+ }
113
+
114
+ var isInternalLink = this.hrefPointsToDomain(href, this.internalLinksDomain) || this.hrefPointsToDomain(href, this.internalLinksDomainWithoutWww)
115
+ if (isInternalLink && href.indexOf(uploadsPath) !== -1) {
116
+ return true
117
+ }
118
+
119
+ // Checks relative links to the uploadsPath
120
+ if (this.stringStartsWith(href, uploadsPath)) {
121
+ return true
122
+ }
123
+ },
124
+
125
+ isExternalLink: function (href) {
126
+ var isInternalLink = this.hrefPointsToDomain(href, this.internalLinksDomain) || this.hrefPointsToDomain(href, this.internalLinksDomainWithoutWww)
127
+ if (!isInternalLink && !this.hrefIsRelative(href)) {
128
+ return true
129
+ }
130
+ },
131
+
132
+ hrefPointsToDomain: function (href, domain) {
133
+ var httpDomain = 'http://' + domain
134
+ var httpsDomain = 'https://' + domain
135
+ var schemaRelativeDomain = '//' + domain
136
+ return this.stringStartsWith(href, domain) ||
137
+ this.stringStartsWith(href, httpDomain) ||
138
+ this.stringStartsWith(href, httpsDomain) ||
139
+ this.stringStartsWith(href, schemaRelativeDomain)
140
+ },
141
+
142
+ stringStartsWith: function (string, stringToFind) {
143
+ return string.substring(0, stringToFind.length) === stringToFind
144
+ },
145
+
146
+ hrefIsRelative: function (href) {
147
+ // Checks that a link is relative, but is not a protocol relative url
148
+ return href[0] === '/' && href[1] !== '/'
149
+ }
150
+ }
151
+
152
+ global.GOVUK = GOVUK
153
+ })(window)
@@ -2,8 +2,9 @@
2
2
  'use strict'
3
3
 
4
4
  var GOVUK = global.GOVUK || {}
5
+ GOVUK.analyticsGA4 = GOVUK.analyticsGA4 || {}
5
6
 
6
- GOVUK.Gtm = {
7
+ GOVUK.analyticsGA4.pageViewTracker = {
7
8
  PIIRemover: new GOVUK.analyticsGA4.PIIRemover(), // imported in analytics-ga4.js
8
9
  nullValue: null,
9
10
 
@@ -20,7 +20,8 @@
20
20
  index_total: this.null,
21
21
  section: this.null,
22
22
  action: this.null,
23
- external: this.null
23
+ external: this.null,
24
+ link_method: this.null
24
25
  }
25
26
  }
26
27
  }
@@ -1,7 +1,9 @@
1
1
  // The following modules are imported in a specific order
2
- //= require ./analytics-ga4/gtm-schemas
2
+ //= require ./analytics-ga4/ga4-schemas
3
3
  //= require ./analytics-ga4/pii-remover
4
- //= require ./analytics-ga4/gtm-page-views
5
- //= require ./analytics-ga4/gtm-click-tracking
4
+ //= require ./analytics-ga4/ga4-page-views
5
+ //= require ./analytics-ga4/ga4-link-tracker
6
+ //= require ./analytics-ga4/ga4-event-tracker
6
7
 
7
- window.GOVUK.Gtm.sendPageView() // this will need integrating with cookie consent before production
8
+ window.GOVUK.analyticsGA4.pageViewTracker.sendPageView() // this will need integrating with cookie consent before production
9
+ window.GOVUK.analyticsGA4.linkTracker.trackLinkClicks()
@@ -150,7 +150,7 @@ module GovukPublishingComponents
150
150
  end
151
151
 
152
152
  def clean_file_path(file)
153
- file[/(?<=#{Regexp.escape(@path.to_s)}\/)[\/a-zA-Z_-]+.[a-zA-Z.]+/]
153
+ file[/(?<=#{Regexp.escape(@path.to_s)}\/)[\/a-zA-Z_-]+.[a-zA-Z+.]+/]
154
154
  end
155
155
 
156
156
  def clean_file_name(name)
@@ -7,6 +7,10 @@
7
7
 
8
8
  <%= render 'govuk_publishing_components/components/title', title: @component_example.name, context: "#{@component_doc.name} example", margin_top: 0 %>
9
9
 
10
+ <% code_example = capture do %>
11
+ <%= render partial: "govuk_publishing_components/component_guide/component_doc/call", locals: { component_doc: @component_doc, example: @component_example } %>
12
+ <% end %>
13
+
10
14
  <div class="component-show">
11
15
  <div class="component-doc">
12
16
  <div class="component-markdown">
@@ -19,6 +23,6 @@
19
23
  <%= render partial: "govuk_publishing_components/component_guide/component_doc/preview", locals: { component_doc: @component_doc, example: @component_example } %>
20
24
 
21
25
  <h2 class="component-doc-h2">How to call this example</h2>
22
- <%= render partial: "govuk_publishing_components/component_guide/component_doc/call", locals: { component_doc: @component_doc, example: @component_example } %>
26
+ <%= code_example %>
23
27
  </div>
24
28
  </div>
@@ -74,8 +74,11 @@
74
74
  <div class="component-markdown">
75
75
  <%= raw(example.html_description) %>
76
76
  </div>
77
+ <% code_example = capture do %>
78
+ <%= render "govuk_publishing_components/component_guide/component_doc/call", component_doc: @component_doc, example: example %>
79
+ <% end %>
77
80
  <%= render "govuk_publishing_components/component_guide/component_doc/preview", component_doc: @component_doc, example: example %>
78
- <%= render "govuk_publishing_components/component_guide/component_doc/call", component_doc: @component_doc, example: example %>
81
+ <%= code_example %>
79
82
  </div>
80
83
  <% end %>
81
84
  </div>
@@ -22,7 +22,7 @@
22
22
  locales = {}
23
23
 
24
24
  data_attributes ||= {}
25
- data_attributes[:module] = 'govuk-accordion gem-accordion'
25
+ ((data_attributes[:module] ||= "") << " " << "govuk-accordion gem-accordion").strip!
26
26
  data_attributes[:anchor_navigation] = anchor_navigation
27
27
  data_attributes[:track_show_all_clicks] = track_show_all_clicks
28
28
  data_attributes[:track_sections] = track_sections
@@ -6,7 +6,7 @@
6
6
  margin_top ||= 3
7
7
  margin_bottom ||= 3
8
8
 
9
- data_attributes[:module] = require_js ? "print-link" : "button"
9
+ ((data_attributes[:module] ||= "") << " " << (require_js ? "print-link" : "button")).strip!
10
10
 
11
11
  shared_helper = GovukPublishingComponents::Presenters::SharedHelper.new({
12
12
  margin_top: margin_top,
@@ -187,16 +187,15 @@ examples:
187
187
 
188
188
  The `data_attributes` option applies attributes to the outermost element in the accordion. Each item can also have a `data_attributes` hash, which are placed on the `button` that triggers the opening and closing - useful for differentiating between each section of the accordion.
189
189
 
190
- Data attributes can be added to the 'Show/hide all' link using the `data_attributes_show_all` option, primarily where custom tracking is required. These attributes are read from the accordion markup and then added to the link by JavaScript (which is how the link is created). More details on how this can be used with the GA4 click tracking can be found in the 'Advanced' section of the [click tracking documentation](https://github.com/alphagov/govuk_publishing_components/blob/main/docs/analytics-gtm/gtm-click-tracking.md).
190
+ Data attributes can be added to the 'Show/hide all' link using the `data_attributes_show_all` option, primarily where custom tracking is required. These attributes are read from the accordion markup and then added to the link by JavaScript (which is how the link is created). More details on how this can be used with the GA4 event tracking can be found in the 'Advanced' section of the [event tracking documentation](https://github.com/alphagov/govuk_publishing_components/blob/main/docs/analytics-gtm/ga4-event-tracker.md).
191
191
 
192
192
  If `track_options` within `data_attributes_show_all` is set, then it is possible to pass a custom dimension when 'Show/Hide all' is clicked.
193
193
  data:
194
194
  data_attributes:
195
- gtm: gtm-accordion
196
- ga: ga-accordion
195
+ custom_data_attr: custom-data-attr-accordion
197
196
  data_attributes_show_all:
198
- gtm-event-name: example
199
- gtm-attributes: "{ 'ui': { 'type': 'type value', 'section': 'section value' } }"
197
+ custom_data_attr-event-name: example
198
+ custom_data_attr-attributes: "{ 'ui': { 'type': 'type value', 'section': 'section value' } }"
200
199
  tracking-options: "{ 'dimension114': 1 }"
201
200
  items:
202
201
  - heading:
@@ -204,25 +203,39 @@ examples:
204
203
  content:
205
204
  html: <p class="govuk-body">This is the content for Writing well for the web.</p>
206
205
  data_attributes:
207
- gtm: gtm-accordion-item-1
206
+ custom_data_attr: custom-data-attr-accordion-item-1
208
207
  - heading:
209
208
  text: Writing well for specialists
210
209
  content:
211
210
  html: <p class="govuk-body">This is the content for Writing well for specialists.</p>
212
211
  data_attributes:
213
- gtm: gtm-accordion-item-2
212
+ custom_data_attr: custom-data-attr-accordion-item-2
214
213
  - heading:
215
214
  text: Know your audience
216
215
  content:
217
216
  html: <p class="govuk-body">This is the content for Know your audience.</p>
218
217
  data_attributes:
219
- gtm: gtm-accordion-item-3
218
+ custom_data_attr: custom-data-attr-accordion-item-3
220
219
  - heading:
221
220
  text: How people read
222
221
  content:
223
222
  html: <p class="govuk-body">This is the content for How people read.</p>
224
223
  data_attributes:
225
- gtm: gtm-accordion-item-4
224
+ custom_data_attr: custom-data-attr-accordion-item-4
225
+ with_custom_data_module:
226
+ description: The component includes its own `data-module` but others can be passed in addition if required, for example to apply tracking to an element. This will be included along with the components own `data-module`.
227
+ data:
228
+ data_attributes:
229
+ module: gem-track-click
230
+ items:
231
+ - heading:
232
+ text: Writing well for the web
233
+ content:
234
+ html: <p class="govuk-body">This is the content for Writing well for the web.</p>
235
+ - heading:
236
+ text: Writing well for specialists
237
+ content:
238
+ html: <p class="govuk-body">This is the content for Writing well for specialists.</p>
226
239
  different_heading_level:
227
240
  description: This will alter the level of the heading, not the appearance of the heading.
228
241
  data:
@@ -26,6 +26,11 @@ examples:
26
26
  track-category: "printButton"
27
27
  track-action: "clicked"
28
28
  track-label: "Print this page"
29
+ with_custom_data_module:
30
+ description: The component includes its own `data-module` but others can be passed in addition if required, for example to apply tracking to an element. This will be included along with the components own `data-module`.
31
+ data:
32
+ data_attributes:
33
+ module: "gem-track-click"
29
34
  with_custom_margins:
30
35
  description: The component accepts a number for margin bottom from `0` to `9` (`0px` to `60px`) using the [GOV.UK Frontend spacing scale](https://design-system.service.gov.uk/styles/spacing/#the-responsive-spacing-scale). It defaults to having margin level `3` on top and bottom.
31
36
  data:
@@ -16,7 +16,6 @@ hr:
16
16
  order_a_copy: Naručite kopiju
17
17
  page:
18
18
  few:
19
- many:
20
19
  one: 1 stranica
21
20
  other: "%{count} stranice"
22
21
  reference: 'Referenca: %{reference}'
@@ -1,3 +1,3 @@
1
1
  module GovukPublishingComponents
2
- VERSION = "30.1.0".freeze
2
+ VERSION = "30.2.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: 30.1.0
4
+ version: 30.2.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: 2022-08-05 00:00:00.000000000 Z
11
+ date: 2022-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: govuk_app_config
@@ -436,9 +436,10 @@ files:
436
436
  - app/assets/javascripts/component_guide/vendor/matches-polyfill.min.js
437
437
  - app/assets/javascripts/govuk_publishing_components/all_components.js
438
438
  - app/assets/javascripts/govuk_publishing_components/analytics-ga4.js
439
- - app/assets/javascripts/govuk_publishing_components/analytics-ga4/gtm-click-tracking.js
440
- - app/assets/javascripts/govuk_publishing_components/analytics-ga4/gtm-page-views.js
441
- - app/assets/javascripts/govuk_publishing_components/analytics-ga4/gtm-schemas.js
439
+ - app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-event-tracker.js
440
+ - app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-link-tracker.js
441
+ - app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-page-views.js
442
+ - app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-schemas.js
442
443
  - app/assets/javascripts/govuk_publishing_components/analytics-ga4/pii-remover.js
443
444
  - app/assets/javascripts/govuk_publishing_components/analytics.js
444
445
  - app/assets/javascripts/govuk_publishing_components/analytics/analytics.js
@@ -1936,7 +1937,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1936
1937
  - !ruby/object:Gem::Version
1937
1938
  version: '0'
1938
1939
  requirements: []
1939
- rubygems_version: 3.3.19
1940
+ rubygems_version: 3.3.20
1940
1941
  signing_key:
1941
1942
  specification_version: 4
1942
1943
  summary: A gem to document components in GOV.UK frontend applications