govuk_publishing_components 30.2.0 → 30.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/govuk_publishing_components/analytics/page-content.js +8 -0
  3. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-event-tracker.js +6 -6
  4. data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-link-tracker.js +23 -5
  5. data/app/assets/javascripts/govuk_publishing_components/components/checkboxes.js +0 -22
  6. data/app/assets/stylesheets/component_guide/application.scss +4 -0
  7. data/app/assets/stylesheets/govuk_publishing_components/components/_layout-footer.scss +7 -0
  8. data/app/assets/stylesheets/govuk_publishing_components/components/_layout-super-navigation-header.scss +1 -1
  9. data/app/models/govuk_publishing_components/component_example.rb +3 -2
  10. data/app/views/govuk_publishing_components/component_guide/show.html.erb +26 -2
  11. data/app/views/govuk_publishing_components/components/_checkboxes.html.erb +2 -3
  12. data/app/views/govuk_publishing_components/components/docs/textarea.yml +7 -0
  13. data/config/locales/en.yml +4 -0
  14. data/lib/govuk_publishing_components/presenters/checkboxes_helper.rb +2 -4
  15. data/lib/govuk_publishing_components/version.rb +1 -1
  16. data/node_modules/sortablejs/README.md +828 -815
  17. data/node_modules/sortablejs/Sortable.js +186 -113
  18. data/node_modules/sortablejs/Sortable.min.js +2 -2
  19. data/node_modules/sortablejs/modular/sortable.complete.esm.js +184 -111
  20. data/node_modules/sortablejs/modular/sortable.core.esm.js +184 -111
  21. data/node_modules/sortablejs/modular/sortable.esm.js +184 -111
  22. data/node_modules/sortablejs/package.json +3 -3
  23. metadata +17 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4aee02160c93679a75c8418c7b1f0da2ed3908a6016f4437f06dfa0091b61096
4
- data.tar.gz: 629859a537593a4f5547cbfa45e866bde739b616ef0598f2428ea07bc0f0af26
3
+ metadata.gz: d544979af086e1b51d9bc444a8df7915e8bfbb5408cd57bd810e895d82bb6248
4
+ data.tar.gz: df81a0cc285b349a82f5f74c16131ccf5b4729103c93aa7a7ea0f9c897791012
5
5
  SHA512:
6
- metadata.gz: 043a2bed5b586217a53aea43f53b9a43219b6f8947aaa90776d00a86ebb1f78c410131085401a2b0802a450426d85be2e22f986447e9e99c4d2afee76f95cbbb
7
- data.tar.gz: a52358d241fd9539a21fd7cb47c4d54fd2e402e0441758ec7348eb9b14c64444cfeaca9c54e03c34e8051c10bcac4c7c0f00999898f3586b5007f320ba9a5d86
6
+ metadata.gz: db5a2631e57d734da3540471a07974d71a73d95ac013bc5d9dcd9185decc34602dd99dd110d6c3092971bf44096d92e9c26967ba33bd2c79b21a465179d7ea7f
7
+ data.tar.gz: 5fca1e9effe07e496bba47fb30ad6b9ff32e99a81b675812c0ae8c27cf51610e04616aa3d3d1b5cc5939dd1fd26cc1209a20c6a95ac7e4f4c41cc82e0fad88a4
@@ -17,6 +17,8 @@
17
17
  // if there are no accordion sections on the browse level 2 page
18
18
  // then it is a default page with one or two lists
19
19
  return document.querySelectorAll('[data-track-count="accordionSection"]').length || document.querySelectorAll('main .govuk-list').length
20
+ case isCostOfLivingHub():
21
+ return document.querySelectorAll('[data-track-count="accordionSection"]').length
20
22
  case isNewBrowsePage():
21
23
  return document.querySelectorAll('[data-track-count="cardList"]').length
22
24
  case isMainstreamBrowsePage():
@@ -51,6 +53,7 @@
51
53
  case isDocumentCollectionPage():
52
54
  return document.querySelectorAll('.document-collection .group-document-list li a').length
53
55
  case isNewBrowsePageLevelTwo():
