govuk_publishing_components 24.13.2 → 24.14.1

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