govuk_publishing_components 24.13.2 → 24.14.1

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 (32) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/govuk_publishing_components/analytics/analytics.js +3 -1
  3. data/app/assets/javascripts/govuk_publishing_components/analytics/custom-dimensions.js +2 -0
  4. data/app/assets/javascripts/govuk_publishing_components/components/accordion.js +6 -5
  5. data/app/assets/javascripts/govuk_publishing_components/components/checkboxes.js +9 -7
  6. data/app/assets/javascripts/govuk_publishing_components/components/contextual-guidance.js +6 -7
  7. data/app/assets/javascripts/govuk_publishing_components/components/cookie-banner.js +7 -7
  8. data/app/assets/javascripts/govuk_publishing_components/components/copy-to-clipboard.js +13 -12
  9. data/app/assets/javascripts/govuk_publishing_components/components/details.js +12 -18
  10. data/app/assets/javascripts/govuk_publishing_components/components/feedback.js +213 -215
  11. data/app/assets/javascripts/govuk_publishing_components/components/govspeak.js +4 -4
  12. data/app/assets/javascripts/govuk_publishing_components/components/modal-dialogue.js +6 -4
  13. data/app/assets/javascripts/govuk_publishing_components/components/print-link.js +4 -3
  14. data/app/assets/javascripts/govuk_publishing_components/components/reorderable-list.js +13 -13
  15. data/app/assets/javascripts/govuk_publishing_components/components/show-password.js +5 -4
  16. data/app/assets/javascripts/govuk_publishing_components/components/step-by-step-nav.js +4 -4
  17. data/app/assets/javascripts/govuk_publishing_components/lib/govspeak/magna-charta.js +3 -3
  18. data/app/assets/javascripts/govuk_publishing_components/lib/header-navigation.js +6 -0
  19. data/app/assets/javascripts/govuk_publishing_components/lib/trigger-event.js +5 -3
  20. data/app/assets/javascripts/govuk_publishing_components/rum-loader.js.erb +36 -0
  21. data/app/assets/javascripts/govuk_publishing_components/vendor/lux/lux-polyfill.js +159 -0
  22. data/app/assets/javascripts/govuk_publishing_components/vendor/lux/lux.js +844 -0
  23. data/app/views/govuk_publishing_components/components/_government_navigation.html.erb +50 -8
  24. data/app/views/govuk_publishing_components/components/_layout_for_public.html.erb +4 -0
  25. data/app/views/govuk_publishing_components/components/_layout_header.html.erb +11 -2
  26. data/app/views/govuk_publishing_components/components/_search.html.erb +5 -2
  27. data/app/views/govuk_publishing_components/components/layout_header/_header_logo.html.erb +3 -3
  28. data/config/initializers/assets.rb +3 -0
  29. data/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_priority.rb +32 -3
  30. data/lib/govuk_publishing_components/presenters/contextual_navigation.rb +1 -0
  31. data/lib/govuk_publishing_components/version.rb +1 -1
  32. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a5f30a829f44913c30260a6dcaa8f09cb443897477370f95d64b977e0ba3e3b
4
- data.tar.gz: 7acbcf428ab0bcc171285ece6d46c19fbf1145b2c55e65de79f0ba6c51f2990a
3
+ metadata.gz: 0f4046fe3e64f043704bbc8da98b2a38f54c6bb854f05733322b4c32513ab12a
4
+ data.tar.gz: 814b350fc60058c20e4ff7dc83cd994e80843e5e1c0a4dcbd76e3dda50a6a41a
5
5
  SHA512:
6
- metadata.gz: 05cc84e714cde48b7fd102495f024ab30284f171ea2fab94b6ef6a7aad9d0642dc78ab8c50b844be7b2eca1efa985e8a2aae4c6e5fa5f6e9f162e87db2d4c53c
7
- data.tar.gz: 4cdb13383ef1ce24a5e688e2a0d1b5bf9b349a18290e3e41537f2c7c75881d1ee472a4c795e4d3c300e5d274e46aba3618b49e9e8e2cfb1ceed018112e1ff864
6
+ metadata.gz: 5a5283a68af388d240fafd32499c0a076c7d4b284e9eee9b676ab6ef4f67415c249d6b7d77c180fd17cf570cf90e5e0780e4a05b8ff49bf6b80e0103cb4a5437
7
+ data.tar.gz: 3d73908921bcea616b99b747facaa2e864fe7d4db8c7d1bf5636d9971b204fac2bd72f52cffe0ce6e54ac09ab4e98ca3206b458c913673328a878eaf9a289d40
@@ -41,7 +41,9 @@
41
41
  // we ignore the possibility of there being campaign variables in the
42
42
  // anchor because we wouldn't know how to detect and parse them if they
43
43
  // were present
44
- return this.pii.stripPIIFromString(location.href.substring(location.origin.length).split('#')[0])
44
+ // IE can't access window.location.origin, so we have to do this slightly complex thing
45
+ var root = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '')
46
+ return this.pii.stripPIIFromString(location.href.substring(root.length).split('#')[0])
45
47
  }