56
+ case isCostOfLivingHub():
54
57
  return document.querySelectorAll('[data-track-count="contentLink"]').length
55
58
  case isNewBrowsePage():
56
59
  return document.querySelectorAll('[data-track-count="cardLink"]').length
@@ -108,6 +111,11 @@
108
111
  getMetaAttribute(metaNavigationTypeSelector) === 'browse level 2'
109
112
  }
110
113
 
114
+ function isCostOfLivingHub () {
115
+ return getMetaAttribute(metaApplicationSelector) === 'collections' &&
116
+ getMetaAttribute(metaNavigationTypeSelector) === 'cost of living hub'
117
+ }
118
+
111
119
  function isNewBrowsePage () {
112
120
  return getMetaAttribute(metaApplicationSelector) === 'collections' &&
113
121
  (getMetaAttribute(metaNavigationTypeSelector) === 'browse level 0' ||
@@ -5,16 +5,16 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
5
5
  (function (Modules) {
6
6
  'use strict'
7
7
 
8
- function GA4EventTracker (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
- GA4EventTracker.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
- GA4EventTracker.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) {
@@ -76,7 +76,7 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
76
76
  }
77
77
  }
78
78
 
79
- GA4EventTracker.prototype.findTrackingAttributes = function (clicked) {
79
+ Ga4EventTracker.prototype.findTrackingAttributes = function (clicked) {
80
80
  if (clicked.hasAttribute('[' + this.trackingTrigger + ']')) {
81
81
  return clicked
82
82
  } else {
@@ -85,7 +85,7 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
85
85
  }
86
86
 
87
87
  // check if an attribute exists or contains the attribute
88
- GA4EventTracker.prototype.getClosestAttribute = function (clicked, attribute) {
88
+ Ga4EventTracker.prototype.getClosestAttribute = function (clicked, attribute) {
89
89
  var isAttributeOnElement = clicked.getAttribute(attribute)
90
90
  var containsAttribute = clicked.querySelector('[' + attribute + ']')
91
91
 
@@ -96,5 +96,5 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
96
96
  }
97
97
  }
98
98
 
99
- Modules.GA4EventTracker = GA4EventTracker
99
+ Modules.Ga4EventTracker = Ga4EventTracker
100
100
  })(window.GOVUK.Modules)
@@ -44,24 +44,26 @@
44
44
  }
45
45
 
46
46
  if (this.isMailToLink(href)) {
47
+ clickData.event_name = 'navigation'
47
48
  clickData.type = 'email'
48
49
  clickData.external = 'true'
49
50
  } else if (this.isDownloadLink(href)) {
50
- clickData.type = 'download'
51
- clickData.external = 'false'
51
+ clickData.event_name = 'file_download'
52
+ clickData.type = this.isPreviewLink(href) ? 'preview' : 'generic download'
53
+ clickData.external = 'true'
52
54
  } else if (this.isExternalLink(href)) {
55
+ clickData.event_name = 'navigation'
53
56
  clickData.type = 'generic link'
54
57
  clickData.external = 'true'
55
58
  }
56
59
 
57
60
  if (Object.keys(clickData).length > 0) {
58
- clickData.event_name = 'navigation'
59
61
  clickData.text = element.textContent.trim()
60
62
  clickData.url = href
61
63
  clickData.link_method = this.getClickType(event)
62
64
 
63
65
  var schema = new window.GOVUK.analyticsGA4.Schemas().eventSchema()
64
- schema.event = 'analytics'
66
+ schema.event = 'event_data'
65
67
 
66
68
  // get attributes from the clickData object to send to GA
67
69
  // only allow it if it already exists in the schema
@@ -124,11 +126,23 @@
124
126
 
125
127
  isExternalLink: function (href) {
126
128
  var isInternalLink = this.hrefPointsToDomain(href, this.internalLinksDomain) || this.hrefPointsToDomain(href, this.internalLinksDomainWithoutWww)
127
- if (!isInternalLink && !this.hrefIsRelative(href)) {
129
+ if (!isInternalLink && !this.hrefIsRelative(href) && !this.hrefIsAnchor(href)) {
128
130
  return true
129
131
  }
130
132
  },
131
133
 
134
+ isPreviewLink: function (href) {
135
+ /* Regex looks for:
136
+ 1. The file extension period (the character '.')
137
+ 2. any alphanumeric characters (so we can match any file type such as jpg, pdf, mp4.)
138
+ 3. the presence of '/preview'.
139
+ For example, .csv/preview or .mp4/preview will be matched.
140
+ Regex is used over JS string methods as this should work with anchor links, query string parameters and files that may have 'preview' in their name.
141
+ */
142
+ var previewRegex = /\.\w+\/preview/i
143
+ return previewRegex.test(href)
144
+ },
145
+
132
146
  hrefPointsToDomain: function (href, domain) {
133
147
  var httpDomain = 'http://' + domain
134
148
  var httpsDomain = 'https://' + domain
@@ -146,6 +160,10 @@
146
160
  hrefIsRelative: function (href) {
147
161
  // Checks that a link is relative, but is not a protocol relative url
148
162
  return href[0] === '/' && href[1] !== '/'
163
+ },
164
+
165
+ hrefIsAnchor: function (href) {
166
+ return href[0] === '#'
149
167
  }
150
168
  }
151
169
 
@@ -9,7 +9,6 @@ window.GOVUK.Modules.GovukCheckboxes = window.GOVUKFrontend.Checkboxes;
9
9
  this.$module = $module
10
10
  this.$checkboxes = this.$module.querySelectorAll('input[type=checkbox]')
11
11
  this.$nestedCheckboxes = this.$module.querySelectorAll('[data-nested=true] input[type=checkbox]')
12
- this.$exclusiveCheckboxes = this.$module.querySelectorAll('[data-exclusive=true] input[type=checkbox]')
13
12
  }
14
13
 
15
14
  GemCheckboxes.prototype.init = function () {
@@ -22,10 +21,6 @@ window.GOVUK.Modules.GovukCheckboxes = window.GOVUKFrontend.Checkboxes;
22
21
  for (i = 0; i < this.$nestedCheckboxes.length; i++) {
23
22
  this.$nestedCheckboxes[i].addEventListener('change', this.handleNestedCheckboxChange.bind(this))
24
23
  }
25
-
26
- for (i = 0; i < this.$exclusiveCheckboxes.length; i++) {
27
- this.$exclusiveCheckboxes[i].addEventListener('change', this.handleExclusiveCheckboxChange)
28
- }
29
24
  }
30
25
 
31
26
  GemCheckboxes.prototype.handleCheckboxChange = function (event) {
@@ -95,23 +90,6 @@ window.GOVUK.Modules.GovukCheckboxes = window.GOVUKFrontend.Checkboxes;
95
90
  }
96
91
  }
97
92
 
98
- GemCheckboxes.prototype.handleExclusiveCheckboxChange = function (event) {
99
- var $currentCheckbox = event.target
100
- var $checkboxes = $currentCheckbox.closest('.govuk-checkboxes')
101
- var $exclusiveOption = $checkboxes.querySelector('input[type=checkbox][data-exclusive]')
102
- var $nonExclusiveOptions = $checkboxes.querySelectorAll('input[type=checkbox]:not([data-exclusive])')
103
-
104
- if ($currentCheckbox.getAttribute('data-exclusive') === 'true' && $currentCheckbox.checked === true) {
105
- for (var i = 0; i < $nonExclusiveOptions.length; i++) {
106
- $nonExclusiveOptions[i].checked = false
107
- }
108
- } else if ($currentCheckbox.getAttribute('data-exclusive') !== 'true' && $currentCheckbox.checked === true) {
109
- if ($exclusiveOption) {
110
- $exclusiveOption.checked = false
111
- }
112
- }
113
- }
114
-
115
93
  GemCheckboxes.prototype.applyAriaControlsAttributes = function ($scope) {
116
94
  var $inputs = $scope.querySelectorAll('[data-controls]')
117
95
 
@@ -499,3 +499,7 @@ $code-delete-bg: #fadddd;
499
499
  top: 0;
500
500
  background: govuk-colour("white");
501
501
  }
502
+
503
+ .component-doc__content-list {
504
+ margin-top: govuk-spacing(5);
505
+ }
@@ -12,3 +12,10 @@
12
12
  .gem-c-layout-footer .govuk-footer__list {
13
13
  padding-bottom: govuk-spacing(7);
14
14
  }
15
+
16
+ .gem-c-layout-footer .govuk-footer__list-item:nth-child(odd):last-child {
17
+ // If there are an uneven number of links in the
18
+ // footer this ensures the left column has more links than the
19
+ // the right column.
20
+ margin-bottom: 20px;
21
+ }
@@ -811,7 +811,7 @@ $button-pipe-colour: darken(govuk-colour("mid-grey"), 20%);
811
811
 
812
812
  .gem-c-layout-super-navigation-header__navigation-second-items--topics {
813
813
  @include govuk-media-query($from: "desktop") {
814
- @include columns($items: 16, $columns: 2, $selector: "li", $flow: column);
814
+ @include columns($items: 17, $columns: 2, $selector: "li", $flow: column);
815
815
  }
816
816
  }
817
817
 
@@ -1,4 +1,5 @@
1
1
  require "rouge"
2
+ require "awesome_print"
2
3
 
3
4
  module GovukPublishingComponents
4
5
  class ComponentExample
@@ -29,8 +30,8 @@ module GovukPublishingComponents
29
30
  end
30
31
 
31
32
  def pretty_data
32
- json_key_regex = /"(\w*)":/ # matches quoted keys ending with a colon, i.e. "key":
33
- output = JSON.pretty_generate(data).gsub('\\n', "\n ").gsub(json_key_regex, '\1:')
33
+ json_key_regex = /"(\w*)"\s*:/ # matches quoted keys ending with a colon, i.e. "key":
34
+ output = data.awesome_inspect(indent: -2, index: false, plain: true).gsub("=>", ":").gsub(json_key_regex, '\1:')
34
35
 
35
36
  quoted_string_regex = /"((?:[^"\\]|\\.)*)"/ # matches "some text" - ignores escaped quotes, i.e. \"
