govuk_publishing_components 27.13.0 → 27.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (21) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/govuk_publishing_components/analytics/auto-scroll-tracker.js +24 -3
  3. data/app/assets/javascripts/govuk_publishing_components/analytics/explicit-cross-domain-links.js +24 -8
  4. data/app/assets/javascripts/govuk_publishing_components/components/cookie-banner.js +1 -0
  5. data/app/assets/javascripts/govuk_publishing_components/components/single-page-notification-button.js +48 -0
  6. data/app/assets/stylesheets/govuk_publishing_components/components/_layout-super-navigation-header.scss +10 -8
  7. data/app/views/govuk_publishing_components/components/_big_number.html.erb +0 -1
  8. data/app/views/govuk_publishing_components/components/_button.html.erb +1 -1
  9. data/app/views/govuk_publishing_components/components/_layout_super_navigation_header.html.erb +1 -1
  10. data/app/views/govuk_publishing_components/components/_search.html.erb +25 -9
  11. data/app/views/govuk_publishing_components/components/_single_page_notification_button.html.erb +13 -17
  12. data/app/views/govuk_publishing_components/components/docs/layout_for_public.yml +1 -1
  13. data/app/views/govuk_publishing_components/components/docs/radio.yml +40 -33
  14. data/app/views/govuk_publishing_components/components/docs/search.yml +25 -0
  15. data/app/views/govuk_publishing_components/components/docs/single_page_notification_button.yml +21 -3
  16. data/config/locales/en.yml +1 -1
  17. data/lib/govuk_publishing_components/presenters/button_helper.rb +24 -0
  18. data/lib/govuk_publishing_components/presenters/single_page_notification_button_helper.rb +37 -0
  19. data/lib/govuk_publishing_components/version.rb +1 -1
  20. data/lib/govuk_publishing_components.rb +1 -0
  21. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 21c2a281f7de0f79303971394f9cad3102533d7e619f660809078457687552ce
4
- data.tar.gz: b246c494a88448ab43d2d2230c12a918b2107eda3217f4f44754ee5b2ef0f4de
3
+ metadata.gz: e405833a40d51e34a480d411380a552a68d49a9c398fa89fa694716e0a22131f
4
+ data.tar.gz: c6f710970b8ecae4c214851ee2e250b80673e38ec004bf161a1ca1042a44af3b
5
5
  SHA512:
6
- metadata.gz: a1a5354695ffc567bfa7547af429dfdfa0145e8c009408a4a8200731e2677f883922b228dd4d3623770483ba704eafecfe68c1a895bf2dc6b978ac3da59b5c7c
7
- data.tar.gz: 344cee88bde5f7c64393028e7020dc62b62eb8794b568b05ecbf94746bb94381bf44cba4627332d8475fadb49cbdc1f79f51598bd7c7194c17eb157a925a0176
6
+ metadata.gz: a24c9485202f161b46daff7ec6b081148c8e58d52f8fed9cab8ab6f2d90b016b1d06e81abf0ffd157b75c7331d7b5151b018bbe58f580c6d8bdf94f23ee0dcab
7
+ data.tar.gz: b63635bfda7d6ccb8ee7e88d810f19e97343d6cb7a08075bba620764cfd609ad0b1043361e1a5b84b49c1787263119b521316b44435dd8c6566754e5635c7b0c
@@ -31,9 +31,21 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
31
31
  return
32
32
  }
33
33
 
34
+ this.trackType = this.$module.getAttribute('data-track-type')
35
+ var trackHeadings = this.$module.getAttribute('data-track-headings')
36
+ if (trackHeadings) {
37
+ try {
38
+ this.config.trackHeadings = JSON.parse(trackHeadings)
39
+ } catch (e) {
40
+ // if there's a problem with the config, don't start the tracker
41
+ console.error('Scroll tracker configuration error: ' + e.message, window.location)
42
+ window.GOVUK.analyticsVars.scrollTrackerStarted = false
43
+ return
44
+ }
45
+ }
46
+
34
47
  window.GOVUK.analyticsVars.scrollTrackerStarted = true
35
48
 
