govuk_publishing_components 13.6.0 → 13.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/govuk_publishing_components/dependencies.js +3 -3
- data/app/assets/javascripts/govuk_publishing_components/lib/toggle.js +52 -28
- data/app/views/govuk_publishing_components/components/docs/related_navigation.yml +216 -201
- data/lib/govuk_publishing_components/presenters/meta_tags.rb +0 -7
- data/lib/govuk_publishing_components/presenters/related_navigation_helper.rb +3 -3
- data/lib/govuk_publishing_components/version.rb +1 -1
- data/node_modules/govuk-frontend/all.js +1197 -943
- data/node_modules/govuk-frontend/components/_all.scss +2 -0
- data/node_modules/govuk-frontend/components/accordion/README.md +17 -0
- data/node_modules/govuk-frontend/components/accordion/_accordion.scss +173 -0
- data/node_modules/govuk-frontend/components/accordion/accordion.js +1011 -0
- data/node_modules/govuk-frontend/components/accordion/macro-options.json +70 -0
- data/node_modules/govuk-frontend/components/accordion/macro.njk +3 -0
- data/node_modules/govuk-frontend/components/accordion/template.njk +27 -0
- data/node_modules/govuk-frontend/components/input/macro-options.json +7 -0
- data/node_modules/govuk-frontend/components/summary-list/README.md +15 -0
- data/node_modules/govuk-frontend/components/summary-list/_summary-list.scss +112 -0
- data/node_modules/govuk-frontend/components/summary-list/macro-options.json +95 -0
- data/node_modules/govuk-frontend/components/summary-list/macro.njk +3 -0
- data/node_modules/govuk-frontend/components/summary-list/template.njk +35 -0
- data/node_modules/govuk-frontend/helpers/_grid.scss +43 -35
- data/node_modules/govuk-frontend/helpers/_visually-hidden.scss +4 -2
- data/node_modules/govuk-frontend/objects/_grid.scss +21 -8
- data/node_modules/govuk-frontend/package.json +11 -11
- data/node_modules/govuk-frontend/settings/_measurements.scss +14 -0
- data/node_modules/govuk-frontend/template.njk +2 -0
- metadata +13 -2
@@ -29,13 +29,6 @@ module GovukPublishingComponents
|
|
29
29
|
meta_tags["govuk:format"] = content_item[:document_type] if content_item[:document_type]
|
30
30
|
meta_tags["govuk:publishing-application"] = content_item[:publishing_app] if content_item[:publishing_app]
|
31
31
|
meta_tags["govuk:schema-name"] = content_item[:schema_name] if content_item[:schema_name]
|
32
|
-
|
33
|
-
user_journey_stage = content_item[:user_journey_document_supertype]
|
34
|
-
meta_tags["govuk:user-journey-stage"] = user_journey_stage if user_journey_stage
|
35
|
-
|
36
|
-
navigation_document_type = content_item[:navigation_document_supertype]
|
37
|
-
meta_tags["govuk:navigation-document-type"] = navigation_document_type if navigation_document_type
|
38
|
-
|
39
32
|
meta_tags["govuk:content-id"] = content_item[:content_id] if content_item[:content_id]
|
40
33
|
meta_tags["govuk:withdrawn"] = "withdrawn" if content_item[:withdrawn_notice].present?
|
41
34
|
meta_tags["govuk:content-has-history"] = "true" if has_content_history?
|
@@ -13,9 +13,9 @@ module GovukPublishingComponents
|
|
13
13
|
statistical_data_sets
|
14
14
|
).freeze
|
15
15
|
|
16
|
-
def initialize(
|
17
|
-
@content_item = content_item
|
18
|
-
@context = context
|
16
|
+
def initialize(options = {})
|
17
|
+
@content_item = options.fetch(:content_item) { raise ArgumentError, 'missing argument: content_item' }
|
18
|
+
@context = options.fetch(:context, nil)
|
19
19
|
end
|
20
20
|
|
21
21
|
def related_navigation
|
@@ -35,167 +35,6 @@ function generateUniqueID () {
|
|
35
35
|
|
36
36
|
(function(undefined) {
|
37
37
|
|
38
|
-
// Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Window/detect.js
|
39
|
-
var detect = ('Window' in this);
|
40
|
-
|
41
|
-
if (detect) return
|
42
|
-
|
43
|
-
// Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Window&flags=always
|
44
|
-
if ((typeof WorkerGlobalScope === "undefined") && (typeof importScripts !== "function")) {
|
45
|
-
(function (global) {
|
46
|
-
if (global.constructor) {
|
47
|
-
global.Window = global.constructor;
|
48
|
-
} else {
|
49
|
-
(global.Window = global.constructor = new Function('return function Window() {}')()).prototype = this;
|
50
|
-
}
|
51
|
-
}(this));
|
52
|
-
}
|
53
|
-
|
54
|
-
})
|
55
|
-
.call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
56
|
-
|
57
|
-
(function(undefined) {
|
58
|
-
|
59
|
-
// Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Document/detect.js
|
60
|
-
var detect = ("Document" in this);
|
61
|
-
|
62
|
-
if (detect) return
|
63
|
-
|
64
|
-
// Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Document&flags=always
|
65
|
-
if ((typeof WorkerGlobalScope === "undefined") && (typeof importScripts !== "function")) {
|
66
|
-
|
67
|
-
if (this.HTMLDocument) { // IE8
|
68
|
-
|
69
|
-
// HTMLDocument is an extension of Document. If the browser has HTMLDocument but not Document, the former will suffice as an alias for the latter.
|
70
|
-
this.Document = this.HTMLDocument;
|
71
|
-
|
72
|
-
} else {
|
73
|
-
|
74
|
-
// Create an empty function to act as the missing constructor for the document object, attach the document object as its prototype. The function needs to be anonymous else it is hoisted and causes the feature detect to prematurely pass, preventing the assignments below being made.
|
75
|
-
this.Document = this.HTMLDocument = document.constructor = (new Function('return function Document() {}')());
|
76
|
-
this.Document.prototype = document;
|
77
|
-
}
|
78
|
-
}
|
79
|
-
|
80
|
-
|
81
|
-
})
|
82
|
-
.call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
83
|
-
|
84
|
-
(function(undefined) {
|
85
|
-
|
86
|
-
// Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Element/detect.js
|
87
|
-
var detect = ('Element' in this && 'HTMLElement' in this);
|
88
|
-
|
89
|
-
if (detect) return
|
90
|
-
|
91
|
-
// Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Element&flags=always
|
92
|
-
(function () {
|
93
|
-
|
94
|
-
// IE8
|
95
|
-
if (window.Element && !window.HTMLElement) {
|
96
|
-
window.HTMLElement = window.Element;
|
97
|
-
return;
|
98
|
-
}
|
99
|
-
|
100
|
-
// create Element constructor
|
101
|
-
window.Element = window.HTMLElement = new Function('return function Element() {}')();
|
102
|
-
|
103
|
-
// generate sandboxed iframe
|
104
|
-
var vbody = document.appendChild(document.createElement('body'));
|
105
|
-
var frame = vbody.appendChild(document.createElement('iframe'));
|
106
|
-
|
107
|
-
// use sandboxed iframe to replicate Element functionality
|
108
|
-
var frameDocument = frame.contentWindow.document;
|
109
|
-
var prototype = Element.prototype = frameDocument.appendChild(frameDocument.createElement('*'));
|
110
|
-
var cache = {};
|
111
|
-
|
112
|
-
// polyfill Element.prototype on an element
|
113
|
-
var shiv = function (element, deep) {
|
114
|
-
var
|
115
|
-
childNodes = element.childNodes || [],
|
116
|
-
index = -1,
|
117
|
-
key, value, childNode;
|
118
|
-
|
119
|
-
if (element.nodeType === 1 && element.constructor !== Element) {
|
120
|
-
element.constructor = Element;
|
121
|
-
|
122
|
-
for (key in cache) {
|
123
|
-
value = cache[key];
|
124
|
-
element[key] = value;
|
125
|
-
}
|
126
|
-
}
|
127
|
-
|
128
|
-
while (childNode = deep && childNodes[++index]) {
|
129
|
-
shiv(childNode, deep);
|
130
|
-
}
|
131
|
-
|
132
|
-
return element;
|
133
|
-
};
|
134
|
-
|
135
|
-
var elements = document.getElementsByTagName('*');
|
136
|
-
var nativeCreateElement = document.createElement;
|
137
|
-
var interval;
|
138
|
-
var loopLimit = 100;
|
139
|
-
|
140
|
-
prototype.attachEvent('onpropertychange', function (event) {
|
141
|
-
var
|
142
|
-
propertyName = event.propertyName,
|
143
|
-
nonValue = !cache.hasOwnProperty(propertyName),
|
144
|
-
newValue = prototype[propertyName],
|
145
|
-
oldValue = cache[propertyName],
|
146
|
-
index = -1,
|
147
|
-
element;
|
148
|
-
|
149
|
-
while (element = elements[++index]) {
|
150
|
-
if (element.nodeType === 1) {
|
151
|
-
if (nonValue || element[propertyName] === oldValue) {
|
152
|
-
element[propertyName] = newValue;
|
153
|
-
}
|
154
|
-
}
|
155
|
-
}
|
156
|
-
|
157
|
-
cache[propertyName] = newValue;
|
158
|
-
});
|
159
|
-
|
160
|
-
prototype.constructor = Element;
|
161
|
-
|
162
|
-
if (!prototype.hasAttribute) {
|
163
|
-
// <Element>.hasAttribute
|
164
|
-
prototype.hasAttribute = function hasAttribute(name) {
|
165
|
-
return this.getAttribute(name) !== null;
|
166
|
-
};
|
167
|
-
}
|
168
|
-
|
169
|
-
// Apply Element prototype to the pre-existing DOM as soon as the body element appears.
|
170
|
-
function bodyCheck() {
|
171
|
-
if (!(loopLimit--)) clearTimeout(interval);
|
172
|
-
if (document.body && !document.body.prototype && /(complete|interactive)/.test(document.readyState)) {
|
173
|
-
shiv(document, true);
|
174
|
-
if (interval && document.body.prototype) clearTimeout(interval);
|
175
|
-
return (!!document.body.prototype);
|
176
|
-
}
|
177
|
-
return false;
|
178
|
-
}
|
179
|
-
if (!bodyCheck()) {
|
180
|
-
document.onreadystatechange = bodyCheck;
|
181
|
-
interval = setInterval(bodyCheck, 25);
|
182
|
-
}
|
183
|
-
|
184
|
-
// Apply to any new elements created after load
|
185
|
-
document.createElement = function createElement(nodeName) {
|
186
|
-
var element = nativeCreateElement(String(nodeName).toLowerCase());
|
187
|
-
return shiv(element);
|
188
|
-
};
|
189
|
-
|
190
|
-
// remove sandboxed iframe
|
191
|
-
document.removeChild(vbody);
|
192
|
-
}());
|
193
|
-
|
194
|
-
})
|
195
|
-
.call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
196
|
-
|
197
|
-
(function(undefined) {
|
198
|
-
|
199
38
|
// Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Object/defineProperty/detect.js
|
200
39
|
var detect = (
|
201
40
|
// In IE8, defineProperty could only act on DOM elements, so full support
|
@@ -282,959 +121,1368 @@ if (detect) return
|
|
282
121
|
.call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
283
122
|
|
284
123
|
(function(undefined) {
|
124
|
+
// Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Function/prototype/bind/detect.js
|
125
|
+
var detect = 'bind' in Function.prototype;
|
285
126
|
|
286
|
-
|
287
|
-
var detect = (
|
288
|
-
(function(global) {
|
127
|
+
if (detect) return
|
289
128
|
|
290
|
-
|
291
|
-
|
129
|
+
// Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Function.prototype.bind&flags=always
|
130
|
+
Object.defineProperty(Function.prototype, 'bind', {
|
131
|
+
value: function bind(that) { // .length is 1
|
132
|
+
// add necessary es5-shim utilities
|
133
|
+
var $Array = Array;
|
134
|
+
var $Object = Object;
|
135
|
+
var ObjectPrototype = $Object.prototype;
|
136
|
+
var ArrayPrototype = $Array.prototype;
|
137
|
+
var Empty = function Empty() {};
|
138
|
+
var to_string = ObjectPrototype.toString;
|
139
|
+
var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';
|
140
|
+
var isCallable; /* inlined from https://npmjs.com/is-callable */ var fnToStr = Function.prototype.toString, tryFunctionObject = function tryFunctionObject(value) { try { fnToStr.call(value); return true; } catch (e) { return false; } }, fnClass = '[object Function]', genClass = '[object GeneratorFunction]'; isCallable = function isCallable(value) { if (typeof value !== 'function') { return false; } if (hasToStringTag) { return tryFunctionObject(value); } var strClass = to_string.call(value); return strClass === fnClass || strClass === genClass; };
|
141
|
+
var array_slice = ArrayPrototype.slice;
|
142
|
+
var array_concat = ArrayPrototype.concat;
|
143
|
+
var array_push = ArrayPrototype.push;
|
144
|
+
var max = Math.max;
|
145
|
+
// /add necessary es5-shim utilities
|
292
146
|
|
293
|
-
|
147
|
+
// 1. Let Target be the this value.
|
148
|
+
var target = this;
|
149
|
+
// 2. If IsCallable(Target) is false, throw a TypeError exception.
|
150
|
+
if (!isCallable(target)) {
|
151
|
+
throw new TypeError('Function.prototype.bind called on incompatible ' + target);
|
152
|
+
}
|
153
|
+
// 3. Let A be a new (possibly empty) internal list of all of the
|
154
|
+
// argument values provided after thisArg (arg1, arg2 etc), in order.
|
155
|
+
// XXX slicedArgs will stand in for "A" if used
|
156
|
+
var args = array_slice.call(arguments, 1); // for normal call
|
157
|
+
// 4. Let F be a new native ECMAScript object.
|
158
|
+
// 11. Set the [[Prototype]] internal property of F to the standard
|
159
|
+
// built-in Function prototype object as specified in 15.3.3.1.
|
160
|
+
// 12. Set the [[Call]] internal property of F as described in
|
161
|
+
// 15.3.4.5.1.
|
162
|
+
// 13. Set the [[Construct]] internal property of F as described in
|
163
|
+
// 15.3.4.5.2.
|
164
|
+
// 14. Set the [[HasInstance]] internal property of F as described in
|
165
|
+
// 15.3.4.5.3.
|
166
|
+
var bound;
|
167
|
+
var binder = function () {
|
294
168
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
169
|
+
if (this instanceof bound) {
|
170
|
+
// 15.3.4.5.2 [[Construct]]
|
171
|
+
// When the [[Construct]] internal method of a function object,
|
172
|
+
// F that was created using the bind function is called with a
|
173
|
+
// list of arguments ExtraArgs, the following steps are taken:
|
174
|
+
// 1. Let target be the value of F's [[TargetFunction]]
|
175
|
+
// internal property.
|
176
|
+
// 2. If target has no [[Construct]] internal method, a
|
177
|
+
// TypeError exception is thrown.
|
178
|
+
// 3. Let boundArgs be the value of F's [[BoundArgs]] internal
|
179
|
+
// property.
|
180
|
+
// 4. Let args be a new list containing the same values as the
|
181
|
+
// list boundArgs in the same order followed by the same
|
182
|
+
// values as the list ExtraArgs in the same order.
|
183
|
+
// 5. Return the result of calling the [[Construct]] internal
|
184
|
+
// method of target providing args as the arguments.
|
303
185
|
|
304
|
-
|
186
|
+
var result = target.apply(
|
187
|
+
this,
|
188
|
+
array_concat.call(args, array_slice.call(arguments))
|
189
|
+
);
|
190
|
+
if ($Object(result) === result) {
|
191
|
+
return result;
|
192
|
+
}
|
193
|
+
return this;
|
305
194
|
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
};
|
325
|
-
|
326
|
-
// This polyfill depends on availability of `document` so will not run in a worker
|
327
|
-
// However, we asssume there are no browsers with worker support that lack proper
|
328
|
-
// support for `Event` within the worker
|
329
|
-
if (typeof document === 'undefined' || typeof window === 'undefined') return;
|
195
|
+
} else {
|
196
|
+
// 15.3.4.5.1 [[Call]]
|
197
|
+
// When the [[Call]] internal method of a function object, F,
|
198
|
+
// which was created using the bind function is called with a
|
199
|
+
// this value and a list of arguments ExtraArgs, the following
|
200
|
+
// steps are taken:
|
201
|
+
// 1. Let boundArgs be the value of F's [[BoundArgs]] internal
|
202
|
+
// property.
|
203
|
+
// 2. Let boundThis be the value of F's [[BoundThis]] internal
|
204
|
+
// property.
|
205
|
+
// 3. Let target be the value of F's [[TargetFunction]] internal
|
206
|
+
// property.
|
207
|
+
// 4. Let args be a new list containing the same values as the
|
208
|
+
// list boundArgs in the same order followed by the same
|
209
|
+
// values as the list ExtraArgs in the same order.
|
210
|
+
// 5. Return the result of calling the [[Call]] internal method
|
211
|
+
// of target providing boundThis as the this value and
|
212
|
+
// providing args as the arguments.
|
330
213
|
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
214
|
+
// equiv: target.call(this, ...boundArgs, ...args)
|
215
|
+
return target.apply(
|
216
|
+
that,
|
217
|
+
array_concat.call(args, array_slice.call(arguments))
|
218
|
+
);
|
335
219
|
|
336
|
-
|
337
|
-
if (index in array && array[index] === element) {
|
338
|
-
return index;
|
339
|
-
}
|
340
|
-
}
|
220
|
+
}
|
341
221
|
|
342
|
-
|
343
|
-
}
|
222
|
+
};
|
344
223
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
224
|
+
// 15. If the [[Class]] internal property of Target is "Function", then
|
225
|
+
// a. Let L be the length property of Target minus the length of A.
|
226
|
+
// b. Set the length own property of F to either 0 or L, whichever is
|
227
|
+
// larger.
|
228
|
+
// 16. Else set the length own property of F to 0.
|
350
229
|
|
351
|
-
|
352
|
-
// Shortcut if browser supports createEvent
|
353
|
-
if ('createEvent' in document) {
|
354
|
-
event = document.createEvent('Event');
|
355
|
-
var bubbles = eventInitDict && eventInitDict.bubbles !== undefined ? eventInitDict.bubbles : false;
|
356
|
-
var cancelable = eventInitDict && eventInitDict.cancelable !== undefined ? eventInitDict.cancelable : false;
|
230
|
+
var boundLength = max(0, target.length - args.length);
|
357
231
|
|
358
|
-
|
232
|
+
// 17. Set the attributes of the length own property of F to the values
|
233
|
+
// specified in 15.3.5.1.
|
234
|
+
var boundArgs = [];
|
235
|
+
for (var i = 0; i < boundLength; i++) {
|
236
|
+
array_push.call(boundArgs, '$' + i);
|
237
|
+
}
|
359
238
|
|
360
|
-
|
361
|
-
|
239
|
+
// XXX Build a dynamic function with desired amount of arguments is the only
|
240
|
+
// way to set the length property of a function.
|
241
|
+
// In environments where Content Security Policies enabled (Chrome extensions,
|
242
|
+
// for ex.) all use of eval or Function costructor throws an exception.
|
243
|
+
// However in all of these environments Function.prototype.bind exists
|
244
|
+
// and so this code will never be executed.
|
245
|
+
bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this, arguments); }')(binder);
|
362
246
|
|
363
|
-
|
247
|
+
if (target.prototype) {
|
248
|
+
Empty.prototype = target.prototype;
|
249
|
+
bound.prototype = new Empty();
|
250
|
+
// Clean up dangling references.
|
251
|
+
Empty.prototype = null;
|
252
|
+
}
|
364
253
|
|
365
|
-
|
366
|
-
|
367
|
-
event.cancelable = eventInitDict && eventInitDict.cancelable !== undefined ? eventInitDict.cancelable : false;
|
254
|
+
// TODO
|
255
|
+
// 18. Set the [[Extensible]] internal property of F to true.
|
368
256
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
257
|
+
// TODO
|
258
|
+
// 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
|
259
|
+
// 20. Call the [[DefineOwnProperty]] internal method of F with
|
260
|
+
// arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]:
|
261
|
+
// thrower, [[Enumerable]]: false, [[Configurable]]: false}, and
|
262
|
+
// false.
|
263
|
+
// 21. Call the [[DefineOwnProperty]] internal method of F with
|
264
|
+
// arguments "arguments", PropertyDescriptor {[[Get]]: thrower,
|
265
|
+
// [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},
|
266
|
+
// and false.
|
379
267
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
listener = arguments[1];
|
268
|
+
// TODO
|
269
|
+
// NOTE Function objects created using Function.prototype.bind do not
|
270
|
+
// have a prototype property or the [[Code]], [[FormalParameters]], and
|
271
|
+
// [[Scope]] internal properties.
|
272
|
+
// XXX can't delete prototype in pure-js.
|
386
273
|
|
387
|
-
|
388
|
-
|
389
|
-
|
274
|
+
// 22. Return F.
|
275
|
+
return bound;
|
276
|
+
}
|
277
|
+
});
|
278
|
+
})
|
279
|
+
.call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
390
280
|
|
391
|
-
|
392
|
-
element._events = {};
|
393
|
-
}
|
281
|
+
(function(undefined) {
|
394
282
|
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
length = events.length,
|
402
|
-
eventElement;
|
283
|
+
// Detection from https://raw.githubusercontent.com/Financial-Times/polyfill-service/master/packages/polyfill-library/polyfills/DOMTokenList/detect.js
|
284
|
+
var detect = (
|
285
|
+
'DOMTokenList' in this && (function (x) {
|
286
|
+
return 'classList' in x ? !x.classList.toggle('x', false) && !x.className : true;
|
287
|
+
})(document.createElement('x'))
|
288
|
+
);
|
403
289
|
|
404
|
-
|
405
|
-
if (event.cancelable !== false) {
|
406
|
-
event.returnValue = false;
|
407
|
-
}
|
408
|
-
};
|
290
|
+
if (detect) return
|
409
291
|
|
410
|
-
|
411
|
-
|
412
|
-
|
292
|
+
// Polyfill from https://raw.githubusercontent.com/Financial-Times/polyfill-service/master/packages/polyfill-library/polyfills/DOMTokenList/polyfill.js
|
293
|
+
(function (global) {
|
294
|
+
var nativeImpl = "DOMTokenList" in global && global.DOMTokenList;
|
413
295
|
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
296
|
+
if (
|
297
|
+
!nativeImpl ||
|
298
|
+
(
|
299
|
+
!!document.createElementNS &&
|
300
|
+
!!document.createElementNS('http://www.w3.org/2000/svg', 'svg') &&
|
301
|
+
!(document.createElementNS("http://www.w3.org/2000/svg", "svg").classList instanceof DOMTokenList)
|
302
|
+
)
|
303
|
+
) {
|
304
|
+
global.DOMTokenList = (function() { // eslint-disable-line no-unused-vars
|
305
|
+
var dpSupport = true;
|
306
|
+
var defineGetter = function (object, name, fn, configurable) {
|
307
|
+
if (Object.defineProperty)
|
308
|
+
Object.defineProperty(object, name, {
|
309
|
+
configurable: false === dpSupport ? true : !!configurable,
|
310
|
+
get: fn
|
311
|
+
});
|
418
312
|
|
419
|
-
|
420
|
-
|
421
|
-
event.target = event.target || event.srcElement || element;
|
422
|
-
event.timeStamp = new Date().getTime();
|
313
|
+
else object.__defineGetter__(name, fn);
|
314
|
+
};
|
423
315
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
316
|
+
/** Ensure the browser allows Object.defineProperty to be used on native JavaScript objects. */
|
317
|
+
try {
|
318
|
+
defineGetter({}, "support");
|
319
|
+
}
|
320
|
+
catch (e) {
|
321
|
+
dpSupport = false;
|
322
|
+
}
|
428
323
|
|
429
|
-
while (++index < length && !event.cancelImmediate) {
|
430
|
-
if (index in events) {
|
431
|
-
eventElement = events[index];
|
432
324
|
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
325
|
+
var _DOMTokenList = function (el, prop) {
|
326
|
+
var that = this;
|
327
|
+
var tokens = [];
|
328
|
+
var tokenMap = {};
|
329
|
+
var length = 0;
|
330
|
+
var maxLength = 0;
|
331
|
+
var addIndexGetter = function (i) {
|
332
|
+
defineGetter(that, i, function () {
|
333
|
+
preop();
|
334
|
+
return tokens[i];
|
335
|
+
}, false);
|
439
336
|
|
440
|
-
|
337
|
+
};
|
338
|
+
var reindex = function () {
|
441
339
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
340
|
+
/** Define getter functions for array-like access to the tokenList's contents. */
|
341
|
+
if (length >= maxLength)
|
342
|
+
for (; maxLength < length; ++maxLength) {
|
343
|
+
addIndexGetter(maxLength);
|
344
|
+
}
|
345
|
+
};
|
446
346
|
|
447
|
-
|
448
|
-
|
347
|
+
/** Helper function called at the start of each class method. Internal use only. */
|
348
|
+
var preop = function () {
|
349
|
+
var error;
|
350
|
+
var i;
|
351
|
+
var args = arguments;
|
352
|
+
var rSpace = /\s+/;
|
449
353
|
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
354
|
+
/** Validate the token/s passed to an instance method, if any. */
|
355
|
+
if (args.length)
|
356
|
+
for (i = 0; i < args.length; ++i)
|
357
|
+
if (rSpace.test(args[i])) {
|
358
|
+
error = new SyntaxError('String "' + args[i] + '" ' + "contains" + ' an invalid character');
|
359
|
+
error.code = 5;
|
360
|
+
error.name = "InvalidCharacterError";
|
361
|
+
throw error;
|
362
|
+
}
|
456
363
|
|
457
|
-
if (element._events && element._events[type] && element._events[type].list) {
|
458
|
-
index = indexOf(element._events[type].list, listener);
|
459
364
|
|
460
|
-
|
461
|
-
|
365
|
+
/** Split the new value apart by whitespace*/
|
366
|
+
if (typeof el[prop] === "object") {
|
367
|
+
tokens = ("" + el[prop].baseVal).replace(/^\s+|\s+$/g, "").split(rSpace);
|
368
|
+
} else {
|
369
|
+
tokens = ("" + el[prop]).replace(/^\s+|\s+$/g, "").split(rSpace);
|
370
|
+
}
|
462
371
|
|
463
|
-
|
464
|
-
|
465
|
-
element.detachEvent('on' + type, element._events[type]);
|
466
|
-
}
|
467
|
-
delete element._events[type];
|
468
|
-
}
|
469
|
-
}
|
470
|
-
}
|
471
|
-
};
|
372
|
+
/** Avoid treating blank strings as single-item token lists */
|
373
|
+
if ("" === tokens[0]) tokens = [];
|
472
374
|
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
375
|
+
/** Repopulate the internal token lists */
|
376
|
+
tokenMap = {};
|
377
|
+
for (i = 0; i < tokens.length; ++i)
|
378
|
+
tokenMap[tokens[i]] = true;
|
379
|
+
length = tokens.length;
|
380
|
+
reindex();
|
381
|
+
};
|
477
382
|
|
478
|
-
|
479
|
-
|
480
|
-
}
|
383
|
+
/** Populate our internal token list if the targeted attribute of the subject element isn't empty. */
|
384
|
+
preop();
|
481
385
|
|
482
|
-
|
386
|
+
/** Return the number of tokens in the underlying string. Read-only. */
|
387
|
+
defineGetter(that, "length", function () {
|
388
|
+
preop();
|
389
|
+
return length;
|
390
|
+
});
|
483
391
|
|
484
|
-
|
485
|
-
|
486
|
-
|
392
|
+
/** Override the default toString/toLocaleString methods to return a space-delimited list of tokens when typecast. */
|
393
|
+
that.toLocaleString =
|
394
|
+
that.toString = function () {
|
395
|
+
preop();
|
396
|
+
return tokens.join(" ");
|
397
|
+
};
|
487
398
|
|
488
|
-
|
489
|
-
|
399
|
+
that.item = function (idx) {
|
400
|
+
preop();
|
401
|
+
return tokens[idx];
|
402
|
+
};
|
490
403
|
|
491
|
-
|
492
|
-
|
404
|
+
that.contains = function (token) {
|
405
|
+
preop();
|
406
|
+
return !!tokenMap[token];
|
407
|
+
};
|
493
408
|
|
494
|
-
|
495
|
-
|
409
|
+
that.add = function () {
|
410
|
+
preop.apply(that, args = arguments);
|
496
411
|
|
497
|
-
|
498
|
-
|
499
|
-
|
412
|
+
for (var args, token, i = 0, l = args.length; i < l; ++i) {
|
413
|
+
token = args[i];
|
414
|
+
if (!tokenMap[token]) {
|
415
|
+
tokens.push(token);
|
416
|
+
tokenMap[token] = true;
|
417
|
+
}
|
418
|
+
}
|
500
419
|
|
501
|
-
|
502
|
-
|
420
|
+
/** Update the targeted attribute of the attached element if the token list's changed. */
|
421
|
+
if (length !== tokens.length) {
|
422
|
+
length = tokens.length >>> 0;
|
423
|
+
if (typeof el[prop] === "object") {
|
424
|
+
el[prop].baseVal = tokens.join(" ");
|
425
|
+
} else {
|
426
|
+
el[prop] = tokens.join(" ");
|
427
|
+
}
|
428
|
+
reindex();
|
429
|
+
}
|
430
|
+
};
|
503
431
|
|
504
|
-
|
505
|
-
|
506
|
-
}
|
432
|
+
that.remove = function () {
|
433
|
+
preop.apply(that, args = arguments);
|
507
434
|
|
508
|
-
|
509
|
-
|
510
|
-
|
435
|
+
/** Build a hash of token names to compare against when recollecting our token list. */
|
436
|
+
for (var args, ignore = {}, i = 0, t = []; i < args.length; ++i) {
|
437
|
+
ignore[args[i]] = true;
|
438
|
+
delete tokenMap[args[i]];
|
439
|
+
}
|
511
440
|
|
512
|
-
|
513
|
-
|
441
|
+
/** Run through our tokens list and reassign only those that aren't defined in the hash declared above. */
|
442
|
+
for (i = 0; i < tokens.length; ++i)
|
443
|
+
if (!ignore[tokens[i]]) t.push(tokens[i]);
|
444
|
+
|
445
|
+
tokens = t;
|
446
|
+
length = t.length >>> 0;
|
447
|
+
|
448
|
+
/** Update the targeted attribute of the attached element. */
|
449
|
+
if (typeof el[prop] === "object") {
|
450
|
+
el[prop].baseVal = tokens.join(" ");
|
451
|
+
} else {
|
452
|
+
el[prop] = tokens.join(" ");
|
453
|
+
}
|
454
|
+
reindex();
|
455
|
+
};
|
456
|
+
|
457
|
+
that.toggle = function (token, force) {
|
458
|
+
preop.apply(that, [token]);
|
459
|
+
|
460
|
+
/** Token state's being forced. */
|
461
|
+
if (undefined !== force) {
|
462
|
+
if (force) {
|
463
|
+
that.add(token);
|
464
|
+
return true;
|
465
|
+
} else {
|
466
|
+
that.remove(token);
|
467
|
+
return false;
|
468
|
+
}
|
469
|
+
}
|
470
|
+
|
471
|
+
/** Token already exists in tokenList. Remove it, and return FALSE. */
|
472
|
+
if (tokenMap[token]) {
|
473
|
+
that.remove(token);
|
474
|
+
return false;
|
475
|
+
}
|
476
|
+
|
477
|
+
/** Otherwise, add the token and return TRUE. */
|
478
|
+
that.add(token);
|
479
|
+
return true;
|
480
|
+
};
|
481
|
+
|
482
|
+
return that;
|
483
|
+
};
|
484
|
+
|
485
|
+
return _DOMTokenList;
|
486
|
+
}());
|
487
|
+
}
|
488
|
+
|
489
|
+
// Add second argument to native DOMTokenList.toggle() if necessary
|
490
|
+
(function () {
|
491
|
+
var e = document.createElement('span');
|
492
|
+
if (!('classList' in e)) return;
|
493
|
+
e.classList.toggle('x', false);
|
494
|
+
if (!e.classList.contains('x')) return;
|
495
|
+
e.classList.constructor.prototype.toggle = function toggle(token /*, force*/) {
|
496
|
+
var force = arguments[1];
|
497
|
+
if (force === undefined) {
|
498
|
+
var add = !this.contains(token);
|
499
|
+
this[add ? 'add' : 'remove'](token);
|
500
|
+
return add;
|
501
|
+
}
|
502
|
+
force = !!force;
|
503
|
+
this[force ? 'add' : 'remove'](token);
|
504
|
+
return force;
|
505
|
+
};
|
506
|
+
}());
|
507
|
+
|
508
|
+
// Add multiple arguments to native DOMTokenList.add() if necessary
|
509
|
+
(function () {
|
510
|
+
var e = document.createElement('span');
|
511
|
+
if (!('classList' in e)) return;
|
512
|
+
e.classList.add('a', 'b');
|
513
|
+
if (e.classList.contains('b')) return;
|
514
|
+
var native = e.classList.constructor.prototype.add;
|
515
|
+
e.classList.constructor.prototype.add = function () {
|
516
|
+
var args = arguments;
|
517
|
+
var l = arguments.length;
|
518
|
+
for (var i = 0; i < l; i++) {
|
519
|
+
native.call(this, args[i]);
|
520
|
+
}
|
521
|
+
};
|
522
|
+
}());
|
523
|
+
|
524
|
+
// Add multiple arguments to native DOMTokenList.remove() if necessary
|
525
|
+
(function () {
|
526
|
+
var e = document.createElement('span');
|
527
|
+
if (!('classList' in e)) return;
|
528
|
+
e.classList.add('a');
|
529
|
+
e.classList.add('b');
|
530
|
+
e.classList.remove('a', 'b');
|
531
|
+
if (!e.classList.contains('b')) return;
|
532
|
+
var native = e.classList.constructor.prototype.remove;
|
533
|
+
e.classList.constructor.prototype.remove = function () {
|
534
|
+
var args = arguments;
|
535
|
+
var l = arguments.length;
|
536
|
+
for (var i = 0; i < l; i++) {
|
537
|
+
native.call(this, args[i]);
|
538
|
+
}
|
539
|
+
};
|
540
|
+
}());
|
541
|
+
|
542
|
+
}(this));
|
543
|
+
|
544
|
+
}).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
545
|
+
|
546
|
+
(function(undefined) {
|
547
|
+
|
548
|
+
// Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Document/detect.js
|
549
|
+
var detect = ("Document" in this);
|
550
|
+
|
551
|
+
if (detect) return
|
552
|
+
|
553
|
+
// Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Document&flags=always
|
554
|
+
if ((typeof WorkerGlobalScope === "undefined") && (typeof importScripts !== "function")) {
|
555
|
+
|
556
|
+
if (this.HTMLDocument) { // IE8
|
557
|
+
|
558
|
+
// HTMLDocument is an extension of Document. If the browser has HTMLDocument but not Document, the former will suffice as an alias for the latter.
|
559
|
+
this.Document = this.HTMLDocument;
|
560
|
+
|
561
|
+
} else {
|
562
|
+
|
563
|
+
// Create an empty function to act as the missing constructor for the document object, attach the document object as its prototype. The function needs to be anonymous else it is hoisted and causes the feature detect to prematurely pass, preventing the assignments below being made.
|
564
|
+
this.Document = this.HTMLDocument = document.constructor = (new Function('return function Document() {}')());
|
565
|
+
this.Document.prototype = document;
|
566
|
+
}
|
567
|
+
}
|
568
|
+
|
569
|
+
|
570
|
+
})
|
571
|
+
.call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
572
|
+
|
573
|
+
(function(undefined) {
|
574
|
+
|
575
|
+
// Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Element/detect.js
|
576
|
+
var detect = ('Element' in this && 'HTMLElement' in this);
|
577
|
+
|
578
|
+
if (detect) return
|
579
|
+
|
580
|
+
// Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Element&flags=always
|
581
|
+
(function () {
|
582
|
+
|
583
|
+
// IE8
|
584
|
+
if (window.Element && !window.HTMLElement) {
|
585
|
+
window.HTMLElement = window.Element;
|
586
|
+
return;
|
587
|
+
}
|
588
|
+
|
589
|
+
// create Element constructor
|
590
|
+
window.Element = window.HTMLElement = new Function('return function Element() {}')();
|
591
|
+
|
592
|
+
// generate sandboxed iframe
|
593
|
+
var vbody = document.appendChild(document.createElement('body'));
|
594
|
+
var frame = vbody.appendChild(document.createElement('iframe'));
|
595
|
+
|
596
|
+
// use sandboxed iframe to replicate Element functionality
|
597
|
+
var frameDocument = frame.contentWindow.document;
|
598
|
+
var prototype = Element.prototype = frameDocument.appendChild(frameDocument.createElement('*'));
|
599
|
+
var cache = {};
|
600
|
+
|
601
|
+
// polyfill Element.prototype on an element
|
602
|
+
var shiv = function (element, deep) {
|
603
|
+
var
|
604
|
+
childNodes = element.childNodes || [],
|
605
|
+
index = -1,
|
606
|
+
key, value, childNode;
|
607
|
+
|
608
|
+
if (element.nodeType === 1 && element.constructor !== Element) {
|
609
|
+
element.constructor = Element;
|
610
|
+
|
611
|
+
for (key in cache) {
|
612
|
+
value = cache[key];
|
613
|
+
element[key] = value;
|
514
614
|
}
|
615
|
+
}
|
515
616
|
|
516
|
-
|
517
|
-
|
617
|
+
while (childNode = deep && childNodes[++index]) {
|
618
|
+
shiv(childNode, deep);
|
619
|
+
}
|
518
620
|
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
621
|
+
return element;
|
622
|
+
};
|
623
|
+
|
624
|
+
var elements = document.getElementsByTagName('*');
|
625
|
+
var nativeCreateElement = document.createElement;
|
626
|
+
var interval;
|
627
|
+
var loopLimit = 100;
|
628
|
+
|
629
|
+
prototype.attachEvent('onpropertychange', function (event) {
|
630
|
+
var
|
631
|
+
propertyName = event.propertyName,
|
632
|
+
nonValue = !cache.hasOwnProperty(propertyName),
|
633
|
+
newValue = prototype[propertyName],
|
634
|
+
oldValue = cache[propertyName],
|
635
|
+
index = -1,
|
636
|
+
element;
|
637
|
+
|
638
|
+
while (element = elements[++index]) {
|
639
|
+
if (element.nodeType === 1) {
|
640
|
+
if (nonValue || element[propertyName] === oldValue) {
|
641
|
+
element[propertyName] = newValue;
|
642
|
+
}
|
525
643
|
}
|
526
|
-
}
|
644
|
+
}
|
645
|
+
|
646
|
+
cache[propertyName] = newValue;
|
647
|
+
});
|
648
|
+
|
649
|
+
prototype.constructor = Element;
|
650
|
+
|
651
|
+
if (!prototype.hasAttribute) {
|
652
|
+
// <Element>.hasAttribute
|
653
|
+
prototype.hasAttribute = function hasAttribute(name) {
|
654
|
+
return this.getAttribute(name) !== null;
|
655
|
+
};
|
656
|
+
}
|
657
|
+
|
658
|
+
// Apply Element prototype to the pre-existing DOM as soon as the body element appears.
|
659
|
+
function bodyCheck() {
|
660
|
+
if (!(loopLimit--)) clearTimeout(interval);
|
661
|
+
if (document.body && !document.body.prototype && /(complete|interactive)/.test(document.readyState)) {
|
662
|
+
shiv(document, true);
|
663
|
+
if (interval && document.body.prototype) clearTimeout(interval);
|
664
|
+
return (!!document.body.prototype);
|
665
|
+
}
|
666
|
+
return false;
|
667
|
+
}
|
668
|
+
if (!bodyCheck()) {
|
669
|
+
document.onreadystatechange = bodyCheck;
|
670
|
+
interval = setInterval(bodyCheck, 25);
|
527
671
|
}
|
672
|
+
|
673
|
+
// Apply to any new elements created after load
|
674
|
+
document.createElement = function createElement(nodeName) {
|
675
|
+
var element = nativeCreateElement(String(nodeName).toLowerCase());
|
676
|
+
return shiv(element);
|
677
|
+
};
|
678
|
+
|
679
|
+
// remove sandboxed iframe
|
680
|
+
document.removeChild(vbody);
|
528
681
|
}());
|
529
682
|
|
530
683
|
})
|
531
684
|
.call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
532
685
|
|
533
|
-
|
534
|
-
* JavaScript 'shim' to trigger the click event of element(s) when the space key is pressed.
|
535
|
-
*
|
536
|
-
* Created since some Assistive Technologies (for example some Screenreaders)
|
537
|
-
* will tell a user to press space on a 'button', so this functionality needs to be shimmed
|
538
|
-
* See https://github.com/alphagov/govuk_elements/pull/272#issuecomment-233028270
|
539
|
-
*
|
540
|
-
* Usage instructions:
|
541
|
-
* the 'shim' will be automatically initialised
|
542
|
-
*/
|
686
|
+
(function(undefined) {
|
543
687
|
|
544
|
-
|
688
|
+
// Detection from https://raw.githubusercontent.com/Financial-Times/polyfill-service/8717a9e04ac7aff99b4980fbedead98036b0929a/packages/polyfill-library/polyfills/Element/prototype/classList/detect.js
|
689
|
+
var detect = (
|
690
|
+
'document' in this && "classList" in document.documentElement && 'Element' in this && 'classList' in Element.prototype && (function () {
|
691
|
+
var e = document.createElement('span');
|
692
|
+
e.classList.add('a', 'b');
|
693
|
+
return e.classList.contains('b');
|
694
|
+
}())
|
695
|
+
);
|
545
696
|
|
546
|
-
|
547
|
-
this.$module = $module;
|
548
|
-
}
|
697
|
+
if (detect) return
|
549
698
|
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
}
|
699
|
+
// Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Element.prototype.classList&flags=always
|
700
|
+
(function (global) {
|
701
|
+
var dpSupport = true;
|
702
|
+
var defineGetter = function (object, name, fn, configurable) {
|
703
|
+
if (Object.defineProperty)
|
704
|
+
Object.defineProperty(object, name, {
|
705
|
+
configurable: false === dpSupport ? true : !!configurable,
|
706
|
+
get: fn
|
707
|
+
});
|
708
|
+
|
709
|
+
else object.__defineGetter__(name, fn);
|
710
|
+
};
|
711
|
+
/** Ensure the browser allows Object.defineProperty to be used on native JavaScript objects. */
|
712
|
+
try {
|
713
|
+
defineGetter({}, "support");
|
714
|
+
}
|
715
|
+
catch (e) {
|
716
|
+
dpSupport = false;
|
717
|
+
}
|
718
|
+
/** Polyfills a property with a DOMTokenList */
|
719
|
+
var addProp = function (o, name, attr) {
|
720
|
+
|
721
|
+
defineGetter(o.prototype, name, function () {
|
722
|
+
var tokenList;
|
723
|
+
|
724
|
+
var THIS = this,
|
725
|
+
|
726
|
+
/** Prevent this from firing twice for some reason. What the hell, IE. */
|
727
|
+
gibberishProperty = "__defineGetter__" + "DEFINE_PROPERTY" + name;
|
728
|
+
if(THIS[gibberishProperty]) return tokenList;
|
729
|
+
THIS[gibberishProperty] = true;
|
730
|
+
|
731
|
+
/**
|
732
|
+
* IE8 can't define properties on native JavaScript objects, so we'll use a dumb hack instead.
|
733
|
+
*
|
734
|
+
* What this is doing is creating a dummy element ("reflection") inside a detached phantom node ("mirror")
|
735
|
+
* that serves as the target of Object.defineProperty instead. While we could simply use the subject HTML
|
736
|
+
* element instead, this would conflict with element types which use indexed properties (such as forms and
|
737
|
+
* select lists).
|
738
|
+
*/
|
739
|
+
if (false === dpSupport) {
|
740
|
+
|
741
|
+
var visage;
|
742
|
+
var mirror = addProp.mirror || document.createElement("div");
|
743
|
+
var reflections = mirror.childNodes;
|
744
|
+
var l = reflections.length;
|
566
745
|
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
this.$module.addEventListener('keydown', this.handleKeyDown);
|
573
|
-
};
|
746
|
+
for (var i = 0; i < l; ++i)
|
747
|
+
if (reflections[i]._R === THIS) {
|
748
|
+
visage = reflections[i];
|
749
|
+
break;
|
750
|
+
}
|
574
751
|
|
575
|
-
|
576
|
-
|
577
|
-
var detect = 'bind' in Function.prototype;
|
752
|
+
/** Couldn't find an element's reflection inside the mirror. Materialise one. */
|
753
|
+
visage || (visage = mirror.appendChild(document.createElement("div")));
|
578
754
|
|
579
|
-
|
755
|
+
tokenList = DOMTokenList.call(visage, THIS, attr);
|
756
|
+
} else tokenList = new DOMTokenList(THIS, attr);
|
580
757
|
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
var $Array = Array;
|
586
|
-
var $Object = Object;
|
587
|
-
var ObjectPrototype = $Object.prototype;
|
588
|
-
var ArrayPrototype = $Array.prototype;
|
589
|
-
var Empty = function Empty() {};
|
590
|
-
var to_string = ObjectPrototype.toString;
|
591
|
-
var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';
|
592
|
-
var isCallable; /* inlined from https://npmjs.com/is-callable */ var fnToStr = Function.prototype.toString, tryFunctionObject = function tryFunctionObject(value) { try { fnToStr.call(value); return true; } catch (e) { return false; } }, fnClass = '[object Function]', genClass = '[object GeneratorFunction]'; isCallable = function isCallable(value) { if (typeof value !== 'function') { return false; } if (hasToStringTag) { return tryFunctionObject(value); } var strClass = to_string.call(value); return strClass === fnClass || strClass === genClass; };
|
593
|
-
var array_slice = ArrayPrototype.slice;
|
594
|
-
var array_concat = ArrayPrototype.concat;
|
595
|
-
var array_push = ArrayPrototype.push;
|
596
|
-
var max = Math.max;
|
597
|
-
// /add necessary es5-shim utilities
|
758
|
+
defineGetter(THIS, name, function () {
|
759
|
+
return tokenList;
|
760
|
+
});
|
761
|
+
delete THIS[gibberishProperty];
|
598
762
|
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
if (!isCallable(target)) {
|
603
|
-
throw new TypeError('Function.prototype.bind called on incompatible ' + target);
|
604
|
-
}
|
605
|
-
// 3. Let A be a new (possibly empty) internal list of all of the
|
606
|
-
// argument values provided after thisArg (arg1, arg2 etc), in order.
|
607
|
-
// XXX slicedArgs will stand in for "A" if used
|
608
|
-
var args = array_slice.call(arguments, 1); // for normal call
|
609
|
-
// 4. Let F be a new native ECMAScript object.
|
610
|
-
// 11. Set the [[Prototype]] internal property of F to the standard
|
611
|
-
// built-in Function prototype object as specified in 15.3.3.1.
|
612
|
-
// 12. Set the [[Call]] internal property of F as described in
|
613
|
-
// 15.3.4.5.1.
|
614
|
-
// 13. Set the [[Construct]] internal property of F as described in
|
615
|
-
// 15.3.4.5.2.
|
616
|
-
// 14. Set the [[HasInstance]] internal property of F as described in
|
617
|
-
// 15.3.4.5.3.
|
618
|
-
var bound;
|
619
|
-
var binder = function () {
|
763
|
+
return tokenList;
|
764
|
+
}, true);
|
765
|
+
};
|
620
766
|
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
// internal property.
|
628
|
-
// 2. If target has no [[Construct]] internal method, a
|
629
|
-
// TypeError exception is thrown.
|
630
|
-
// 3. Let boundArgs be the value of F's [[BoundArgs]] internal
|
631
|
-
// property.
|
632
|
-
// 4. Let args be a new list containing the same values as the
|
633
|
-
// list boundArgs in the same order followed by the same
|
634
|
-
// values as the list ExtraArgs in the same order.
|
635
|
-
// 5. Return the result of calling the [[Construct]] internal
|
636
|
-
// method of target providing args as the arguments.
|
767
|
+
addProp(global.Element, "classList", "className");
|
768
|
+
addProp(global.HTMLElement, "classList", "className");
|
769
|
+
addProp(global.HTMLLinkElement, "relList", "rel");
|
770
|
+
addProp(global.HTMLAnchorElement, "relList", "rel");
|
771
|
+
addProp(global.HTMLAreaElement, "relList", "rel");
|
772
|
+
}(this));
|
637
773
|
|
638
|
-
|
639
|
-
this,
|
640
|
-
array_concat.call(args, array_slice.call(arguments))
|
641
|
-
);
|
642
|
-
if ($Object(result) === result) {
|
643
|
-
return result;
|
644
|
-
}
|
645
|
-
return this;
|
774
|
+
}).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
646
775
|
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
776
|
+
function Accordion ($module) {
|
777
|
+
this.$module = $module;
|
778
|
+
this.moduleId = $module.getAttribute('id');
|
779
|
+
this.$sections = $module.querySelectorAll('.govuk-accordion__section');
|
780
|
+
this.$openAllButton = '';
|
781
|
+
this.browserSupportsSessionStorage = helper.checkForSessionStorage();
|
782
|
+
|
783
|
+
this.controlsClass = 'govuk-accordion__controls';
|
784
|
+
this.openAllClass = 'govuk-accordion__open-all';
|
785
|
+
this.iconClass = 'govuk-accordion__icon';
|
786
|
+
|
787
|
+
this.sectionHeaderClass = 'govuk-accordion__section-header';
|
788
|
+
this.sectionHeaderFocusedClass = 'govuk-accordion__section-header--focused';
|
789
|
+
this.sectionHeadingClass = 'govuk-accordion__section-heading';
|
790
|
+
this.sectionSummaryClass = 'govuk-accordion__section-summary';
|
791
|
+
this.sectionButtonClass = 'govuk-accordion__section-button';
|
792
|
+
this.sectionExpandedClass = 'govuk-accordion__section--expanded';
|
793
|
+
}
|
665
794
|
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
795
|
+
// Initialize component
|
796
|
+
Accordion.prototype.init = function () {
|
797
|
+
// Check for module
|
798
|
+
if (!this.$module) {
|
799
|
+
return
|
800
|
+
}
|
671
801
|
|
672
|
-
|
802
|
+
this.initControls();
|
673
803
|
|
674
|
-
|
804
|
+
this.initSectionHeaders();
|
675
805
|
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
// 16. Else set the length own property of F to 0.
|
806
|
+
// See if "Open all" button text should be updated
|
807
|
+
var areAllSectionsOpen = this.checkIfAllSectionsOpen();
|
808
|
+
this.updateOpenAllButton(areAllSectionsOpen);
|
809
|
+
};
|
681
810
|
|
682
|
-
|
811
|
+
// Initialise controls and set attributes
|
812
|
+
Accordion.prototype.initControls = function () {
|
813
|
+
// Create "Open all" button and set attributes
|
814
|
+
this.$openAllButton = document.createElement('button');
|
815
|
+
this.$openAllButton.setAttribute('type', 'button');
|
816
|
+
this.$openAllButton.innerHTML = 'Open all <span class="govuk-visually-hidden">sections</span>';
|
817
|
+
this.$openAllButton.setAttribute('class', this.openAllClass);
|
818
|
+
this.$openAllButton.setAttribute('aria-expanded', 'false');
|
819
|
+
this.$openAllButton.setAttribute('type', 'button');
|
820
|
+
|
821
|
+
// Create control wrapper and add controls to it
|
822
|
+
var accordionControls = document.createElement('div');
|
823
|
+
accordionControls.setAttribute('class', this.controlsClass);
|
824
|
+
accordionControls.appendChild(this.$openAllButton);
|
825
|
+
this.$module.insertBefore(accordionControls, this.$module.firstChild);
|
826
|
+
|
827
|
+
// Handle events for the controls
|
828
|
+
this.$openAllButton.addEventListener('click', this.onOpenOrCloseAllToggle.bind(this));
|
829
|
+
};
|
683
830
|
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
831
|
+
// Initialise section headers
|
832
|
+
Accordion.prototype.initSectionHeaders = function () {
|
833
|
+
// Loop through section headers
|
834
|
+
nodeListForEach(this.$sections, function ($section, i) {
|
835
|
+
// Set header attributes
|
836
|
+
var header = $section.querySelector('.' + this.sectionHeaderClass);
|
837
|
+
this.initHeaderAttributes(header, i);
|
690
838
|
|
691
|
-
|
692
|
-
// way to set the length property of a function.
|
693
|
-
// In environments where Content Security Policies enabled (Chrome extensions,
|
694
|
-
// for ex.) all use of eval or Function costructor throws an exception.
|
695
|
-
// However in all of these environments Function.prototype.bind exists
|
696
|
-
// and so this code will never be executed.
|
697
|
-
bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this, arguments); }')(binder);
|
839
|
+
this.setExpanded(this.isExpanded($section), $section);
|
698
840
|
|
699
|
-
|
700
|
-
|
701
|
-
bound.prototype = new Empty();
|
702
|
-
// Clean up dangling references.
|
703
|
-
Empty.prototype = null;
|
704
|
-
}
|
841
|
+
// Handle events
|
842
|
+
header.addEventListener('click', this.onSectionToggle.bind(this, $section));
|
705
843
|
|
706
|
-
|
707
|
-
|
844
|
+
// See if there is any state stored in sessionStorage and set the sections to
|
845
|
+
// open or closed.
|
846
|
+
this.setInitialState($section);
|
847
|
+
}.bind(this));
|
848
|
+
};
|
708
849
|
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
850
|
+
// Set individual header attributes
|
851
|
+
Accordion.prototype.initHeaderAttributes = function ($headerWrapper, index) {
|
852
|
+
var $module = this;
|
853
|
+
var $span = $headerWrapper.querySelector('.' + this.sectionButtonClass);
|
854
|
+
var $heading = $headerWrapper.querySelector('.' + this.sectionHeadingClass);
|
855
|
+
var $summary = $headerWrapper.querySelector('.' + this.sectionSummaryClass);
|
856
|
+
|
857
|
+
// Copy existing span element to an actual button element, for improved accessibility.
|
858
|
+
var $button = document.createElement('button');
|
859
|
+
$button.setAttribute('type', 'button');
|
860
|
+
$button.setAttribute('id', this.moduleId + '-heading-' + (index + 1));
|
861
|
+
$button.setAttribute('aria-controls', this.moduleId + '-content-' + (index + 1));
|
862
|
+
|
863
|
+
// Copy all attributes (https://developer.mozilla.org/en-US/docs/Web/API/Element/attributes) from $span to $button
|
864
|
+
for (var i = 0; i < $span.attributes.length; i++) {
|
865
|
+
var attr = $span.attributes.item(i);
|
866
|
+
$button.setAttribute(attr.nodeName, attr.nodeValue);
|
867
|
+
}
|
719
868
|
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
869
|
+
$button.addEventListener('focusin', function (e) {
|
870
|
+
if (!$headerWrapper.classList.contains($module.sectionHeaderFocusedClass)) {
|
871
|
+
$headerWrapper.className += ' ' + $module.sectionHeaderFocusedClass;
|
872
|
+
}
|
873
|
+
});
|
725
874
|
|
726
|
-
|
727
|
-
|
728
|
-
}
|
875
|
+
$button.addEventListener('blur', function (e) {
|
876
|
+
$headerWrapper.classList.remove($module.sectionHeaderFocusedClass);
|
729
877
|
});
|
730
|
-
})
|
731
|
-
.call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
732
878
|
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
*
|
737
|
-
* http://caniuse.com/#feat=details
|
738
|
-
*
|
739
|
-
* Usage instructions:
|
740
|
-
* the 'polyfill' will be automatically initialised
|
741
|
-
*/
|
879
|
+
if (typeof ($summary) !== 'undefined' && $summary !== null) {
|
880
|
+
$button.setAttribute('aria-describedby', this.moduleId + '-summary-' + (index + 1));
|
881
|
+
}
|
742
882
|
|
743
|
-
|
744
|
-
|
883
|
+
// $span could contain HTML elements (see https://www.w3.org/TR/2011/WD-html5-20110525/content-models.html#phrasing-content)
|
884
|
+
$button.innerHTML = $span.innerHTML;
|
745
885
|
|
746
|
-
|
747
|
-
|
886
|
+
$heading.removeChild($span);
|
887
|
+
$heading.appendChild($button);
|
748
888
|
|
749
|
-
|
750
|
-
|
751
|
-
|
889
|
+
// Add "+/-" icon
|
890
|
+
var icon = document.createElement('span');
|
891
|
+
icon.className = this.iconClass;
|
892
|
+
icon.setAttribute('aria-hidden', 'true');
|
752
893
|
|
753
|
-
|
754
|
-
|
755
|
-
* @param {object} node element
|
756
|
-
* @param {function} callback function
|
757
|
-
*/
|
758
|
-
Details.prototype.handleInputs = function (node, callback) {
|
759
|
-
node.addEventListener('keypress', function (event) {
|
760
|
-
var target = event.target;
|
761
|
-
// When the key gets pressed - check if it is enter or space
|
762
|
-
if (event.keyCode === KEY_ENTER || event.keyCode === KEY_SPACE$1) {
|
763
|
-
if (target.nodeName.toLowerCase() === 'summary') {
|
764
|
-
// Prevent space from scrolling the page
|
765
|
-
// and enter from submitting a form
|
766
|
-
event.preventDefault();
|
767
|
-
// Click to let the click event do all the necessary action
|
768
|
-
if (target.click) {
|
769
|
-
target.click();
|
770
|
-
} else {
|
771
|
-
// except Safari 5.1 and under don't support .click() here
|
772
|
-
callback(event);
|
773
|
-
}
|
774
|
-
}
|
775
|
-
}
|
776
|
-
});
|
894
|
+
$heading.appendChild(icon);
|
895
|
+
};
|
777
896
|
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
if (target.nodeName.toLowerCase() === 'summary') {
|
783
|
-
event.preventDefault();
|
784
|
-
}
|
785
|
-
}
|
786
|
-
});
|
897
|
+
// When section toggled, set and store state
|
898
|
+
Accordion.prototype.onSectionToggle = function ($section) {
|
899
|
+
var expanded = this.isExpanded($section);
|
900
|
+
this.setExpanded(!expanded, $section);
|
787
901
|
|
788
|
-
|
902
|
+
// Store the state in sessionStorage when a change is triggered
|
903
|
+
this.storeState($section);
|
789
904
|
};
|
790
905
|
|
791
|
-
|
792
|
-
|
906
|
+
// When Open/Close All toggled, set and store state
|
907
|
+
Accordion.prototype.onOpenOrCloseAllToggle = function () {
|
908
|
+
var $module = this;
|
909
|
+
var $sections = this.$sections;
|
793
910
|
|
794
|
-
|
795
|
-
return
|
796
|
-
}
|
911
|
+
var nowExpanded = !this.checkIfAllSectionsOpen();
|
797
912
|
|
798
|
-
|
799
|
-
|
800
|
-
|
913
|
+
nodeListForEach($sections, function ($section) {
|
914
|
+
$module.setExpanded(nowExpanded, $section);
|
915
|
+
// Store the state in sessionStorage when a change is triggered
|
916
|
+
$module.storeState($section);
|
917
|
+
});
|
801
918
|
|
802
|
-
|
803
|
-
|
804
|
-
if (!$summary || !$content) {
|
805
|
-
return
|
806
|
-
}
|
919
|
+
$module.updateOpenAllButton(nowExpanded);
|
920
|
+
};
|
807
921
|
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
922
|
+
// Set section attributes when opened/closed
|
923
|
+
Accordion.prototype.setExpanded = function (expanded, $section) {
|
924
|
+
var $button = $section.querySelector('.' + this.sectionButtonClass);
|
925
|
+
$button.setAttribute('aria-expanded', expanded);
|
926
|
+
|
927
|
+
if (expanded) {
|
928
|
+
$section.classList.add(this.sectionExpandedClass);
|
929
|
+
} else {
|
930
|
+
$section.classList.remove(this.sectionExpandedClass);
|
812
931
|
}
|
813
932
|
|
814
|
-
//
|
815
|
-
|
933
|
+
// See if "Open all" button text should be updated
|
934
|
+
var areAllSectionsOpen = this.checkIfAllSectionsOpen();
|
935
|
+
this.updateOpenAllButton(areAllSectionsOpen);
|
936
|
+
};
|
816
937
|
|
817
|
-
|
818
|
-
|
938
|
+
// Get state of section
|
939
|
+
Accordion.prototype.isExpanded = function ($section) {
|
940
|
+
return $section.classList.contains(this.sectionExpandedClass)
|
941
|
+
};
|
819
942
|
|
820
|
-
|
821
|
-
|
943
|
+
// Check if all sections are open
|
944
|
+
Accordion.prototype.checkIfAllSectionsOpen = function () {
|
945
|
+
// Get a count of all the Accordion sections
|
946
|
+
var sectionsCount = this.$sections.length;
|
947
|
+
// Get a count of all Accordion sections that are expanded
|
948
|
+
var expandedSectionCount = this.$module.querySelectorAll('.' + this.sectionExpandedClass).length;
|
949
|
+
var areAllSectionsOpen = sectionsCount === expandedSectionCount;
|
822
950
|
|
823
|
-
|
824
|
-
|
825
|
-
if (!NATIVE_DETAILS) {
|
826
|
-
$summary.tabIndex = 0;
|
827
|
-
}
|
951
|
+
return areAllSectionsOpen
|
952
|
+
};
|
828
953
|
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
954
|
+
// Update "Open all" button
|
955
|
+
Accordion.prototype.updateOpenAllButton = function (expanded) {
|
956
|
+
var newButtonText = expanded ? 'Close all' : 'Open all';
|
957
|
+
newButtonText += '<span class="govuk-visually-hidden"> sections</span>';
|
958
|
+
this.$openAllButton.setAttribute('aria-expanded', expanded);
|
959
|
+
this.$openAllButton.innerHTML = newButtonText;
|
960
|
+
};
|
961
|
+
|
962
|
+
// Check for `window.sessionStorage`, and that it actually works.
|
963
|
+
var helper = {
|
964
|
+
checkForSessionStorage: function () {
|
965
|
+
var testString = 'this is the test string';
|
966
|
+
var result;
|
967
|
+
try {
|
968
|
+
window.sessionStorage.setItem(testString, testString);
|
969
|
+
result = window.sessionStorage.getItem(testString) === testString.toString();
|
970
|
+
window.sessionStorage.removeItem(testString);
|
971
|
+
return result
|
972
|
+
} catch (exception) {
|
973
|
+
if ((typeof console === 'undefined' || typeof console.log === 'undefined')) {
|
974
|
+
console.log('Notice: sessionStorage not available.');
|
975
|
+
}
|
839
976
|
}
|
840
977
|
}
|
841
|
-
|
842
|
-
// Bind an event to handle summary elements
|
843
|
-
this.handleInputs($summary, this.setAttributes.bind(this));
|
844
978
|
};
|
845
979
|
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
var $content = this.$content;
|
980
|
+
// Set the state of the accordions in sessionStorage
|
981
|
+
Accordion.prototype.storeState = function ($section) {
|
982
|
+
if (this.browserSupportsSessionStorage) {
|
983
|
+
// We need a unique way of identifying each content in the accordion. Since
|
984
|
+
// an `#id` should be unique and an `id` is required for `aria-` attributes
|
985
|
+
// `id` can be safely used.
|
986
|
+
var $button = $section.querySelector('.' + this.sectionButtonClass);
|
854
987
|
|
855
|
-
|
856
|
-
|
988
|
+
if ($button) {
|
989
|
+
var contentId = $button.getAttribute('aria-controls');
|
990
|
+
var contentState = $button.getAttribute('aria-expanded');
|
857
991
|
|
858
|
-
|
859
|
-
|
992
|
+
if (typeof contentId === 'undefined' && (typeof console === 'undefined' || typeof console.log === 'undefined')) {
|
993
|
+
console.error(new Error('No aria controls present in accordion section heading.'));
|
994
|
+
}
|
860
995
|
|
861
|
-
|
862
|
-
|
996
|
+
if (typeof contentState === 'undefined' && (typeof console === 'undefined' || typeof console.log === 'undefined')) {
|
997
|
+
console.error(new Error('No aria expanded present in accordion section heading.'));
|
998
|
+
}
|
863
999
|
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
$module.removeAttribute('open');
|
1000
|
+
// Only set the state when both `contentId` and `contentState` are taken from the DOM.
|
1001
|
+
if (contentId && contentState) {
|
1002
|
+
window.sessionStorage.setItem(contentId, contentState);
|
1003
|
+
}
|
869
1004
|
}
|
870
1005
|
}
|
871
|
-
return true
|
872
1006
|
};
|
873
1007
|
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
1008
|
+
// Read the state of the accordions from sessionStorage
|
1009
|
+
Accordion.prototype.setInitialState = function ($section) {
|
1010
|
+
if (this.browserSupportsSessionStorage) {
|
1011
|
+
var $button = $section.querySelector('.' + this.sectionButtonClass);
|
1012
|
+
|
1013
|
+
if ($button) {
|
1014
|
+
var contentId = $button.getAttribute('aria-controls');
|
1015
|
+
var contentState = contentId ? window.sessionStorage.getItem(contentId) : null;
|
1016
|
+
|
1017
|
+
if (contentState !== null) {
|
1018
|
+
this.setExpanded(contentState === 'true', $section);
|
1019
|
+
}
|
1020
|
+
}
|
1021
|
+
}
|
882
1022
|
};
|
883
1023
|
|
884
1024
|
(function(undefined) {
|
885
1025
|
|
886
|
-
|
887
|
-
|
888
|
-
'DOMTokenList' in this && (function (x) {
|
889
|
-
return 'classList' in x ? !x.classList.toggle('x', false) && !x.className : true;
|
890
|
-
})(document.createElement('x'))
|
891
|
-
);
|
1026
|
+
// Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Window/detect.js
|
1027
|
+
var detect = ('Window' in this);
|
892
1028
|
|
893
|
-
|
1029
|
+
if (detect) return
|
894
1030
|
|
895
|
-
|
896
|
-
|
897
|
-
|
1031
|
+
// Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Window&flags=always
|
1032
|
+
if ((typeof WorkerGlobalScope === "undefined") && (typeof importScripts !== "function")) {
|
1033
|
+
(function (global) {
|
1034
|
+
if (global.constructor) {
|
1035
|
+
global.Window = global.constructor;
|
1036
|
+
} else {
|
1037
|
+
(global.Window = global.constructor = new Function('return function Window() {}')()).prototype = this;
|
1038
|
+
}
|
1039
|
+
}(this));
|
1040
|
+
}
|
898
1041
|
|
899
|
-
|
900
|
-
|
901
|
-
(
|
902
|
-
!!document.createElementNS &&
|
903
|
-
!!document.createElementNS('http://www.w3.org/2000/svg', 'svg') &&
|
904
|
-
!(document.createElementNS("http://www.w3.org/2000/svg", "svg").classList instanceof DOMTokenList)
|
905
|
-
)
|
906
|
-
) {
|
907
|
-
global.DOMTokenList = (function() { // eslint-disable-line no-unused-vars
|
908
|
-
var dpSupport = true;
|
909
|
-
var defineGetter = function (object, name, fn, configurable) {
|
910
|
-
if (Object.defineProperty)
|
911
|
-
Object.defineProperty(object, name, {
|
912
|
-
configurable: false === dpSupport ? true : !!configurable,
|
913
|
-
get: fn
|
914
|
-
});
|
1042
|
+
})
|
1043
|
+
.call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
915
1044
|
|
916
|
-
|
917
|
-
|
1045
|
+
(function(undefined) {
|
1046
|
+
|
1047
|
+
// Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Event/detect.js
|
1048
|
+
var detect = (
|
1049
|
+
(function(global) {
|
1050
|
+
|
1051
|
+
if (!('Event' in global)) return false;
|
1052
|
+
if (typeof global.Event === 'function') return true;
|
1053
|
+
|
1054
|
+
try {
|
1055
|
+
|
1056
|
+
// In IE 9-11, the Event object exists but cannot be instantiated
|
1057
|
+
new Event('click');
|
1058
|
+
return true;
|
1059
|
+
} catch(e) {
|
1060
|
+
return false;
|
1061
|
+
}
|
1062
|
+
}(this))
|
1063
|
+
);
|
1064
|
+
|
1065
|
+
if (detect) return
|
1066
|
+
|
1067
|
+
// Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Event&flags=always
|
1068
|
+
(function () {
|
1069
|
+
var unlistenableWindowEvents = {
|
1070
|
+
click: 1,
|
1071
|
+
dblclick: 1,
|
1072
|
+
keyup: 1,
|
1073
|
+
keypress: 1,
|
1074
|
+
keydown: 1,
|
1075
|
+
mousedown: 1,
|
1076
|
+
mouseup: 1,
|
1077
|
+
mousemove: 1,
|
1078
|
+
mouseover: 1,
|
1079
|
+
mouseenter: 1,
|
1080
|
+
mouseleave: 1,
|
1081
|
+
mouseout: 1,
|
1082
|
+
storage: 1,
|
1083
|
+
storagecommit: 1,
|
1084
|
+
textinput: 1
|
1085
|
+
};
|
1086
|
+
|
1087
|
+
// This polyfill depends on availability of `document` so will not run in a worker
|
1088
|
+
// However, we asssume there are no browsers with worker support that lack proper
|
1089
|
+
// support for `Event` within the worker
|
1090
|
+
if (typeof document === 'undefined' || typeof window === 'undefined') return;
|
1091
|
+
|
1092
|
+
function indexOf(array, element) {
|
1093
|
+
var
|
1094
|
+
index = -1,
|
1095
|
+
length = array.length;
|
1096
|
+
|
1097
|
+
while (++index < length) {
|
1098
|
+
if (index in array && array[index] === element) {
|
1099
|
+
return index;
|
1100
|
+
}
|
1101
|
+
}
|
1102
|
+
|
1103
|
+
return -1;
|
1104
|
+
}
|
1105
|
+
|
1106
|
+
var existingProto = (window.Event && window.Event.prototype) || null;
|
1107
|
+
window.Event = Window.prototype.Event = function Event(type, eventInitDict) {
|
1108
|
+
if (!type) {
|
1109
|
+
throw new Error('Not enough arguments');
|
1110
|
+
}
|
1111
|
+
|
1112
|
+
var event;
|
1113
|
+
// Shortcut if browser supports createEvent
|
1114
|
+
if ('createEvent' in document) {
|
1115
|
+
event = document.createEvent('Event');
|
1116
|
+
var bubbles = eventInitDict && eventInitDict.bubbles !== undefined ? eventInitDict.bubbles : false;
|
1117
|
+
var cancelable = eventInitDict && eventInitDict.cancelable !== undefined ? eventInitDict.cancelable : false;
|
1118
|
+
|
1119
|
+
event.initEvent(type, bubbles, cancelable);
|
1120
|
+
|
1121
|
+
return event;
|
1122
|
+
}
|
1123
|
+
|
1124
|
+
event = document.createEventObject();
|
1125
|
+
|
1126
|
+
event.type = type;
|
1127
|
+
event.bubbles = eventInitDict && eventInitDict.bubbles !== undefined ? eventInitDict.bubbles : false;
|
1128
|
+
event.cancelable = eventInitDict && eventInitDict.cancelable !== undefined ? eventInitDict.cancelable : false;
|
1129
|
+
|
1130
|
+
return event;
|
1131
|
+
};
|
1132
|
+
if (existingProto) {
|
1133
|
+
Object.defineProperty(window.Event, 'prototype', {
|
1134
|
+
configurable: false,
|
1135
|
+
enumerable: false,
|
1136
|
+
writable: true,
|
1137
|
+
value: existingProto
|
1138
|
+
});
|
1139
|
+
}
|
1140
|
+
|
1141
|
+
if (!('createEvent' in document)) {
|
1142
|
+
window.addEventListener = Window.prototype.addEventListener = Document.prototype.addEventListener = Element.prototype.addEventListener = function addEventListener() {
|
1143
|
+
var
|
1144
|
+
element = this,
|
1145
|
+
type = arguments[0],
|
1146
|
+
listener = arguments[1];
|
1147
|
+
|
1148
|
+
if (element === window && type in unlistenableWindowEvents) {
|
1149
|
+
throw new Error('In IE8 the event: ' + type + ' is not available on the window object. Please see https://github.com/Financial-Times/polyfill-service/issues/317 for more information.');
|
1150
|
+
}
|
1151
|
+
|
1152
|
+
if (!element._events) {
|
1153
|
+
element._events = {};
|
1154
|
+
}
|
1155
|
+
|
1156
|
+
if (!element._events[type]) {
|
1157
|
+
element._events[type] = function (event) {
|
1158
|
+
var
|
1159
|
+
list = element._events[event.type].list,
|
1160
|
+
events = list.slice(),
|
1161
|
+
index = -1,
|
1162
|
+
length = events.length,
|
1163
|
+
eventElement;
|
1164
|
+
|
1165
|
+
event.preventDefault = function preventDefault() {
|
1166
|
+
if (event.cancelable !== false) {
|
1167
|
+
event.returnValue = false;
|
1168
|
+
}
|
1169
|
+
};
|
1170
|
+
|
1171
|
+
event.stopPropagation = function stopPropagation() {
|
1172
|
+
event.cancelBubble = true;
|
1173
|
+
};
|
1174
|
+
|
1175
|
+
event.stopImmediatePropagation = function stopImmediatePropagation() {
|
1176
|
+
event.cancelBubble = true;
|
1177
|
+
event.cancelImmediate = true;
|
1178
|
+
};
|
1179
|
+
|
1180
|
+
event.currentTarget = element;
|
1181
|
+
event.relatedTarget = event.fromElement || null;
|
1182
|
+
event.target = event.target || event.srcElement || element;
|
1183
|
+
event.timeStamp = new Date().getTime();
|
1184
|
+
|
1185
|
+
if (event.clientX) {
|
1186
|
+
event.pageX = event.clientX + document.documentElement.scrollLeft;
|
1187
|
+
event.pageY = event.clientY + document.documentElement.scrollTop;
|
1188
|
+
}
|
1189
|
+
|
1190
|
+
while (++index < length && !event.cancelImmediate) {
|
1191
|
+
if (index in events) {
|
1192
|
+
eventElement = events[index];
|
918
1193
|
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
}
|
1194
|
+
if (indexOf(list, eventElement) !== -1 && typeof eventElement === 'function') {
|
1195
|
+
eventElement.call(element, event);
|
1196
|
+
}
|
1197
|
+
}
|
1198
|
+
}
|
1199
|
+
};
|
926
1200
|
|
1201
|
+
element._events[type].list = [];
|
927
1202
|
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
var length = 0;
|
933
|
-
var maxLength = 0;
|
934
|
-
var addIndexGetter = function (i) {
|
935
|
-
defineGetter(that, i, function () {
|
936
|
-
preop();
|
937
|
-
return tokens[i];
|
938
|
-
}, false);
|
1203
|
+
if (element.attachEvent) {
|
1204
|
+
element.attachEvent('on' + type, element._events[type]);
|
1205
|
+
}
|
1206
|
+
}
|
939
1207
|
|
940
|
-
|
941
|
-
|
1208
|
+
element._events[type].list.push(listener);
|
1209
|
+
};
|
942
1210
|
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
1211
|
+
window.removeEventListener = Window.prototype.removeEventListener = Document.prototype.removeEventListener = Element.prototype.removeEventListener = function removeEventListener() {
|
1212
|
+
var
|
1213
|
+
element = this,
|
1214
|
+
type = arguments[0],
|
1215
|
+
listener = arguments[1],
|
1216
|
+
index;
|
949
1217
|
|
950
|
-
|
951
|
-
|
952
|
-
var error;
|
953
|
-
var i;
|
954
|
-
var args = arguments;
|
955
|
-
var rSpace = /\s+/;
|
1218
|
+
if (element._events && element._events[type] && element._events[type].list) {
|
1219
|
+
index = indexOf(element._events[type].list, listener);
|
956
1220
|
|
957
|
-
|
958
|
-
|
959
|
-
for (i = 0; i < args.length; ++i)
|
960
|
-
if (rSpace.test(args[i])) {
|
961
|
-
error = new SyntaxError('String "' + args[i] + '" ' + "contains" + ' an invalid character');
|
962
|
-
error.code = 5;
|
963
|
-
error.name = "InvalidCharacterError";
|
964
|
-
throw error;
|
965
|
-
}
|
1221
|
+
if (index !== -1) {
|
1222
|
+
element._events[type].list.splice(index, 1);
|
966
1223
|
|
1224
|
+
if (!element._events[type].list.length) {
|
1225
|
+
if (element.detachEvent) {
|
1226
|
+
element.detachEvent('on' + type, element._events[type]);
|
1227
|
+
}
|
1228
|
+
delete element._events[type];
|
1229
|
+
}
|
1230
|
+
}
|
1231
|
+
}
|
1232
|
+
};
|
967
1233
|
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
tokens = ("" + el[prop]).replace(/^\s+|\s+$/g, "").split(rSpace);
|
973
|
-
}
|
1234
|
+
window.dispatchEvent = Window.prototype.dispatchEvent = Document.prototype.dispatchEvent = Element.prototype.dispatchEvent = function dispatchEvent(event) {
|
1235
|
+
if (!arguments.length) {
|
1236
|
+
throw new Error('Not enough arguments');
|
1237
|
+
}
|
974
1238
|
|
975
|
-
|
976
|
-
|
1239
|
+
if (!event || typeof event.type !== 'string') {
|
1240
|
+
throw new Error('DOM Events Exception 0');
|
1241
|
+
}
|
977
1242
|
|
978
|
-
|
979
|
-
tokenMap = {};
|
980
|
-
for (i = 0; i < tokens.length; ++i)
|
981
|
-
tokenMap[tokens[i]] = true;
|
982
|
-
length = tokens.length;
|
983
|
-
reindex();
|
984
|
-
};
|
1243
|
+
var element = this, type = event.type;
|
985
1244
|
|
986
|
-
|
987
|
-
|
1245
|
+
try {
|
1246
|
+
if (!event.bubbles) {
|
1247
|
+
event.cancelBubble = true;
|
988
1248
|
|
989
|
-
|
990
|
-
|
991
|
-
preop();
|
992
|
-
return length;
|
993
|
-
});
|
1249
|
+
var cancelBubbleEvent = function (event) {
|
1250
|
+
event.cancelBubble = true;
|
994
1251
|
|
995
|
-
|
996
|
-
|
997
|
-
that.toString = function () {
|
998
|
-
preop();
|
999
|
-
return tokens.join(" ");
|
1000
|
-
};
|
1252
|
+
(element || window).detachEvent('on' + type, cancelBubbleEvent);
|
1253
|
+
};
|
1001
1254
|
|
1002
|
-
|
1003
|
-
|
1004
|
-
return tokens[idx];
|
1005
|
-
};
|
1255
|
+
this.attachEvent('on' + type, cancelBubbleEvent);
|
1256
|
+
}
|
1006
1257
|
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
};
|
1258
|
+
this.fireEvent('on' + type, event);
|
1259
|
+
} catch (error) {
|
1260
|
+
event.target = element;
|
1011
1261
|
|
1012
|
-
|
1013
|
-
|
1262
|
+
do {
|
1263
|
+
event.currentTarget = element;
|
1014
1264
|
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
tokens.push(token);
|
1019
|
-
tokenMap[token] = true;
|
1020
|
-
}
|
1021
|
-
}
|
1265
|
+
if ('_events' in element && typeof element._events[type] === 'function') {
|
1266
|
+
element._events[type].call(element, event);
|
1267
|
+
}
|
1022
1268
|
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
if (typeof el[prop] === "object") {
|
1027
|
-
el[prop].baseVal = tokens.join(" ");
|
1028
|
-
} else {
|
1029
|
-
el[prop] = tokens.join(" ");
|
1030
|
-
}
|
1031
|
-
reindex();
|
1032
|
-
}
|
1033
|
-
};
|
1269
|
+
if (typeof element['on' + type] === 'function') {
|
1270
|
+
element['on' + type].call(element, event);
|
1271
|
+
}
|
1034
1272
|
|
1035
|
-
|
1036
|
-
|
1273
|
+
element = element.nodeType === 9 ? element.parentWindow : element.parentNode;
|
1274
|
+
} while (element && !event.cancelBubble);
|
1275
|
+
}
|
1037
1276
|
|
1038
|
-
|
1039
|
-
|
1040
|
-
ignore[args[i]] = true;
|
1041
|
-
delete tokenMap[args[i]];
|
1042
|
-
}
|
1277
|
+
return true;
|
1278
|
+
};
|
1043
1279
|
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1280
|
+
// Add the DOMContentLoaded Event
|
1281
|
+
document.attachEvent('onreadystatechange', function() {
|
1282
|
+
if (document.readyState === 'complete') {
|
1283
|
+
document.dispatchEvent(new Event('DOMContentLoaded', {
|
1284
|
+
bubbles: true
|
1285
|
+
}));
|
1286
|
+
}
|
1287
|
+
});
|
1288
|
+
}
|
1289
|
+
}());
|
1047
1290
|
|
1048
|
-
|
1049
|
-
|
1291
|
+
})
|
1292
|
+
.call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
1050
1293
|
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1294
|
+
/**
|
1295
|
+
* JavaScript 'shim' to trigger the click event of element(s) when the space key is pressed.
|
1296
|
+
*
|
1297
|
+
* Created since some Assistive Technologies (for example some Screenreaders)
|
1298
|
+
* will tell a user to press space on a 'button', so this functionality needs to be shimmed
|
1299
|
+
* See https://github.com/alphagov/govuk_elements/pull/272#issuecomment-233028270
|
1300
|
+
*
|
1301
|
+
* Usage instructions:
|
1302
|
+
* the 'shim' will be automatically initialised
|
1303
|
+
*/
|
1059
1304
|
|
1060
|
-
|
1061
|
-
preop.apply(that, [token]);
|
1305
|
+
var KEY_SPACE = 32;
|
1062
1306
|
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
that.add(token);
|
1067
|
-
return true;
|
1068
|
-
} else {
|
1069
|
-
that.remove(token);
|
1070
|
-
return false;
|
1071
|
-
}
|
1072
|
-
}
|
1307
|
+
function Button ($module) {
|
1308
|
+
this.$module = $module;
|
1309
|
+
}
|
1073
1310
|
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1311
|
+
/**
|
1312
|
+
* Add event handler for KeyDown
|
1313
|
+
* if the event target element has a role='button' and the event is key space pressed
|
1314
|
+
* then it prevents the default event and triggers a click event
|
1315
|
+
* @param {object} event event
|
1316
|
+
*/
|
1317
|
+
Button.prototype.handleKeyDown = function (event) {
|
1318
|
+
// get the target element
|
1319
|
+
var target = event.target;
|
1320
|
+
// if the element has a role='button' and the pressed key is a space, we'll simulate a click
|
1321
|
+
if (target.getAttribute('role') === 'button' && event.keyCode === KEY_SPACE) {
|
1322
|
+
event.preventDefault();
|
1323
|
+
// trigger the target's click event
|
1324
|
+
target.click();
|
1325
|
+
}
|
1326
|
+
};
|
1079
1327
|
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1328
|
+
/**
|
1329
|
+
* Initialise an event listener for keydown at document level
|
1330
|
+
* this will help listening for later inserted elements with a role="button"
|
1331
|
+
*/
|
1332
|
+
Button.prototype.init = function () {
|
1333
|
+
this.$module.addEventListener('keydown', this.handleKeyDown);
|
1334
|
+
};
|
1084
1335
|
|
1085
|
-
|
1086
|
-
|
1336
|
+
/**
|
1337
|
+
* JavaScript 'polyfill' for HTML5's <details> and <summary> elements
|
1338
|
+
* and 'shim' to add accessiblity enhancements for all browsers
|
1339
|
+
*
|
1340
|
+
* http://caniuse.com/#feat=details
|
1341
|
+
*
|
1342
|
+
* Usage instructions:
|
1343
|
+
* the 'polyfill' will be automatically initialised
|
1344
|
+
*/
|
1087
1345
|
|
1088
|
-
|
1089
|
-
|
1090
|
-
}
|
1346
|
+
var KEY_ENTER = 13;
|
1347
|
+
var KEY_SPACE$1 = 32;
|
1091
1348
|
|
1092
|
-
|
1093
|
-
|
1094
|
-
var e = document.createElement('span');
|
1095
|
-
if (!('classList' in e)) return;
|
1096
|
-
e.classList.toggle('x', false);
|
1097
|
-
if (!e.classList.contains('x')) return;
|
1098
|
-
e.classList.constructor.prototype.toggle = function toggle(token /*, force*/) {
|
1099
|
-
var force = arguments[1];
|
1100
|
-
if (force === undefined) {
|
1101
|
-
var add = !this.contains(token);
|
1102
|
-
this[add ? 'add' : 'remove'](token);
|
1103
|
-
return add;
|
1104
|
-
}
|
1105
|
-
force = !!force;
|
1106
|
-
this[force ? 'add' : 'remove'](token);
|
1107
|
-
return force;
|
1108
|
-
};
|
1109
|
-
}());
|
1349
|
+
// Create a flag to know if the browser supports navtive details
|
1350
|
+
var NATIVE_DETAILS = typeof document.createElement('details').open === 'boolean';
|
1110
1351
|
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
if (!('classList' in e)) return;
|
1115
|
-
e.classList.add('a', 'b');
|
1116
|
-
if (e.classList.contains('b')) return;
|
1117
|
-
var native = e.classList.constructor.prototype.add;
|
1118
|
-
e.classList.constructor.prototype.add = function () {
|
1119
|
-
var args = arguments;
|
1120
|
-
var l = arguments.length;
|
1121
|
-
for (var i = 0; i < l; i++) {
|
1122
|
-
native.call(this, args[i]);
|
1123
|
-
}
|
1124
|
-
};
|
1125
|
-
}());
|
1352
|
+
function Details ($module) {
|
1353
|
+
this.$module = $module;
|
1354
|
+
}
|
1126
1355
|
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1356
|
+
/**
|
1357
|
+
* Handle cross-modal click events
|
1358
|
+
* @param {object} node element
|
1359
|
+
* @param {function} callback function
|
1360
|
+
*/
|
1361
|
+
Details.prototype.handleInputs = function (node, callback) {
|
1362
|
+
node.addEventListener('keypress', function (event) {
|
1363
|
+
var target = event.target;
|
1364
|
+
// When the key gets pressed - check if it is enter or space
|
1365
|
+
if (event.keyCode === KEY_ENTER || event.keyCode === KEY_SPACE$1) {
|
1366
|
+
if (target.nodeName.toLowerCase() === 'summary') {
|
1367
|
+
// Prevent space from scrolling the page
|
1368
|
+
// and enter from submitting a form
|
1369
|
+
event.preventDefault();
|
1370
|
+
// Click to let the click event do all the necessary action
|
1371
|
+
if (target.click) {
|
1372
|
+
target.click();
|
1373
|
+
} else {
|
1374
|
+
// except Safari 5.1 and under don't support .click() here
|
1375
|
+
callback(event);
|
1376
|
+
}
|
1377
|
+
}
|
1378
|
+
}
|
1379
|
+
});
|
1144
1380
|
|
1145
|
-
|
1381
|
+
// Prevent keyup to prevent clicking twice in Firefox when using space key
|
1382
|
+
node.addEventListener('keyup', function (event) {
|
1383
|
+
var target = event.target;
|
1384
|
+
if (event.keyCode === KEY_SPACE$1) {
|
1385
|
+
if (target.nodeName.toLowerCase() === 'summary') {
|
1386
|
+
event.preventDefault();
|
1387
|
+
}
|
1388
|
+
}
|
1389
|
+
});
|
1146
1390
|
|
1147
|
-
|
1391
|
+
node.addEventListener('click', callback);
|
1392
|
+
};
|
1148
1393
|
|
1149
|
-
|
1394
|
+
Details.prototype.init = function () {
|
1395
|
+
var $module = this.$module;
|
1150
1396
|
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
var e = document.createElement('span');
|
1155
|
-
e.classList.add('a', 'b');
|
1156
|
-
return e.classList.contains('b');
|
1157
|
-
}())
|
1158
|
-
);
|
1397
|
+
if (!$module) {
|
1398
|
+
return
|
1399
|
+
}
|
1159
1400
|
|
1160
|
-
|
1401
|
+
// Save shortcuts to the inner summary and content elements
|
1402
|
+
var $summary = this.$summary = $module.getElementsByTagName('summary').item(0);
|
1403
|
+
var $content = this.$content = $module.getElementsByTagName('div').item(0);
|
1161
1404
|
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
Object.defineProperty(object, name, {
|
1168
|
-
configurable: false === dpSupport ? true : !!configurable,
|
1169
|
-
get: fn
|
1170
|
-
});
|
1405
|
+
// If <details> doesn't have a <summary> and a <div> representing the content
|
1406
|
+
// it means the required HTML structure is not met so the script will stop
|
1407
|
+
if (!$summary || !$content) {
|
1408
|
+
return
|
1409
|
+
}
|
1171
1410
|
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
}
|
1178
|
-
catch (e) {
|
1179
|
-
dpSupport = false;
|
1180
|
-
}
|
1181
|
-
/** Polyfills a property with a DOMTokenList */
|
1182
|
-
var addProp = function (o, name, attr) {
|
1411
|
+
// If the content doesn't have an ID, assign it one now
|
1412
|
+
// which we'll need for the summary's aria-controls assignment
|
1413
|
+
if (!$content.id) {
|
1414
|
+
$content.id = 'details-content-' + generateUniqueID();
|
1415
|
+
}
|
1183
1416
|
|
1184
|
-
|
1185
|
-
|
1417
|
+
// Add ARIA role="group" to details
|
1418
|
+
$module.setAttribute('role', 'group');
|
1186
1419
|
|
1187
|
-
|
1420
|
+
// Add role=button to summary
|
1421
|
+
$summary.setAttribute('role', 'button');
|
1188
1422
|
|
1189
|
-
|
1190
|
-
|
1191
|
-
if(THIS[gibberishProperty]) return tokenList;
|
1192
|
-
THIS[gibberishProperty] = true;
|
1423
|
+
// Add aria-controls
|
1424
|
+
$summary.setAttribute('aria-controls', $content.id);
|
1193
1425
|
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
* element instead, this would conflict with element types which use indexed properties (such as forms and
|
1200
|
-
* select lists).
|
1201
|
-
*/
|
1202
|
-
if (false === dpSupport) {
|
1426
|
+
// Set tabIndex so the summary is keyboard accessible for non-native elements
|
1427
|
+
// http://www.saliences.com/browserBugs/tabIndex.html
|
1428
|
+
if (!NATIVE_DETAILS) {
|
1429
|
+
$summary.tabIndex = 0;
|
1430
|
+
}
|
1203
1431
|
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1432
|
+
// Detect initial open state
|
1433
|
+
var openAttr = $module.getAttribute('open') !== null;
|
1434
|
+
if (openAttr === true) {
|
1435
|
+
$summary.setAttribute('aria-expanded', 'true');
|
1436
|
+
$content.setAttribute('aria-hidden', 'false');
|
1437
|
+
} else {
|
1438
|
+
$summary.setAttribute('aria-expanded', 'false');
|
1439
|
+
$content.setAttribute('aria-hidden', 'true');
|
1440
|
+
if (!NATIVE_DETAILS) {
|
1441
|
+
$content.style.display = 'none';
|
1442
|
+
}
|
1443
|
+
}
|
1208
1444
|
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
break;
|
1213
|
-
}
|
1445
|
+
// Bind an event to handle summary elements
|
1446
|
+
this.handleInputs($summary, this.setAttributes.bind(this));
|
1447
|
+
};
|
1214
1448
|
|
1215
|
-
|
1216
|
-
|
1449
|
+
/**
|
1450
|
+
* Define a statechange function that updates aria-expanded and style.display
|
1451
|
+
* @param {object} summary element
|
1452
|
+
*/
|
1453
|
+
Details.prototype.setAttributes = function () {
|
1454
|
+
var $module = this.$module;
|
1455
|
+
var $summary = this.$summary;
|
1456
|
+
var $content = this.$content;
|
1217
1457
|
|
1218
|
-
|
1219
|
-
|
1458
|
+
var expanded = $summary.getAttribute('aria-expanded') === 'true';
|
1459
|
+
var hidden = $content.getAttribute('aria-hidden') === 'true';
|
1220
1460
|
|
1221
|
-
|
1222
|
-
|
1223
|
-
});
|
1224
|
-
delete THIS[gibberishProperty];
|
1461
|
+
$summary.setAttribute('aria-expanded', (expanded ? 'false' : 'true'));
|
1462
|
+
$content.setAttribute('aria-hidden', (hidden ? 'false' : 'true'));
|
1225
1463
|
|
1226
|
-
|
1227
|
-
|
1228
|
-
};
|
1464
|
+
if (!NATIVE_DETAILS) {
|
1465
|
+
$content.style.display = (expanded ? 'none' : '');
|
1229
1466
|
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
}
|
1467
|
+
var hasOpenAttr = $module.getAttribute('open') !== null;
|
1468
|
+
if (!hasOpenAttr) {
|
1469
|
+
$module.setAttribute('open', 'open');
|
1470
|
+
} else {
|
1471
|
+
$module.removeAttribute('open');
|
1472
|
+
}
|
1473
|
+
}
|
1474
|
+
return true
|
1475
|
+
};
|
1236
1476
|
|
1237
|
-
|
1477
|
+
/**
|
1478
|
+
* Remove the click event from the node element
|
1479
|
+
* @param {object} node element
|
1480
|
+
*/
|
1481
|
+
Details.prototype.destroy = function (node) {
|
1482
|
+
node.removeEventListener('keypress');
|
1483
|
+
node.removeEventListener('keyup');
|
1484
|
+
node.removeEventListener('click');
|
1485
|
+
};
|
1238
1486
|
|
1239
1487
|
function CharacterCount ($module) {
|
1240
1488
|
this.$module = $module;
|
@@ -2021,6 +2269,12 @@ function initAll () {
|
|
2021
2269
|
// Find all buttons with [role=button] on the document to enhance.
|
2022
2270
|
new Button(document).init();
|
2023
2271
|
|
2272
|
+
// Find all global accordion components to enhance.
|
2273
|
+
var $accordions = document.querySelectorAll('[data-module="accordion"]');
|
2274
|
+
nodeListForEach($accordions, function ($accordion) {
|
2275
|
+
new Accordion($accordion).init();
|
2276
|
+
});
|
2277
|
+
|
2024
2278
|
// Find all global details elements to enhance.
|
2025
2279
|
var $details = document.querySelectorAll('details');
|
2026
2280
|
nodeListForEach($details, function ($detail) {
|