36
37
  output.gsub(quoted_string_regex) do |group|
@@ -28,7 +28,30 @@
28
28
  </div>
29
29
  </div>
30
30
 
31
- <h2 class="component-doc-h2">
31
+ <% if @component_doc.other_examples.any? %>
32
+ <div class="component-doc__content-list">
33
+ <%
34
+ content_items = [
35
+ {
36
+ href: "#default",
37
+ text: "How it looks",
38
+ }
39
+ ]
40
+
41
+ @component_doc.other_examples.each do | example |
42
+ content_items << {
43
+ href: "##{example.id}",
44
+ text: example.name
45
+ }
46
+ end
47
+ %>
48
+ <%= render "govuk_publishing_components/components/contents_list", {
49
+ contents: content_items
50
+ } %>
51
+ </div>
52
+ <% end %>
53
+
54
+ <h2 class="component-doc-h2" id="default">
32
55
  <a href="<%= component_example_path(@component_doc.id, "default") %>" class="govuk-link">How it looks</a>
33
56
  <small>(<a href="<%= component_preview_path(@component_doc.id, "default") %>" class="govuk-link">preview</a>)</small>
34
57
  <small>(<a href="<%= component_preview_all_path(@component_doc.id) %>" class="govuk-link">preview all</a>)</small>