36
- this.trackType = this.$module.getAttribute('data-track-type')
37
49
  if (this.trackType === 'headings') {
38
50
  this.track = new AutoScrollTracker.Heading(this.config)
39
51
  } else {
@@ -145,15 +157,24 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
145
157
 
146
158
  // check heading is inside allowed elements, generally ignores everything outside of page content
147
159
  AutoScrollTracker.Heading.prototype.findAllowedHeadings = function () {
148
- var headings = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
149
160
  var headingsFound = []
161
+ var headings = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
162
+ var trackHeadings = this.config.trackHeadings
150
163
 
164
+ // this is a loop that only happens once as we currently only have one
165
+ // allowed element for headings to be in - 'main'
151
166
  for (var h = 0; h < this.config.allowHeadingsInside.length; h++) {
152
167
  var insideElements = document.querySelectorAll(this.config.allowHeadingsInside[h])
153
168
  for (var e = 0; e < insideElements.length; e++) {
154
169
  var found = insideElements[e].querySelectorAll(headings)
155
170
  for (var f = 0; f < found.length; f++) {
156
- headingsFound.push(found[f])
171
+ if (trackHeadings) {
172
+ if (trackHeadings.includes(found[f].textContent.trim())) {
173
+ headingsFound.push(found[f])
174
+ }
175
+ } else {
176
+ headingsFound.push(found[f])
177
+ }
157
178
  }
158
179
  }
159
180
  }
@@ -10,12 +10,18 @@
10
10
 
11
11
  var cookieBannerEngaged = GOVUK.cookie('cookies_preferences_set')
12
12
 
13
- // If not engaged, append only ?cookie-consent=not-engaged
14
- // If engaged and rejected, append only ?cookie-consent=reject
15
- // If engaged and accepted usage, append ?_ga=clientid if available and cookie-consent=accept
13
+ // If not engaged, append only ?cookie_consent=not-engaged
14
+ // If engaged and rejected, append only ?cookie_consent=reject
15
+ // If engaged and accepted usage, append ?_ga=clientid if available and cookie_consent=accept
16
16
 
17
17
  if (cookieBannerEngaged !== 'true') {
18
18
  this.decorate(element, 'cookie_consent=not-engaged')
19
+ this.start = this.start.bind(this, $module)
20
+
21
+ // if the user has not engaged with the cookie banner yet, listen for the cookie consent accept/reject events
22
+ // re-start the module if cookies are accepted or rejected on the current page – setting cookie preferences does not reload the page
23
+ window.addEventListener('cookie-consent', this.start)
24
+ window.addEventListener('cookie-reject', this.start)
19
25
  return
20
26
  }
21
27
  var cookieConsent = GOVUK.getConsentCookie()
@@ -50,6 +56,8 @@
50
56
  this.decorate = function (element, param) {
51
57
  var attribute = 'href'
52
58
  var attributeValue = element.getAttribute(attribute)
59
+ var cookieConsentParameterPattern = /cookie_consent=[^&]*/
60
+ var paramIsCookieConsent = param.match(cookieConsentParameterPattern)
53
61
 
54
62
  if (!attributeValue) {
55
63
  attribute = 'action'
@@ -58,13 +66,21 @@
58
66
 
59
67
  if (!attributeValue) { return }
60
68
 
61
- if (attributeValue.includes('?')) {
62
- attributeValue += '&' + param
63
- element.setAttribute(attribute, attributeValue)
69
+ var attributeHasCookieConsent = attributeValue.match(cookieConsentParameterPattern)
70
+
71
+ if (attributeHasCookieConsent && paramIsCookieConsent) {
72
+ // if the decorate function has received a cookie_consent parameter, but the target element already has a cookie_consent parameter, replace the existing parameter with the new value
73
+ attributeValue = attributeValue.replace(cookieConsentParameterPattern, param)
64
74
  } else {
65
- attributeValue += '?' + param
66
- element.setAttribute(attribute, attributeValue)
75
+ // otherwise, simply append the parameter to the target element href query string
76
+ if (attributeValue.includes('?')) {
77
+ attributeValue += '&' + param
78
+ } else {
79
+ attributeValue += '?' + param
80
+ }
67
81
  }
82
+
83
+ element.setAttribute(attribute, attributeValue)
68
84
  }
69
85
  }
70
86
 
@@ -97,6 +97,7 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
97
97
  this.$module.cookieBannerConfirmationMessage.focus()
98
98
  window.GOVUK.cookie('cookies_preferences_set', 'true', { days: 365 })
99
99
  window.GOVUK.setDefaultConsentCookie()
100
+ window.GOVUK.triggerEvent(window, 'cookie-reject')
100
101
  }
101
102
 
102
103
  CookieBanner.prototype.showConfirmationMessage = function () {
@@ -0,0 +1,48 @@
1
+ /* global XMLHttpRequest */
2
+ window.GOVUK = window.GOVUK || {}
3
+ window.GOVUK.Modules = window.GOVUK.Modules || {};
4
+
5
+ (function (Modules) {
6
+ function SinglePageNotificationButton ($module) {
7
+ this.$module = $module
8
+ this.basePath = this.$module.querySelector('input[name="base_path"]').value
9
+ this.buttonLocation = this.$module.getAttribute('data-button-location')
10
+
11
+ this.personalisationEndpoint = '/api/personalisation/check-email-subscription?base_path=' + this.basePath
12
+ // This attribute is passed through to the personalisation API to ensure the updated button has the same button_location for analytics
13
+ if (this.buttonLocation) this.personalisationEndpoint += '&button_location=' + this.buttonLocation
14
+ }
15
+
16
+ SinglePageNotificationButton.prototype.init = function () {
17
+ var xhr = new XMLHttpRequest()
18
+ xhr.open('GET', this.personalisationEndpoint, true)
19
+
20
+ xhr.onreadystatechange = function () {
21
+ if (xhr.readyState === 4 && xhr.status === 200) {
22
+ var responseText = xhr.responseText
23
+ // if response text exists and is JSON parse-able, parse the response and get the button html
24
+ if (responseText && this.responseIsJSON(responseText)) {
25
+ var newButton = JSON.parse(responseText).button_html
26
+ var html = document.createElement('div')
27
+ html.innerHTML = newButton
28
+ // test that the html returned contains the button component; if yes, swap the button for the updated version
29
+ var responseButtonContainer = html.querySelector('form.gem-c-single-page-notification-button')
30
+ if (responseButtonContainer) {
31
+ this.$module.parentNode.replaceChild(responseButtonContainer, this.$module)
32
+ }
33
+ }
34
+ }
35
+ }.bind(this)
36
+ xhr.send()
37
+ }
38
+
39
+ SinglePageNotificationButton.prototype.responseIsJSON = function (string) {
40
+ try {
41
+ JSON.parse(string)
42
+ } catch (e) {
43
+ return false
44
+ }
45
+ return true
46
+ }
47
+ Modules.SinglePageNotificationButton = SinglePageNotificationButton
48
+ })(window.GOVUK.Modules)
@@ -102,6 +102,7 @@ $icon-size: 20px;
102
102
  $chevron-indent-spacing: 7px;
103
103
  $black-bar-height: 50px;
104
104
  $search-width-or-height: $black-bar-height;
105
+ $pseudo-underline-height: 3px;
105
106
 
106
107
  @mixin chevron($colour, $update: false) {
107
108
  @if ($update == true) {
@@ -111,7 +112,7 @@ $search-width-or-height: $black-bar-height;
111
112
  @include prefixed-transform($rotate: 45deg, $translateY: -35%);
112
113
  border-bottom: 2px solid $colour;
113
114
  border-right: 2px solid $colour;
114
- content: " ";
115
+ content: "";
115
116
  display: inline-block;
116
117
  height: 8px;
117
118
  margin: 0 8px 0 2px;
@@ -123,7 +124,7 @@ $search-width-or-height: $black-bar-height;
123
124
  @mixin make-selectable-area-bigger {
124
125
  background: none;
125
126
  bottom: 0;
126
- content: " ";
127
+ content: "";
127
128
  left: 0;
128
129
  position: absolute;
129
130
  right: 0;
@@ -133,11 +134,11 @@ $search-width-or-height: $black-bar-height;
133
134
  @mixin pseudo-underline {
134
135
  background: none;
135
136
  bottom: 0;
136
- content: " ";
137
- height: 3px;
138
- left: govuk-spacing(3);
137
+ content: "";
138
+ height: $pseudo-underline-height;
139
+ left: govuk-spacing(5);
139
140
  position: absolute;
140
- right: govuk-spacing(3);
141
+ right: govuk-spacing(6);
141
142
  top: auto;
142
143
  }
143
144
 
@@ -441,7 +442,7 @@ $search-width-or-height: $black-bar-height;
441
442
  font-size: govuk-px-to-rem(16px);
442
443
  }
443
444
  height: $black-bar-height;
444
- padding: govuk-spacing(3);
445
+ padding: govuk-spacing(3) govuk-spacing(6) govuk-spacing(3) govuk-spacing(5);
445
446
  position: relative;
446
447
  text-decoration: none;
447
448
 
@@ -762,7 +763,7 @@ $search-width-or-height: $black-bar-height;
762
763
 
763
764
  &:hover {
764
765
  background: govuk-colour("black");
765
- border-bottom: govuk-spacing(1) solid govuk-colour("mid-grey");
766
+ border-bottom: $pseudo-underline-height solid govuk-colour("mid-grey");
766
767
  color: govuk-colour("mid-grey");
767
768
  }
768
769
 
@@ -845,6 +846,7 @@ $search-width-or-height: $black-bar-height;
845
846
 
846
847
  // Navigation menu items.
847
848
  .gem-c-layout-super-navigation-header__navigation-second-items {
849
+ list-style: none;
848
850
  margin: 0;
849
851
  padding: govuk-spacing(6) govuk-spacing(4);
850
852
 
@@ -1,5 +1,4 @@
1
1
  <%
2
- href ||= nil
3
2
  number ||= nil
4
3
  label ||= nil
5
4
  href ||= nil
@@ -27,5 +27,5 @@
27
27
  <% end %>
28
28
 
29
29
  <% if button.info_text %>
30
- <%= tag.span button.info_text, class: button.info_text_classes %>
30
+ <%= tag.span button.info_text, button.info_text_options %>
31
31
  <% end %>
@@ -144,7 +144,7 @@
144
144
  </div>
145
145
  <div class="govuk-grid-column-two-thirds-from-desktop">
146
146
  <% if link[:menu_contents].present? %>
147
- <ul class="govuk-list gem-c-layout-super-navigation-header__navigation-second-items gem-c-layout-super-navigation-header__navigation-second-items--<%= link[:label].parameterize %>">
147
+ <ul class="gem-c-layout-super-navigation-header__navigation-second-items gem-c-layout-super-navigation-header__navigation-second-items--<%= link[:label].parameterize %>">
148
148
  <% link[:menu_contents].each do | item | %>
149
149
  <%
150
150
  has_description = item[:description].present?
@@ -1,9 +1,12 @@
1
1
  <%
2
2
  shared_helper = GovukPublishingComponents::Presenters::SharedHelper.new(local_assigns)
3
+ heading_helper = GovukPublishingComponents::Presenters::HeadingHelper.new(local_assigns)
3
4
 
4
5
  aria_controls ||= nil
5
6
  button_text ||= t("components.search_box.search_button")
6
7
  id ||= "search-main-" + SecureRandom.hex(4)
8
+ wrap_label_in_a_heading ||= false
9
+ label_margin_bottom ||= nil
7
10
  label_size ||= nil
8
11
  label_text ||= t("components.search_box.label")
9
12
  name ||= "q"
@@ -14,13 +17,6 @@
14
17
  data_attributes ||= {}
15
18
  data_attributes[:module] = 'gem-track-click'
16
19
 
17
- label_classes = []
18
- if (shared_helper.valid_heading_size?(label_size))
19
- label_classes << "govuk-label govuk-label--#{label_size}"
20
- else
21
- label_classes << "gem-c-search__label"
22
- end
23
-
24
20
  classes = %w[gem-c-search govuk-!-display-none-print]
25
21
  classes << (shared_helper.get_margin_top)
26
22
  classes << (shared_helper.get_margin_bottom) if local_assigns[:margin_bottom]
@@ -32,11 +28,31 @@
32
28
  classes << "gem-c-search--on-white"
33
29
  end
34
30
  classes << "gem-c-search--separate-label" if local_assigns.include?(:inline_label) or local_assigns.include?(:label_size)
31
+
32
+ label_classes = []
33
+ if (shared_helper.valid_heading_size?(label_size))
34
+ label_classes << "govuk-label govuk-label--#{label_size}"
35
+ else
36
+ label_classes << "gem-c-search__label"
37
+ end
38
+ label_classes << "govuk-!-margin-bottom-#{label_margin_bottom}" if [*1..9].include?(label_margin_bottom) and local_assigns.include?(:inline_label)
39
+
40
+ tag_label = capture do
41
+ tag.label({ for: id, class: label_classes }) do
42
+ label_text
43
+ end
44
+ end
35
45
  %>
36
46
 
37
47
  <div class="<%= classes.join(" ") %>" data-module="gem-toggle-input-class-on-focus">
38
- <%= tag.label({ for: id, class: label_classes }) do %>
39
- <%= label_text %>
48
+ <% if wrap_label_in_a_heading %>
49
+ <%= content_tag(shared_helper.get_heading_level, {
50
+ class: "govuk-!-margin-0",
51
+ }) do %>
52
+ <%= tag_label %>
53
+ <% end %>
54
+ <% else %>
55
+ <%= tag_label %>
40
56
  <% end %>
41
57
  <div class="gem-c-search__item-wrapper">
42
58
  <%= tag.input(
@@ -1,23 +1,19 @@
1
1
  <%
2
- page ||= ''
3
- data_attributes ||= {}
4
- base_path ||= nil
5
- local_assigns[:margin_bottom] ||= 3
6
- already_subscribed ||= false
7
- text ||= already_subscribed ? t('components.single_page_notification_button.unsubscribe_text') : t('components.single_page_notification_button.subscribe_text')
8
-
2
+ component_helper = GovukPublishingComponents::Presenters::SinglePageNotificationButtonHelper.new(local_assigns)
9
3
  shared_helper = GovukPublishingComponents::Presenters::SharedHelper.new(local_assigns)
10
- wrapper_classes = %w(gem-c-single-page-notification-button govuk-!-display-none-print)
4
+
5
+ wrapper_classes = %w(govuk-!-display-none-print)
11
6
  wrapper_classes << shared_helper.get_margin_bottom
12
- classes = "govuk-body-s gem-c-single-page-notification-button__submit"
13
7
  %>
14
8
  <% button_text = capture do %>
15
- <svg class="gem-c-single-page-notification-button__icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" height="18" width="18" viewBox="0 0 459.334 459.334"><path fill="currentColor" d="M177.216 404.514c-.001.12-.009.239-.009.359 0 30.078 24.383 54.461 54.461 54.461s54.461-24.383 54.461-54.461c0-.12-.008-.239-.009-.359H175.216zM403.549 336.438l-49.015-72.002v-89.83c0-60.581-43.144-111.079-100.381-122.459V24.485C254.152 10.963 243.19 0 229.667 0s-24.485 10.963-24.485 24.485v27.663c-57.237 11.381-100.381 61.879-100.381 122.459v89.83l-49.015 72.002a24.76 24.76 0 0 0 20.468 38.693H383.08a24.761 24.761 0 0 0 20.469-38.694z"/></svg><%= text %>
9
+ <svg class="gem-c-single-page-notification-button__icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" height="18" width="18" viewBox="0 0 459.334 459.334"><path fill="currentColor" d="M177.216 404.514c-.001.12-.009.239-.009.359 0 30.078 24.383 54.461 54.461 54.461s54.461-24.383 54.461-54.461c0-.12-.008-.239-.009-.359H175.216zM403.549 336.438l-49.015-72.002v-89.83c0-60.581-43.144-111.079-100.381-122.459V24.485C254.152 10.963 243.19 0 229.667 0s-24.485 10.963-24.485 24.485v27.663c-57.237 11.381-100.381 61.879-100.381 122.459v89.83l-49.015 72.002a24.76 24.76 0 0 0 20.468 38.693H383.08a24.761 24.761 0 0 0 20.469-38.694z"/></svg><%= component_helper.button_text %>
16
10
  <% end %>
17
- <%= tag.form class: wrapper_classes, action: "/email/subscriptions/single-page/new", method: "POST", data: data_attributes do %>
18
- <input type="hidden" name="base_path" value="<%= base_path %>">
19
- <%= content_tag(:button, button_text, {
20
- class: classes,
21
- type: "submit",
22
- }) %>
23
- <% end if base_path.presence %>
11
+ <%= tag.div class: wrapper_classes, data: { module: "gem-track-click"} do %>
12
+ <%= tag.form class: "gem-c-single-page-notification-button", action: "/email/subscriptions/single-page/new", method: "POST", data: component_helper.data do %>
13
+ <input type="hidden" name="base_path" value="<%= component_helper.base_path %>">
14
+ <%= content_tag(:button, button_text, {
15
+ class: "govuk-body-s gem-c-single-page-notification-button__submit",
16
+ type: "submit",
17
+ }) %>
18
+ <% end %>
19
+ <% end if component_helper.base_path %>
@@ -69,7 +69,7 @@ examples:
69
69
  <h2 class="govuk-heading-l">This is a title</h2>
70
70
  <p class="govuk-body">This is some body text with <a href="https://example.com">a link</a>.
71
71
  with_current_account_navigation:
72
- description: "The account layout renders with an account-specific nav to help users navigate different areas of their account. This flag is here to allow control over which option in the nav is highlighted as `current`. Valid options are currently `your-account`, `manage`, and `security`."
72
+ description: "The account layout renders with an account-specific nav to help users navigate different areas of their account. This flag is here to allow control over which option in the nav is highlighted as `current`. Valid options are currently `your-account` and `manage`."
73
73
  data:
74
74
  show_account_layout: true
75
75
  account_nav_location: "manage"
@@ -37,6 +37,7 @@ govuk_frontend_components:
37
37
  examples:
38
38
  default:
39
39
  data:
40
+ heading: How do you want to sign in?
40
41
  name: "radio-group"
41
42
  items:
42
43
  - value: "government-gateway"
@@ -45,6 +46,7 @@ examples:
45
46
  text: "Use GOV.UK Verify"
46
47
  with_small_radios:
47
48
  data:
49
+ heading: How do you want to sign in?
48
50
  name: "radio-group"
49
51
  small: true
50
52
  items:
@@ -52,9 +54,10 @@ examples:
52
54
  text: "Use Government Gateway"
53
55
  - value: "govuk-verify"
54
56
  text: "Use GOV.UK Verify"
55
- with_bold:
56
- description: Used to provide better contrast between long labels and hint text, Note that the `:or` option [is documented as a string due to a bug](https://github.com/alphagov/govuk_publishing_components/issues/102)
57
+ with_bold_labels:
58
+ description: Used to provide better contrast between long labels and hint text.
57
59
  data:
60
+ heading: How do you want to sign in?
58
61
  name: "radio-group-bold"
59
62
  items:
60
63
  - value: "government-gateway"
@@ -65,9 +68,10 @@ examples:
65
68
  text: "Use GOV.UK Verify"
66
69
  hint_text: "You'll have an account if you've already proved your identity with a certified company, such as the Post Office."
67
70
  bold: true
68
- with_bottom_margin:
71
+ with_custom_bottom_margin:
69
72
  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 a margin bottom of `30px` (`6`).
70
73
  data:
74
+ heading: How do you want to sign in?
71
75
  name: "radio-group"
72
76
  margin_bottom: 9
73
77
  items:
@@ -77,6 +81,7 @@ examples:
77
81
  text: "Use GOV.UK Verify"
78
82
  with_hint_on_form_group:
79
83
  data:
84
+ heading: How do you want to sign in?
80
85
  name: "radio-group-error"
81
86
  id_prefix: "hint"
82
87
  hint: "You’ll need to prove your identity using one of the following methods"
@@ -97,10 +102,10 @@ examples:
97
102
  text: "Yes"
98
103
  - value: "no"
99
104
  text: "No"
100
- with_heading:
105
+ with_custom_heading_size:
101
106
  description: |
102
- By default, text supplied for the `legend` is wrapped inside a `h2`.
103
-
107
+ By default, text supplied for the `legend` is wrapped inside a `h2`.
108
+
104
109
  The font size of this heading can be changed using the `heading_size` option. Valid options are `s`, `m`, `l`, `xl`, defaulting to `m` if no option is passed.
105
110
  data:
106
111
  name: "radio-group-description"
@@ -113,10 +118,10 @@ examples:
113
118
  text: "Green"
114
119
  - value: "blue"
115
120
  text: "Blue"
116
- with_different_heading_level:
121
+ with_custom_heading_level:
117
122
  description: |
118
123
  By default, text supplied for the `legend` is wrapped inside a `h2`. This can be changed using the `heading_level` option.
119
-
124
+
120
125
  If `heading_level` is `1` and `heading_size` is not set, the text size will be `xl`.
121
126
  data:
122
127
  name: "radio-group-description"
@@ -129,22 +134,10 @@ examples:
129
134
  text: "Green"
130
135
  - value: "blue"
131
136
  text: "Blue"
132
- with_heading_and_hint:
133
- data:
134
- name: "radio-group-heading"
135
- heading: "What is your favourite colour?"
136
- hint: "If your favourite is not below, pick the colour closest to it."
137
- items:
138
- - value: "red"
139
- text: "Red"
140
- - value: "green"
141
- text: "Green"
142
- - value: "blue"
143
- text: "Blue"
144
- with_page_header_and_caption:
137
+ with_page_heading_and_caption:
145
138
  description: |
146
139
  A caption can be added using the `heading_caption` option. Captions will only be displayed if text for the heading option is present.
147
-
140
+
148
141
  The pattern is used across GOV.UK to show a high-level section that this page belongs to.
149
142
  data:
150
143
  name: "radio-group-heading"
@@ -167,7 +160,7 @@ examples:
167
160
  text: "Yes"
168
161
  - value: "no"
169
162
  text: "No"
170
- with_description_only:
163
+ with_description:
171
164
  data:
172
165
  name: "radio-group-description"
173
166
  heading: "What is your favourite colour?"
@@ -217,6 +210,7 @@ examples:
217
210
  text: "Blue"
218
211
  with_hint_text_on_radios:
219
212
  data:
213
+ heading: How do you want to sign in?
220
214
  name: "radio-group-hint-text"
221
215
  items:
222
216
  - value: "government-gateway"
@@ -227,6 +221,7 @@ examples:
227
221
  text: "Use GOV.UK Verify"
228
222
  with_checked_option:
229
223
  data:
224
+ heading: How do you want to sign in?
230
225
  name: "radio-group-checked"
231
226
  items:
232
227
  - value: "government-gateway"
@@ -236,15 +231,17 @@ examples:
236
231
  checked: true
237
232
  with_data_attributes:
238
233
  data:
234
+ heading: How do you want to sign in?
239
235
  name: "radio-group-data-attributes"
240
236
  items:
241
- - value: "cool-button"
242
- text: "Best button in town"
243
- data_attributes: { "contextual-guidance": "cool-buttons-guidance" }
244
- - value: "no-data-attributes-button"
245
- text: "Worst button in town"
237
+ - value: "government-gateway"
238
+ text: "Use Government Gateway"
239
+ - value: "govuk-verify"
240
+ text: "Use GOV.UK Verify"
241
+ data_attributes: { "contextual-guidance": "government-gateway" }
246
242
  with_custom_id_prefix:
247
243
  data:
244
+ heading: How do you want to sign in?
248
245
  id_prefix: 'custom'
249
246
  name: "radio-custom-id-prefix"
250
247
  items:
@@ -255,6 +252,7 @@ examples:
255
252
  with_or_divider:
256
253
  description: "See [related service manual guidance for this pattern](https://www.gov.uk/service-manual/design/writing-for-user-interfaces#ask-questions-that-users-can-understand)"
257
254
  data:
255
+ heading: How do you want to sign in?
258
256
  name: "radio-group-or-divider"
259
257
  items:
260
258
  - value: "government-gateway"
@@ -267,6 +265,7 @@ examples:
267
265
  extreme:
268
266
  description: 'Note that the `:or` option [is documented as a string due to a bug](https://github.com/alphagov/govuk_publishing_components/issues/102)'
269
267
  data:
268
+ heading: How do you want to sign in?
270
269
  id_prefix: 'extreme'
271
270
  name: "radio-custom-extreme"
272
271
  items:
@@ -289,6 +288,7 @@ examples:
289
288
  bold: true
290
289
  with_error_on_form_group:
291
290
  data:
291
+ heading: How do you want to sign in?
292
292
  name: "radio-group-error"
293
293
  id_prefix: "error"
294
294
  error_message: "Please select one option"
@@ -300,6 +300,7 @@ examples:
300
300
  with_error_and_hint_on_form_group:
301
301
  description: ""
302
302
  data:
303
+ heading: How do you want to sign in?
303
304
  name: "radio-group-error"
304
305
  id_prefix: "error"
305
306
  error_message: "Please select one option"
@@ -311,6 +312,7 @@ examples:
311
312
  text: "Use GOV.UK Verify"
312
313
  with_error_items_on_form_group:
313
314
  data:
315
+ heading: How do you want to sign in?
314
316
  name: "radio-group-error"
315
317
  id_prefix: "error"
316
318
  error_items:
@@ -325,6 +327,7 @@ examples:
325
327
  text: "Use GOV.UK Verify"
326
328
  conditional:
327
329
  data:
330
+ heading: How do you want to sign in?
328
331
  name: "radio-group-conditional"
329
332
  id_prefix: "conditional"
330
333
  items:
@@ -336,7 +339,8 @@ examples:
336
339
  conditional: "You’ll need to prove your identity using GOV.UK Verify"
337
340
  conditional_checked:
338
341
  data:
339
- name: "radio-group-conditional"
342
+ heading: How do you want to sign in?
343
+ name: "radio-group-conditional-checked"
340
344
  id_prefix: "conditional-checked"
341
345
  items:
342
346
  - value: "government-gateway"
@@ -348,6 +352,7 @@ examples:
348
352
  conditional: "You’ll need to prove your identity using GOV.UK Verify"
349
353
  tracking-url:
350
354
  data:
355
+ heading: How do you want to sign in?
351
356
  name: "radio-group-tracking-url"
352
357
  id_prefix: "tracking-url"
353
358
  items:
@@ -360,15 +365,17 @@ examples:
360
365
  inline:
361
366
  description: "When providing few options, radio buttons should be inline rather than stacked. We recommend this for two small options like yes and no, on and off"
362
367
  data:
368
+ heading: Have you changed your name?
363
369
  name: "inline-radios"
364
370
  inline: true
365
371
  items:
366
- - value: "on"
367
- text: "On"
368
- - value: "off"
369
- text: "Off"
372
+ - value: "yes"
373
+ text: "Yes"
374
+ - value: "no"
375
+ text: "No"
370
376
  with_custom_id_attribute:
371
377
  data:
378
+ heading: How do you want to sign in?
372
379
  name: "radio-group"
373
380
  id: "radio-group"
374
381
  items:
@@ -69,3 +69,28 @@ examples:
69
69
  Allows the label text size to be set to `xl`, `l`, `m`, or `s`. If this is set, then `inline_label` is automatically set to `false`.
70
70
  data:
71
71
  label_size: "xl"
72
+ wrap_label_inside_a_heading:
73
+ description: |
74
+ Puts the label inside a heading; heading level defaults to 2 if not set.
75
+
76
+ (The size of the label can still be set with `label_size` to appear more like a heading.)
77
+ data:
78
+ wrap_label_in_a_heading: true
79
+ heading_level: 1
80
+ with_margin_bottom:
81
+ description: |
82
+ Allows the spacing at the bottom of the component to be adjusted.
83
+
84
+ This accepts a number 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 no margin bottom.
85
+ data:
86
+ margin_bottom: 9
87
+ with_margin_bottom_for_the_label:
88
+ description: |
89
+ Allows the spacing between the label and the input be adjusted.
90
+
91
+ Requires `inline_label` to be false.
92
+
93
+ This accepts a number 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 no margin bottom.
94
+ data:
95
+ label_margin_bottom: 9
96
+ inline_label: false
@@ -1,9 +1,10 @@
1
1
  name: Single page notification button
2
2
  description: A button that subscribes the user to email notifications to a page
3
3
  body: |
4
- By default, the component displays with the "Get emails about this page" state. The component does not render without the `base_path` parameter.
4
+ By default, the component displays with the "Get emails about this page" state.
5
+ If the `js-enhancement` flag is present, the component uses JavaScript to check if the user has already subscribed to email notifications on the current page. If yes, the state of the component updates accordingly.
5
6
 
6
- The `base_path` is necessary for [checking if an email subscription is active on page load](https://github.com/alphagov/account-api/blob/main/docs/api.md#get-apipersonalisationcheck-email-subscriptiontopic_slug) and the creation/deletion of an email notification subscription.
7
+ The component does not render without the `base_path` parameter. The `base_path` is necessary for [checking if an email subscription is active on page load](https://github.com/alphagov/account-api/blob/main/docs/api.md#get-apipersonalisationcheck-email-subscriptiontopic_slug) and the creation/deletion of an email notification subscription.
7
8
 
8
9
  When the button is clicked, the `base_path` is submitted to an endpoint which proceeds to check the user's authentication status and whether they are already subscribed to the page or not. Depending on these factors, they will be routed accordingly.
9
10
  accessibility_criteria: |
@@ -23,10 +24,27 @@ examples:
23
24
  data:
24
25
  base_path: '/current-page-path'
25
26
  data_attributes:
26
- category: fancyButtons
27
+ test_attribute: "testing"
27
28
  with_margin_bottom:
28
29
  description: |
29
30
  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 a margin bottom of 15px.
30
31
  data:
31
32
  base_path: '/current-page-path'
32
33
  margin_bottom: 5
34
+ with_js_enhancement:
35
+ description: |
36
+ If the `js-enhancement` flag is present, the component uses JavaScript to check if the user has already subscribed to email notifications on the current page. If yes, the state of the component updates accordingly.
37
+ data:
38
+ base_path: '/current-page-path'
39
+ js_enhancement: true
40
+ with_button_location:
41
+ description: |
42
+ When there is more than one button on a page, we should specify their location so that Analytics can differentiate between them.
43
+
44
+ The location should have one of two values: "top" or "bottom".
45
+
46
+ When this parameter is passed, its value is reflected in the `data-action` attribute (i.e "Unsubscribe-button-top"). When the flag is not present, `data-action` defaults to "Subscribe-button" or "Unsubscribe-button", depending on the state of the button.
47
+ data:
48
+ base_path: '/current-page-path'
49
+ js_enhancement: true
50
+ button_location: 'top'
@@ -87,7 +87,7 @@ en:
87
87
  statistics: Statistics
88
88
  worldwide: Worldwide
89
89
  layout_footer:
90
- copyright_html: <a class="govuk-footer__link govuk-footer__copyright-logo" href="http://www.nationalarchives.gov.uk/information-management/re-using-public-sector-information/copyright-and-re-use/crown-copyright/">© Crown copyright</a>
90
+ copyright_html: <a class="govuk-footer__link govuk-footer__copyright-logo" href="https://www.nationalarchives.gov.uk/information-management/re-using-public-sector-information/uk-government-licensing-framework/crown-copyright/">© Crown copyright</a>
91
91
  licence_html: All content is available under the <a class="govuk-footer__link" href="https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/" rel="license">Open Government Licence v3.0</a>, except where otherwise stated
92
92
  support_links: Support links
93
93
  layout_for_public:
@@ -11,6 +11,7 @@ module GovukPublishingComponents
11
11
  :rel,
12
12
  :data_attributes,
13
13
  :margin_bottom,
14
+ :id,
14
15
  :inline_layout,
15
16
  :target,
16
17
  :type,
@@ -49,16 +50,39 @@ module GovukPublishingComponents
49
50
  @value = local_assigns[:value]
50
51
  @classes = local_assigns[:classes]
51
52
  @aria_label = local_assigns[:aria_label]
53
+ @info_text_id = "info-text-id-#{SecureRandom.hex(4)}"
54
+ @button_id = "button-id-#{SecureRandom.hex(4)}"
52
55
  end
53
56
 
54
57
  def link?
55
58
  href.present?
56
59
  end
57
60
 
61
+ def info_text?
62
+ info_text.present?
63
+ end
64
+
65
+ def aria_labelledby
66
+ if info_text?
67
+ text = "#{@button_id} "
68
+ text << @info_text_id
69
+ text
70
+ end
71
+ end
72
+
73
+ def info_text_options
74
+ options = { class: info_text_classes }
75
+ options[:aria] = { hidden: true } if info_text?
76
+ options[:id] = @info_text_id if info_text?
77
+ options
78
+ end
79
+
58
80
  def html_options
59
81
  options = { class: css_classes }
60
82
  options[:role] = "button" if link?
61
83
  options[:type] = button_type
84
+ options[:id] = @button_id if info_text?
85
+ options[:aria] = { labelledby: aria_labelledby }
62
86
  options[:rel] = rel if rel
63
87
  options[:data] = data_attributes if data_attributes
64
88
  options[:title] = title if title
@@ -0,0 +1,37 @@
1
+ module GovukPublishingComponents
2
+ module Presenters
3
+ class SinglePageNotificationButtonHelper
4
+ attr_reader :already_subscribed, :data_attributes, :base_path, :js_enhancement, :button_type, :button_location
5
+
6
+ def initialize(local_assigns)
7
+ @local_assigns = local_assigns
8
+ @data_attributes = @local_assigns[:data_attributes] || {}
9
+ @js_enhancement = @local_assigns[:js_enhancement] || false
10
+ @already_subscribed = @local_assigns[:already_subscribed] || false
11
+ @base_path = @local_assigns[:base_path] || nil
12
+ @button_location = button_location_is_valid? ? @local_assigns[:button_location] : nil
13
+ @button_type = @local_assigns[:already_subscribed] ? "Unsubscribe" : "Subscribe"
14
+ end
15
+
16
+ def data
17
+ @data_attributes[:track_label] = base_path
18
+ # data-action for tracking should have the format of e.g. "Unsubscribe-button-top", or "Subscribe-button-bottom"
19
+ # when button_location is not present data-action will fall back to "Unsubscribe-button"/"Subscribe-button"
20
+ @data_attributes[:track_action] = [button_type, "button", button_location].compact.join("-")
21
+ @data_attributes[:module] = "single-page-notification-button" if js_enhancement
22
+ @data_attributes[:track_category] = "Single-page-notification-button"
23
+ # This attribute is passed through to the personalisation API to ensure when a new button is returned from the API, it has the same button_location
24
+ @data_attributes[:button_location] = button_location
25
+ @data_attributes
26
+ end
27
+
28
+ def button_location_is_valid?
29
+ %w[bottom top].include? @local_assigns[:button_location]
30
+ end
31
+
32
+ def button_text
33
+ @already_subscribed ? I18n.t("components.single_page_notification_button.unsubscribe_text") : I18n.t("components.single_page_notification_button.subscribe_text")
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,3 +1,3 @@
1
1
  module GovukPublishingComponents
2
- VERSION = "27.13.0".freeze
2
+ VERSION = "27.15.0".freeze
3
3
  end
@@ -33,6 +33,7 @@ require "govuk_publishing_components/presenters/intervention_helper"
33
33
  require "govuk_publishing_components/presenters/organisation_logo_helper"
34
34
  require "govuk_publishing_components/presenters/highlight_boxes_helper"
35
35
  require "govuk_publishing_components/presenters/taxonomy_list_helper"
36
+ require "govuk_publishing_components/presenters/single_page_notification_button_helper"
36
37
 
37
38
  require "govuk_publishing_components/app_helpers/taxon_breadcrumbs"
38
39
  require "govuk_publishing_components/app_helpers/table_helper"
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: 27.13.0
4
+ version: 27.15.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: 2021-11-17 00:00:00.000000000 Z
11
+ date: 2021-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: govuk_app_config
@@ -501,6 +501,7 @@ files:
501
501
  - app/assets/javascripts/govuk_publishing_components/components/radio.js
502
502
  - app/assets/javascripts/govuk_publishing_components/components/reorderable-list.js
503
503
  - app/assets/javascripts/govuk_publishing_components/components/show-password.js
504
+ - app/assets/javascripts/govuk_publishing_components/components/single-page-notification-button.js
504
505
  - app/assets/javascripts/govuk_publishing_components/components/step-by-step-nav.js
505
506
  - app/assets/javascripts/govuk_publishing_components/components/tabs.js
506
507
  - app/assets/javascripts/govuk_publishing_components/dependencies.js
@@ -968,6 +969,7 @@ files:
968
969
  - lib/govuk_publishing_components/presenters/schema_org.rb
969
970
  - lib/govuk_publishing_components/presenters/select.rb
970
971
  - lib/govuk_publishing_components/presenters/shared_helper.rb
972
+ - lib/govuk_publishing_components/presenters/single_page_notification_button_helper.rb
971
973
  - lib/govuk_publishing_components/presenters/step_by_step_nav_helper.rb
972
974
  - lib/govuk_publishing_components/presenters/subscription_links_helper.rb
973
975
  - lib/govuk_publishing_components/presenters/taxonomy_list_helper.rb