govuk_publishing_components 35.15.5 → 35.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/config/govuk_publishing_components_manifest.js +1 -0
- data/app/assets/images/option-select/input-icon.svg +3 -0
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/ga4-page-views.js +19 -1
- data/app/assets/javascripts/govuk_publishing_components/analytics-ga4/pii-remover.js +1 -1
- data/app/assets/javascripts/govuk_publishing_components/components/option-select.js +312 -0
- data/app/assets/stylesheets/govuk_publishing_components/_all_components.scss +1 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/_image-card.scss +26 -0
- data/app/assets/stylesheets/govuk_publishing_components/components/_option-select.scss +172 -0
- data/app/views/govuk_publishing_components/components/_image_card.html.erb +8 -2
- data/app/views/govuk_publishing_components/components/_option_select.html.erb +71 -0
- data/app/views/govuk_publishing_components/components/docs/image_card.yml +13 -0
- data/app/views/govuk_publishing_components/components/docs/option_select.yml +343 -0
- data/config/locales/ar.yml +4 -0
- data/config/locales/az.yml +4 -0
- data/config/locales/be.yml +4 -0
- data/config/locales/bg.yml +4 -0
- data/config/locales/bn.yml +4 -0
- data/config/locales/cs.yml +4 -0
- data/config/locales/cy.yml +4 -0
- data/config/locales/da.yml +4 -0
- data/config/locales/de.yml +4 -0
- data/config/locales/dr.yml +4 -0
- data/config/locales/el.yml +4 -0
- data/config/locales/en.yml +4 -0
- data/config/locales/es-419.yml +4 -0
- data/config/locales/es.yml +4 -0
- data/config/locales/et.yml +4 -0
- data/config/locales/fa.yml +4 -0
- data/config/locales/fi.yml +4 -0
- data/config/locales/fr.yml +4 -0
- data/config/locales/gd.yml +4 -0
- data/config/locales/gu.yml +4 -0
- data/config/locales/he.yml +4 -0
- data/config/locales/hi.yml +4 -0
- data/config/locales/hr.yml +4 -0
- data/config/locales/hu.yml +4 -0
- data/config/locales/hy.yml +4 -0
- data/config/locales/id.yml +4 -0
- data/config/locales/is.yml +4 -0
- data/config/locales/it.yml +4 -0
- data/config/locales/ja.yml +4 -0
- data/config/locales/ka.yml +4 -0
- data/config/locales/kk.yml +4 -0
- data/config/locales/ko.yml +4 -0
- data/config/locales/lt.yml +4 -0
- data/config/locales/lv.yml +4 -0
- data/config/locales/ms.yml +4 -0
- data/config/locales/mt.yml +4 -0
- data/config/locales/nl.yml +4 -0
- data/config/locales/no.yml +4 -0
- data/config/locales/pa-pk.yml +4 -0
- data/config/locales/pa.yml +4 -0
- data/config/locales/pl.yml +4 -0
- data/config/locales/ps.yml +4 -0
- data/config/locales/pt.yml +4 -0
- data/config/locales/ro.yml +4 -0
- data/config/locales/ru.yml +4 -0
- data/config/locales/si.yml +4 -0
- data/config/locales/sk.yml +4 -0
- data/config/locales/sl.yml +4 -0
- data/config/locales/so.yml +4 -0
- data/config/locales/sq.yml +4 -0
- data/config/locales/sr.yml +4 -0
- data/config/locales/sv.yml +4 -0
- data/config/locales/sw.yml +4 -0
- data/config/locales/ta.yml +4 -0
- data/config/locales/th.yml +4 -0
- data/config/locales/tk.yml +4 -0
- data/config/locales/tr.yml +4 -0
- data/config/locales/uk.yml +4 -0
- data/config/locales/ur.yml +4 -0
- data/config/locales/uz.yml +4 -0
- data/config/locales/vi.yml +4 -0
- data/config/locales/zh-hk.yml +4 -0
- data/config/locales/zh-tw.yml +4 -0
- data/config/locales/zh.yml +4 -0
- data/lib/govuk_publishing_components/presenters/image_card_helper.rb +6 -2
- data/lib/govuk_publishing_components/version.rb +1 -1
- data/node_modules/axe-core/axe.js +6 -6
- data/node_modules/axe-core/axe.min.js +2 -2
- data/node_modules/axe-core/locales/_template.json +4 -4
- data/node_modules/axe-core/package.json +1 -1
- data/node_modules/axe-core/sri-history.json +4 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d631949b7bdb6aa90aff397986118f929cbae4071ef96b3a623c123c6496224d
|
4
|
+
data.tar.gz: ef75a103619c27bc964664673a17475579132d0b909e254fce0afcc6316256d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '01786b90a26218b6b5dff054852d4e67a77f36d307029ff6fd03f8b15cd005e9264f8719a03f78f05dc776f284c24c972eb6101940e8afd41a44a696c3b404f5'
|
7
|
+
data.tar.gz: 775eb1304962e2349b3e19c8ce7acfb92dc927443a7a01253692909c174f6b5e196129d40104f773794b2ac8e1674e0c65361e605808910f01163b9d69ad5f6a
|
@@ -60,6 +60,7 @@
|
|
60
60
|
//= link govuk_publishing_components/components/_metadata.css
|
61
61
|
//= link govuk_publishing_components/components/_modal-dialogue.css
|
62
62
|
//= link govuk_publishing_components/components/_notice.css
|
63
|
+
//= link govuk_publishing_components/components/_option-select.css
|
63
64
|
//= link govuk_publishing_components/components/_organisation-logo.css
|
64
65
|
//= link govuk_publishing_components/components/_panel.css
|
65
66
|
//= link govuk_publishing_components/components/_phase-banner.css
|
@@ -0,0 +1,3 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="40" height="40">
|
2
|
+
<path d="M25.7 24.8L21.9 21c.7-1 1.1-2.2 1.1-3.5 0-3.6-2.9-6.5-6.5-6.5S10 13.9 10 17.5s2.9 6.5 6.5 6.5c1.6 0 3-.6 4.1-1.5l3.7 3.7 1.4-1.4zM12 17.5c0-2.5 2-4.5 4.5-4.5s4.5 2 4.5 4.5-2 4.5-4.5 4.5-4.5-2-4.5-4.5z" fill="currentColor" />
|
3
|
+
</svg>
|
@@ -59,7 +59,8 @@ window.GOVUK.analyticsGa4.analyticsModules = window.GOVUK.analyticsGa4.analytics
|
|
59
59
|
devolved_nations_banner: this.getElementAttribute('data-ga4-devolved-nations-banner') || undefined,
|
60
60
|
cookie_banner: document.querySelector('[data-ga4-cookie-banner]') ? 'true' : undefined,
|
61
61
|
intervention: this.getInterventionPresence(),
|
62
|
-
query_string: this.getQueryString()
|
62
|
+
query_string: this.getQueryString(),
|
63
|
+
search_term: this.getSearchTerm()
|
63
64
|
}
|
64
65
|
}
|
65
66
|
window.GOVUK.analyticsGa4.core.sendData(data)
|
@@ -74,6 +75,23 @@ window.GOVUK.analyticsGa4.analyticsModules = window.GOVUK.analyticsGa4.analytics
|
|
74
75
|
return window.location.search
|
75
76
|
},
|
76
77
|
|
78
|
+
getSearchTerm: function () {
|
79
|
+
var queryString = this.getSearch()
|
80
|
+
|
81
|
+
if (!queryString) {
|
82
|
+
return undefined
|
83
|
+
}
|
84
|
+
|
85
|
+
var searchTerm = queryString.match(/keywords=([^&]*)/)
|
86
|
+
if (!searchTerm) {
|
87
|
+
return undefined
|
88
|
+
}
|
89
|
+
|
90
|
+
searchTerm = searchTerm[0].replace('keywords=', '')
|
91
|
+
searchTerm = this.PIIRemover.stripPIIWithOverride(searchTerm, true, true)
|
92
|
+
return searchTerm
|
93
|
+
},
|
94
|
+
|
77
95
|
getQueryString: function () {
|
78
96
|
var queryString = this.getSearch()
|
79
97
|
if (queryString) {
|
@@ -2,7 +2,7 @@
|
|
2
2
|
'use strict'
|
3
3
|
|
4
4
|
var GOVUK = global.GOVUK || {}
|
5
|
-
var EMAIL_PATTERN = /[^\s
|
5
|
+
var EMAIL_PATTERN = /[^\s=/?&#+]+(?:@|%40)[^\s=/?&+]+/g
|
6
6
|
var POSTCODE_PATTERN = /\b[A-PR-UWYZ][A-HJ-Z]?[0-9][0-9A-HJKMNPR-Y]?(?:[\s+]|%20)*[0-9](?!refund)[ABD-HJLNPQ-Z]{2,3}\b/gi
|
7
7
|
var DATE_PATTERN_NUMERIC = /\d{4}(-?)\d{2}(-?)\d{2}/g
|
8
8
|
var DATE_PATTERN_STRING = /\d{1,2}\s(January|February|March|April|May|June|July|August|September|October|November|December)\s\d{4}/g
|
@@ -0,0 +1,312 @@
|
|
1
|
+
window.GOVUK = window.GOVUK || {}
|
2
|
+
window.GOVUK.Modules = window.GOVUK.Modules || {};
|
3
|
+
|
4
|
+
(function (Modules) {
|
5
|
+
/* This JavaScript provides two functional enhancements to option-select components:
|
6
|
+
1) A count that shows how many results have been checked in the option-container
|
7
|
+
2) Open/closing of the list of checkboxes
|
8
|
+
*/
|
9
|
+
function OptionSelect ($module) {
|
10
|
+
this.$optionSelect = $module
|
11
|
+
this.$options = this.$optionSelect.querySelectorAll("input[type='checkbox']")
|
12
|
+
this.$optionsContainer = this.$optionSelect.querySelector('.js-options-container')
|
13
|
+
this.$optionList = this.$optionsContainer.querySelector('.js-auto-height-inner')
|
14
|
+
this.$allCheckboxes = this.$optionsContainer.querySelectorAll('.govuk-checkboxes__item')
|
15
|
+
this.hasFilter = this.$optionSelect.getAttribute('data-filter-element') || ''
|
16
|
+
|
17
|
+
this.checkedCheckboxes = []
|
18
|
+
|
19
|
+
this.mq = window.matchMedia('(min-width: 641px)')
|
20
|
+
this.isClosedOnLoad = this.$optionSelect.getAttribute('data-closed-on-load')
|
21
|
+
this.isClosedOnLoadMobile = this.$optionSelect.getAttribute('data-closed-on-load-mobile')
|
22
|
+
}
|
23
|
+
|
24
|
+
OptionSelect.prototype.init = function () {
|
25
|
+
if (this.hasFilter.length) {
|
26
|
+
var filterEl = document.createElement('div')
|
27
|
+
filterEl.innerHTML = this.hasFilter
|
28
|
+
|
29
|
+
var optionSelectFilter = document.createElement('div')
|
30
|
+
optionSelectFilter.classList.add('gem-c-option-select__filter')
|
31
|
+
optionSelectFilter.innerHTML = filterEl.childNodes[0].nodeValue
|
32
|
+
|
33
|
+
this.$optionsContainer.parentNode.insertBefore(optionSelectFilter, this.$optionsContainer)
|
34
|
+
|
35
|
+
this.$filter = this.$optionSelect.querySelector('input[name="option-select-filter"]')
|
36
|
+
this.$filterCount = document.getElementById(this.$filter.getAttribute('aria-describedby'))
|
37
|
+
this.filterTextSingle = ' ' + this.$filterCount.getAttribute('data-single')
|
38
|
+
this.filterTextMultiple = ' ' + this.$filterCount.getAttribute('data-multiple')
|
39
|
+
this.filterTextSelected = ' ' + this.$filterCount.getAttribute('data-selected')
|
40
|
+
this.checkboxLabels = []
|
41
|
+
this.filterTimeout = 0
|
42
|
+
|
43
|
+
this.getAllCheckedCheckboxes()
|
44
|
+
for (var i = 0; i < this.$allCheckboxes.length; i++) {
|
45
|
+
this.checkboxLabels.push(this.cleanString(this.$allCheckboxes[i].textContent))
|
46
|
+
}
|
47
|
+
|
48
|
+
this.$filter.addEventListener('keyup', this.typeFilterText.bind(this))
|
49
|
+
}
|
50
|
+
|
51
|
+
// Attach listener to update checked count
|
52
|
+
this.$optionsContainer.querySelector('.gem-c-checkboxes__list').addEventListener('change', this.updateCheckedCount.bind(this))
|
53
|
+
|
54
|
+
// Replace div.container-head with a button
|
55
|
+
this.replaceHeadingSpanWithButton()
|
56
|
+
|
57
|
+
// Add js-collapsible class to parent for CSS
|
58
|
+
this.$optionSelect.classList.add('js-collapsible')
|
59
|
+
|
60
|
+
// Add open/close listeners
|
61
|
+
var button = this.$optionSelect.querySelector('.js-container-button')
|
62
|
+
button.addEventListener('click', this.toggleOptionSelect.bind(this))
|
63
|
+
|
64
|
+
// Toggle option visibility depending on screen size (min-width: 641px) and
|
65
|
+
// presence of any 'closed' properties (`data-closed-on-load`, `data-closed-on-load-mobile`).
|
66
|
+
// See https://github.com/alphagov/govuk-frontend/blob/main/packages/govuk-frontend/src/govuk/settings/_media-queries.scss#L10-L14
|
67
|
+
if (this.mq.matches) {
|
68
|
+
this.toggleVisibility(true)
|
69
|
+
} else {
|
70
|
+
this.toggleVisibility(false)
|
71
|
+
}
|
72
|
+
|
73
|
+
var checkedString = this.checkedString()
|
74
|
+
if (checkedString) {
|
75
|
+
this.attachCheckedCounter(checkedString)
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
OptionSelect.prototype.toggleVisibility = function (isTabletOrLarger) {
|
80
|
+
if (isTabletOrLarger) {
|
81
|
+
if (this.isClosedOnLoad === 'true') {
|
82
|
+
this.close()
|
83
|
+
} else {
|
84
|
+
this.setupHeight()
|
85
|
+
}
|
86
|
+
} else {
|
87
|
+
if (this.isClosedOnLoadMobile === 'true' || this.isClosedOnLoad === 'true') {
|
88
|
+
this.close()
|
89
|
+
} else {
|
90
|
+
this.setContainerHeight(201)
|
91
|
+
}
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
OptionSelect.prototype.typeFilterText = function (event) {
|
96
|
+
event.stopPropagation()
|
97
|
+
var ENTER_KEY = 13
|
98
|
+
|
99
|
+
if (event.keyCode !== ENTER_KEY) {
|
100
|
+
clearTimeout(this.filterTimeout)
|
101
|
+
this.filterTimeout = setTimeout(
|
102
|
+
function () { this.doFilter(this) }.bind(this),
|
103
|
+
300
|
104
|
+
)
|
105
|
+
} else {
|
106
|
+
event.preventDefault() // prevents finder forms from being submitted when user presses ENTER
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
OptionSelect.prototype.cleanString = function cleanString (text) {
|
111
|
+
text = text.replace(/&/g, 'and')
|
112
|
+
text = text.replace(/[’',:–-]/g, '') // remove punctuation characters
|
113
|
+
text = text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // escape special characters
|
114
|
+
return text.trim().replace(/\s\s+/g, ' ').toLowerCase() // replace multiple spaces with one
|
115
|
+
}
|
116
|
+
|
117
|
+
OptionSelect.prototype.getAllCheckedCheckboxes = function getAllCheckedCheckboxes () {
|
118
|
+
this.checkedCheckboxes = []
|
119
|
+
|
120
|
+
for (var i = 0; i < this.$options.length; i++) {
|
121
|
+
if (this.$options[i].checked) {
|
122
|
+
this.checkedCheckboxes.push(i)
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
OptionSelect.prototype.doFilter = function doFilter (obj) {
|
128
|
+
var filterBy = obj.cleanString(obj.$filter.value)
|
129
|
+
var showCheckboxes = obj.checkedCheckboxes.slice()
|
130
|
+
var i = 0
|
131
|
+
|
132
|
+
for (i = 0; i < obj.$allCheckboxes.length; i++) {
|
133
|
+
if (showCheckboxes.indexOf(i) === -1 && obj.checkboxLabels[i].search(filterBy) !== -1) {
|
134
|
+
showCheckboxes.push(i)
|
135
|
+
}
|
136
|
+
}
|
137
|
+
|
138
|
+
for (i = 0; i < obj.$allCheckboxes.length; i++) {
|
139
|
+
obj.$allCheckboxes[i].style.display = 'none'
|
140
|
+
}
|
141
|
+
|
142
|
+
for (i = 0; i < showCheckboxes.length; i++) {
|
143
|
+
obj.$allCheckboxes[showCheckboxes[i]].style.display = 'block'
|
144
|
+
}
|
145
|
+
|
146
|
+
var lenChecked = obj.$optionsContainer.querySelectorAll('.govuk-checkboxes__input:checked').length
|
147
|
+
var len = showCheckboxes.length + lenChecked
|
148
|
+
var html = len + (len === 1 ? obj.filterTextSingle : obj.filterTextMultiple) + ', ' + lenChecked + obj.filterTextSelected
|
149
|
+
obj.$filterCount.innerHTML = html
|
150
|
+
}
|
151
|
+
|
152
|
+
OptionSelect.prototype.replaceHeadingSpanWithButton = function replaceHeadingSpanWithButton () {
|
153
|
+
/* Replace the span within the heading with a button element. This is based on feedback from Léonie Watson.
|
154
|
+
* The button has all of the accessibility hooks that are used by screen readers and etc.
|
155
|
+
* We do this in the JavaScript because if the JavaScript is not active then the button shouldn't
|
156
|
+
* be there as there is no JS to handle the click event.
|
157
|
+
*/
|
158
|
+
var containerHead = this.$optionSelect.querySelector('.js-container-button')
|
159
|
+
var jsContainerHeadHTML = containerHead.innerHTML
|
160
|
+
|
161
|
+
// Create button and replace the preexisting html with the button.
|
162
|
+
var button = document.createElement('button')
|
163
|
+
button.setAttribute('class', 'js-container-button gem-c-option-select__title gem-c-option-select__button')
|
164
|
+
// Add type button to override default type submit when this component is used within a form
|
165
|
+
button.setAttribute('type', 'button')
|
166
|
+
button.setAttribute('aria-expanded', true)
|
167
|
+
button.setAttribute('id', containerHead.getAttribute('id'))
|
168
|
+
button.setAttribute('aria-controls', this.$optionsContainer.getAttribute('id'))
|
169
|
+
button.innerHTML = jsContainerHeadHTML
|
170
|
+
containerHead.parentNode.replaceChild(button, containerHead)
|
171
|
+
|
172
|
+
// GA4 Accordion tracking. Relies on the ga4-finder-tracker setting the index first, so we wrap this in a custom event.
|
173
|
+
window.addEventListener('ga4-filter-indexes-added', function () {
|
174
|
+
if (window.GOVUK.analyticsGa4) {
|
175
|
+
if (window.GOVUK.analyticsGa4.Ga4FinderTracker) {
|
176
|
+
window.GOVUK.analyticsGa4.Ga4FinderTracker.addFilterButtonTracking(button, button.innerHTML)
|
177
|
+
}
|
178
|
+
}
|
179
|
+
})
|
180
|
+
}
|
181
|
+
|
182
|
+
OptionSelect.prototype.attachCheckedCounter = function attachCheckedCounter (checkedString) {
|
183
|
+
var element = document.createElement('div')
|
184
|
+
element.setAttribute('class', 'gem-c-option-select__selected-counter js-selected-counter')
|
185
|
+
element.innerHTML = checkedString
|
186
|
+
this.$optionSelect.querySelector('.js-container-button').insertAdjacentElement('afterend', element)
|
187
|
+
}
|
188
|
+
|
189
|
+
OptionSelect.prototype.updateCheckedCount = function updateCheckedCount () {
|
190
|
+
var checkedString = this.checkedString()
|
191
|
+
var checkedStringElement = this.$optionSelect.querySelector('.js-selected-counter')
|
192
|
+
|
193
|
+
if (checkedString) {
|
194
|
+
if (checkedStringElement === null) {
|
195
|
+
this.attachCheckedCounter(checkedString)
|
196
|
+
} else {
|
197
|
+
checkedStringElement.textContent = checkedString
|
198
|
+
}
|
199
|
+
} else if (checkedStringElement) {
|
200
|
+
checkedStringElement.parentNode.removeChild(checkedStringElement)
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
OptionSelect.prototype.checkedString = function checkedString () {
|
205
|
+
this.getAllCheckedCheckboxes()
|
206
|
+
var count = this.checkedCheckboxes.length
|
207
|
+
var checkedString = false
|
208
|
+
if (count > 0) {
|
209
|
+
checkedString = count + ' selected'
|
210
|
+
}
|
211
|
+
|
212
|
+
return checkedString
|
213
|
+
}
|
214
|
+
|
215
|
+
OptionSelect.prototype.toggleOptionSelect = function toggleOptionSelect (e) {
|
216
|
+
if (this.isClosed()) {
|
217
|
+
this.open()
|
218
|
+
} else {
|
219
|
+
this.close()
|
220
|
+
}
|
221
|
+
e.preventDefault()
|
222
|
+
}
|
223
|
+
|
224
|
+
OptionSelect.prototype.open = function open () {
|
225
|
+
if (this.isClosed()) {
|
226
|
+
this.$optionSelect.querySelector('.js-container-button').setAttribute('aria-expanded', true)
|
227
|
+
this.$optionSelect.classList.remove('js-closed')
|
228
|
+
this.$optionSelect.classList.add('js-opened')
|
229
|
+
if (!this.$optionsContainer.style.height) {
|
230
|
+
this.setupHeight()
|
231
|
+
}
|
232
|
+
}
|
233
|
+
}
|
234
|
+
|
235
|
+
OptionSelect.prototype.close = function close () {
|
236
|
+
this.$optionSelect.classList.remove('js-opened')
|
237
|
+
this.$optionSelect.classList.add('js-closed')
|
238
|
+
this.$optionSelect.querySelector('.js-container-button').setAttribute('aria-expanded', false)
|
239
|
+
}
|
240
|
+
|
241
|
+
OptionSelect.prototype.isClosed = function isClosed () {
|
242
|
+
return this.$optionSelect.classList.contains('js-closed')
|
243
|
+
}
|
244
|
+
|
245
|
+
OptionSelect.prototype.setContainerHeight = function setContainerHeight (height) {
|
246
|
+
this.$optionsContainer.style.height = height + 'px'
|
247
|
+
}
|
248
|
+
|
249
|
+
OptionSelect.prototype.isCheckboxVisible = function isCheckboxVisible (option) {
|
250
|
+
var initialOptionContainerHeight = this.$optionsContainer.clientHeight
|
251
|
+
var optionListOffsetTop = this.$optionList.getBoundingClientRect().top
|
252
|
+
var distanceFromTopOfContainer = option.getBoundingClientRect().top - optionListOffsetTop
|
253
|
+
return distanceFromTopOfContainer < initialOptionContainerHeight
|
254
|
+
}
|
255
|
+
|
256
|
+
OptionSelect.prototype.getVisibleCheckboxes = function getVisibleCheckboxes () {
|
257
|
+
var visibleCheckboxes = []
|
258
|
+
for (var i = 0; i < this.$options.length; i++) {
|
259
|
+
if (this.isCheckboxVisible(this.$options[i])) {
|
260
|
+
visibleCheckboxes.push(this.$options[i])
|
261
|
+
}
|
262
|
+
}
|
263
|
+
|
264
|
+
// add an extra checkbox, if the label of the first is too long it collapses onto itself
|
265
|
+
if (this.$options[visibleCheckboxes.length]) {
|
266
|
+
visibleCheckboxes.push(this.$options[visibleCheckboxes.length])
|
267
|
+
}
|
268
|
+
return visibleCheckboxes
|
269
|
+
}
|
270
|
+
|
271
|
+
OptionSelect.prototype.isFacetsContainerHidden = function isFacetsContainerHidden () {
|
272
|
+
var facetsContent = this.$optionSelect.parentElement
|
273
|
+
var isFacetsContentHidden = false
|
274
|
+
// check whether this is hidden by progressive disclosure,
|
275
|
+
// because height calculations won't work
|
276
|
+
// would use offsetParent === null but for IE10+
|
277
|
+
if (facetsContent) {
|
278
|
+
isFacetsContentHidden = !(facetsContent.offsetWidth || facetsContent.offsetHeight || facetsContent.getClientRects().length)
|
279
|
+
}
|
280
|
+
|
281
|
+
return isFacetsContentHidden
|
282
|
+
}
|
283
|
+
|
284
|
+
OptionSelect.prototype.setupHeight = function setupHeight () {
|
285
|
+
var initialOptionContainerHeight = this.$optionsContainer.clientHeight
|
286
|
+
var height = this.$optionList.offsetHeight
|
287
|
+
|
288
|
+
var isFacetsContainerHidden = this.isFacetsContainerHidden()
|
289
|
+
|
290
|
+
if (isFacetsContainerHidden) {
|
291
|
+
initialOptionContainerHeight = 200
|
292
|
+
height = 200
|
293
|
+
}
|
294
|
+
|
295
|
+
// Resize if the list is only slightly bigger than its container
|
296
|
+
// If isFacetsContainerHidden is true, then 200 < 250
|
297
|
+
// And the container height is always set to 201px
|
298
|
+
if (height < initialOptionContainerHeight + 50) {
|
299
|
+
this.setContainerHeight(height + 1)
|
300
|
+
return
|
301
|
+
}
|
302
|
+
|
303
|
+
// Resize to cut last item cleanly in half
|
304
|
+
var visibleCheckboxes = this.getVisibleCheckboxes()
|
305
|
+
|
306
|
+
var lastVisibleCheckbox = visibleCheckboxes[visibleCheckboxes.length - 1]
|
307
|
+
var position = lastVisibleCheckbox.parentNode.offsetTop // parent element is relative
|
308
|
+
this.setContainerHeight(position + (lastVisibleCheckbox.clientHeight / 1.5))
|
309
|
+
}
|
310
|
+
|
311
|
+
Modules.OptionSelect = OptionSelect
|
312
|
+
})(window.GOVUK.Modules)
|
@@ -57,6 +57,7 @@ $govuk-new-link-styles: true;
|
|
57
57
|
@import "components/metadata";
|
58
58
|
@import "components/modal-dialogue";
|
59
59
|
@import "components/notice";
|
60
|
+
@import "components/option-select";
|
60
61
|
@import "components/organisation-logo";
|
61
62
|
@import "components/panel";
|
62
63
|
@import "components/phase-banner";
|
@@ -41,6 +41,13 @@
|
|
41
41
|
}
|
42
42
|
}
|
43
43
|
|
44
|
+
@include govuk-media-query($from: tablet) {
|
45
|
+
.gem-c-image-card.gem-c-image-card--two-thirds {
|
46
|
+
margin: 0 (- govuk-spacing(3)) govuk-spacing(6) (- govuk-spacing(3));
|
47
|
+
display: block;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
44
51
|
@include govuk-media-query($from: mobile, $until: tablet) {
|
45
52
|
.gem-c-image-card {
|
46
53
|
margin: 0 (- govuk-spacing(3)) govuk-spacing(6) (- govuk-spacing(3));
|
@@ -53,6 +60,25 @@
|
|
53
60
|
.gem-c-image-card__text-wrapper {
|
54
61
|
@include govuk-grid-column($width: one-half, $at: mobile);
|
55
62
|
}
|
63
|
+
|
64
|
+
.gem-c-image-card__image-wrapper.gem-c-image-card__image-wrapper--one-third {
|
65
|
+
@include govuk-grid-column($width: one-third, $float: right, $at: mobile);
|
66
|
+
}
|
67
|
+
|
68
|
+
.gem-c-image-card__text-wrapper.gem-c-image-card__text-wrapper--two-thirds {
|
69
|
+
@include govuk-grid-column($width: two-thirds, $float: right, $at: mobile);
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
@include govuk-media-query($from: tablet) {
|
74
|
+
.gem-c-image-card__image-wrapper.gem-c-image-card__image-wrapper--one-third {
|
75
|
+
@include govuk-grid-column($width: one-third, $float: right, $at: tablet);
|
76
|
+
}
|
77
|
+
|
78
|
+
.gem-c-image-card__text-wrapper.gem-c-image-card__text-wrapper--two-thirds {
|
79
|
+
@include govuk-grid-column($width: two-thirds, $float: right, $at: tablet);
|
80
|
+
padding-left: 0;
|
81
|
+
}
|
56
82
|
}
|
57
83
|
|
58
84
|
.gem-c-image-card__image {
|
@@ -0,0 +1,172 @@
|
|
1
|
+
@import "govuk_publishing_components/individual_component_support";
|
2
|
+
|
3
|
+
.gem-c-option-select {
|
4
|
+
position: relative;
|
5
|
+
padding: 0 0 govuk-spacing(2);
|
6
|
+
margin-bottom: govuk-spacing(2);
|
7
|
+
border-bottom: 1px solid $govuk-border-colour;
|
8
|
+
|
9
|
+
@include govuk-media-query($from: desktop) {
|
10
|
+
// Redefine scrollbars on desktop where these lists are scrollable
|
11
|
+
// so they are always visible in option lists
|
12
|
+
::-webkit-scrollbar {
|
13
|
+
-webkit-appearance: none;
|
14
|
+
width: 7px;
|
15
|
+
}
|
16
|
+
|
17
|
+
::-webkit-scrollbar-thumb {
|
18
|
+
border-radius: 4px;
|
19
|
+
|
20
|
+
background-color: rgba(0, 0, 0, .5);
|
21
|
+
-webkit-box-shadow: 0 0 1px rgba(255, 255, 255, .87);
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
.gem-c-checkboxes {
|
26
|
+
margin: 0;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
.gem-c-option-select__title {
|
31
|
+
@include govuk-font(19);
|
32
|
+
margin: 0;
|
33
|
+
}
|
34
|
+
|
35
|
+
.gem-c-option-select__button {
|
36
|
+
z-index: 1;
|
37
|
+
background: none;
|
38
|
+
border: 0;
|
39
|
+
text-align: left;
|
40
|
+
padding: 0;
|
41
|
+
cursor: pointer;
|
42
|
+
color: $govuk-link-colour;
|
43
|
+
|
44
|
+
&:hover {
|
45
|
+
text-decoration: underline;
|
46
|
+
text-underline-offset: .1em;
|
47
|
+
@include govuk-link-hover-decoration;
|
48
|
+
}
|
49
|
+
|
50
|
+
&::-moz-focus-inner {
|
51
|
+
border: 0;
|
52
|
+
}
|
53
|
+
|
54
|
+
&:focus {
|
55
|
+
outline: none;
|
56
|
+
text-decoration: none;
|
57
|
+
@include govuk-focused-text;
|
58
|
+
}
|
59
|
+
|
60
|
+
&[disabled] {
|
61
|
+
background-image: none;
|
62
|
+
color: inherit;
|
63
|
+
}
|
64
|
+
|
65
|
+
// Extend the touch area of the button to span the heading
|
66
|
+
&:after {
|
67
|
+
content: "";
|
68
|
+
position: absolute;
|
69
|
+
top: 0;
|
70
|
+
right: 0;
|
71
|
+
bottom: 0;
|
72
|
+
left: 0;
|
73
|
+
z-index: 2;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
.gem-c-option-select__icon {
|
78
|
+
display: none;
|
79
|
+
position: absolute;
|
80
|
+
top: 0;
|
81
|
+
left: 9px;
|
82
|
+
width: 30px;
|
83
|
+
height: 40px;
|
84
|
+
fill: govuk-colour("black");
|
85
|
+
}
|
86
|
+
|
87
|
+
.gem-c-option-select__container {
|
88
|
+
position: relative;
|
89
|
+
max-height: 200px;
|
90
|
+
overflow-y: auto;
|
91
|
+
overflow-x: hidden;
|
92
|
+
background-color: govuk-colour("white");
|
93
|
+
|
94
|
+
&:focus {
|
95
|
+
outline: 0;
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
.gem-c-option-select__container--large {
|
100
|
+
max-height: 600px;
|
101
|
+
}
|
102
|
+
|
103
|
+
.gem-c-option-select__container-inner {
|
104
|
+
padding: govuk-spacing(1) 13px;
|
105
|
+
}
|
106
|
+
|
107
|
+
.gem-c-option-select__filter {
|
108
|
+
position: relative;
|
109
|
+
background: govuk-colour("white");
|
110
|
+
padding: 13px 13px govuk-spacing(2) 13px;
|
111
|
+
}
|
112
|
+
|
113
|
+
.gem-c-option-select__filter-input {
|
114
|
+
@include govuk-font(19);
|
115
|
+
background: image-url("option-select/input-icon.svg") govuk-colour("white") no-repeat -5px -3px;
|
116
|
+
|
117
|
+
@include govuk-media-query($from: tablet) {
|
118
|
+
@include govuk-font(16);
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
.gem-c-option-select__filter-input.govuk-input {
|
123
|
+
padding-left: 33px;
|
124
|
+
}
|
125
|
+
|
126
|
+
.js-enabled {
|
127
|
+
.gem-c-option-select__heading {
|
128
|
+
position: relative;
|
129
|
+
padding: 10px 8px 5px 43px;
|
130
|
+
margin: 0;
|
131
|
+
}
|
132
|
+
|
133
|
+
[aria-expanded="true"] ~ .gem-c-option-select__icon--up {
|
134
|
+
display: block;
|
135
|
+
}
|
136
|
+
|
137
|
+
[aria-expanded="false"] ~ .gem-c-option-select__icon--down {
|
138
|
+
display: block;
|
139
|
+
}
|
140
|
+
|
141
|
+
.gem-c-option-select__container {
|
142
|
+
height: 200px;
|
143
|
+
}
|
144
|
+
|
145
|
+
.gem-c-option-select__container--large {
|
146
|
+
height: 600px;
|
147
|
+
}
|
148
|
+
|
149
|
+
[data-closed-on-load="true"] .gem-c-option-select__container {
|
150
|
+
display: none;
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
.gem-c-option-select__selected-counter {
|
155
|
+
@include govuk-font($size: 14);
|
156
|
+
color: $govuk-text-colour;
|
157
|
+
margin-top: 3px;
|
158
|
+
}
|
159
|
+
|
160
|
+
.gem-c-option-select.js-closed {
|
161
|
+
.gem-c-option-select__filter,
|
162
|
+
.gem-c-option-select__container {
|
163
|
+
display: none;
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
167
|
+
.gem-c-option-select.js-opened {
|
168
|
+
.gem-c-option-select__filter,
|
169
|
+
.gem-c-option-select__container {
|
170
|
+
display: block;
|
171
|
+
}
|
172
|
+
}
|
@@ -7,11 +7,17 @@
|
|
7
7
|
brand_helper = GovukPublishingComponents::AppHelpers::BrandHelper.new(brand)
|
8
8
|
card_helper = GovukPublishingComponents::Presenters::ImageCardHelper.new(local_assigns, brand_helper)
|
9
9
|
shared_helper = GovukPublishingComponents::Presenters::SharedHelper.new(local_assigns)
|
10
|
+
|
10
11
|
classes = %w[gem-c-image-card]
|
12
|
+
classes << "govuk-grid-row" if card_helper.two_thirds
|
11
13
|
classes << "gem-c-image-card--large" if card_helper.large
|
14
|
+
classes << "gem-c-image-card--two-thirds" if card_helper.two_thirds
|
12
15
|
classes << "gem-c-image-card--no-image" unless (card_helper.image_src || card_helper.youtube_video_id)
|
13
16
|
classes << brand_helper.brand_class if brand_helper.brand_class
|
14
17
|
|
18
|
+
text_wrapper_classes = %w[gem-c-image-card__text-wrapper]
|
19
|
+
text_wrapper_classes << "gem-c-image-card__text-wrapper--two-thirds" if card_helper.two_thirds
|
20
|
+
|
15
21
|
font_size ||= card_helper.large ? 'm' : 's'
|
16
22
|
heading_class = %w[gem-c-image-card__title]
|
17
23
|
heading_class << shared_helper.get_heading_size(font_size, 's')
|
@@ -33,7 +39,7 @@
|
|
33
39
|
%>
|
34
40
|
<% if card_helper.href || card_helper.extra_details.any? %>
|
35
41
|
<%= content_tag(:div, class: classes, "data-module": data_modules, lang: card_helper.lang) do %>
|
36
|
-
|
42
|
+
<%= content_tag(:div, class: text_wrapper_classes) do %>
|
37
43
|
<div class="gem-c-image-card__header-and-context-wrapper">
|
38
44
|
<% if card_helper.heading_text %>
|
39
45
|
<%= content_tag(shared_helper.get_heading_level, class: heading_class) do %>
|
@@ -69,7 +75,7 @@
|
|
69
75
|
<% if card_helper.metadata %>
|
70
76
|
<p class="gem-c-image-card__metadata"><%= card_helper.metadata %></p>
|
71
77
|
<% end %>
|
72
|
-
|
78
|
+
<% end %>
|
73
79
|
<%= card_helper.media %>
|
74
80
|
<% end %>
|
75
81
|
<% end %>
|