govuk_publishing_components 21.63.0 → 21.65.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/govuk_publishing_components/action-link-arrow--transparent.svg +1 -0
  3. data/app/assets/javascripts/govuk_publishing_components/components/govspeak.js +17 -15
  4. data/app/assets/javascripts/govuk_publishing_components/components/step-by-step-nav.js +402 -340
  5. data/app/assets/javascripts/govuk_publishing_components/dependencies.js +0 -5
  6. data/app/assets/javascripts/govuk_publishing_components/lib.js +1 -0
  7. data/app/assets/javascripts/govuk_publishing_components/lib/govspeak/barchart-enhancement.js +18 -11
  8. data/app/assets/javascripts/govuk_publishing_components/lib/govspeak/magna-charta.js +423 -0
  9. data/app/assets/javascripts/govuk_publishing_components/lib/toggle.js +126 -65
  10. data/app/assets/javascripts/govuk_publishing_components/vendor/polyfills/closest.js +23 -0
  11. data/app/assets/javascripts/govuk_publishing_components/vendor/polyfills/indexOf.js +9 -0
  12. data/app/assets/stylesheets/govuk_publishing_components/components/_action-link.scss +8 -2
  13. data/app/assets/stylesheets/govuk_publishing_components/components/_panel.scss +7 -1
  14. data/app/views/govuk_publishing_components/component_guide/example.html.erb +4 -1
  15. data/app/views/govuk_publishing_components/component_guide/show.html.erb +3 -1
  16. data/app/views/govuk_publishing_components/components/_action_link.html.erb +2 -0
  17. data/app/views/govuk_publishing_components/components/_cookie_banner.html.erb +1 -1
  18. data/app/views/govuk_publishing_components/components/_panel.html.erb +13 -11
  19. data/app/views/govuk_publishing_components/components/_radio.html.erb +3 -1
  20. data/app/views/govuk_publishing_components/components/_search.html.erb +6 -2
  21. data/app/views/govuk_publishing_components/components/_step_by_step_nav_header.html.erb +2 -2
  22. data/app/views/govuk_publishing_components/components/docs/action_link.yml +8 -0
  23. data/app/views/govuk_publishing_components/components/docs/step_by_step_nav_header.yml +3 -1
  24. data/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_priority.rb +19 -5
  25. data/lib/govuk_publishing_components/presenters/contextual_navigation.rb +1 -1
  26. data/lib/govuk_publishing_components/version.rb +1 -1
  27. metadata +6 -3
  28. data/app/assets/javascripts/govuk_publishing_components/vendor/magna-charta.min.js +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca5313136ffde496204e61ad0ff9ac47a3a7fb9bb4b24a04698be2e64acd392f
4
- data.tar.gz: 6d5956d2c5d2dceb4c7386c966b61cd3bb0201acfc591c13b1908a5cdeb0b840
3
+ metadata.gz: c223c076bcecd87fb23721eba8271d89a681ad4a67a11103d14330a3fefd17ac
4
+ data.tar.gz: 69114b477b5b22856acf4378b875bcdb69ba05b4d127eb4c9b5d0dc465f00993
5
5
  SHA512:
6
- metadata.gz: 3988ac7785d2cd680e5a15a8ee039150477d3aae4cf9cb9b8436eafc0a892e5052f07fdfc9a39628667b5a092a2639e019ac821c19893e1c366756ac82a17865
7
- data.tar.gz: 75b96e067b7dadea877d8ee84437653cdfbb088cf90a3eed87ce7618c6635bc22f56c7996a021c8f33e89f49bb607adeae24351bd46bc32f5d59aed97f63639d
6
+ metadata.gz: 616fd5f93cdc4229bc187915bd2021a0ab9b6637aaed0532c0880b7ef12a76ad9f0264e274ca69635c07f84ec121497a3e32157373836f595a8b9159f57087af
7
+ data.tar.gz: 6ee53e65daf9887db6f6acc92bc0d53d6394fd8a9fa6994e51baf0581700679ed7897d32a68d151176b0a0ccedc7f64d37826448cacf69240d92cfe6894884a8
@@ -0,0 +1 @@
1
+ <svg width="39" height="39" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M17.01 6.818l-2.828 2.828 7.853 7.854-22 .066L0 21.5h22.035l-7.853 7.854 2.828 2.828L29.69 19.5zM39 19.5C39 30.27 30.27 39 19.5 39 9.373 39 1.05 31.28.092 21.405A19.737 19.737 0 010 19.5C0 8.73 8.73 0 19.5 0S39 8.73 39 19.5z" fill="#fff500"/></svg>
@@ -2,25 +2,27 @@ window.GOVUK = window.GOVUK || {}
2
2
  window.GOVUK.Modules = window.GOVUK.Modules || {};
3
3
 
