govuk_publishing_components 21.62.0 → 21.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/govuk_publishing_components/components/govspeak.js +17 -15
  3. data/app/assets/javascripts/govuk_publishing_components/components/step-by-step-nav.js +402 -340
  4. data/app/assets/javascripts/govuk_publishing_components/dependencies.js +0 -5
  5. data/app/assets/javascripts/govuk_publishing_components/lib.js +1 -0
  6. data/app/assets/javascripts/govuk_publishing_components/lib/govspeak/barchart-enhancement.js +18 -11
  7. data/app/assets/javascripts/govuk_publishing_components/lib/govspeak/magna-charta.js +423 -0
  8. data/app/assets/javascripts/govuk_publishing_components/lib/toggle.js +126 -65
  9. data/app/assets/javascripts/govuk_publishing_components/vendor/polyfills/closest.js +23 -0
  10. data/app/assets/javascripts/govuk_publishing_components/vendor/polyfills/indexOf.js +9 -0
  11. data/app/assets/stylesheets/govuk_publishing_components/components/_breadcrumbs.scss +3 -16
  12. data/app/assets/stylesheets/govuk_publishing_components/components/_panel.scss +7 -1
  13. data/app/views/govuk_publishing_components/component_guide/example.html.erb +4 -1
  14. data/app/views/govuk_publishing_components/component_guide/show.html.erb +3 -1
  15. data/app/views/govuk_publishing_components/components/_breadcrumbs.html.erb +1 -1
  16. data/app/views/govuk_publishing_components/components/_cookie_banner.html.erb +1 -1
  17. data/app/views/govuk_publishing_components/components/_document_list.html.erb +18 -9
  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/docs/document_list.yml +18 -0
  22. data/app/views/govuk_publishing_components/components/feedback/_problem_form.html.erb +6 -6
  23. data/app/views/govuk_publishing_components/components/feedback/_survey_signup_form.html.erb +6 -6
  24. data/app/views/govuk_publishing_components/components/feedback/_yes_no_banner.html.erb +8 -10
  25. data/config/locales/en.yml +18 -0
  26. data/lib/govuk_publishing_components/presenters/breadcrumb_selector.rb +5 -0
  27. data/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_priority.rb +19 -5
  28. data/lib/govuk_publishing_components/presenters/contextual_navigation.rb +1 -1
  29. data/lib/govuk_publishing_components/version.rb +1 -1
  30. metadata +5 -3
  31. data/app/assets/javascripts/govuk_publishing_components/vendor/magna-charta.min.js +0 -4
@@ -9,9 +9,4 @@ $(document).ready(function () {
9
9
  'use strict'
10
10
 
11
11
  window.GOVUK.modules.start()
12
-
13
- // Static has a Toggle module in here we have a GemToggle module, we can't
14
- // easily change govspeak to use GemToggle but we can use the GemToggle module
15
- var gemToggle = new window.GOVUK.Modules.GemToggle()
16
- gemToggle.start($('[data-module=toggle]'))
17
12
  })
@@ -1 +1,2 @@
1
+ // = require_tree ./vendor/polyfills/
1
2
  // = require_tree ./lib
@@ -1,4 +1,4 @@
1
- // = require govuk_publishing_components/vendor/magna-charta.min
1
+ // = require govuk_publishing_components/lib/govspeak/magna-charta
2
2
 
3
3
  window.GOVUK = window.GOVUK || {};
4
4
 
@@ -10,16 +10,23 @@ window.GOVUK = window.GOVUK || {};
10
10
  }
11
11
 
12
12
  BarchartEnhancement.prototype.init = function () {
13
- // the not selectors are protection against initialising twice since that
14
- // causes quite a mess. The not .mc-chart is because it creates a second
15
- // .js-barchart-table element with .mc-chart and then the
16
- // .js-barchart-table-init is given when we initialise
17
- var $barcharts = this.$element.find('.js-barchart-table:not(.mc-chart):not(.js-barchart-table-init)')
18
- $barcharts.each(function () {
19
- var $table = $(this)
20
- $.magnaCharta($table, { toggleText: 'Change between chart and table' })
21
- $table.addClass('js-barchart-table-init')
22
- })
13
+ var $barchartsOriginal = this.$element.querySelectorAll('.js-barchart-table')
14
+ var $barcharts = []
15
+
16
+ for (var j = 0; j < $barchartsOriginal.length; j++) {
17
+ // this prevents the code from initialising more than once
18
+ // we'd use :not selectors for $barchartsOriginal but for lack of IE8 support
19
+ var styles = $barchartsOriginal[j].className
20
+ if (styles.indexOf('mc-chart') === -1 && styles.indexOf('js-barchart-table-init') === -1) {
21
+ $barcharts.push($barchartsOriginal[j])
22
+ }
23
+ }
24
+
25
+ for (var i = 0; i < $barcharts.length; i++) {
26
+ var $table = $barcharts[i]
27
+ new GOVUK.Modules.MagnaCharta().start($table, { toggleText: 'Change between chart and table' })
28
+ $table.className = $table.className + ' js-barchart-table-init'
29
+ }
23
30
  }
