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
@@ -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)