4
4
  (function (Modules) {
5
- 'use strict'
5
+ function Govspeak () { }
6
6
 
7
- Modules.Govspeak = function () {
8
- this.start = function ($element) {
9
- if (!$element.hasClass('disable-youtube')) {
10
- this.embedYoutube($element)
11
- }
7
+ Govspeak.prototype.start = function ($module) {
8
+ this.$module = $module[0]
12
9
 
13
- this.createBarcharts($element)
10
+ if (this.$module.className.indexOf('disable-youtube') === -1) {
11
+ this.embedYoutube()
14
12
  }
15
13
 
16
- this.embedYoutube = function ($jqElement) {
17
- var enhancement = new window.GOVUK.GovspeakYoutubeLinkEnhancement($jqElement[0])
18
- enhancement.init()
19
- }
14
+ this.createBarcharts()
15
+ }
20
16
 
21
- this.createBarcharts = function ($element) {
22
- var enhancement = new window.GOVUK.GovspeakBarchartEnhancement($element)
23
- enhancement.init()
24
- }
17
+ Govspeak.prototype.embedYoutube = function () {
18
+ var enhancement = new window.GOVUK.GovspeakYoutubeLinkEnhancement(this.$module)
19
+ enhancement.init()
25
20
  }
21
+
22
+ Govspeak.prototype.createBarcharts = function () {
23
+ var enhancement = new window.GOVUK.GovspeakBarchartEnhancement(this.$module)
24
+ enhancement.init()
25
+ }
26
+
27
+ Modules.Govspeak = Govspeak
26
28
  })(window.GOVUK.Modules)
@@ -1,432 +1,494 @@
1
- /* eslint-env jquery */
1
+ //= require govuk/vendor/polyfills/Element/prototype/classList.js
2
+ //= require ../vendor/polyfills/closest.js
3
+ //= require ../vendor/polyfills/indexOf.js
2
4
 
3
5
  window.GOVUK = window.GOVUK || {}
4
6
  window.GOVUK.Modules = window.GOVUK.Modules || {};
5
7
 
6
8
  (function (Modules) {
7
- 'use strict'
8
-
9
- Modules.Gemstepnav = function () {
10
- var actions = {} // stores text for JS appended elements 'show' and 'hide' on steps, and 'show/hide all' button
11
- var rememberShownStep = false
12
- var stepNavSize
13
- var sessionStoreLink = 'govuk-step-nav-active-link'
14
- var activeLinkClass = 'gem-c-step-nav__list-item--active'
15
- var activeStepClass = 'gem-c-step-nav__step--active'
16
- var activeLinkHref = '#content'
17
- var uniqueId
18
-
19
- this.start = function ($element) {
20
- // Indicate that js has worked
21
- $element.addClass('gem-c-step-nav--active')
22
-
23
- // Prevent FOUC, remove class hiding content
24
- $element.removeClass('js-hidden')
25
-
26
- stepNavSize = $element.hasClass('gem-c-step-nav--large') ? 'Big' : 'Small'
27
- rememberShownStep = !!$element.filter('[data-remember]').length && stepNavSize === 'Big'
28
- var $steps = $element.find('.js-step')
29
- var $stepHeaders = $element.find('.js-toggle-panel')
30
- var totalSteps = $element.find('.js-panel').length
31
- var totalLinks = $element.find('.gem-c-step-nav__link').length
32
- var $showOrHideAllButton
33
-
34
- uniqueId = $element.data('id') || false
35
-
36
- if (uniqueId) {
37
- sessionStoreLink = sessionStoreLink + '_' + uniqueId
38
- }
9
+ function Gemstepnav () { }
10
+
11
+ Gemstepnav.prototype.start = function ($module) {
12
+ this.$module = $module[0]
13
+ this.$module.actions = {} // stores text for JS appended elements 'show' and 'hide' on steps, and 'show/hide all' button
14
+ this.$module.rememberShownStep = false
15
+ this.$module.stepNavSize = false
16
+ this.$module.sessionStoreLink = 'govuk-step-nav-active-link'
17
+ this.$module.activeLinkClass = 'gem-c-step-nav__list-item--active'
18
+ this.$module.activeStepClass = 'gem-c-step-nav__step--active'
19
+ this.$module.activeLinkHref = '#content'
20
+ this.$module.uniqueId = false
21
+
22
+ // Indicate that js has worked
23
+ this.$module.classList.add('gem-c-step-nav--active')
24
+
25
+ // Prevent FOUC, remove class hiding content
26
+ this.$module.classList.remove('js-hidden')
27
+
28
+ this.$module.stepNavSize = this.$module.classList.contains('gem-c-step-nav--large') ? 'Big' : 'Small'
29
+ this.$module.rememberShownStep = !!this.$module.hasAttribute('data-remember') && this.$module.stepNavSize === 'Big'
30
+
31
+ this.$module.steps = this.$module.querySelectorAll('.js-step')
32
+ this.$module.stepHeaders = this.$module.querySelectorAll('.js-toggle-panel')
33
+ this.$module.totalSteps = this.$module.querySelectorAll('.js-panel').length
34
+ this.$module.totalLinks = this.$module.querySelectorAll('.gem-c-step-nav__link').length
35
+ this.$module.showOrHideAllButton = false
36
+
37
+ this.$module.uniqueId = this.$module.getAttribute('data-id') || false
38
+
39
+ if (this.$module.uniqueId) {
40
+ this.$module.sessionStoreLink = this.$module.sessionStoreLink + '_' + this.$module.uniqueId
41
+ }
39
42
 
40
- var stepNavTracker = new StepNavTracker(totalSteps, totalLinks, uniqueId)
43
+ var stepNavTracker = new this.StepNavTracker(this.$module.uniqueId, this.$module.totalSteps, this.$module.totalLinks)
41
44
 
42
- getTextForInsertedElements()
43
- addButtonstoSteps()
44
- addShowHideAllButton()
45
- addShowHideToggle()
46
- addAriaControlsAttrForShowHideAllButton()
45
+ this.getTextForInsertedElements()
46
+ this.addButtonstoSteps()
47
+ this.addShowHideAllButton()
48
+ this.addShowHideToggle()
49
+ this.addAriaControlsAttrForShowHideAllButton()
47
50
 
48
- ensureOnlyOneActiveLink()
49
- showPreviouslyOpenedSteps()
51
+ this.ensureOnlyOneActiveLink()
52
+ this.showPreviouslyOpenedSteps()
50
53
 
51
- bindToggleForSteps(stepNavTracker)
52
- bindToggleShowHideAllButton(stepNavTracker)
53
- bindComponentLinkClicks(stepNavTracker)
54
+ this.bindToggleForSteps(stepNavTracker)
55
+ this.bindToggleShowHideAllButton(stepNavTracker)
56
+ this.bindComponentLinkClicks(stepNavTracker)
57
+ }
54
58
 
55
- function getTextForInsertedElements () {
56
- actions.showText = $element.attr('data-show-text')
57
- actions.hideText = $element.attr('data-hide-text')
58
- actions.showAllText = $element.attr('data-show-all-text')
59
- actions.hideAllText = $element.attr('data-hide-all-text')
60
- }
59
+ Gemstepnav.prototype.getTextForInsertedElements = function () {
60
+ this.$module.actions.showText = this.$module.getAttribute('data-show-text')
61
+ this.$module.actions.hideText = this.$module.getAttribute('data-hide-text')
62
+ this.$module.actions.showAllText = this.$module.getAttribute('data-show-all-text')
63
+ this.$module.actions.hideAllText = this.$module.getAttribute('data-hide-all-text')
64
+ }
61
65
 
62
- function addShowHideAllButton () {
63
- $element.prepend('<div class="gem-c-step-nav__controls"><button aria-expanded="false" class="gem-c-step-nav__button gem-c-step-nav__button--controls js-step-controls-button">' + actions.showAllText + '</button></div>')
64
- }
66
+ Gemstepnav.prototype.addShowHideAllButton = function () {
67
+ var showall = document.createElement('div')
68
+ showall.className = 'gem-c-step-nav__controls'
69
+ showall.innerHTML = '<button aria-expanded="false" class="gem-c-step-nav__button gem-c-step-nav__button--controls js-step-controls-button">' + this.$module.actions.showAllText + '</button>'
65
70
 
66
- function addShowHideToggle () {
67
- $stepHeaders.each(function () {
68
- var linkText = actions.showText // eslint-disable-line no-unused-vars
71
+ var steps = this.$module.querySelectorAll('.gem-c-step-nav__steps')[0]
72
+ this.$module.insertBefore(showall, steps)
69
73
 
70
- if (headerIsOpen($(this))) {
71
- linkText = actions.hideText
72
- }
74
+ this.$module.showOrHideAllButton = this.$module.querySelectorAll('.js-step-controls-button')[0]
75
+ }
73
76
 
74
- if (!$(this).find('.js-toggle-link').length) {
75
- $(this).find('.js-step-title-button').append(
76
- '<span class="gem-c-step-nav__toggle-link js-toggle-link" aria-hidden="true" hidden></span>'
77
- )
78
- }
79
- })
80
- }
77
+ Gemstepnav.prototype.addShowHideToggle = function () {
78
+ for (var i = 0; i < this.$module.stepHeaders.length; i++) {
79
+ var thisel = this.$module.stepHeaders[i]
81
80
 
82
- function headerIsOpen ($stepHeader) {
83
- return (typeof $stepHeader.closest('.js-step').data('show') !== 'undefined')
81
+ if (!thisel.querySelectorAll('.js-toggle-link').length) {
82
+ var span = document.createElement('span')
83
+ span.className = 'gem-c-step-nav__toggle-link js-toggle-link'
84
+ span.setAttribute('aria-hidden', true)
85
+ span.setAttribute('hidden', 'hidden')
86
+ thisel.querySelectorAll('.js-step-title-button')[0].appendChild(span)
84
87
  }
88
+ }
89
+ }
85
90
 
86
- function addAriaControlsAttrForShowHideAllButton () {
87
- var ariaControlsValue = $element.find('.js-panel').first().attr('id')
91
+ Gemstepnav.prototype.headerIsOpen = function (stepHeader) {
92
+ return (typeof stepHeader.parentNode.getAttribute('show') !== 'undefined')
93
+ }
88
94
 
89
- $showOrHideAllButton = $element.find('.js-step-controls-button')
90
- $showOrHideAllButton.attr('aria-controls', ariaControlsValue)
91
- }
95
+ Gemstepnav.prototype.addAriaControlsAttrForShowHideAllButton = function () {
96
+ var ariaControlsValue = this.$module.querySelectorAll('.js-panel')[0].getAttribute('id')
97
+ this.$module.showOrHideAllButton.setAttribute('aria-controls', ariaControlsValue)
98
+ }
92
99
 
93
- // called by show all/hide all, sets all steps accordingly
94
- function setAllStepsShownState (isShown) {
95
- var data = []
100
+ // called by show all/hide all, sets all steps accordingly
101
+ Gemstepnav.prototype.setAllStepsShownState = function (isShown) {
102
+ var data = []
96
103
 
97
- $.each($steps, function () {
98
- var stepView = new StepView($(this))
99
- stepView.setIsShown(isShown)
104
+ for (var i = 0; i < this.$module.steps.length; i++) {
105
+ var stepView = new this.StepView(this.$module.steps[i], this.$module.actions.showText, this.$module.actions.hideText)
106
+ stepView.setIsShown(isShown)
100
107
 
101
- if (isShown) {
102
- data.push($(this).attr('id'))
103
- }
104
- })
105
-
106
- if (isShown) {
107
- saveToSessionStorage(uniqueId, JSON.stringify(data))
108
- } else {
109
- removeFromSessionStorage(uniqueId)
110
- }
108
+ if (isShown) {
109
+ data.push(this.$module.steps[i].getAttribute('id'))
111
110
  }
111
+ }
112
112
 
113
- // called on load, determines whether each step should be open or closed
114
- function showPreviouslyOpenedSteps () {
115
- var data = loadFromSessionStorage(uniqueId) || []
113
+ if (isShown) {
114
+ this.saveToSessionStorage(this.$module.uniqueId, JSON.stringify(data))
115
+ } else {
116
+ this.removeFromSessionStorage(this.$module.uniqueId)
117
+ }
118
+ }
116
119
 
117
- $.each($steps, function () {
118
- var id = $(this).attr('id')
119
- var stepView = new StepView($(this))
120
+ // called on load, determines whether each step should be open or closed
121
+ Gemstepnav.prototype.showPreviouslyOpenedSteps = function () {
122
+ var data = this.loadFromSessionStorage(this.$module.uniqueId) || []
120
123
 
121
- // show the step if it has been remembered or if it has the 'data-show' attribute
122
- if ((rememberShownStep && data.indexOf(id) > -1) || typeof $(this).attr('data-show') !== 'undefined') {
123
- stepView.setIsShown(true)
124
- } else {
125
- stepView.setIsShown(false)
126
- }
127
- })
124
+ for (var i = 0; i < this.$module.steps.length; i++) {
125
+ var thisel = this.$module.steps[i]
126
+ var id = thisel.getAttribute('id')
127
+ var stepView = new this.StepView(thisel, this.$module.actions.showText, this.$module.actions.hideText)
128
+ var shouldBeShown = thisel.hasAttribute('data-show')
128
129
 
129
- if (data.length > 0) {
130
- $showOrHideAllButton.attr('aria-expanded', true)
131
- setShowHideAllText()
132
- }
130
+ // show the step if it has been remembered or if it has the 'data-show' attribute
131
+ if ((this.$module.rememberShownStep && data.indexOf(id) > -1) || (shouldBeShown && shouldBeShown !== 'undefined')) {
132
+ stepView.setIsShown(true)
133
+ } else {
134
+ stepView.setIsShown(false)
133
135
  }
136
+ }
134
137
 
135
- function addButtonstoSteps () {
136
- $.each($steps, function () {
137
- var $step = $(this)
138
- var $title = $step.find('.js-step-title')
139
- var contentId = $step.find('.js-panel').first().attr('id')
138
+ if (data.length > 0) {
139
+ this.$module.showOrHideAllButton.setAttribute('aria-expanded', true)
140
+ this.setShowHideAllText()
141
+ }
142
+ }
140
143
 
141
- $title.wrapInner(
142
- '<span class="js-step-title-text"></span>'
143
- )
144
+ Gemstepnav.prototype.addButtonstoSteps = function () {
145
+ for (var i = 0; i < this.$module.steps.length; i++) {
146
+ var thisel = this.$module.steps[i]
147
+ var title = thisel.querySelectorAll('.js-step-title')[0]
148
+ var contentId = thisel.querySelectorAll('.js-panel')[0].getAttribute('id')
149
+ var titleText = title.textContent || title.innerText // IE8 fallback
144
150
 
145
- $title.wrapInner(
146
- '<button ' +
151
+ title.outerHTML =
152
+ '<span class="js-step-title">' +
153
+ '<button ' +
147
154
  'class="gem-c-step-nav__button gem-c-step-nav__button--title js-step-title-button" ' +
148
155
  'aria-expanded="false" aria-controls="' + contentId + '">' +
149
- '</button>'
150
- )
151
- })
152
- }
156
+ '<span class="js-step-title-text">' + titleText + '</span>' +
157
+ '</button>' +
158
+ '</span>'
159
+ }
160
+ }
153
161
 
154
- function bindToggleForSteps (stepNavTracker) {
155
- $element.find('.js-toggle-panel').click(function (event) {
156
- var $step = $(this).closest('.js-step')
162
+ Gemstepnav.prototype.bindToggleForSteps = function (stepNavTracker) {
163
+ var that = this
164
+ var togglePanels = this.$module.querySelectorAll('.js-toggle-panel')
157
165
 
158
- var stepView = new StepView($step)
159
- stepView.toggle()
166
+ for (var i = 0; i < togglePanels.length; i++) {
167
+ togglePanels[i].addEventListener('click', function (event) {
168
+ var stepView = new that.StepView(this.parentNode, that.$module.actions.showText, that.$module.actions.hideText)
169
+ stepView.toggle()
160
170
 
161
- var stepIsOptional = typeof $step.data('optional') !== 'undefined'
162
- var toggleClick = new StepToggleClick(event, stepView, $steps, stepNavTracker, stepIsOptional)
163
- toggleClick.track()
171
+ var stepIsOptional = this.parentNode.hasAttribute('data-optional')
172
+ var toggleClick = new that.StepToggleClick(event, stepView, stepNavTracker, stepIsOptional, that.$module.stepNavSize)
173
+ toggleClick.trackClick()
164
174
 
165
- setShowHideAllText()
166
- rememberStepState($step)
167
- })
168
- }
175
+ that.setShowHideAllText()
176
+ that.rememberStepState(this.parentNode)
177
+ })
178
+ }
179
+ }
169
180
 
170
- // if the step is open, store its id in session store
171
- // if the step is closed, remove its id from session store
172
- function rememberStepState ($step) {
173
- if (rememberShownStep) {
174
- var data = JSON.parse(loadFromSessionStorage(uniqueId)) || []
175
- var thisstep = $step.attr('id')
176
- var shown = $step.hasClass('step-is-shown')
177
-
178
- if (shown) {
179
- data.push(thisstep)
180
- } else {
181
- var i = data.indexOf(thisstep)
182
- if (i > -1) {
183
- data.splice(i, 1)
184
- }
185
- }
186
- saveToSessionStorage(uniqueId, JSON.stringify(data))
181
+ // if the step is open, store its id in session store
182
+ // if the step is closed, remove its id from session store
183
+ Gemstepnav.prototype.rememberStepState = function (step) {
184
+ if (this.$module.rememberShownStep) {
185
+ var data = JSON.parse(this.loadFromSessionStorage(this.$module.uniqueId)) || []
186
+ var thisstep = step.getAttribute('id')
187
+ var shown = step.classList.contains('step-is-shown')
188
+
189
+ if (shown) {
190
+ data.push(thisstep)
191
+ } else {
192
+ var i = data.indexOf(thisstep)
193
+ if (i > -1) {
194
+ data.splice(i, 1)
187
195
  }
188
196
  }
197
+ this.saveToSessionStorage(this.$module.uniqueId, JSON.stringify(data))
198
+ }
199
+ }
189
200
 
190
- // tracking click events on links in step content
191
- function bindComponentLinkClicks (stepNavTracker) {
192
- $element.find('.js-link').click(function (event) {
193
- var linkClick = new componentLinkClick(event, stepNavTracker, $(this).attr('data-position')) // eslint-disable-line no-new, new-cap
194
- linkClick.track()
195
- var thisLinkHref = $(this).attr('href')
196
-
197
- if ($(this).attr('rel') !== 'external') {
198
- saveToSessionStorage(sessionStoreLink, $(this).attr('data-position'))
199
- }
200
-
201
- if (thisLinkHref === activeLinkHref) {
202
- setOnlyThisLinkActive($(this))
203
- setActiveStepClass()
204
- }
205
- })
206
- }
201
+ // tracking click events on links in step content
202
+ Gemstepnav.prototype.bindComponentLinkClicks = function (stepNavTracker) {
203
+ var jsLinks = this.$module.querySelectorAll('.js-link')
204
+ var that = this
207
205
 
208
- function saveToSessionStorage (key, value) {
209
- window.sessionStorage.setItem(key, value)
210
- }
206
+ for (var i = 0; i < jsLinks.length; i++) {
207
+ jsLinks[i].addEventListener('click', function (event) {
208
+ var dataPosition = this.getAttribute('data-position')
209
+ var linkClick = new that.ComponentLinkClick(event, stepNavTracker, dataPosition, that.$module.stepNavSize)
210
+ linkClick.trackClick()
211
211
 
212
- function loadFromSessionStorage (key) {
213
- return window.sessionStorage.getItem(key)
214
- }
212
+ if (this.getAttribute('rel') !== 'external') {
213
+ that.saveToSessionStorage(that.$module.sessionStoreLink, dataPosition)
214
+ }
215
215
 
216
- function removeFromSessionStorage (key) {
217
- window.sessionStorage.removeItem(key)
218
- }
216
+ if (this.getAttribute('href') === that.$module.activeLinkHref) {
217
+ that.setOnlyThisLinkActive(this)
218
+ that.setActiveStepClass()
219
+ }
220
+ })
221
+ }
222
+ }
219
223
 
220
- function setOnlyThisLinkActive (clicked) {
221
- $element.find('.' + activeLinkClass).removeClass(activeLinkClass)
222
- clicked.parent().addClass(activeLinkClass)
223
- }
224
+ Gemstepnav.prototype.saveToSessionStorage = function (key, value) {
225
+ window.sessionStorage.setItem(key, value)
226
+ }
224
227
 
225
- // if a link occurs more than once in a step nav, the backend doesn't know which one to highlight
226
- // so it gives all those links the 'active' attribute and highlights the last step containing that link
227
- // if the user clicked on one of those links previously, it will be in the session store
228
- // this code ensures only that link and its corresponding step have the highlighting
229
- // otherwise it accepts what the backend has already passed to the component
230
- function ensureOnlyOneActiveLink () {
231
- var $activeLinks = $element.find('.js-list-item.' + activeLinkClass)
228
+ Gemstepnav.prototype.loadFromSessionStorage = function (key, value) {
229
+ return window.sessionStorage.getItem(key)
230
+ }
232
231
 
233
- if ($activeLinks.length <= 1) {
234
- return
235
- }
232
+ Gemstepnav.prototype.removeFromSessionStorage = function (key) {
233
+ window.sessionStorage.removeItem(key)
234
+ }
236
235
 
237
- var lastClicked = loadFromSessionStorage(sessionStoreLink) || $element.find('.' + activeLinkClass).first().attr('data-position')
236
+ Gemstepnav.prototype.setOnlyThisLinkActive = function (clicked) {
237
+ var allActiveLinks = this.$module.querySelectorAll('.' + this.$module.activeLinkClass)
238
+ for (var i = 0; i < allActiveLinks.length; i++) {
239
+ allActiveLinks[i].classList.remove(this.$module.activeLinkClass)
240
+ }
241
+ clicked.parentNode.classList.add(this.$module.activeLinkClass)
242
+ }
238
243
 
239
- // it's possible for the saved link position value to not match any of the currently duplicate highlighted links
240
- // so check this otherwise it'll take the highlighting off all of them
241
- if (!$element.find('.js-link[data-position="' + lastClicked + '"]').parent().hasClass(activeLinkClass)) {
242
- lastClicked = $element.find('.' + activeLinkClass).first().find('.js-link').attr('data-position')
243
- }
244
- removeActiveStateFromAllButCurrent($activeLinks, lastClicked)
245
- setActiveStepClass()
246
- }
244
+ // if a link occurs more than once in a step nav, the backend doesn't know which one to highlight
245
+ // so it gives all those links the 'active' attribute and highlights the last step containing that link
246
+ // if the user clicked on one of those links previously, it will be in the session store
247
+ // this code ensures only that link and its corresponding step have the highlighting
248
+ // otherwise it accepts what the backend has already passed to the component
249
+ Gemstepnav.prototype.ensureOnlyOneActiveLink = function () {
250
+ var activeLinks = this.$module.querySelectorAll('.js-list-item.' + this.$module.activeLinkClass)
247
251
 
248
- function removeActiveStateFromAllButCurrent ($activeLinks, current) {
249
- $activeLinks.each(function () {
250
- if ($(this).find('.js-link').attr('data-position').toString() !== current.toString()) {
251
- $(this).removeClass(activeLinkClass)
252
- $(this).find('.visuallyhidden').remove()
253
- }
254
- })
255
- }
252
+ if (activeLinks.length <= 1) {
253
+ return
254
+ }
256
255
 
257
- function setActiveStepClass () {
258
- $element.find('.' + activeStepClass).removeClass(activeStepClass).removeAttr('data-show')
259
- $element.find('.' + activeLinkClass).closest('.gem-c-step-nav__step').addClass(activeStepClass).attr('data-show', '')
260
- }
256
+ var loaded = this.loadFromSessionStorage(this.$module.sessionStoreLink)
257
+ var activeParent = this.$module.querySelectorAll('.' + this.$module.activeLinkClass)[0]
258
+ var activeChild = activeParent.firstChild
259
+ var foundLink = activeChild.getAttribute('data-position')
260
+ var lastClicked = loaded || foundLink // the value saved has priority
261
261
 
262
- function bindToggleShowHideAllButton (stepNavTracker) {
263
- $showOrHideAllButton = $element.find('.js-step-controls-button')
264
- $showOrHideAllButton.on('click', function () {
265
- var shouldshowAll
266
-
267
- if ($showOrHideAllButton.text() === actions.showAllText) {
268
- $showOrHideAllButton.text(actions.hideAllText)
269
- $element.find('.js-toggle-link').html(actions.hideText)
270
- shouldshowAll = true
271
-
272
- stepNavTracker.track('pageElementInteraction', 'stepNavAllShown', {
273
- label: actions.showAllText + ': ' + stepNavSize
274
- })
275
- } else {
276
- $showOrHideAllButton.text(actions.showAllText)
277
- $element.find('.js-toggle-link').html(actions.showText)
278
- shouldshowAll = false
279
-
280
- stepNavTracker.track('pageElementInteraction', 'stepNavAllHidden', {
281
- label: actions.hideAllText + ': ' + stepNavSize
282
- })
283
- }
284
-
285
- setAllStepsShownState(shouldshowAll)
286
- $showOrHideAllButton.attr('aria-expanded', shouldshowAll)
287
- setShowHideAllText()
288
-
289
- return false
290
- })
262
+ // it's possible for the saved link position value to not match any of the currently duplicate highlighted links
263
+ // so check this otherwise it'll take the highlighting off all of them
264
+ var checkLink = this.$module.querySelectorAll('[data-position="' + lastClicked + '"]')[0]
265
+
266
+ if (checkLink) {
267
+ if (!checkLink.parentNode.classList.contains(this.$module.activeLinkClass)) {
268
+ lastClicked = checkLink
291
269
  }
270
+ } else {
271
+ lastClicked = foundLink
272
+ }
273
+
274
+ this.removeActiveStateFromAllButCurrent(activeLinks, lastClicked)
275
+ this.setActiveStepClass()
276
+ }
292
277
 
293
- function setShowHideAllText () {
294
- var shownSteps = $element.find('.step-is-shown').length
295
- // Find out if the number of is-opens == total number of steps
296
- if (shownSteps === totalSteps) {
297
- $showOrHideAllButton.text(actions.hideAllText)
298
- } else {
299
- $showOrHideAllButton.text(actions.showAllText)
278
+ Gemstepnav.prototype.removeActiveStateFromAllButCurrent = function (activeLinks, current) {
279
+ for (var i = 0; i < activeLinks.length; i++) {
280
+ var thisel = activeLinks[i]
281
+ if (thisel.querySelectorAll('.js-link')[0].getAttribute('data-position').toString() !== current.toString()) {
282
+ thisel.classList.remove(this.$module.activeLinkClass)
283
+ var visuallyHidden = thisel.querySelectorAll('.visuallyhidden')
284
+ if (visuallyHidden.length) {
285
+ visuallyHidden[0].parentNode.removeChild(visuallyHidden[0])
300
286
  }
301
287
  }
302
288
  }
289
+ }
303
290
 
304
- function StepView ($stepElement) {
305
- var $titleLink = $stepElement.find('.js-step-title-button')
306
- var $stepContent = $stepElement.find('.js-panel')
291
+ Gemstepnav.prototype.setActiveStepClass = function () {
292
+ // remove the 'active/open' state from all steps
293
+ var allActiveSteps = this.$module.querySelectorAll('.' + this.$module.activeStepClass)
294
+ for (var i = 0; i < allActiveSteps.length; i++) {
295
+ allActiveSteps[i].classList.remove(this.$module.activeStepClass)
296
+ allActiveSteps[i].removeAttribute('data-show')
297
+ }
307
298
 
308
- this.title = $stepElement.find('.js-step-title-text').text().trim()
309
- this.element = $stepElement
299
+ // find the current page link and apply 'active/open' state to parent step
300
+ var activeLink = this.$module.querySelectorAll('.' + this.$module.activeLinkClass)[0]
301
+ if (activeLink) {
302
+ var activeStep = activeLink.closest('.gem-c-step-nav__step')
303
+ activeStep.classList.add(this.$module.activeStepClass)
304
+ activeStep.setAttribute('data-show', '')
305
+ }
306
+ }
310
307
 
311
- this.show = show
312
- this.hide = hide
313
- this.toggle = toggle
314
- this.setIsShown = setIsShown
315
- this.isShown = isShown
316
- this.isHidden = isHidden
317
- this.numberOfContentItems = numberOfContentItems
308
+ Gemstepnav.prototype.bindToggleShowHideAllButton = function (stepNavTracker) {
309
+ var that = this
318
310
 
319
- function show () {
320
- setIsShown(true)
321
- }
311
+ this.$module.showOrHideAllButton.addEventListener('click', function (event) {
312
+ var shouldshowAll
313
+ var showHideTexts = that.$module.querySelectorAll('.js-toggle-link')
314
+ var textContent = this.textContent || this.innerText
322
315
 
323
- function hide () {
324
- setIsShown(false)
325
- }
316
+ if (textContent === that.$module.actions.showAllText) {
317
+ that.$module.showOrHideAllButton.textContent = that.$module.actions.hideAllText
318
+ for (var i = 0; i < showHideTexts.length; i++) {
319
+ showHideTexts[i].innerHTML = that.$module.actions.hideText
320
+ }
321
+ shouldshowAll = true
326
322
 
327
- function toggle () {
328
- setIsShown(isHidden())
329
- }
323
+ stepNavTracker.trackClick('pageElementInteraction', 'stepNavAllShown', {
324
+ label: that.$module.actions.showAllText + ': ' + that.$module.stepNavSize
325
+ })
326
+ } else {
327
+ that.$module.showOrHideAllButton.textContent = that.$module.actions.showAllText
328
+ for (var j = 0; j < showHideTexts.length; j++) {
329
+ showHideTexts[j].innerHTML = that.$module.actions.showText
330
+ }
331
+ shouldshowAll = false
330
332
 
331
- function setIsShown (isShown) {
332
- $stepElement.toggleClass('step-is-shown', isShown)
333
- $stepContent.toggleClass('js-hidden', !isShown)
334
- $titleLink.attr('aria-expanded', isShown)
335
- $stepElement.find('.js-toggle-link').html(isShown ? actions.hideText : actions.showText)
333
+ stepNavTracker.trackClick('pageElementInteraction', 'stepNavAllHidden', {
334
+ label: that.$module.actions.hideAllText + ': ' + that.$module.stepNavSize
335
+ })
336
336
  }
337
337
 
338
- function isShown () {
339
- return $stepElement.hasClass('step-is-shown')
340
- }
338
+ that.setAllStepsShownState(shouldshowAll)
339
+ that.$module.showOrHideAllButton.setAttribute('aria-expanded', shouldshowAll)
340
+ that.setShowHideAllText()
341
341
 
342
- function isHidden () {
343
- return !isShown()
344
- }
342
+ return false
343
+ })
344
+ }
345
345
 
346
- function numberOfContentItems () {
347
- return $stepContent.find('.js-link').length
348
- }
346
+ Gemstepnav.prototype.setShowHideAllText = function () {
347
+ var shownSteps = this.$module.querySelectorAll('.step-is-shown').length
348
+ // Find out if the number of is-opens == total number of steps
349
+ if (shownSteps === this.$module.totalSteps) {
350
+ this.$module.showOrHideAllButton.textContent = this.$module.actions.hideAllText
351
+ } else {
352
+ this.$module.showOrHideAllButton.textContent = this.$module.actions.showAllText
349
353
  }
354
+ }
350
355
 
351
- function StepToggleClick (event, stepView, $steps, stepNavTracker, stepIsOptional) {
352
- this.track = trackClick
353
- var $target = $(event.target)
356
+ Gemstepnav.prototype.StepView = function (stepElement, showText, hideText) {
357
+ this.stepElement = stepElement
358
+ this.stepContent = this.stepElement.querySelectorAll('.js-panel')[0]
359
+ this.titleButton = this.stepElement.querySelectorAll('.js-step-title-button')[0]
360
+ var textElement = this.stepElement.querySelectorAll('.js-step-title-text')[0]
361
+ this.title = textElement.textContent || textElement.innerText
362
+ this.title = this.title.replace(/^\s+|\s+$/g, '') // this is 'trim' but supporting IE8
363
+ this.showText = showText
364
+ this.hideText = hideText
365
+
366
+ this.show = function () {
367
+ this.setIsShown(true)
368
+ }
354
369
 
355
- function trackClick () {
356
- var trackingOptions = { label: trackingLabel(), dimension28: stepView.numberOfContentItems().toString() }
357
- stepNavTracker.track('pageElementInteraction', trackingAction(), trackingOptions)
358
- }
370
+ this.hide = function () {
371
+ this.setIsShown(false)
372
+ }
359
373
 
360
- function trackingLabel () {
361
- return $target.closest('.js-toggle-panel').attr('data-position') + ' - ' + stepView.title + ' - ' + locateClickElement() + ': ' + stepNavSize + isOptional()
362
- }
374
+ this.toggle = function () {
375
+ this.setIsShown(this.isHidden())
376
+ }
363
377
 
364
- // returns index of the clicked step in the overall number of steps
365
- function stepIndex () { // eslint-disable-line no-unused-vars
366
- return $steps.index(stepView.element) + 1
378
+ this.setIsShown = function (isShown) {
379
+ if (isShown) {
380
+ this.stepElement.classList.add('step-is-shown')
381
+ this.stepContent.classList.remove('js-hidden')
382
+ } else {
383
+ this.stepElement.classList.remove('step-is-shown')
384
+ this.stepContent.classList.add('js-hidden')
367
385
  }
368
386
 
369
- function trackingAction () {
370
- return (stepView.isHidden() ? 'stepNavHidden' : 'stepNavShown')
371
- }
387
+ this.titleButton.setAttribute('aria-expanded', isShown)
388
+ var showHideText = this.stepElement.querySelectorAll('.js-toggle-link')[0]
389
+ showHideText.innerHTML = isShown ? this.hideText : this.showText
390
+ }
372
391
 
373
- function locateClickElement () {
374
- if (clickedOnIcon()) {
375
- return iconType() + ' click'
376
- } else if (clickedOnHeading()) {
377
- return 'Heading click'
378
- } else {
379
- return 'Elsewhere click'
380
- }
381
- }
392
+ this.isShown = function () {
393
+ return this.stepElement.classList.contains('step-is-shown')
394
+ }
382
395
 
383
- function clickedOnIcon () {
384
- return $target.hasClass('js-toggle-link')
385
- }
396
+ this.isHidden = function () {
397
+ return !this.isShown()
398
+ }
386
399
 
387
- function clickedOnHeading () {
388
- return $target.hasClass('js-step-title-text')
389
- }
400
+ this.numberOfContentItems = function () {
401
+ return this.stepContent.querySelectorAll('.js-link').length
402
+ }
403
+ }
390
404
 
391
- function iconType () {
392
- return (stepView.isHidden() ? 'Minus' : 'Plus')
393
- }
405
+ Gemstepnav.prototype.StepToggleClick = function (event, stepView, stepNavTracker, stepIsOptional, stepNavSize) {
406
+ this.target = event.target
407
+ this.stepIsOptional = stepIsOptional
408
+ this.stepNavSize = stepNavSize
409
+
410
+ this.trackClick = function () {
411
+ var trackingOptions = { label: this.trackingLabel(), dimension28: stepView.numberOfContentItems().toString() }
412
+ stepNavTracker.trackClick('pageElementInteraction', this.trackingAction(), trackingOptions)
413
+ }
414
+
415
+ this.trackingLabel = function () {
416
+ var clickedNearbyToggle = this.target.closest('.js-step').querySelectorAll('.js-toggle-panel')[0]
417
+ return clickedNearbyToggle.getAttribute('data-position') + ' - ' + stepView.title + ' - ' + this.locateClickElement() + ': ' + this.stepNavSize + this.isOptional()
418
+ }
419
+
420
+ // returns index of the clicked step in the overall number of steps
421
+ this.stepIndex = function () { // eslint-disable-line no-unused-vars
422
+ return this.$module.steps.index(stepView.element) + 1
423
+ }
424
+
425
+ this.trackingAction = function () {
426
+ return (stepView.isHidden() ? 'stepNavHidden' : 'stepNavShown')
427
+ }
394
428
 
395
- function isOptional () {
396
- return (stepIsOptional ? ' ; optional' : '')
429
+ this.locateClickElement = function () {
430
+ if (this.clickedOnIcon()) {
431
+ return this.iconType() + ' click'
432
+ } else if (this.clickedOnHeading()) {
433
+ return 'Heading click'
434
+ } else {
435
+ return 'Elsewhere click'
397
436
  }
398
437
  }
399
438
 
400
- function componentLinkClick (event, stepNavTracker, linkPosition) {
401
- this.track = trackClick
439
+ this.clickedOnIcon = function () {
440
+ return this.target.classList.contains('js-toggle-link')
441
+ }
402
442
 
403
- function trackClick () {
404
- var trackingOptions = { label: $(event.target).attr('href') + ' : ' + stepNavSize }
405
- var dimension28 = $(event.target).closest('.gem-c-step-nav__list').attr('data-length')
443
+ this.clickedOnHeading = function () {
444
+ return this.target.classList.contains('js-step-title-text')
445
+ }
406
446
 
407
- if (dimension28) {
408
- trackingOptions.dimension28 = dimension28
409
- }
447
+ this.iconType = function () {
448
+ return (stepView.isHidden() ? 'Minus' : 'Plus')
449
+ }
450
+
451
+ this.isOptional = function () {
452
+ return (this.stepIsOptional ? ' ; optional' : '')
453
+ }
454
+ }
455
+
456
+ Gemstepnav.prototype.ComponentLinkClick = function (event, stepNavTracker, linkPosition, size) {
457
+ this.size = size
458
+ this.target = event.target
410
459
 
411
- stepNavTracker.track('stepNavLinkClicked', linkPosition, trackingOptions)
460
+ this.trackClick = function () {
461
+ var trackingOptions = { label: this.target.getAttribute('href') + ' : ' + this.size }
462
+ var dimension28 = this.target.closest('.gem-c-step-nav__list').getAttribute('data-length')
463
+
464
+ if (dimension28) {
465
+ trackingOptions.dimension28 = dimension28
412
466
  }
467
+
468
+ stepNavTracker.trackClick('stepNavLinkClicked', linkPosition, trackingOptions)
413
469
  }
470
+ }
414
471
 
415
- // A helper that sends a custom event request to Google Analytics if
416
- // the GOVUK module is setup
417
- function StepNavTracker (totalSteps, totalLinks, uniqueId) {
418
- this.track = function (category, action, options) {
419
- // dimension26 records the total number of expand/collapse steps in this step nav
420
- // dimension27 records the total number of links in this step nav
421
- // dimension28 records the number of links in the step that was shown/hidden (handled in click event)
422
- if (window.GOVUK.analytics && window.GOVUK.analytics.trackEvent) {
423
- options = options || {}
424
- options.dimension26 = options.dimension26 || totalSteps.toString()
425
- options.dimension27 = options.dimension27 || totalLinks.toString()
426
- options.dimension96 = options.dimension96 || uniqueId
427
- window.GOVUK.analytics.trackEvent(category, action, options)
428
- }
472
+ // A helper that sends a custom event request to Google Analytics if
473
+ // the GOVUK module is setup
474
+ Gemstepnav.prototype.StepNavTracker = function (uniqueId, totalSteps, totalLinks) {
475
+ this.totalSteps = totalSteps
476
+ this.totalLinks = totalLinks
477
+ this.uniqueId = uniqueId
478
+
479
+ this.trackClick = function (category, action, options) {
480
+ // dimension26 records the total number of expand/collapse steps in this step nav
481
+ // dimension27 records the total number of links in this step nav
482
+ // dimension28 records the number of links in the step that was shown/hidden (handled in click event)
483
+ if (window.GOVUK.analytics && window.GOVUK.analytics.trackEvent) {
484
+ options = options || {}
485
+ options.dimension26 = options.dimension26 || this.totalSteps.toString()
486
+ options.dimension27 = options.dimension27 || this.totalLinks.toString()
487
+ options.dimension96 = options.dimension96 || this.uniqueId
488
+ window.GOVUK.analytics.trackEvent(category, action, options)
429
489
  }
430
490
  }
431
491
  }
492
+
493
+ Modules.Gemstepnav = Gemstepnav
432
494
  })(window.GOVUK.Modules)