46
48
 
47
49
  Analytics.prototype.trackPageview = function (path, title, options) {
@@ -33,6 +33,8 @@
33
33
 
34
34
  if (window.devicePixelRatio) {
35
35
  customDimensions.dimension11 = window.devicePixelRatio
36
+ } else {
37
+ customDimensions.dimension11 = window.screen.deviceXDPI / window.screen.logicalXDPI
36
38
  }
37
39
 
38
40
  return customDimensions
@@ -7,15 +7,12 @@ window.GOVUK = window.GOVUK || {}
7
7
  window.GOVUK.Modules = window.GOVUK.Modules || {};
8
8
 
9
9
  (function (Modules) {
10
- function GemAccordion () { }
11
-
12
- GemAccordion.prototype.start = function ($module) {
13
- this.$module = $module[0]
10
+ function GemAccordion ($module) {
11
+ this.$module = $module
14
12
  this.sectionClass = 'gem-c-accordion__section'
15
13
  this.moduleId = this.$module.getAttribute('id')
16
14
  this.sections = this.$module.querySelectorAll('.' + this.sectionClass)
17
15
  this.openAllButton = ''
18
- this.browserSupportsSessionStorage = helper.checkForSessionStorage()
19
16
  this.controlsClass = 'gem-c-accordion__controls'
20
17
  this.openAllClass = 'gem-c-accordion__open-all'
21
18
  this.openAllTextClass = 'gem-c-accordion__open-all-text'
@@ -39,6 +36,10 @@ window.GOVUK.Modules = window.GOVUK.Modules || {};
39
36
  this.$module.actions.showAllText = this.$module.getAttribute('data-show-all-text')
40
37
  this.$module.actions.hideAllText = this.$module.getAttribute('data-hide-all-text')
41
38
  this.$module.actions.thisSectionVisuallyHidden = this.$module.getAttribute('data-this-section-visually-hidden')
39
+ }
40
+
41
+ GemAccordion.prototype.init = function () {
42
+ this.browserSupportsSessionStorage = helper.checkForSessionStorage()
42
43
 
43
44
  // Indicate that JavaScript has worked
44
45
  this.$module.classList.add('gem-c-accordion--active')
@@ -6,14 +6,14 @@ window.GOVUK.Modules = window.GOVUK.Modules || {}
6
6
  window.GOVUK.Modules.Checkboxes = window.GOVUKFrontend;
7
7
 
8
8
  (function (Modules) {
9
- function GovukCheckboxes () { }
10
-
11
- GovukCheckboxes.prototype.start = function ($module) {
12
- this.$module = $module[0]
9
+ function GovukCheckboxes ($module) {
10
+ this.$module = $module
13
11
  this.$checkboxes = this.$module.querySelectorAll('input[type=checkbox]')
14
12
  this.$nestedCheckboxes = this.$module.querySelectorAll('[data-nested=true] input[type=checkbox]')
15
13
  this.$exclusiveCheckboxes = this.$module.querySelectorAll('[data-exclusive=true] input[type=checkbox]')
14
+ }
16
15
 
16
+ GovukCheckboxes.prototype.init = function () {
17
17
  this.applyAriaControlsAttributes(this.$module)
18
18
 
19
19
  for (var i = 0; i < this.$checkboxes.length; i++) {
@@ -33,7 +33,9 @@ window.GOVUK.Modules.Checkboxes = window.GOVUKFrontend;
33
33
  if (window.GOVUK.analytics && window.GOVUK.analytics.trackEvent) {
34
34
  // Where checkboxes are manipulated externally in finders, `suppressAnalytics`
35
35
  // is passed to prevent duplicate GA events.
36
- if (!event.detail || (event.detail && event.detail.suppressAnalytics !== true)) {
36
+ // use Oliver Steele's Nested Object Access Pattern https://hackernoon.com/accessing-nested-objects-in-javascript-f02f1bd6387f
37
+ var allowAnalytics = ((event || {}).detail || {}).suppressAnalytics !== true
38
+ if (allowAnalytics) {
37
39
  var $checkbox = event.target
38
40
  var category = $checkbox.getAttribute('data-track-category')
39
41
  if (category) {
@@ -100,11 +102,11 @@ window.GOVUK.Modules.Checkboxes = window.GOVUKFrontend;
100
102
  var $exclusiveOption = $checkboxes.querySelector('input[type=checkbox][data-exclusive]')
101
103
  var $nonExclusiveOptions = $checkboxes.querySelectorAll('input[type=checkbox]:not([data-exclusive])')
102
104
 
103
- if ($currentCheckbox.dataset.exclusive === 'true' && $currentCheckbox.checked === true) {
105
+ if ($currentCheckbox.getAttribute('data-exclusive') === 'true' && $currentCheckbox.checked === true) {
104
106
  for (var i = 0; i < $nonExclusiveOptions.length; i++) {
105
107
  $nonExclusiveOptions[i].checked = false
106
108
  }
107
- } else if ($currentCheckbox.dataset.exclusive !== 'true' && $currentCheckbox.checked === true) {
109
+ } else if ($currentCheckbox.getAttribute('data-exclusive') !== 'true' && $currentCheckbox.checked === true) {
108
110
  if ($exclusiveOption) {
109
111
  $exclusiveOption.checked = false
110
112
  }
@@ -2,22 +2,21 @@ window.GOVUK = window.GOVUK || {}
2
2
  window.GOVUK.Modules = window.GOVUK.Modules || {};
3
3
 
4
4
  (function (Modules) {
5
- function ContextualGuidance () { }
6
-
7
- ContextualGuidance.prototype.start = function ($module) {
8
- this.$module = $module[0]
5
+ function ContextualGuidance ($module) {
6
+ this.$module = $module
9
7
  this.$guidance = this.$module.querySelector('.gem-c-contextual-guidance__wrapper')
10
8
  this.$inputId = this.$guidance.getAttribute('for')
11
9
  this.$input = this.$module.querySelector('#' + this.$inputId)
10
+ }
11
+
12
+ ContextualGuidance.prototype.init = function () {
12
13
  if (!this.$input) return
13
14
  this.$input.addEventListener('focus', this.handleFocus.bind(this))
14
15
  }
15
16
 
16
17
  ContextualGuidance.prototype.handleFocus = function (event) {
17
18
  this.hideAllGuidance()
18
- if (!event.target.dataset.contextualGuidanceHideOnly) {
19
- this.$guidance.style.display = 'block'
20
- }
19
+ this.$guidance.style.display = 'block'
21
20
  }
22
21
 
23
22
  ContextualGuidance.prototype.hideAllGuidance = function () {
@@ -2,18 +2,18 @@ window.GOVUK = window.GOVUK || {}
2
2
  window.GOVUK.Modules = window.GOVUK.Modules || {};
3
3
 
4
4
  (function (Modules) {
5
- function CookieBanner () { }
5
+ function CookieBanner ($module) {
6
+ this.$module = $module
7
+ this.$module.cookieBanner = document.querySelector('.gem-c-cookie-banner')
8
+ this.$module.cookieBannerConfirmationMessage = this.$module.querySelector('.gem-c-cookie-banner__confirmation')
9
+ this.$module.cookieBannerConfirmationMessageText = this.$module.querySelector('.gem-c-cookie-banner__confirmation-message')
10
+ }
6
11
 
7
- CookieBanner.prototype.start = function ($module) {
8
- this.$module = $module[0]
12
+ CookieBanner.prototype.init = function () {
9
13
  this.$module.hideCookieMessage = this.hideCookieMessage.bind(this)
10
14
  this.$module.showConfirmationMessage = this.showConfirmationMessage.bind(this)
11
15
  this.$module.setCookieConsent = this.setCookieConsent.bind(this)
12
16
  this.$module.rejectCookieConsent = this.rejectCookieConsent.bind(this)
13
-
14
- this.$module.cookieBanner = document.querySelector('.gem-c-cookie-banner')
15
- this.$module.cookieBannerConfirmationMessage = this.$module.querySelector('.gem-c-cookie-banner__confirmation')
16
- this.$module.cookieBannerConfirmationMessageText = this.$module.querySelector('.gem-c-cookie-banner__confirmation-message')
17
17
  this.setupCookieMessage()
18
18
  }
19
19
 
@@ -2,23 +2,24 @@ window.GOVUK = window.GOVUK || {}
2
2
  window.GOVUK.Modules = window.GOVUK.Modules || {};
3
3
 
4
4
  (function (Modules) {
5
- function CopyToClipboard () { }
6
-
7
- CopyToClipboard.prototype.start = function ($module) {
8
- this.$module = $module[0]
5
+ function CopyToClipboard ($module) {
6
+ this.$module = $module
7
+ this.$input = this.$module.querySelector('.gem-c-input')
8
+ this.$copyButton = this.$module.querySelector('.gem-c-button')
9
+ }
9
10
 
10
- var input = this.$module.querySelector('.gem-c-input')
11
- var copyButton = this.$module.querySelector('.gem-c-button')
11
+ CopyToClipboard.prototype.init = function () {
12
+ if (!this.$input || !this.$copyButton) return
12
13
 
13
- input.addEventListener('click', function () {
14
- input.select()
15
- })
14
+ this.$input.addEventListener('click', function () {
15
+ this.$input.select()
16
+ }.bind(this))
16
17
 
17
- copyButton.addEventListener('click', function (event) {
18
+ this.$copyButton.addEventListener('click', function (event) {
18
19
  event.preventDefault()
19
- input.select()
20
+ this.$input.select()
20
21
  document.execCommand('copy')
21
- })
22
+ }.bind(this))
22
23
  }
23
24
 
24
25
  Modules.CopyToClipboard = CopyToClipboard
@@ -5,26 +5,20 @@ window.GOVUK.Modules = window.GOVUK.Modules || {}
5
5
  window.GOVUK.Modules.Details = window.GOVUKFrontend;
6
6
 
7
7
  (function (Modules) {
8
- function GovukDetails () { }
9
-
10
- GovukDetails.prototype.start = function ($module) {
11
- this.$module = $module[0]
12
-
13
- var customTrackLabel = this.$module.getAttribute('data-track-label')
8
+ function GovukDetails ($module) {
9
+ this.$module = $module
10
+ this.customTrackLabel = this.$module.getAttribute('data-track-label')
11
+ this.detailsClick = this.$module.querySelector('[data-details-track-click]')
12
+ }
14
13
 
15
- // If a custom label has been provided, we can simply call the tracking module
16
- if (customTrackLabel) {
14
+ GovukDetails.prototype.init = function () {
15
+ if (this.customTrackLabel) { // If a custom label has been provided, we can simply call the tracking module
17
16
  var trackDetails = new window.GOVUK.Modules.GemTrackClick()
18
- trackDetails.start($module)
19
- } else {
20
- // If no custom label is set, we use the open/close status as the label
21
- var detailsClick = this.$module.querySelector('[data-details-track-click]')
22
-
23
- if (detailsClick) {
24
- detailsClick.addEventListener('click', function (event) {
25
- this.trackDefault(this.$module)
26
- }.bind(this))
27
- }
17
+ trackDetails.start($(this.$module))
18
+ } else if (this.detailsClick) { // If no custom label is set, we use the open/close status as the label
19
+ this.detailsClick.addEventListener('click', function (event) {
20
+ this.trackDefault(this.$module)
21
+ }.bind(this))
28
22
  }
29
23
  }
30
24
 
@@ -3,244 +3,242 @@ window.GOVUK = window.GOVUK || {}
3
3
  window.GOVUK.Modules = window.GOVUK.Modules || {};
4
4
 
5
5
  (function (Modules) {
6
- 'use strict'
7
-
8
- Modules.Feedback = function () {
9
- this.start = function ($element) {
10
- this.element = $element[0]
11
- this.somethingIsWrongForm = this.element.querySelector('#something-is-wrong')
12
- this.surveyForm = this.element.querySelector('#page-is-not-useful')
13
- this.prompt = this.element.querySelector('.js-prompt')
14
- this.forms = this.element.querySelectorAll('.js-feedback-form')
15
- this.toggleForms = this.element.querySelectorAll('.js-toggle-form')
16
- this.closeForms = this.element.querySelectorAll('.js-close-form')
17
- this.activeForm = false
18
- this.pageIsUsefulButton = this.element.querySelector('.js-page-is-useful')
19
- this.pageIsNotUsefulButton = this.element.querySelector('.js-page-is-not-useful')
20
- this.somethingIsWrongButton = this.element.querySelector('.js-something-is-wrong')
21
- this.promptQuestions = this.element.querySelectorAll('.js-prompt-questions')
22
- this.promptSuccessMessage = this.element.querySelector('.js-prompt-success')
23
- this.surveyWrapper = this.element.querySelector('#survey-wrapper')
6
+ function Feedback ($module) {
7
+ this.$module = $module
8
+ this.somethingIsWrongForm = this.$module.querySelector('#something-is-wrong')
9
+ this.surveyForm = this.$module.querySelector('#page-is-not-useful')
10
+ this.prompt = this.$module.querySelector('.js-prompt')
11
+ this.forms = this.$module.querySelectorAll('.js-feedback-form')
12
+ this.toggleForms = this.$module.querySelectorAll('.js-toggle-form')
13
+ this.closeForms = this.$module.querySelectorAll('.js-close-form')
14
+ this.activeForm = false
15
+ this.pageIsUsefulButton = this.$module.querySelector('.js-page-is-useful')
16
+ this.pageIsNotUsefulButton = this.$module.querySelector('.js-page-is-not-useful')
17
+ this.somethingIsWrongButton = this.$module.querySelector('.js-something-is-wrong')
18
+ this.promptQuestions = this.$module.querySelectorAll('.js-prompt-questions')
19
+ this.promptSuccessMessage = this.$module.querySelector('.js-prompt-success')
20
+ this.surveyWrapper = this.$module.querySelector('#survey-wrapper')
21
+ this.jshiddenClass = 'js-hidden'
22
+ }
24
23
 
25
- var thisModule = this
26
- var jshiddenClass = 'js-hidden'
24
+ Feedback.prototype.init = function () {
25
+ this.setInitialAriaAttributes()
26
+ this.setHiddenValues()
27
27
 
28
- setInitialAriaAttributes()
29
- setHiddenValues()
28
+ for (var j = 0; j < this.toggleForms.length; j++) {
29
+ this.toggleForms[j].addEventListener('click', function (e) {
30
+ e.preventDefault()
31
+ var el = e.target
32
+ this.toggleForm(el.getAttribute('aria-controls'))
33
+ this.trackEvent(this.getTrackEventParams(el))
34
+ this.updateAriaAttributes(el)
35
+ }.bind(this))
36
+ }
30
37
 
31
- for (var j = 0; j < this.toggleForms.length; j++) {
32
- this.toggleForms[j].addEventListener('click', function (e) {
33
- e.preventDefault()
34
- var el = e.target
35
- toggleForm(el.getAttribute('aria-controls'))
36
- trackEvent(getTrackEventParams(el))
37
- updateAriaAttributes(el)
38
- })
39
- }
38
+ for (var i = 0; i < this.closeForms.length; i++) {
39
+ this.closeForms[i].addEventListener('click', function (e) {
40
+ e.preventDefault()
41
+ var el = e.target
42
+ var formToToggle = el.getAttribute('aria-controls')
43
+ this.toggleForm(formToToggle)
44
+ this.trackEvent(this.getTrackEventParams(el))
45
+ this.setInitialAriaAttributes()
46
+ this.revealInitialPrompt()
47
+ var refocusClass = '.js-' + formToToggle
48
+ this.$module.querySelector(refocusClass).focus()
49
+ }.bind(this))
50
+ }
40
51
 
41
- for (var i = 0; i < this.closeForms.length; i++) {
42
- this.closeForms[i].addEventListener('click', function (e) {
43
- e.preventDefault()
44
- var el = e.target
45
- var formToToggle = el.getAttribute('aria-controls')
46
- toggleForm(formToToggle)
47
- trackEvent(getTrackEventParams(el))
48
- setInitialAriaAttributes()
49
- revealInitialPrompt()
50
- var refocusClass = '.js-' + formToToggle
51
- thisModule.element.querySelector(refocusClass).focus()
52
- })
52
+ this.pageIsUsefulButton.addEventListener('click', function (e) {
53
+ e.preventDefault()
54
+ this.trackEvent(this.getTrackEventParams(this.pageIsUsefulButton))
55
+ this.showFormSuccess()
56
+ this.revealInitialPrompt()
57
+ }.bind(this))
58
+
59
+ this.pageIsNotUsefulButton.addEventListener('click', function (e) {
60
+ var gaClientId
61
+ var dummyGaClientId = '111111111.1111111111'
62
+ if (window.GOVUK.cookie('_ga') === null || window.GOVUK.cookie('_ga') === '') {
63
+ gaClientId = dummyGaClientId
64
+ } else {
65
+ gaClientId = window.GOVUK.cookie('_ga').split('.').slice(-2).join('.')
53
66
  }
54
-
55
- this.pageIsUsefulButton.addEventListener('click', function (e) {
56
- e.preventDefault()
57
- trackEvent(getTrackEventParams(thisModule.pageIsUsefulButton))
58
- showFormSuccess()
59
- revealInitialPrompt()
60
- })
61
-
62
- this.pageIsNotUsefulButton.addEventListener('click', function (e) {
63
- var gaClientId
64
- var dummyGaClientId = '111111111.1111111111'
65
- if (window.GOVUK.cookie('_ga') === null || window.GOVUK.cookie('_ga') === '') {
66
- gaClientId = dummyGaClientId
67
- } else {
68
- gaClientId = window.GOVUK.cookie('_ga').split('.').slice(-2).join('.')
69
- }
70
- setHiddenValuesNotUsefulForm(gaClientId)
71
- })
72
-
73
- // much of the JS needed to support sending the form contents via this script is
74
- // unsupported by IE, even IE11. This check causes IE to not intercept form submits
75
- // and let them happen normally, which is handled already by the backend
76
- if (typeof window.URLSearchParams === 'function') {
77
- for (var f = 0; f < this.forms.length; f++) {
78
- this.forms[f].addEventListener('submit', function (e) {
79
- e.preventDefault()
80
- var $form = e.target
81
- var xhr = new XMLHttpRequest()
82
- var url = $form.getAttribute('action')
83
- var params = new FormData($form)
84
- params = new URLSearchParams(params).toString()
85
-
86
- xhr.open('POST', url, true)
87
- xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
88
-
89
- xhr.onreadystatechange = function () {
90
- if (xhr.readyState === 4 && xhr.status === 200) {
91
- trackEvent(getTrackEventParams($form))
92
- showFormSuccess(xhr.message)
93
- revealInitialPrompt()
94
- setInitialAriaAttributes()
95
- thisModule.activeForm.classList.toggle(jshiddenClass)
96
- } else {
97
- showError(xhr)
98
- enableSubmitFormButton($form)
99
- }
67
+ this.setHiddenValuesNotUsefulForm(gaClientId)
68
+ }.bind(this))
69
+
70
+ // much of the JS needed to support sending the form contents via this script is
71
+ // unsupported by IE, even IE11. This check causes IE to not intercept form submits
72
+ // and let them happen normally, which is handled already by the backend
73
+ if (typeof window.URLSearchParams === 'function') {
74
+ for (var f = 0; f < this.forms.length; f++) {
75
+ this.forms[f].addEventListener('submit', function (e) {
76
+ e.preventDefault()
77
+ var $form = e.target
78
+ var xhr = new XMLHttpRequest()
79
+ var url = $form.getAttribute('action')
80
+ var params = new FormData($form)
81
+ params = new URLSearchParams(params).toString()
82
+
83
+ xhr.open('POST', url, true)
84
+ xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
85
+
86
+ xhr.onreadystatechange = function () {
87
+ if (xhr.readyState === 4 && xhr.status === 200) {
88
+ this.trackEvent(this.getTrackEventParams($form))
89
+ this.showFormSuccess(xhr.message)
90
+ this.revealInitialPrompt()
91
+ this.setInitialAriaAttributes()
92
+ this.activeForm.classList.toggle(this.jshiddenClass)
93
+ } else {
94
+ this.showError(xhr)
95
+ this.enableSubmitFormButton($form)
100
96
  }
97
+ }.bind(this)
101
98
 
102
- disableSubmitFormButton($form)
103
- xhr.send(params)
104
- })
105
- }
99
+ this.disableSubmitFormButton($form)
100
+ xhr.send(params)
101
+ }.bind(this))
106
102
  }
103
+ }
104
+ }
107
105
 
108
- function disableSubmitFormButton ($form) {
109
- var formButton = $form.querySelector('[type="submit"]')
110
- formButton.setAttribute('disabled', true)
111
- }
106
+ Feedback.prototype.disableSubmitFormButton = function ($form) {
107
+ var formButton = $form.querySelector('[type="submit"]')
108
+ formButton.setAttribute('disabled', true)
109
+ }
112
110
 
113
- function enableSubmitFormButton ($form) {
114
- var formButton = $form.querySelector('[type="submit"]')
115
- formButton.removeAttribute('disabled')
116
- }
111
+ Feedback.prototype.enableSubmitFormButton = function ($form) {
112
+ var formButton = $form.querySelector('[type="submit"]')
113
+ formButton.removeAttribute('disabled')
114
+ }
117
115
 
118
- function setInitialAriaAttributes () {
119
- for (var i = 0; i < thisModule.forms.length; i++) {
120
- thisModule.forms[i].setAttribute('aria-hidden', true)
121
- }
122
- thisModule.pageIsNotUsefulButton.setAttribute('aria-expanded', false)
123
- thisModule.somethingIsWrongButton.setAttribute('aria-expanded', false)
124
- }
116
+ Feedback.prototype.setInitialAriaAttributes = function () {
117
+ for (var i = 0; i < this.forms.length; i++) {
118
+ this.forms[i].setAttribute('aria-hidden', true)
119
+ }
120
+ this.pageIsNotUsefulButton.setAttribute('aria-expanded', false)
121
+ this.somethingIsWrongButton.setAttribute('aria-expanded', false)
122
+ }
125
123
 
126
- function setHiddenValues () {
127
- var javascriptEnabled = document.createElement('input')
128
- javascriptEnabled.setAttribute('type', 'hidden')
129
- javascriptEnabled.setAttribute('name', 'javascript_enabled')
130
- javascriptEnabled.setAttribute('value', true)
131
- thisModule.somethingIsWrongForm.appendChild(javascriptEnabled)
132
-
133
- var referrer = document.createElement('input')
134
- referrer.setAttribute('type', 'hidden')
135
- referrer.setAttribute('name', 'referrer')
136
- referrer.setAttribute('value', document.referrer || 'unknown')
137
- thisModule.somethingIsWrongForm.appendChild(referrer)
138
- thisModule.somethingIsWrongForm.invalidInfoError = [
139
- '<h2>Sorry, we’re unable to send your message as you haven’t given us any information.</h2>',
140
- ' <p>Please tell us what you were doing or what went wrong</p>'
141
- ].join('')
142
- }
124
+ Feedback.prototype.setHiddenValues = function () {
125
+ var javascriptEnabled = document.createElement('input')
126
+ javascriptEnabled.setAttribute('type', 'hidden')
127
+ javascriptEnabled.setAttribute('name', 'javascript_enabled')
128
+ javascriptEnabled.setAttribute('value', true)
129
+ this.somethingIsWrongForm.appendChild(javascriptEnabled)
130
+
131
+ var referrer = document.createElement('input')
132
+ referrer.setAttribute('type', 'hidden')
133
+ referrer.setAttribute('name', 'referrer')
134
+ referrer.setAttribute('value', document.referrer || 'unknown')
135
+ this.somethingIsWrongForm.appendChild(referrer)
136
+ this.somethingIsWrongForm.invalidInfoError = [
137
+ '<h2>Sorry, we’re unable to send your message as you haven’t given us any information.</h2>',
138
+ ' <p>Please tell us what you were doing or what went wrong</p>'
139
+ ].join('')
140
+ }
143
141
 
144
- function setHiddenValuesNotUsefulForm (gaClientId) {
145
- var currentPathName = window.location.pathname.replace(/[^\s=?&]+(?:@|%40)[^\s=?&]+/, '[email]')
146
- var finalPathName = encodeURI(currentPathName)
147
- thisModule.surveyForm.invalidInfoError = [
148
- '<h2>Sorry, we’re unable to send your message as you haven’t given us a valid email address.</h2>',
149
- ' <p>Enter an email address in the correct format, like name@example.com</p>'
150
- ].join('')
151
- if (document.querySelectorAll('[name="email_survey_signup[ga_client_id]"]').length === 0) {
152
- var hiddenInput = document.createElement('input')
153
- hiddenInput.setAttribute('type', 'hidden')
154
- hiddenInput.setAttribute('name', 'email_survey_signup[ga_client_id]')
155
- hiddenInput.setAttribute('value', gaClientId || '0')
156
- thisModule.surveyForm.appendChild(hiddenInput)
157
- }
158
-
159
- if (document.querySelectorAll('.gem-c-feedback__email-link#take-survey').length === 0) {
160
- var takeSurvey = document.createElement('a')
161
- takeSurvey.setAttribute('href', 'https://www.smartsurvey.co.uk/s/gov-uk-banner/?c=' + finalPathName + '&amp;gcl=' + gaClientId)
162
- takeSurvey.setAttribute('class', 'gem-c-feedback__email-link govuk-link')
163
- takeSurvey.setAttribute('id', 'take-survey')
164
- takeSurvey.setAttribute('target', '_blank')
165
- takeSurvey.setAttribute('rel', 'noopener noreferrer')
166
- takeSurvey.innerHTML = 'Don’t have an email address?'
167
- thisModule.surveyWrapper.appendChild(takeSurvey)
168
- }
169
- }
142
+ Feedback.prototype.setHiddenValuesNotUsefulForm = function (gaClientId) {
143
+ var currentPathName = window.location.pathname.replace(/[^\s=?&]+(?:@|%40)[^\s=?&]+/, '[email]')
144
+ var finalPathName = encodeURI(currentPathName)
145
+ this.surveyForm.invalidInfoError = [
146
+ '<h2>Sorry, we’re unable to send your message as you haven’t given us a valid email address.</h2>',
147
+ ' <p>Enter an email address in the correct format, like name@example.com</p>'
148
+ ].join('')
149
+ if (document.querySelectorAll('[name="email_survey_signup[ga_client_id]"]').length === 0) {
150
+ var hiddenInput = document.createElement('input')
151
+ hiddenInput.setAttribute('type', 'hidden')
152
+ hiddenInput.setAttribute('name', 'email_survey_signup[ga_client_id]')
153
+ hiddenInput.setAttribute('value', gaClientId || '0')
154
+ this.surveyForm.appendChild(hiddenInput)
155
+ }
170
156
 
171
- function updateAriaAttributes (linkClicked) {
172
- linkClicked.setAttribute('aria-expanded', true)
173
- var controls = linkClicked.getAttribute('aria-controls')
174
- var ariaControls = document.querySelector('#' + controls)
175
- ariaControls.setAttribute('aria-hidden', false)
176
- }
157
+ if (document.querySelectorAll('.gem-c-feedback__email-link#take-survey').length === 0) {
158
+ var takeSurvey = document.createElement('a')
159
+ takeSurvey.setAttribute('href', 'https://www.smartsurvey.co.uk/s/gov-uk-banner/?c=' + finalPathName + '&amp;gcl=' + gaClientId)
160
+ takeSurvey.setAttribute('class', 'gem-c-feedback__email-link govuk-link')
161
+ takeSurvey.setAttribute('id', 'take-survey')
162
+ takeSurvey.setAttribute('target', '_blank')
163
+ takeSurvey.setAttribute('rel', 'noopener noreferrer')
164
+ takeSurvey.innerHTML = 'Don’t have an email address?'
165
+ this.surveyWrapper.appendChild(takeSurvey)
166
+ }
167
+ }
177
168
 
178
- function toggleForm (formId) {
179
- thisModule.activeForm = thisModule.element.querySelector('#' + formId)
180
- thisModule.activeForm.classList.toggle(jshiddenClass)
181
- thisModule.prompt.classList.toggle(jshiddenClass)
169
+ Feedback.prototype.updateAriaAttributes = function (linkClicked) {
170
+ linkClicked.setAttribute('aria-expanded', true)
171
+ var controls = linkClicked.getAttribute('aria-controls')
172
+ var ariaControls = document.querySelector('#' + controls)
173
+ ariaControls.setAttribute('aria-hidden', false)
174
+ }
182
175
 
183
- var formIsVisible = !thisModule.activeForm.classList.contains(jshiddenClass)
176
+ Feedback.prototype.toggleForm = function (formId) {
177
+ this.activeForm = this.$module.querySelector('#' + formId)
178
+ this.activeForm.classList.toggle(this.jshiddenClass)
179
+ this.prompt.classList.toggle(this.jshiddenClass)
184
180
 
185
- if (formIsVisible) {
186
- thisModule.activeForm.querySelector('.gem-c-input').focus()
187
- } else {
188
- thisModule.activeForm = false
189
- }
190
- }
181
+ var formIsVisible = !this.activeForm.classList.contains(this.jshiddenClass)
191
182
 
192
- function getTrackEventParams ($node) {
193
- return {
194
- category: $node.getAttribute('data-track-category'),
195
- action: $node.getAttribute('data-track-action')
196
- }
197
- }
183
+ if (formIsVisible) {
184
+ this.activeForm.querySelector('.gem-c-input').focus()
185
+ } else {
186
+ this.activeForm = false
187
+ }
188
+ }
198
189
 
199
- function trackEvent (trackEventParams) {
200
- if (window.GOVUK.analytics && window.GOVUK.analytics.trackEvent) {
201
- window.GOVUK.analytics.trackEvent(trackEventParams.category, trackEventParams.action)
202
- }
203
- }
190
+ Feedback.prototype.getTrackEventParams = function ($node) {
191
+ return {
192
+ category: $node.getAttribute('data-track-category'),
193
+ action: $node.getAttribute('data-track-action')
194
+ }
195
+ }
204
196
 
205
- function showError (error) {
206
- var genericError = [
207
- '<h2>Sorry, we’re unable to receive your message right now.</h2>',
208
- ' <p>If the problem persists, we have other ways for you to provide',
209
- ' feedback on the <a href="/contact/govuk">contact page</a>.</p>'
210
- ].join('')
211
- // if the response is not a 404 or 500, show the error message if it exists
212
- // otherwise show the generic message
213
- if ('response' in error) {
214
- if (typeof error.response === 'object' && error.response !== null) {
215
- error = error.response.message === 'email survey sign up failure' ? genericError : error.response.message
216
- } else {
217
- error = genericError
218
- }
219
- } else if (error.status === 422) {
220
- // there's clobbering by nginx on all 422 requests, which is why the response returns a rendered html page instead of the expected JSON
221
- // this is a temporary workaround to ensure that we are displaying relevant error messages to the users
222
- error = thisModule.activeForm.invalidInfoError || genericError
223
- } else {
224
- error = genericError
225
- }
226
- var $errors = thisModule.activeForm.querySelector('.js-errors')
227
- $errors.innerHTML = error
228
- $errors.classList.remove(jshiddenClass)
229
- $errors.focus()
230
- }
197
+ Feedback.prototype.trackEvent = function (trackEventParams) {
198
+ if (window.GOVUK.analytics && window.GOVUK.analytics.trackEvent) {
199
+ window.GOVUK.analytics.trackEvent(trackEventParams.category, trackEventParams.action)
200
+ }
201
+ }
231
202
 
232
- function showFormSuccess () {
233
- for (var i = 0; i < thisModule.promptQuestions.length; i++) {
234
- thisModule.promptQuestions[i].classList.add(jshiddenClass)
235
- }
236
- thisModule.promptSuccessMessage.classList.remove(jshiddenClass)
237
- thisModule.promptSuccessMessage.focus()
203
+ Feedback.prototype.showError = function (error) {
204
+ var genericError = [
205
+ '<h2>Sorry, we’re unable to receive your message right now.</h2>',
206
+ ' <p>If the problem persists, we have other ways for you to provide',
207
+ ' feedback on the <a href="/contact/govuk">contact page</a>.</p>'
208
+ ].join('')
209
+ // if the response is not a 404 or 500, show the error message if it exists
210
+ // otherwise show the generic message
211
+ if ('response' in error) {
212
+ if (typeof error.response === 'object' && error.response !== null) {
213
+ error = error.response.message === 'email survey sign up failure' ? genericError : error.response.message
214
+ } else {
215
+ error = genericError
238
216
  }
217
+ } else if (error.status === 422) {
218
+ // there's clobbering by nginx on all 422 requests, which is why the response returns a rendered html page instead of the expected JSON
219
+ // this is a temporary workaround to ensure that we are displaying relevant error messages to the users
220
+ error = this.activeForm.invalidInfoError || genericError
221
+ } else {
222
+ error = genericError
223
+ }
224
+ var $errors = this.activeForm.querySelector('.js-errors')
225
+ $errors.innerHTML = error
226
+ $errors.classList.remove(this.jshiddenClass)
227
+ $errors.focus()
228
+ }
239
229
 
240
- function revealInitialPrompt () {
241
- thisModule.prompt.classList.remove(jshiddenClass)
242
- thisModule.prompt.focus()
243
- }
230
+ Feedback.prototype.showFormSuccess = function () {
231
+ for (var i = 0; i < this.promptQuestions.length; i++) {
232
+ this.promptQuestions[i].classList.add(this.jshiddenClass)
244
233
  }
234
+ this.promptSuccessMessage.classList.remove(this.jshiddenClass)
235
+ this.promptSuccessMessage.focus()
245
236
  }
237
+
238
+ Feedback.prototype.revealInitialPrompt = function () {
239
+ this.prompt.classList.remove(this.jshiddenClass)
240
+ this.prompt.focus()
241
+ }
242
+
243
+ Modules.Feedback = Feedback
246
244
  })(window.GOVUK.Modules)