@@ -65,8 +88,9 @@
65
88
  <% if @component_doc.other_examples.any? %>
66
89
  <div class="examples">
67
90
  <h2 class="component-doc-h2">Other examples</h2>
91
+
68
92
  <% @component_doc.other_examples.each do |example| %>
69
- <div class="component-example">
93
+ <div class="component-example" id="<%= example.id %>">
70
94
  <h3 class="example-title">
71
95
  <a href="<%= component_example_path(@component_doc.id, example.id) %>" class="govuk-link"><%= example.name %></a>
72
96
  <small>(<a href="<%= component_preview_path(@component_doc.id, example.id) %>" class="govuk-link">preview</a>)</small>
@@ -4,7 +4,7 @@
4
4
  id = cb_helper.id
5
5
  %>
6
6
 
7
- <%= tag.div id: id, class: cb_helper.css_classes, data: { module: "gem-checkboxes" } do %>
7
+ <%= tag.div id: id, class: cb_helper.css_classes, data: { module: "gem-checkboxes govuk-checkboxes" } do %>
8
8
  <% if cb_helper.should_have_fieldset %>
9
9
  <% if cb_helper.heading_markup %>
10
10
  <%= tag.fieldset class: "govuk-fieldset", "aria-describedby": cb_helper.fieldset_describedby do %>
