katalyst-govuk-formbuilder 1.2.2 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/app/assets/builds/katalyst/govuk/formbuilder.css +25 -21
- data/app/assets/{javascripts → builds}/katalyst/govuk/formbuilder.js +606 -203
- data/app/assets/builds/katalyst/govuk/formbuilder.min.js +1 -0
- data/app/assets/config/katalyst-govuk-formbuilder.js +2 -0
- data/app/assets/stylesheets/katalyst/govuk/components/richtextarea/_index.scss +48 -0
- data/app/assets/stylesheets/katalyst/govuk/components/richtextarea/_richtextarea.scss +2 -0
- data/app/assets/stylesheets/katalyst/govuk/formbuilder.scss +26 -0
- data/config/importmap.rb +5 -0
- data/lib/govuk_design_system_formbuilder/elements/check_box_field.rb +5 -5
- data/lib/govuk_design_system_formbuilder/elements/rich_text_area.rb +2 -1
- data/lib/katalyst/govuk/formbuilder/engine.rb +3 -8
- data/lib/katalyst/govuk/formbuilder/frontend.rb +2 -0
- data/lib/katalyst/govuk/formbuilder/version.rb +3 -1
- data/lib/katalyst/govuk/formbuilder.rb +2 -0
- metadata +8 -4
- data/app/assets/javascripts/katalyst/govuk/formbuilder.min.js +0 -1
@@ -7,18 +7,122 @@ function nodeListForEach(nodes, callback) {
|
|
7
7
|
}
|
8
8
|
}
|
9
9
|
|
10
|
+
function mergeConfigs() {
|
11
|
+
var flattenObject = function(configObject) {
|
12
|
+
var flattenedObject = {};
|
13
|
+
var flattenLoop = function(obj, prefix) {
|
14
|
+
for (var key in obj) {
|
15
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
|
16
|
+
continue;
|
17
|
+
}
|
18
|
+
var value = obj[key];
|
19
|
+
var prefixedKey = prefix ? prefix + "." + key : key;
|
20
|
+
if (typeof value === "object") {
|
21
|
+
flattenLoop(value, prefixedKey);
|
22
|
+
} else {
|
23
|
+
flattenedObject[prefixedKey] = value;
|
24
|
+
}
|
25
|
+
}
|
26
|
+
};
|
27
|
+
flattenLoop(configObject);
|
28
|
+
return flattenedObject;
|
29
|
+
};
|
30
|
+
var formattedConfigObject = {};
|
31
|
+
for (var i = 0; i < arguments.length; i++) {
|
32
|
+
var obj = flattenObject(arguments[i]);
|
33
|
+
for (var key in obj) {
|
34
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
35
|
+
formattedConfigObject[key] = obj[key];
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
return formattedConfigObject;
|
40
|
+
}
|
41
|
+
|
42
|
+
function extractConfigByNamespace(configObject, namespace) {
|
43
|
+
if (!configObject || typeof configObject !== "object") {
|
44
|
+
throw new Error('Provide a `configObject` of type "object".');
|
45
|
+
}
|
46
|
+
if (!namespace || typeof namespace !== "string") {
|
47
|
+
throw new Error('Provide a `namespace` of type "string" to filter the `configObject` by.');
|
48
|
+
}
|
49
|
+
var newObject = {};
|
50
|
+
for (var key in configObject) {
|
51
|
+
var keyParts = key.split(".");
|
52
|
+
if (Object.prototype.hasOwnProperty.call(configObject, key) && keyParts[0] === namespace) {
|
53
|
+
if (keyParts.length > 1) {
|
54
|
+
keyParts.shift();
|
55
|
+
}
|
56
|
+
var newKey = keyParts.join(".");
|
57
|
+
newObject[newKey] = configObject[key];
|
58
|
+
}
|
59
|
+
}
|
60
|
+
return newObject;
|
61
|
+
}
|
62
|
+
|
10
63
|
(function(undefined$1) {
|
11
|
-
var detect = "
|
64
|
+
var detect = "defineProperty" in Object && function() {
|
65
|
+
try {
|
66
|
+
var a = {};
|
67
|
+
Object.defineProperty(a, "test", {
|
68
|
+
value: 42
|
69
|
+
});
|
70
|
+
return true;
|
71
|
+
} catch (e) {
|
72
|
+
return false;
|
73
|
+
}
|
74
|
+
}();
|
12
75
|
if (detect) return;
|
13
|
-
|
14
|
-
(
|
15
|
-
|
16
|
-
|
76
|
+
(function(nativeDefineProperty) {
|
77
|
+
var supportsAccessors = Object.prototype.hasOwnProperty("__defineGetter__");
|
78
|
+
var ERR_ACCESSORS_NOT_SUPPORTED = "Getters & setters cannot be defined on this javascript engine";
|
79
|
+
var ERR_VALUE_ACCESSORS = "A property cannot both have accessors and be writable or have a value";
|
80
|
+
Object.defineProperty = function defineProperty(object, property, descriptor) {
|
81
|
+
if (nativeDefineProperty && (object === window || object === document || object === Element.prototype || object instanceof Element)) {
|
82
|
+
return nativeDefineProperty(object, property, descriptor);
|
83
|
+
}
|
84
|
+
if (object === null || !(object instanceof Object || typeof object === "object")) {
|
85
|
+
throw new TypeError("Object.defineProperty called on non-object");
|
86
|
+
}
|
87
|
+
if (!(descriptor instanceof Object)) {
|
88
|
+
throw new TypeError("Property description must be an object");
|
89
|
+
}
|
90
|
+
var propertyString = String(property);
|
91
|
+
var hasValueOrWritable = "value" in descriptor || "writable" in descriptor;
|
92
|
+
var getterType = "get" in descriptor && typeof descriptor.get;
|
93
|
+
var setterType = "set" in descriptor && typeof descriptor.set;
|
94
|
+
if (getterType) {
|
95
|
+
if (getterType !== "function") {
|
96
|
+
throw new TypeError("Getter must be a function");
|
97
|
+
}
|
98
|
+
if (!supportsAccessors) {
|
99
|
+
throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
|
100
|
+
}
|
101
|
+
if (hasValueOrWritable) {
|
102
|
+
throw new TypeError(ERR_VALUE_ACCESSORS);
|
103
|
+
}
|
104
|
+
Object.__defineGetter__.call(object, propertyString, descriptor.get);
|
17
105
|
} else {
|
18
|
-
|
106
|
+
object[propertyString] = descriptor.value;
|
19
107
|
}
|
20
|
-
|
21
|
-
|
108
|
+
if (setterType) {
|
109
|
+
if (setterType !== "function") {
|
110
|
+
throw new TypeError("Setter must be a function");
|
111
|
+
}
|
112
|
+
if (!supportsAccessors) {
|
113
|
+
throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
|
114
|
+
}
|
115
|
+
if (hasValueOrWritable) {
|
116
|
+
throw new TypeError(ERR_VALUE_ACCESSORS);
|
117
|
+
}
|
118
|
+
Object.__defineSetter__.call(object, propertyString, descriptor.set);
|
119
|
+
}
|
120
|
+
if ("value" in descriptor) {
|
121
|
+
object[propertyString] = descriptor.value;
|
122
|
+
}
|
123
|
+
return object;
|
124
|
+
};
|
125
|
+
})(Object.defineProperty);
|
22
126
|
}).call("object" === typeof window && window || "object" === typeof self && self || "object" === typeof global && global || {});
|
23
127
|
|
24
128
|
(function(undefined$1) {
|
@@ -105,68 +209,99 @@ function nodeListForEach(nodes, callback) {
|
|
105
209
|
}).call("object" === typeof window && window || "object" === typeof self && self || "object" === typeof global && global || {});
|
106
210
|
|
107
211
|
(function(undefined$1) {
|
108
|
-
var detect =
|
109
|
-
|
110
|
-
var a = {};
|
111
|
-
Object.defineProperty(a, "test", {
|
112
|
-
value: 42
|
113
|
-
});
|
114
|
-
return true;
|
115
|
-
} catch (e) {
|
212
|
+
var detect = function() {
|
213
|
+
if (!document.documentElement.dataset) {
|
116
214
|
return false;
|
117
215
|
}
|
216
|
+
var el = document.createElement("div");
|
217
|
+
el.setAttribute("data-a-b", "c");
|
218
|
+
return el.dataset && el.dataset.aB == "c";
|
118
219
|
}();
|
119
220
|
if (detect) return;
|
120
|
-
(
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
if (setterType) {
|
153
|
-
if (setterType !== "function") {
|
154
|
-
throw new TypeError("Setter must be a function");
|
155
|
-
}
|
156
|
-
if (!supportsAccessors) {
|
157
|
-
throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
|
158
|
-
}
|
159
|
-
if (hasValueOrWritable) {
|
160
|
-
throw new TypeError(ERR_VALUE_ACCESSORS);
|
221
|
+
Object.defineProperty(Element.prototype, "dataset", {
|
222
|
+
get: function() {
|
223
|
+
var element = this;
|
224
|
+
var attributes = this.attributes;
|
225
|
+
var map = {};
|
226
|
+
for (var i = 0; i < attributes.length; i++) {
|
227
|
+
var attribute = attributes[i];
|
228
|
+
if (attribute && attribute.name && /^data-\w[.\w-]*$/.test(attribute.name)) {
|
229
|
+
var name = attribute.name;
|
230
|
+
var value = attribute.value;
|
231
|
+
var propName = name.substr(5).replace(/-./g, (function(prop) {
|
232
|
+
return prop.charAt(1).toUpperCase();
|
233
|
+
}));
|
234
|
+
if ("__defineGetter__" in Object.prototype && "__defineSetter__" in Object.prototype) {
|
235
|
+
Object.defineProperty(map, propName, {
|
236
|
+
enumerable: true,
|
237
|
+
get: function() {
|
238
|
+
return this.value;
|
239
|
+
}.bind({
|
240
|
+
value: value || ""
|
241
|
+
}),
|
242
|
+
set: function setter(name, value) {
|
243
|
+
if (typeof value !== "undefined") {
|
244
|
+
this.setAttribute(name, value);
|
245
|
+
} else {
|
246
|
+
this.removeAttribute(name);
|
247
|
+
}
|
248
|
+
}.bind(element, name)
|
249
|
+
});
|
250
|
+
} else {
|
251
|
+
map[propName] = value;
|
252
|
+
}
|
161
253
|
}
|
162
|
-
Object.__defineSetter__.call(object, propertyString, descriptor.set);
|
163
254
|
}
|
164
|
-
|
165
|
-
|
255
|
+
return map;
|
256
|
+
}
|
257
|
+
});
|
258
|
+
}).call("object" === typeof window && window || "object" === typeof self && self || "object" === typeof global && global || {});
|
259
|
+
|
260
|
+
(function(undefined$1) {
|
261
|
+
var detect = "trim" in String.prototype;
|
262
|
+
if (detect) return;
|
263
|
+
String.prototype.trim = function() {
|
264
|
+
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "");
|
265
|
+
};
|
266
|
+
}).call("object" === typeof window && window || "object" === typeof self && self || "object" === typeof global && global || {});
|
267
|
+
|
268
|
+
function normaliseString(value) {
|
269
|
+
if (typeof value !== "string") {
|
270
|
+
return value;
|
271
|
+
}
|
272
|
+
var trimmedValue = value.trim();
|
273
|
+
if (trimmedValue === "true") {
|
274
|
+
return true;
|
275
|
+
}
|
276
|
+
if (trimmedValue === "false") {
|
277
|
+
return false;
|
278
|
+
}
|
279
|
+
if (trimmedValue.length > 0 && isFinite(trimmedValue)) {
|
280
|
+
return Number(trimmedValue);
|
281
|
+
}
|
282
|
+
return value;
|
283
|
+
}
|
284
|
+
|
285
|
+
function normaliseDataset(dataset) {
|
286
|
+
var out = {};
|
287
|
+
for (var key in dataset) {
|
288
|
+
out[key] = normaliseString(dataset[key]);
|
289
|
+
}
|
290
|
+
return out;
|
291
|
+
}
|
292
|
+
|
293
|
+
(function(undefined$1) {
|
294
|
+
var detect = "Window" in this;
|
295
|
+
if (detect) return;
|
296
|
+
if (typeof WorkerGlobalScope === "undefined" && typeof importScripts !== "function") {
|
297
|
+
(function(global) {
|
298
|
+
if (global.constructor) {
|
299
|
+
global.Window = global.constructor;
|
300
|
+
} else {
|
301
|
+
(global.Window = global.constructor = new Function("return function Window() {}")()).prototype = this;
|
166
302
|
}
|
167
|
-
|
168
|
-
|
169
|
-
})(Object.defineProperty);
|
303
|
+
})(this);
|
304
|
+
}
|
170
305
|
}).call("object" === typeof window && window || "object" === typeof self && self || "object" === typeof global && global || {});
|
171
306
|
|
172
307
|
(function(undefined$1) {
|
@@ -415,22 +550,36 @@ var KEY_SPACE = 32;
|
|
415
550
|
|
416
551
|
var DEBOUNCE_TIMEOUT_IN_SECONDS = 1;
|
417
552
|
|
418
|
-
function Button($module) {
|
553
|
+
function Button($module, config) {
|
554
|
+
if (!$module) {
|
555
|
+
return this;
|
556
|
+
}
|
419
557
|
this.$module = $module;
|
420
558
|
this.debounceFormSubmitTimer = null;
|
559
|
+
var defaultConfig = {
|
560
|
+
preventDoubleClick: false
|
561
|
+
};
|
562
|
+
this.config = mergeConfigs(defaultConfig, config || {}, normaliseDataset($module.dataset));
|
421
563
|
}
|
422
564
|
|
565
|
+
Button.prototype.init = function() {
|
566
|
+
if (!this.$module) {
|
567
|
+
return;
|
568
|
+
}
|
569
|
+
this.$module.addEventListener("keydown", this.handleKeyDown);
|
570
|
+
this.$module.addEventListener("click", this.debounce.bind(this));
|
571
|
+
};
|
572
|
+
|
423
573
|
Button.prototype.handleKeyDown = function(event) {
|
424
|
-
var target = event.target;
|
425
|
-
if (target.getAttribute("role") === "button" && event.keyCode === KEY_SPACE) {
|
574
|
+
var $target = event.target;
|
575
|
+
if ($target.getAttribute("role") === "button" && event.keyCode === KEY_SPACE) {
|
426
576
|
event.preventDefault();
|
427
|
-
target.click();
|
577
|
+
$target.click();
|
428
578
|
}
|
429
579
|
};
|
430
580
|
|
431
581
|
Button.prototype.debounce = function(event) {
|
432
|
-
|
433
|
-
if (target.getAttribute("data-prevent-double-click") !== "true") {
|
582
|
+
if (!this.config.preventDoubleClick) {
|
434
583
|
return;
|
435
584
|
}
|
436
585
|
if (this.debounceFormSubmitTimer) {
|
@@ -442,11 +591,260 @@ Button.prototype.debounce = function(event) {
|
|
442
591
|
}.bind(this), DEBOUNCE_TIMEOUT_IN_SECONDS * 1e3);
|
443
592
|
};
|
444
593
|
|
445
|
-
|
446
|
-
this
|
447
|
-
|
594
|
+
(function(undefined$1) {
|
595
|
+
var detect = "document" in this && "matches" in document.documentElement;
|
596
|
+
if (detect) return;
|
597
|
+
Element.prototype.matches = Element.prototype.webkitMatchesSelector || Element.prototype.oMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.mozMatchesSelector || function matches(selector) {
|
598
|
+
var element = this;
|
599
|
+
var elements = (element.document || element.ownerDocument).querySelectorAll(selector);
|
600
|
+
var index = 0;
|
601
|
+
while (elements[index] && elements[index] !== element) {
|
602
|
+
++index;
|
603
|
+
}
|
604
|
+
return !!elements[index];
|
605
|
+
};
|
606
|
+
}).call("object" === typeof window && window || "object" === typeof self && self || "object" === typeof global && global || {});
|
607
|
+
|
608
|
+
(function(undefined$1) {
|
609
|
+
var detect = "document" in this && "closest" in document.documentElement;
|
610
|
+
if (detect) return;
|
611
|
+
Element.prototype.closest = function closest(selector) {
|
612
|
+
var node = this;
|
613
|
+
while (node) {
|
614
|
+
if (node.matches(selector)) return node; else node = "SVGElement" in window && node instanceof SVGElement ? node.parentNode : node.parentElement;
|
615
|
+
}
|
616
|
+
return null;
|
617
|
+
};
|
618
|
+
}).call("object" === typeof window && window || "object" === typeof self && self || "object" === typeof global && global || {});
|
619
|
+
|
620
|
+
function closestAttributeValue($element, attributeName) {
|
621
|
+
var closestElementWithAttribute = $element.closest("[" + attributeName + "]");
|
622
|
+
if (closestElementWithAttribute) {
|
623
|
+
return closestElementWithAttribute.getAttribute(attributeName);
|
624
|
+
}
|
625
|
+
}
|
626
|
+
|
627
|
+
function I18n(translations, config) {
|
628
|
+
this.translations = translations || {};
|
629
|
+
this.locale = config && config.locale || document.documentElement.lang || "en";
|
630
|
+
}
|
631
|
+
|
632
|
+
I18n.prototype.t = function(lookupKey, options) {
|
633
|
+
if (!lookupKey) {
|
634
|
+
throw new Error("i18n: lookup key missing");
|
635
|
+
}
|
636
|
+
if (options && typeof options.count !== "undefined") {
|
637
|
+
lookupKey = lookupKey + "." + this.getPluralSuffix(lookupKey, options.count);
|
638
|
+
}
|
639
|
+
if (lookupKey in this.translations) {
|
640
|
+
var translationString = this.translations[lookupKey];
|
641
|
+
if (translationString.match(/%{(.\S+)}/)) {
|
642
|
+
if (!options) {
|
643
|
+
throw new Error("i18n: cannot replace placeholders in string if no option data provided");
|
644
|
+
}
|
645
|
+
return this.replacePlaceholders(translationString, options);
|
646
|
+
} else {
|
647
|
+
return translationString;
|
648
|
+
}
|
649
|
+
} else {
|
650
|
+
return lookupKey;
|
651
|
+
}
|
652
|
+
};
|
653
|
+
|
654
|
+
I18n.prototype.replacePlaceholders = function(translationString, options) {
|
655
|
+
var formatter;
|
656
|
+
if (this.hasIntlNumberFormatSupport()) {
|
657
|
+
formatter = new Intl.NumberFormat(this.locale);
|
658
|
+
}
|
659
|
+
return translationString.replace(/%{(.\S+)}/g, (function(placeholderWithBraces, placeholderKey) {
|
660
|
+
if (Object.prototype.hasOwnProperty.call(options, placeholderKey)) {
|
661
|
+
var placeholderValue = options[placeholderKey];
|
662
|
+
if (placeholderValue === false) {
|
663
|
+
return "";
|
664
|
+
}
|
665
|
+
if (typeof placeholderValue === "number" && formatter) {
|
666
|
+
return formatter.format(placeholderValue);
|
667
|
+
}
|
668
|
+
return placeholderValue;
|
669
|
+
} else {
|
670
|
+
throw new Error("i18n: no data found to replace " + placeholderWithBraces + " placeholder in string");
|
671
|
+
}
|
672
|
+
}));
|
673
|
+
};
|
674
|
+
|
675
|
+
I18n.prototype.hasIntlPluralRulesSupport = function() {
|
676
|
+
return Boolean(window.Intl && ("PluralRules" in window.Intl && Intl.PluralRules.supportedLocalesOf(this.locale).length));
|
677
|
+
};
|
678
|
+
|
679
|
+
I18n.prototype.hasIntlNumberFormatSupport = function() {
|
680
|
+
return Boolean(window.Intl && ("NumberFormat" in window.Intl && Intl.NumberFormat.supportedLocalesOf(this.locale).length));
|
681
|
+
};
|
682
|
+
|
683
|
+
I18n.prototype.getPluralSuffix = function(lookupKey, count) {
|
684
|
+
count = Number(count);
|
685
|
+
if (!isFinite(count)) {
|
686
|
+
return "other";
|
687
|
+
}
|
688
|
+
var preferredForm;
|
689
|
+
if (this.hasIntlPluralRulesSupport()) {
|
690
|
+
preferredForm = new Intl.PluralRules(this.locale).select(count);
|
691
|
+
} else {
|
692
|
+
preferredForm = this.selectPluralFormUsingFallbackRules(count);
|
693
|
+
}
|
694
|
+
if (lookupKey + "." + preferredForm in this.translations) {
|
695
|
+
return preferredForm;
|
696
|
+
} else if (lookupKey + ".other" in this.translations) {
|
697
|
+
if (console && "warn" in console) {
|
698
|
+
console.warn('i18n: Missing plural form ".' + preferredForm + '" for "' + this.locale + '" locale. Falling back to ".other".');
|
699
|
+
}
|
700
|
+
return "other";
|
701
|
+
} else {
|
702
|
+
throw new Error('i18n: Plural form ".other" is required for "' + this.locale + '" locale');
|
703
|
+
}
|
704
|
+
};
|
705
|
+
|
706
|
+
I18n.prototype.selectPluralFormUsingFallbackRules = function(count) {
|
707
|
+
count = Math.abs(Math.floor(count));
|
708
|
+
var ruleset = this.getPluralRulesForLocale();
|
709
|
+
if (ruleset) {
|
710
|
+
return I18n.pluralRules[ruleset](count);
|
711
|
+
}
|
712
|
+
return "other";
|
448
713
|
};
|
449
714
|
|
715
|
+
I18n.prototype.getPluralRulesForLocale = function() {
|
716
|
+
var locale = this.locale;
|
717
|
+
var localeShort = locale.split("-")[0];
|
718
|
+
for (var pluralRule in I18n.pluralRulesMap) {
|
719
|
+
if (Object.prototype.hasOwnProperty.call(I18n.pluralRulesMap, pluralRule)) {
|
720
|
+
var languages = I18n.pluralRulesMap[pluralRule];
|
721
|
+
for (var i = 0; i < languages.length; i++) {
|
722
|
+
if (languages[i] === locale || languages[i] === localeShort) {
|
723
|
+
return pluralRule;
|
724
|
+
}
|
725
|
+
}
|
726
|
+
}
|
727
|
+
}
|
728
|
+
};
|
729
|
+
|
730
|
+
I18n.pluralRulesMap = {
|
731
|
+
arabic: [ "ar" ],
|
732
|
+
chinese: [ "my", "zh", "id", "ja", "jv", "ko", "ms", "th", "vi" ],
|
733
|
+
french: [ "hy", "bn", "fr", "gu", "hi", "fa", "pa", "zu" ],
|
734
|
+
german: [ "af", "sq", "az", "eu", "bg", "ca", "da", "nl", "en", "et", "fi", "ka", "de", "el", "hu", "lb", "no", "so", "sw", "sv", "ta", "te", "tr", "ur" ],
|
735
|
+
irish: [ "ga" ],
|
736
|
+
russian: [ "ru", "uk" ],
|
737
|
+
scottish: [ "gd" ],
|
738
|
+
spanish: [ "pt-PT", "it", "es" ],
|
739
|
+
welsh: [ "cy" ]
|
740
|
+
};
|
741
|
+
|
742
|
+
I18n.pluralRules = {
|
743
|
+
arabic: function(n) {
|
744
|
+
if (n === 0) {
|
745
|
+
return "zero";
|
746
|
+
}
|
747
|
+
if (n === 1) {
|
748
|
+
return "one";
|
749
|
+
}
|
750
|
+
if (n === 2) {
|
751
|
+
return "two";
|
752
|
+
}
|
753
|
+
if (n % 100 >= 3 && n % 100 <= 10) {
|
754
|
+
return "few";
|
755
|
+
}
|
756
|
+
if (n % 100 >= 11 && n % 100 <= 99) {
|
757
|
+
return "many";
|
758
|
+
}
|
759
|
+
return "other";
|
760
|
+
},
|
761
|
+
chinese: function() {
|
762
|
+
return "other";
|
763
|
+
},
|
764
|
+
french: function(n) {
|
765
|
+
return n === 0 || n === 1 ? "one" : "other";
|
766
|
+
},
|
767
|
+
german: function(n) {
|
768
|
+
return n === 1 ? "one" : "other";
|
769
|
+
},
|
770
|
+
irish: function(n) {
|
771
|
+
if (n === 1) {
|
772
|
+
return "one";
|
773
|
+
}
|
774
|
+
if (n === 2) {
|
775
|
+
return "two";
|
776
|
+
}
|
777
|
+
if (n >= 3 && n <= 6) {
|
778
|
+
return "few";
|
779
|
+
}
|
780
|
+
if (n >= 7 && n <= 10) {
|
781
|
+
return "many";
|
782
|
+
}
|
783
|
+
return "other";
|
784
|
+
},
|
785
|
+
russian: function(n) {
|
786
|
+
var lastTwo = n % 100;
|
787
|
+
var last = lastTwo % 10;
|
788
|
+
if (last === 1 && lastTwo !== 11) {
|
789
|
+
return "one";
|
790
|
+
}
|
791
|
+
if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) {
|
792
|
+
return "few";
|
793
|
+
}
|
794
|
+
if (last === 0 || last >= 5 && last <= 9 || lastTwo >= 11 && lastTwo <= 14) {
|
795
|
+
return "many";
|
796
|
+
}
|
797
|
+
return "other";
|
798
|
+
},
|
799
|
+
scottish: function(n) {
|
800
|
+
if (n === 1 || n === 11) {
|
801
|
+
return "one";
|
802
|
+
}
|
803
|
+
if (n === 2 || n === 12) {
|
804
|
+
return "two";
|
805
|
+
}
|
806
|
+
if (n >= 3 && n <= 10 || n >= 13 && n <= 19) {
|
807
|
+
return "few";
|
808
|
+
}
|
809
|
+
return "other";
|
810
|
+
},
|
811
|
+
spanish: function(n) {
|
812
|
+
if (n === 1) {
|
813
|
+
return "one";
|
814
|
+
}
|
815
|
+
if (n % 1e6 === 0 && n !== 0) {
|
816
|
+
return "many";
|
817
|
+
}
|
818
|
+
return "other";
|
819
|
+
},
|
820
|
+
welsh: function(n) {
|
821
|
+
if (n === 0) {
|
822
|
+
return "zero";
|
823
|
+
}
|
824
|
+
if (n === 1) {
|
825
|
+
return "one";
|
826
|
+
}
|
827
|
+
if (n === 2) {
|
828
|
+
return "two";
|
829
|
+
}
|
830
|
+
if (n === 3) {
|
831
|
+
return "few";
|
832
|
+
}
|
833
|
+
if (n === 6) {
|
834
|
+
return "many";
|
835
|
+
}
|
836
|
+
return "other";
|
837
|
+
}
|
838
|
+
};
|
839
|
+
|
840
|
+
(function(undefined$1) {
|
841
|
+
var detect = "Date" in self && "now" in self.Date && "getTime" in self.Date.prototype;
|
842
|
+
if (detect) return;
|
843
|
+
Date.now = function() {
|
844
|
+
return (new Date).getTime();
|
845
|
+
};
|
846
|
+
}).call("object" === typeof window && window || "object" === typeof self && self || "object" === typeof global && global || {});
|
847
|
+
|
450
848
|
(function(undefined$1) {
|
451
849
|
var detect = "DOMTokenList" in this && function(x) {
|
452
850
|
return "classList" in x ? !x.classList.toggle("x", false) && !x.className : true;
|
@@ -685,7 +1083,57 @@ Button.prototype.init = function() {
|
|
685
1083
|
})(this);
|
686
1084
|
}).call("object" === typeof window && window || "object" === typeof self && self || "object" === typeof global && global || {});
|
687
1085
|
|
688
|
-
|
1086
|
+
var CHARACTER_COUNT_TRANSLATIONS = {
|
1087
|
+
charactersUnderLimit: {
|
1088
|
+
one: "You have %{count} character remaining",
|
1089
|
+
other: "You have %{count} characters remaining"
|
1090
|
+
},
|
1091
|
+
charactersAtLimit: "You have 0 characters remaining",
|
1092
|
+
charactersOverLimit: {
|
1093
|
+
one: "You have %{count} character too many",
|
1094
|
+
other: "You have %{count} characters too many"
|
1095
|
+
},
|
1096
|
+
wordsUnderLimit: {
|
1097
|
+
one: "You have %{count} word remaining",
|
1098
|
+
other: "You have %{count} words remaining"
|
1099
|
+
},
|
1100
|
+
wordsAtLimit: "You have 0 words remaining",
|
1101
|
+
wordsOverLimit: {
|
1102
|
+
one: "You have %{count} word too many",
|
1103
|
+
other: "You have %{count} words too many"
|
1104
|
+
},
|
1105
|
+
textareaDescription: {
|
1106
|
+
other: ""
|
1107
|
+
}
|
1108
|
+
};
|
1109
|
+
|
1110
|
+
function CharacterCount($module, config) {
|
1111
|
+
if (!$module) {
|
1112
|
+
return this;
|
1113
|
+
}
|
1114
|
+
var defaultConfig = {
|
1115
|
+
threshold: 0,
|
1116
|
+
i18n: CHARACTER_COUNT_TRANSLATIONS
|
1117
|
+
};
|
1118
|
+
var datasetConfig = normaliseDataset($module.dataset);
|
1119
|
+
var configOverrides = {};
|
1120
|
+
if ("maxwords" in datasetConfig || "maxlength" in datasetConfig) {
|
1121
|
+
configOverrides = {
|
1122
|
+
maxlength: false,
|
1123
|
+
maxwords: false
|
1124
|
+
};
|
1125
|
+
}
|
1126
|
+
this.config = mergeConfigs(defaultConfig, config || {}, configOverrides, datasetConfig);
|
1127
|
+
this.i18n = new I18n(extractConfigByNamespace(this.config, "i18n"), {
|
1128
|
+
locale: closestAttributeValue($module, "lang")
|
1129
|
+
});
|
1130
|
+
if (this.config.maxwords) {
|
1131
|
+
this.maxLength = this.config.maxwords;
|
1132
|
+
} else if (this.config.maxlength) {
|
1133
|
+
this.maxLength = this.config.maxlength;
|
1134
|
+
} else {
|
1135
|
+
return;
|
1136
|
+
}
|
689
1137
|
this.$module = $module;
|
690
1138
|
this.$textarea = $module.querySelector(".govuk-js-character-count");
|
691
1139
|
this.$visibleCountMessage = null;
|
@@ -693,40 +1141,30 @@ function CharacterCount($module) {
|
|
693
1141
|
this.lastInputTimestamp = null;
|
694
1142
|
}
|
695
1143
|
|
696
|
-
CharacterCount.prototype.defaults = {
|
697
|
-
characterCountAttribute: "data-maxlength",
|
698
|
-
wordCountAttribute: "data-maxwords"
|
699
|
-
};
|
700
|
-
|
701
1144
|
CharacterCount.prototype.init = function() {
|
702
1145
|
if (!this.$textarea) {
|
703
1146
|
return;
|
704
1147
|
}
|
705
|
-
var $module = this.$module;
|
706
1148
|
var $textarea = this.$textarea;
|
707
|
-
var $
|
708
|
-
$
|
1149
|
+
var $textareaDescription = document.getElementById($textarea.id + "-info");
|
1150
|
+
if ($textareaDescription.innerText.match(/^\s*$/)) {
|
1151
|
+
$textareaDescription.innerText = this.i18n.t("textareaDescription", {
|
1152
|
+
count: this.maxLength
|
1153
|
+
});
|
1154
|
+
}
|
1155
|
+
$textarea.insertAdjacentElement("afterend", $textareaDescription);
|
709
1156
|
var $screenReaderCountMessage = document.createElement("div");
|
710
1157
|
$screenReaderCountMessage.className = "govuk-character-count__sr-status govuk-visually-hidden";
|
711
1158
|
$screenReaderCountMessage.setAttribute("aria-live", "polite");
|
712
1159
|
this.$screenReaderCountMessage = $screenReaderCountMessage;
|
713
|
-
$
|
1160
|
+
$textareaDescription.insertAdjacentElement("afterend", $screenReaderCountMessage);
|
714
1161
|
var $visibleCountMessage = document.createElement("div");
|
715
|
-
$visibleCountMessage.className = $
|
1162
|
+
$visibleCountMessage.className = $textareaDescription.className;
|
716
1163
|
$visibleCountMessage.classList.add("govuk-character-count__status");
|
717
1164
|
$visibleCountMessage.setAttribute("aria-hidden", "true");
|
718
1165
|
this.$visibleCountMessage = $visibleCountMessage;
|
719
|
-
$
|
720
|
-
$
|
721
|
-
this.options = this.getDataset($module);
|
722
|
-
var countAttribute = this.defaults.characterCountAttribute;
|
723
|
-
if (this.options.maxwords) {
|
724
|
-
countAttribute = this.defaults.wordCountAttribute;
|
725
|
-
}
|
726
|
-
this.maxLength = $module.getAttribute(countAttribute);
|
727
|
-
if (!this.maxLength) {
|
728
|
-
return;
|
729
|
-
}
|
1166
|
+
$textareaDescription.insertAdjacentElement("afterend", $visibleCountMessage);
|
1167
|
+
$textareaDescription.classList.add("govuk-visually-hidden");
|
730
1168
|
$textarea.removeAttribute("maxlength");
|
731
1169
|
this.bindChangeEvents();
|
732
1170
|
if ("onpageshow" in window) {
|
@@ -737,32 +1175,6 @@ CharacterCount.prototype.init = function() {
|
|
737
1175
|
this.updateCountMessage();
|
738
1176
|
};
|
739
1177
|
|
740
|
-
CharacterCount.prototype.getDataset = function(element) {
|
741
|
-
var dataset = {};
|
742
|
-
var attributes = element.attributes;
|
743
|
-
if (attributes) {
|
744
|
-
for (var i = 0; i < attributes.length; i++) {
|
745
|
-
var attribute = attributes[i];
|
746
|
-
var match = attribute.name.match(/^data-(.+)/);
|
747
|
-
if (match) {
|
748
|
-
dataset[match[1]] = attribute.value;
|
749
|
-
}
|
750
|
-
}
|
751
|
-
}
|
752
|
-
return dataset;
|
753
|
-
};
|
754
|
-
|
755
|
-
CharacterCount.prototype.count = function(text) {
|
756
|
-
var length;
|
757
|
-
if (this.options.maxwords) {
|
758
|
-
var tokens = text.match(/\S+/g) || [];
|
759
|
-
length = tokens.length;
|
760
|
-
} else {
|
761
|
-
length = text.length;
|
762
|
-
}
|
763
|
-
return length;
|
764
|
-
};
|
765
|
-
|
766
1178
|
CharacterCount.prototype.bindChangeEvents = function() {
|
767
1179
|
var $textarea = this.$textarea;
|
768
1180
|
$textarea.addEventListener("keyup", this.handleKeyUp.bind(this));
|
@@ -770,7 +1182,24 @@ CharacterCount.prototype.bindChangeEvents = function() {
|
|
770
1182
|
$textarea.addEventListener("blur", this.handleBlur.bind(this));
|
771
1183
|
};
|
772
1184
|
|
773
|
-
CharacterCount.prototype.
|
1185
|
+
CharacterCount.prototype.handleKeyUp = function() {
|
1186
|
+
this.updateVisibleCountMessage();
|
1187
|
+
this.lastInputTimestamp = Date.now();
|
1188
|
+
};
|
1189
|
+
|
1190
|
+
CharacterCount.prototype.handleFocus = function() {
|
1191
|
+
this.valueChecker = setInterval(function() {
|
1192
|
+
if (!this.lastInputTimestamp || Date.now() - 500 >= this.lastInputTimestamp) {
|
1193
|
+
this.updateIfValueChanged();
|
1194
|
+
}
|
1195
|
+
}.bind(this), 1e3);
|
1196
|
+
};
|
1197
|
+
|
1198
|
+
CharacterCount.prototype.handleBlur = function() {
|
1199
|
+
clearInterval(this.valueChecker);
|
1200
|
+
};
|
1201
|
+
|
1202
|
+
CharacterCount.prototype.updateIfValueChanged = function() {
|
774
1203
|
if (!this.$textarea.oldValue) this.$textarea.oldValue = "";
|
775
1204
|
if (this.$textarea.value !== this.$textarea.oldValue) {
|
776
1205
|
this.$textarea.oldValue = this.$textarea.value;
|
@@ -801,7 +1230,7 @@ CharacterCount.prototype.updateVisibleCountMessage = function() {
|
|
801
1230
|
$visibleCountMessage.classList.remove("govuk-error-message");
|
802
1231
|
$visibleCountMessage.classList.add("govuk-hint");
|
803
1232
|
}
|
804
|
-
$visibleCountMessage.
|
1233
|
+
$visibleCountMessage.innerText = this.getCountMessage();
|
805
1234
|
};
|
806
1235
|
|
807
1236
|
CharacterCount.prototype.updateScreenReaderCountMessage = function() {
|
@@ -811,52 +1240,45 @@ CharacterCount.prototype.updateScreenReaderCountMessage = function() {
|
|
811
1240
|
} else {
|
812
1241
|
$screenReaderCountMessage.setAttribute("aria-hidden", true);
|
813
1242
|
}
|
814
|
-
$screenReaderCountMessage.
|
1243
|
+
$screenReaderCountMessage.innerText = this.getCountMessage();
|
815
1244
|
};
|
816
1245
|
|
817
|
-
CharacterCount.prototype.
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
1246
|
+
CharacterCount.prototype.count = function(text) {
|
1247
|
+
if (this.config.maxwords) {
|
1248
|
+
var tokens = text.match(/\S+/g) || [];
|
1249
|
+
return tokens.length;
|
1250
|
+
} else {
|
1251
|
+
return text.length;
|
1252
|
+
}
|
1253
|
+
};
|
1254
|
+
|
1255
|
+
CharacterCount.prototype.getCountMessage = function() {
|
1256
|
+
var remainingNumber = this.maxLength - this.count(this.$textarea.value);
|
1257
|
+
var countType = this.config.maxwords ? "words" : "characters";
|
1258
|
+
return this.formatCountMessage(remainingNumber, countType);
|
1259
|
+
};
|
1260
|
+
|
1261
|
+
CharacterCount.prototype.formatCountMessage = function(remainingNumber, countType) {
|
1262
|
+
if (remainingNumber === 0) {
|
1263
|
+
return this.i18n.t(countType + "AtLimit");
|
826
1264
|
}
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
1265
|
+
var translationKeySuffix = remainingNumber < 0 ? "OverLimit" : "UnderLimit";
|
1266
|
+
return this.i18n.t(countType + translationKeySuffix, {
|
1267
|
+
count: Math.abs(remainingNumber)
|
1268
|
+
});
|
831
1269
|
};
|
832
1270
|
|
833
1271
|
CharacterCount.prototype.isOverThreshold = function() {
|
1272
|
+
if (!this.config.threshold) {
|
1273
|
+
return true;
|
1274
|
+
}
|
834
1275
|
var $textarea = this.$textarea;
|
835
|
-
var options = this.options;
|
836
1276
|
var currentLength = this.count($textarea.value);
|
837
1277
|
var maxLength = this.maxLength;
|
838
|
-
var
|
839
|
-
var thresholdValue = maxLength * thresholdPercent / 100;
|
1278
|
+
var thresholdValue = maxLength * this.config.threshold / 100;
|
840
1279
|
return thresholdValue <= currentLength;
|
841
1280
|
};
|
842
1281
|
|
843
|
-
CharacterCount.prototype.handleKeyUp = function() {
|
844
|
-
this.updateVisibleCountMessage();
|
845
|
-
this.lastInputTimestamp = Date.now();
|
846
|
-
};
|
847
|
-
|
848
|
-
CharacterCount.prototype.handleFocus = function() {
|
849
|
-
this.valueChecker = setInterval(function() {
|
850
|
-
if (!this.lastInputTimestamp || Date.now() - 500 >= this.lastInputTimestamp) {
|
851
|
-
this.checkIfValueChanged();
|
852
|
-
}
|
853
|
-
}.bind(this), 1e3);
|
854
|
-
};
|
855
|
-
|
856
|
-
CharacterCount.prototype.handleBlur = function() {
|
857
|
-
clearInterval(this.valueChecker);
|
858
|
-
};
|
859
|
-
|
860
1282
|
function Checkboxes($module) {
|
861
1283
|
this.$module = $module;
|
862
1284
|
this.$inputs = $module.querySelectorAll('input[type="checkbox"]');
|
@@ -866,11 +1288,11 @@ Checkboxes.prototype.init = function() {
|
|
866
1288
|
var $module = this.$module;
|
867
1289
|
var $inputs = this.$inputs;
|
868
1290
|
nodeListForEach($inputs, (function($input) {
|
869
|
-
var
|
870
|
-
if (!
|
1291
|
+
var targetId = $input.getAttribute("data-aria-controls");
|
1292
|
+
if (!targetId || !document.getElementById(targetId)) {
|
871
1293
|
return;
|
872
1294
|
}
|
873
|
-
$input.setAttribute("aria-controls",
|
1295
|
+
$input.setAttribute("aria-controls", targetId);
|
874
1296
|
$input.removeAttribute("data-aria-controls");
|
875
1297
|
}));
|
876
1298
|
if ("onpageshow" in window) {
|
@@ -918,53 +1340,34 @@ Checkboxes.prototype.unCheckExclusiveInputs = function($input) {
|
|
918
1340
|
};
|
919
1341
|
|
920
1342
|
Checkboxes.prototype.handleClick = function(event) {
|
921
|
-
var $
|
922
|
-
if ($
|
1343
|
+
var $clickedInput = event.target;
|
1344
|
+
if ($clickedInput.type !== "checkbox") {
|
923
1345
|
return;
|
924
1346
|
}
|
925
|
-
var hasAriaControls = $
|
1347
|
+
var hasAriaControls = $clickedInput.getAttribute("aria-controls");
|
926
1348
|
if (hasAriaControls) {
|
927
|
-
this.syncConditionalRevealWithInputState($
|
1349
|
+
this.syncConditionalRevealWithInputState($clickedInput);
|
928
1350
|
}
|
929
|
-
if (!$
|
1351
|
+
if (!$clickedInput.checked) {
|
930
1352
|
return;
|
931
1353
|
}
|
932
|
-
var hasBehaviourExclusive = $
|
1354
|
+
var hasBehaviourExclusive = $clickedInput.getAttribute("data-behaviour") === "exclusive";
|
933
1355
|
if (hasBehaviourExclusive) {
|
934
|
-
this.unCheckAllInputsExcept($
|
1356
|
+
this.unCheckAllInputsExcept($clickedInput);
|
935
1357
|
} else {
|
936
|
-
this.unCheckExclusiveInputs($
|
1358
|
+
this.unCheckExclusiveInputs($clickedInput);
|
937
1359
|
}
|
938
1360
|
};
|
939
1361
|
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
var element = this;
|
945
|
-
var elements = (element.document || element.ownerDocument).querySelectorAll(selector);
|
946
|
-
var index = 0;
|
947
|
-
while (elements[index] && elements[index] !== element) {
|
948
|
-
++index;
|
949
|
-
}
|
950
|
-
return !!elements[index];
|
951
|
-
};
|
952
|
-
}).call("object" === typeof window && window || "object" === typeof self && self || "object" === typeof global && global || {});
|
953
|
-
|
954
|
-
(function(undefined$1) {
|
955
|
-
var detect = "document" in this && "closest" in document.documentElement;
|
956
|
-
if (detect) return;
|
957
|
-
Element.prototype.closest = function closest(selector) {
|
958
|
-
var node = this;
|
959
|
-
while (node) {
|
960
|
-
if (node.matches(selector)) return node; else node = "SVGElement" in window && node instanceof SVGElement ? node.parentNode : node.parentElement;
|
961
|
-
}
|
962
|
-
return null;
|
963
|
-
};
|
964
|
-
}).call("object" === typeof window && window || "object" === typeof self && self || "object" === typeof global && global || {});
|
965
|
-
|
966
|
-
function ErrorSummary($module) {
|
1362
|
+
function ErrorSummary($module, config) {
|
1363
|
+
if (!$module) {
|
1364
|
+
return this;
|
1365
|
+
}
|
967
1366
|
this.$module = $module;
|
1367
|
+
var defaultConfig = {
|
1368
|
+
disableAutoFocus: false
|
1369
|
+
};
|
1370
|
+
this.config = mergeConfigs(defaultConfig, config || {}, normaliseDataset($module.dataset));
|
968
1371
|
}
|
969
1372
|
|
970
1373
|
ErrorSummary.prototype.init = function() {
|
@@ -978,7 +1381,7 @@ ErrorSummary.prototype.init = function() {
|
|
978
1381
|
|
979
1382
|
ErrorSummary.prototype.setFocus = function() {
|
980
1383
|
var $module = this.$module;
|
981
|
-
if (
|
1384
|
+
if (this.config.disableAutoFocus) {
|
982
1385
|
return;
|
983
1386
|
}
|
984
1387
|
$module.setAttribute("tabindex", "-1");
|
@@ -989,8 +1392,8 @@ ErrorSummary.prototype.setFocus = function() {
|
|
989
1392
|
};
|
990
1393
|
|
991
1394
|
ErrorSummary.prototype.handleClick = function(event) {
|
992
|
-
var target = event.target;
|
993
|
-
if (this.focusTarget(target)) {
|
1395
|
+
var $target = event.target;
|
1396
|
+
if (this.focusTarget($target)) {
|
994
1397
|
event.preventDefault();
|
995
1398
|
}
|
996
1399
|
};
|
@@ -1025,9 +1428,9 @@ ErrorSummary.prototype.getFragmentFromUrl = function(url) {
|
|
1025
1428
|
ErrorSummary.prototype.getAssociatedLegendOrLabel = function($input) {
|
1026
1429
|
var $fieldset = $input.closest("fieldset");
|
1027
1430
|
if ($fieldset) {
|
1028
|
-
var legends = $fieldset.getElementsByTagName("legend");
|
1029
|
-
if (legends.length) {
|
1030
|
-
var $candidateLegend = legends[0];
|
1431
|
+
var $legends = $fieldset.getElementsByTagName("legend");
|
1432
|
+
if ($legends.length) {
|
1433
|
+
var $candidateLegend = $legends[0];
|
1031
1434
|
if ($input.type === "checkbox" || $input.type === "radio") {
|
1032
1435
|
return $candidateLegend;
|
1033
1436
|
}
|
@@ -1053,11 +1456,11 @@ Radios.prototype.init = function() {
|
|
1053
1456
|
var $module = this.$module;
|
1054
1457
|
var $inputs = this.$inputs;
|
1055
1458
|
nodeListForEach($inputs, (function($input) {
|
1056
|
-
var
|
1057
|
-
if (!
|
1459
|
+
var targetId = $input.getAttribute("data-aria-controls");
|
1460
|
+
if (!targetId || !document.getElementById(targetId)) {
|
1058
1461
|
return;
|
1059
1462
|
}
|
1060
|
-
$input.setAttribute("aria-controls",
|
1463
|
+
$input.setAttribute("aria-controls", targetId);
|
1061
1464
|
$input.removeAttribute("data-aria-controls");
|
1062
1465
|
}));
|
1063
1466
|
if ("onpageshow" in window) {
|