govuk_publishing_components 30.2.0 → 30.4.0

Sign up to get free protection for your applications and to get access to all the features.
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