24
31
 
25
32
  GOVUK.GovspeakBarchartEnhancement = BarchartEnhancement
@@ -0,0 +1,423 @@
1
+ //= require govuk/vendor/polyfills/Element/prototype/classList.js
2
+ // This is a non-jQuery version of Magna Charta: https://github.com/alphagov/magna-charta
3
+ window.GOVUK = window.GOVUK || {}
4
+ window.GOVUK.Modules = window.GOVUK.Modules || {};
5
+
6
+ (function (Modules) {
7
+ function MagnaCharta () { }
8
+
9
+ MagnaCharta.prototype.start = function ($module, options) {
10
+ this.$module = $module[0]
11
+ this.options = {
12
+ outOf: 65,
13
+ applyOnInit: true,
14
+ toggleText: 'Toggle between chart and table',
15
+ autoOutdent: false,
16
+ outdentAll: false,
17
+ toggleAfter: false, // BOOL set TRUE to append the toggle link
18
+ returnReference: false // for testing purposes
19
+ }
20
+
21
+ for (var k in options) this.options[k] = options[k]
22
+ this.detectIEVersion()
23
+
24
+ // Magna Charta doesn't work in IE7 or less - so plain tables are shown to those browsers
25
+ this.ENABLED = !(this.ie && this.ie < 8)
26
+
27
+ // store a reference to the table in the object
28
+ this.$table = $module
29
+
30
+ // lets make what will become the new graph
31
+ this.$graph = document.createElement('div')
32
+
33
+ // set the graph to aria-hidden, which isn't changed at any point
34
+ // the graph is totally inaccessible, so we let screen readers navigate the table
35
+ // and ignore the graph entirely
36
+ this.$graph.setAttribute('aria-hidden', 'true')
37
+
38
+ // copy over classes from the table, and add the extra one
39
+ this.$graph.setAttribute('class', this.$table.className)
40
+ this.$graph.classList.add('mc-chart')
41
+
42
+ // set the stacked option based on
43
+ // giving the table a class of mc-stacked
44
+ this.options.stacked = this.$table.classList.contains('mc-stacked')
45
+
46
+ // set the negative option based on
47
+ // giving the table a class of mc-negative
48
+ this.options.negative = this.$table.classList.contains('mc-negative')
49
+
50
+ // true if it's a 'multiple' table
51
+ // this means multiple bars per rows, but not stacked.
52
+ var moreThanTwoTDs = this.$table.querySelectorAll('tbody tr')[0].querySelectorAll('td').length > 2
53
+ this.options.multiple = !this.options.stacked && (this.$table.classList.contains('mc-multiple') || moreThanTwoTDs)
54
+
55
+ // set the outdent options
56
+ // which can be set via classes or overriden by setting the value to true
57
+ // in the initial options object that's passed in
58
+ this.options.autoOutdent = this.options.autoOutdent || this.$table.classList.contains('mc-auto-outdent')
59
+
60
+ this.options.outdentAll = this.options.outdentAll || this.$table.classList.contains('mc-outdented')
61
+
62
+ // add a mc-multiple class if it is
63
+ if (this.options.multiple) {
64
+ this.$graph.classList.add('mc-multiple')
65
+ }
66
+
67
+ this.options.hasCaption = !!this.$table.querySelectorAll('caption').length
68
+
69
+ if (this.ENABLED) {
70
+ this.apply()
71
+ // if applyOnInit is false, toggle immediately to show the table and hide the graph
72
+ if (!this.options.applyOnInit) {
73
+ this.toggleLink.click()
74
+ }
75
+ }
76
+
77
+ if (this.options.returnReference) {
78
+ return this
79
+ }
80
+ }
81
+
82
+ MagnaCharta.prototype.detectIEVersion = function () {
83
+ // detect IE version: James Padolsey, https://gist.github.com/527683
84
+ this.ie = (function () {
85
+ var undef
86
+ var v = 3
87
+ var div = document.createElement('div')
88
+ var all = div.getElementsByTagName('i')
89
+
90
+ do {
91
+ div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->'
92
+ } while (v < 10 && all[0])
93
+
94
+ return (v > 4) ? v : undef
95
+ })()
96
+ }
97
+
98
+ MagnaCharta.prototype.apply = function () {
99
+ if (this.ENABLED) {
100
+ this.constructChart()
101
+ this.addClassesToHeader()
102
+ this.applyWidths()
103
+ this.insert()
104
+ this.$table.classList.add('visually-hidden')
105
+ this.applyOutdent()
106
+ }
107
+ }
108
+
109
+ // methods for constructing the chart
110
+ MagnaCharta.prototype.construct = {}
111
+
112
+ // constructs the header
113
+ MagnaCharta.prototype.construct.thead = function () {
114
+ var thead = document.createElement('div')
115
+ thead.classList.add('mc-thead')
116
+
117
+ var tr = document.createElement('div')
118
+ tr.classList.add('mc-tr')
119
+
120
+ var output = ''
121
+ var allTheTHs = this.$table.querySelectorAll('th')
122
+
123
+ for (var i = 0; i < allTheTHs.length; i++) {
124
+ output += '<div class="mc-th">'
125
+ output += allTheTHs[i].innerHTML
126
+ output += '</div>'
127
+ }
128
+
129
+ tr.innerHTML = output
130
+ thead.appendChild(tr)
131
+
132
+ return thead
133
+ }
134
+
135
+ MagnaCharta.prototype.construct.tbody = function () {
136
+ var tbody = document.createElement('div')
137
+ tbody.classList.add('mc-tbody')
138
+
139
+ var allTheTbodyTrs = this.$table.querySelectorAll('tbody tr')
140
+
141
+ for (var i = 0; i < allTheTbodyTrs.length; i++) {
142
+ var tr = document.createElement('div')
143
+ tr.classList.add('mc-tr')
144
+
145
+ var cellsOutput = ''
146
+ var allTheTds = allTheTbodyTrs[i].querySelectorAll('td')
147
+
148
+ for (var j = 0; j < allTheTds.length; j++) {
149
+ cellsOutput += '<div class="mc-td">'
150
+ cellsOutput += allTheTds[j].innerHTML
151
+ cellsOutput += '</div>'
152
+ }
153
+ tr.innerHTML = cellsOutput
154
+ tbody.appendChild(tr)
155
+ }
156
+
157
+ return tbody
158
+ }
159
+
160
+ MagnaCharta.prototype.construct.caption = function () {
161
+ var cap = this.$table.querySelector('caption')
162
+ return cap.cloneNode(true)
163
+ }
164
+
165
+ // construct a link to allow the user to toggle between chart and table
166
+ MagnaCharta.prototype.construct.toggleLink = function (toggleText) {
167
+ var link = document.createElement('a')
168
+ link.setAttribute('href', '#')
169
+ link.classList.add('mc-toggle-link')
170
+ link.innerHTML = toggleText
171
+ link.setAttribute('aria-hidden', 'true')
172
+
173
+ return link
174
+ }
175
+
176
+ // toggles between showing the table and showing the chart
177
+ MagnaCharta.prototype.addToggleClick = function () {
178
+ var that = this
179
+
180
+ this.toggleLink.addEventListener('click', function (e) {
181
+ e.preventDefault()
182
+ that.$graph.classList.toggle('visually-hidden')
183
+ that.$table.classList.toggle('visually-hidden')
184
+ })
185
+ }
186
+
187
+ MagnaCharta.prototype.constructChart = function () {
188
+ // turn every element in the table into divs with appropriate classes
189
+ // call them and define this as scope so it's easier to
190
+ // get at options and properties
191
+ var thead = this.construct.thead.call(this)
192
+ var tbody = this.construct.tbody.call(this)
193
+ this.toggleLink = this.construct.toggleLink(this.options.toggleText)
194
+ this.addToggleClick(this.toggleLink)
195
+
196
+ if (this.options.hasCaption) {
197
+ var caption = this.construct.caption.call(this)
198
+ this.$graph.appendChild(caption)
199
+ }
200
+
201
+ if (this.options.toggleAfter) {
202
+ this.$table.insertAdjacentElement('afterend', this.toggleLink)
203
+ } else {
204
+ this.$table.insertAdjacentElement('beforebegin', this.toggleLink)
205
+ }
206
+
207
+ this.$graph.appendChild(thead)
208
+ this.$graph.appendChild(tbody)
209
+ }
210
+
211
+ // some handy utility methods
212
+ MagnaCharta.prototype.utils = {
213
+ isFloat: function (val) {
214
+ return !isNaN(parseFloat(val))
215
+ },
216
+ stripValue: function (val) {
217
+ var re = new RegExp('\\,|£|%|[a-z]', 'gi')
218
+ return val.replace(re, '')
219
+ },
220
+ returnMax: function (values) {
221
+ var max = 0
222
+ for (var i = 0; i < values.length; i++) {
223
+ if (values[i] > max) { max = values[i] }
224
+ }
225
+ return max
226
+ },
227
+ isNegative: function (value) {
228
+ return (value < 0)
229
+ }
230
+ }
231
+
232
+ MagnaCharta.prototype.addClassesToHeader = function () {
233
+ var headerCells = this.$graph.querySelectorAll('.mc-th')
234
+ var looplength = headerCells.length
235
+
236
+ if (this.options.stacked) {
237
+ var last = looplength - 1
238
+ headerCells[last].classList.add('mc-stacked-header', 'mc-header-total')
239
+ looplength -= 1
240
+ }
241
+
242
+ // we deliberately don't apply this to the first cell
243
+ for (var i = 1; i < looplength; i++) {
244
+ headerCells[i].classList.add('mc-key-header')
245
+ if (!headerCells[i].classList.contains('mc-stacked-header')) {
246
+ headerCells[i].classList.add('mc-key-' + i)
247
+ }
248
+ }
249
+ }
250
+
251
+ MagnaCharta.prototype.calculateMaxWidth = function () {
252
+ // store the cell values in here so we can figure out the maximum value later
253
+ var values = []
254
+
255
+ // var to store the maximum negative value (used only for negative charts)
256
+ var maxNegativeValue = 0
257
+
258
+ // loop through every tr in the table
259
+ var trs = this.$graph.querySelectorAll('.mc-tr')
260
+ for (var i = 0; i < trs.length; i++) {
261
+ var $this = trs[i]
262
+
263
+ // the first td is going to be the key, so ignore it
264
+ // we'd use $this.querySelectorAll('.mc-td:not(:first-child)') but for IE8
265
+ var $bodyCellsOriginal = $this.querySelectorAll('.mc-td')
266
+ var $bodyCells = []
267
+ for (var k = 1; k < $bodyCellsOriginal.length; k++) {
268
+ $bodyCells.push($bodyCellsOriginal[k])
269
+ }
270
+
271
+ var bodyCellsLength = $bodyCells.length
272
+
273
+ // might be the row containing th elements, so we need to check
274
+ if (bodyCellsLength) {
275
+ // if it's stacked, the last column is a totals
276
+ // so we don't want that in our calculations
277
+ if (this.options.stacked) {
278
+ $bodyCells[bodyCellsLength - 1].classList.add('mc-stacked-total')
279
+ bodyCellsLength -= 1
280
+ }
281
+
282
+ // first td in each row is key
283
+ var firstCell = $this.querySelector('.mc-td')
284
+ if (firstCell) {
285
+ firstCell.classList.add('mc-key-cell')
286
+ }
287
+
288
+ // store the total value of the bar cells in a row
289
+ // for anything but stacked, this is just the value of one <td>
290
+ var cellsTotalValue = 0
291
+
292
+ for (var j = 0; j < bodyCellsLength; j++) {
293
+ var $cell = $bodyCells[j]
294
+ $cell.classList.add('mc-bar-cell')
295
+ $cell.classList.add('mc-bar-' + (j + 1))
296
+ var cellVal = this.utils.stripValue($cell.innerText)
297
+
298
+ if (this.utils.isFloat(cellVal)) {
299
+ var parsedVal = parseFloat(cellVal, 10)
300
+ var absParsedVal = Math.abs(parsedVal)
301
+ if (parsedVal === 0) {
302
+ $cell.classList.add('mc-bar-zero')
303
+ }
304
+
305
+ if (this.options.negative) {
306
+ if (this.utils.isNegative(parsedVal)) {
307
+ $cell.classList.add('mc-bar-negative')
308
+ if (absParsedVal > maxNegativeValue) {
309
+ maxNegativeValue = absParsedVal
310
+ }
311
+ } else {
312
+ $cell.classList.add('mc-bar-positive')
313
+ }
314
+ }
315
+ // now we are done with our negative calculations
316
+ // set parsedVal to absParsedVal
317
+ parsedVal = absParsedVal
318
+
319
+ if (!this.options.stacked) {
320
+ cellsTotalValue = parsedVal
321
+ values.push(parsedVal)
322
+ } else {
323
+ cellsTotalValue += parsedVal
324
+ }
325
+ }
326
+ }
327
+ }
328
+
329
+ // if stacked, we need to push the total value of the row to the values array
330
+ if (this.options.stacked) { values.push(cellsTotalValue) }
331
+ }
332
+
333
+ var resp = {}
334
+ resp.max = parseFloat(this.utils.returnMax(values), 10)
335
+ resp.single = parseFloat(this.options.outOf / resp.max, 10)
336
+
337
+ if (this.options.negative) {
338
+ resp.marginLeft = parseFloat(maxNegativeValue, 10) * resp.single
339
+ resp.maxNegative = parseFloat(maxNegativeValue, 10)
340
+ }
341
+
342
+ return resp
343
+ }
344
+
345
+ MagnaCharta.prototype.applyWidths = function () {
346
+ this.dimensions = this.calculateMaxWidth()
347
+ var trs = this.$graph.querySelectorAll('.mc-tr')
348
+
349
+ for (var i = 0; i < trs.length; i++) {
350
+ var cells = trs[i].querySelectorAll('.mc-bar-cell')
351
+
352
+ for (var j = 0; j < cells.length; j++) {
353
+ var $cell = cells[j]
354
+ var parsedCellVal = parseFloat(this.utils.stripValue($cell.innerText), 10)
355
+ var parsedVal = parsedCellVal * this.dimensions.single
356
+ var absParsedCellVal = Math.abs(parsedCellVal)
357
+ var absParsedVal = Math.abs(parsedVal)
358
+
359
+ // apply the left margin to the positive bars
360
+ if (this.options.negative) {
361
+ if ($cell.classList.contains('mc-bar-positive')) {
362
+ $cell.style.marginLeft = this.dimensions.marginLeft + '%'
363
+ } else {
364
+ // if its negative but not the maximum negative
365
+ // we need to give it enough margin to push it further right to align
366
+ if (absParsedCellVal < this.dimensions.maxNegative) {
367
+ // left margin needs to be (largestNegVal - thisNegVal) * single
368
+ var leftMarg = (this.dimensions.maxNegative - absParsedCellVal) * this.dimensions.single
369
+ $cell.style.marginLeft = leftMarg + '%'
370
+ }
371
+ }
372
+ }
373
+
374
+ // wrap the cell value in a span tag
375
+ $cell.innerHTML = '<span>' + $cell.innerHTML + '</span>'
376
+ $cell.style.width = absParsedVal + '%'
377
+ }
378
+ }
379
+ }
380
+
381
+ MagnaCharta.prototype.insert = function () {
382
+ this.$table.insertAdjacentElement('afterend', this.$graph)
383
+ }
384
+
385
+ MagnaCharta.prototype.applyOutdent = function () {
386
+ /*
387
+ * this figures out if a cell needs an outdent and applies it
388
+ * it needs an outdent if the width of the text is greater than the width of the bar
389
+ * if this is the case, wrap the value in a span, and use absolute positioning
390
+ * to push it out (the bar is styled to be relative)
391
+ * unfortunately this has to be done once the chart has been inserted
392
+ */
393
+ var cells = this.$graph.querySelectorAll('.mc-bar-cell')
394
+
395
+ for (var i = 0; i < cells.length; i++) {
396
+ var $cell = cells[i]
397
+ var cellVal = parseFloat(this.utils.stripValue($cell.innerText), 10)
398
+ var $cellSpan = $cell.querySelector('span')
399
+ var spanWidth = parseFloat(window.getComputedStyle($cellSpan, null).width.replace('px', '')) + 10 // +10 just for extra padding
400
+ var cellWidth = parseFloat(window.getComputedStyle($cell, null).width.replace('px', ''))
401
+
402
+ if (!this.options.stacked) {
403
+ // if it's 0, it is effectively outdented
404
+ if (cellVal === 0) { $cell.classList.add('mc-bar-outdented') }
405
+
406
+ if ((this.options.autoOutdent && spanWidth > cellWidth) || this.options.outdentAll) {
407
+ $cell.classList.add('mc-bar-outdented')
408
+ $cellSpan.style.marginLeft = '100%'
409
+ $cellSpan.style.display = 'inline-block'
410
+ } else {
411
+ $cell.classList.add('mc-bar-indented')
412
+ }
413
+ } else {
414
+ // if it's a stacked graph
415
+ if (spanWidth > cellWidth && cellVal > 0) {
416
+ $cell.classList.add('mc-value-overflow')
417
+ }
418
+ }
419
+ }
420
+ }
421
+
422
+ Modules.MagnaCharta = MagnaCharta
423
+ })(window.GOVUK.Modules)