@@ -24,8 +24,7 @@
24
24
 
25
25
  <%= tag.ul class: cb_helper.list_classes, data: {
26
26
  module: ('govuk-checkboxes' if cb_helper.has_conditional),
27
- nested: ('true' if cb_helper.has_nested),
28
- exclusive: ('true' if cb_helper.has_exclusive)
27
+ nested: ('true' if cb_helper.has_nested)
29
28
  } do %>
30
29
  <% cb_helper.items.each_with_index do |item, index| %>
31
30
  <% if item === :or %>
@@ -103,3 +103,10 @@ examples:
103
103
  name: "described"
104
104
  rows: 2
105
105
  describedby: "contextual-guidance"
106
+ with_data_attributes:
107
+ data:
108
+ label:
109
+ text: "This textarea has a data attribute"
110
+ name: "with_data_attrbutes"
111
+ data:
112
+ module: "some-awesome-module-here"
@@ -96,6 +96,8 @@ en:
96
96
  href: "/browse/childcare-parenting"
97
97
  - text: Citizenship and living in the UK
98
98
  href: "/browse/citizenship"
99
+ - text: Cost of living support
100
+ href: "/cost-of-living"
99
101
  - text: Crime, justice and the law
100
102
  href: "/browse/justice"
101
103
  - text: Disabled people
@@ -175,6 +177,8 @@ en:
175
177
  href: "/browse/childcare-parenting"
176
178
  - label: Citizenship and living in the UK
177
179
  href: "/browse/citizenship"
180
+ - label: Cost of living support
181
+ href: "/cost-of-living"
178
182
  - label: Crime, justice and the law
179
183
  href: "/browse/justice"
180
184
  - label: Disabled people
@@ -14,8 +14,7 @@ module GovukPublishingComponents
14
14
  :id,
15
15
  :hint_text,
16
16
  :description,
17
- :heading_caption,
18
- :has_exclusive
17
+ :heading_caption
19
18
 
20
19
  def initialize(options)
21
20
  @items = options[:items] || []
@@ -29,7 +28,6 @@ module GovukPublishingComponents
29
28
 
30
29
  # check if any item is set as being conditional
31
30
  @has_conditional = options[:items].any? { |item| item.is_a?(Hash) && item[:conditional] }
32
- @has_exclusive = options[:items].any? { |item| item.is_a?(Hash) && item[:exclusive] }
33
31
  @has_nested = options[:items].any? { |item| item.is_a?(Hash) && item[:items] }
34
32
 
35
33
  @id = options[:id] || "checkboxes-#{SecureRandom.hex(4)}"
@@ -97,7 +95,7 @@ module GovukPublishingComponents
97
95
  data = checkbox[:data_attributes] || {}
98
96
  data[:controls] = controls
99
97
  data["aria-controls"] = aria_controls
100
- data[:exclusive] = checkbox[:exclusive]
98
+ data[:behaviour] = "exclusive" if checkbox[:exclusive]
101
99
 
102
100
  capture do
103
101
  concat check_box_tag checkbox_name, checkbox[:value], checked, class: "govuk-checkboxes__input", id: checkbox_id, data: data
@@ -1,3 +1,3 @@
1
1
  module GovukPublishingComponents
2
- VERSION = "30.2.0".freeze
2
+ VERSION = "30.4.0".freeze
3
3
  end