hmrc-frontend 5.9.0 → 5.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/hmrc/all.js CHANGED
@@ -942,881 +942,883 @@
942
942
  }
943
943
  };
944
944
 
945
- (function (undefined) {
946
- // Detection from https://github.com/Financial-Times/polyfill-library/blob/987630a085e29226da16b5dc542042c687560191/polyfills/Array/prototype/forEach/detect.js
947
- var detect = ('forEach' in Array.prototype);
948
- if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Array.prototype.forEach&flags=always
945
+ function BackLinkHelper($module, window, document) {
946
+ this.$module = $module;
947
+ this.window = window;
948
+ this.document = document;
949
+ }
949
950
 
950
- (function () {
951
- Array.prototype.forEach = function forEach(callback) {
952
- if (this === undefined || this === null) {
953
- throw new TypeError(this + " is not an object");
954
- }
951
+ BackLinkHelper.prototype.init = function init() {
952
+ var _this = this;
955
953
 
956
- if (typeof callback !== "function") {
957
- throw new TypeError(callback + " is not a function");
958
- }
954
+ // do nothing if History API is absent
955
+ if (this.window.history) {
956
+ // store referrer value to cater for IE
957
+ var docReferrer = this.document.referrer; // prevent resubmit warning
959
958
 
960
- var object = Object(this),
961
- scope = arguments[1],
962
- arraylike = object instanceof String ? object.split("") : object,
963
- length = Math.max(Math.min(arraylike.length, 9007199254740991), 0) || 0,
964
- index = -1;
959
+ if (this.window.history.replaceState && typeof this.window.history.replaceState === 'function') {
960
+ this.window.history.replaceState(null, null, this.window.location.href);
961
+ } // handle 'Back' click, dependent upon presence of referrer & no host change
965
962
 
966
- while (++index < length) {
967
- if (index in arraylike) {
968
- callback.call(scope, arraylike[index], index, object);
963
+
964
+ this.$module.addEventListener('click', function (event) {
965
+ event.preventDefault();
966
+
967
+ if (_this.window.history.back && typeof _this.window.history.back === 'function') {
968
+ if (docReferrer !== '' && docReferrer.indexOf(_this.window.location.host) !== -1) {
969
+ _this.window.history.back();
969
970
  }
970
971
  }
971
- };
972
- })();
973
- }).call('object' === (typeof window === "undefined" ? "undefined" : _typeof(window)) && window || 'object' === (typeof self === "undefined" ? "undefined" : _typeof(self)) && self || 'object' === (typeof global === "undefined" ? "undefined" : _typeof(global)) && global || {});
972
+ });
973
+ }
974
+ };
974
975
 
975
- (function (undefined) {
976
- // Detection from https://github.com/Financial-Times/polyfill-library/blob/987630a085e29226da16b5dc542042c687560191/polyfills/Object/keys/detect.js
977
- var detect = 'keys' in Object && function () {
978
- // Safari 5.0 bug where Object.keys doesn't work with arguments
979
- return Object.keys(arguments).length === 2;
980
- }(1, 2) && function () {
981
- try {
982
- return true;
983
- } catch (e) {
984
- return false;
976
+ var Event_1 = createCommonjsModule(function (module, exports) {
977
+ (function (global, factory) {
978
+ factory();
979
+ })(commonjsGlobal, function () {
980
+
981
+ (function (undefined) {
982
+ // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Window/detect.js
983
+ var detect = ('Window' in this);
984
+ if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Window&flags=always
985
+
986
+ if (typeof WorkerGlobalScope === "undefined" && typeof importScripts !== "function") {
987
+ (function (global) {
988
+ if (global.constructor) {
989
+ global.Window = global.constructor;
990
+ } else {
991
+ (global.Window = global.constructor = new Function('return function Window() {}')()).prototype = this;
992
+ }
993
+ })(this);
985
994
  }
986
- }();
995
+ }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
996
+ (function (undefined) {
997
+ // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Document/detect.js
998
+ var detect = ("Document" in this);
999
+ if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Document&flags=always
987
1000
 
988
- if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Object.assign&flags=always
1001
+ if (typeof WorkerGlobalScope === "undefined" && typeof importScripts !== "function") {
1002
+ if (this.HTMLDocument) {
1003
+ // IE8
1004
+ // HTMLDocument is an extension of Document. If the browser has HTMLDocument but not Document, the former will suffice as an alias for the latter.
1005
+ this.Document = this.HTMLDocument;
1006
+ } else {
1007
+ // 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.
1008
+ this.Document = this.HTMLDocument = document.constructor = new Function('return function Document() {}')();
1009
+ this.Document.prototype = document;
1010
+ }
1011
+ }
1012
+ }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
1013
+ (function (undefined) {
1014
+ // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Element/detect.js
1015
+ var detect = 'Element' in this && 'HTMLElement' in this;
1016
+ if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Element&flags=always
989
1017
 
990
- Object.keys = function () {
1018
+ (function () {
1019
+ // IE8
1020
+ if (window.Element && !window.HTMLElement) {
1021
+ window.HTMLElement = window.Element;
1022
+ return;
1023
+ } // create Element constructor
991
1024
 
992
- var has = Object.prototype.hasOwnProperty;
993
- var toStr = Object.prototype.toString;
994
- var isEnumerable = Object.prototype.propertyIsEnumerable;
995
- var hasDontEnumBug = !isEnumerable.call({
996
- toString: null
997
- }, "toString");
998
- var hasProtoEnumBug = isEnumerable.call(function () {}, "prototype");
999
- var dontEnums = ["toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "constructor"];
1000
1025
 
1001
- var equalsConstructorPrototype = function equalsConstructorPrototype(o) {
1002
- var ctor = o.constructor;
1003
- return ctor && ctor.prototype === o;
1004
- };
1026
+ window.Element = window.HTMLElement = new Function('return function Element() {}')(); // generate sandboxed iframe
1005
1027
 
1006
- var excludedKeys = {
1007
- $console: true,
1008
- $external: true,
1009
- $frame: true,
1010
- $frameElement: true,
1011
- $frames: true,
1012
- $innerHeight: true,
1013
- $innerWidth: true,
1014
- $outerHeight: true,
1015
- $outerWidth: true,
1016
- $pageXOffset: true,
1017
- $pageYOffset: true,
1018
- $parent: true,
1019
- $scrollLeft: true,
1020
- $scrollTop: true,
1021
- $scrollX: true,
1022
- $scrollY: true,
1023
- $self: true,
1024
- $webkitIndexedDB: true,
1025
- $webkitStorageInfo: true,
1026
- $window: true
1027
- };
1028
+ var vbody = document.appendChild(document.createElement('body'));
1029
+ var frame = vbody.appendChild(document.createElement('iframe')); // use sandboxed iframe to replicate Element functionality
1028
1030
 
1029
- var hasAutomationEqualityBug = function () {
1030
- /* global window */
1031
- if (typeof window === "undefined") {
1032
- return false;
1033
- }
1031
+ var frameDocument = frame.contentWindow.document;
1032
+ var prototype = Element.prototype = frameDocument.appendChild(frameDocument.createElement('*'));
1033
+ var cache = {}; // polyfill Element.prototype on an element
1034
1034
 
1035
- for (var k in window) {
1036
- try {
1037
- if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && _typeof(window[k]) === 'object') {
1038
- try {
1039
- equalsConstructorPrototype(window[k]);
1040
- } catch (e) {
1041
- return true;
1042
- }
1035
+ var shiv = function (element, deep) {
1036
+ var childNodes = element.childNodes || [],
1037
+ index = -1,
1038
+ key,
1039
+ value,
1040
+ childNode;
1041
+
1042
+ if (element.nodeType === 1 && element.constructor !== Element) {
1043
+ element.constructor = Element;
1044
+
1045
+ for (key in cache) {
1046
+ value = cache[key];
1047
+ element[key] = value;
1043
1048
  }
1044
- } catch (e) {
1045
- return true;
1046
1049
  }
1047
- }
1048
-
1049
- return false;
1050
- }();
1051
1050
 
1052
- var equalsConstructorPrototypeIfNotBuggy = function equalsConstructorPrototypeIfNotBuggy(o) {
1053
- /* global window */
1054
- if (typeof window === "undefined" || !hasAutomationEqualityBug) {
1055
- return equalsConstructorPrototype(o);
1056
- }
1051
+ while (childNode = deep && childNodes[++index]) {
1052
+ shiv(childNode, deep);
1053
+ }
1057
1054
 
1058
- try {
1059
- return equalsConstructorPrototype(o);
1060
- } catch (e) {
1061
- return false;
1062
- }
1063
- };
1055
+ return element;
1056
+ };
1064
1057
 
1065
- function isArgumentsObject(value) {
1066
- var str = toStr.call(value);
1067
- var isArgs = str === "[object Arguments]";
1058
+ var elements = document.getElementsByTagName('*');
1059
+ var nativeCreateElement = document.createElement;
1060
+ var interval;
1061
+ var loopLimit = 100;
1062
+ prototype.attachEvent('onpropertychange', function (event) {
1063
+ var propertyName = event.propertyName,
1064
+ nonValue = !cache.hasOwnProperty(propertyName),
1065
+ newValue = prototype[propertyName],
1066
+ oldValue = cache[propertyName],
1067
+ index = -1,
1068
+ element;
1068
1069
 
1069
- if (!isArgs) {
1070
- isArgs = str !== "[object Array]" && value !== null && _typeof(value) === "object" && typeof value.length === "number" && value.length >= 0 && toStr.call(value.callee) === "[object Function]";
1071
- }
1070
+ while (element = elements[++index]) {
1071
+ if (element.nodeType === 1) {
1072
+ if (nonValue || element[propertyName] === oldValue) {
1073
+ element[propertyName] = newValue;
1074
+ }
1075
+ }
1076
+ }
1072
1077
 
1073
- return isArgs;
1074
- }
1078
+ cache[propertyName] = newValue;
1079
+ });
1080
+ prototype.constructor = Element;
1075
1081
 
1076
- return function keys(object) {
1077
- var isFunction = toStr.call(object) === "[object Function]";
1078
- var isArguments = isArgumentsObject(object);
1079
- var isString = toStr.call(object) === "[object String]";
1080
- var theKeys = [];
1082
+ if (!prototype.hasAttribute) {
1083
+ // <Element>.hasAttribute
1084
+ prototype.hasAttribute = function hasAttribute(name) {
1085
+ return this.getAttribute(name) !== null;
1086
+ };
1087
+ } // Apply Element prototype to the pre-existing DOM as soon as the body element appears.
1081
1088
 
1082
- if (object === undefined || object === null) {
1083
- throw new TypeError("Cannot convert undefined or null to object");
1084
- }
1085
1089
 
1086
- var skipProto = hasProtoEnumBug && isFunction;
1090
+ function bodyCheck() {
1091
+ if (!loopLimit--) clearTimeout(interval);
1087
1092
 
1088
- if (isString && object.length > 0 && !has.call(object, 0)) {
1089
- for (var i = 0; i < object.length; ++i) {
1090
- theKeys.push(String(i));
1093
+ if (document.body && !document.body.prototype && /(complete|interactive)/.test(document.readyState)) {
1094
+ shiv(document, true);
1095
+ if (interval && document.body.prototype) clearTimeout(interval);
1096
+ return !!document.body.prototype;
1091
1097
  }
1092
- }
1093
1098
 
1094
- if (isArguments && object.length > 0) {
1095
- for (var j = 0; j < object.length; ++j) {
1096
- theKeys.push(String(j));
1097
- }
1098
- } else {
1099
- for (var name in object) {
1100
- if (!(skipProto && name === "prototype") && has.call(object, name)) {
1101
- theKeys.push(String(name));
1102
- }
1103
- }
1099
+ return false;
1104
1100
  }
1105
1101
 
1106
- if (hasDontEnumBug) {
1107
- var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object);
1102
+ if (!bodyCheck()) {
1103
+ document.onreadystatechange = bodyCheck;
1104
+ interval = setInterval(bodyCheck, 25);
1105
+ } // Apply to any new elements created after load
1108
1106
 
1109
- for (var k = 0; k < dontEnums.length; ++k) {
1110
- if (!(skipConstructor && dontEnums[k] === "constructor") && has.call(object, dontEnums[k])) {
1111
- theKeys.push(dontEnums[k]);
1112
- }
1113
- }
1114
- }
1115
1107
 
1116
- return theKeys;
1117
- };
1118
- }();
1119
- }).call("object" === (typeof window === "undefined" ? "undefined" : _typeof(window)) && window || "object" === (typeof self === "undefined" ? "undefined" : _typeof(self)) && self || "object" === (typeof global === "undefined" ? "undefined" : _typeof(global)) && global || {});
1108
+ document.createElement = function createElement(nodeName) {
1109
+ var element = nativeCreateElement(String(nodeName).toLowerCase());
1110
+ return shiv(element);
1111
+ }; // remove sandboxed iframe
1120
1112
 
1121
- (function (undefined) {
1122
- // Detection from https://github.com/Financial-Times/polyfill-library/blob/987630a085e29226da16b5dc542042c687560191/polyfills/Object/assign/detect.js
1123
- var detect = ('assign' in Object);
1124
- if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Object.assign&flags=always
1125
1113
 
1126
- (function () {
1127
- // 7.1.13 ToObject ( argument )
1128
- function toObject(argument) {
1129
- if (argument === null || argument === undefined) {
1130
- throw new TypeError('Cannot call method on ' + argument);
1114
+ document.removeChild(vbody);
1115
+ })();
1116
+ }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
1117
+ (function (undefined) {
1118
+ // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Object/defineProperty/detect.js
1119
+ var detect = // In IE8, defineProperty could only act on DOM elements, so full support
1120
+ // for the feature requires the ability to set a property on an arbitrary object
1121
+ 'defineProperty' in Object && function () {
1122
+ try {
1123
+ var a = {};
1124
+ Object.defineProperty(a, 'test', {
1125
+ value: 42
1126
+ });
1127
+ return true;
1128
+ } catch (e) {
1129
+ return false;
1131
1130
  }
1131
+ }();
1132
1132
 
1133
- return Object(argument);
1134
- }
1135
-
1136
- Object.defineProperty(Object, 'assign', {
1137
- enumerable: false,
1138
- configurable: true,
1139
- writable: true,
1140
- value: function assign(target, source) {
1141
- // eslint-disable-line no-unused-vars
1142
- // 1. Let to be ? ToObject(target).
1143
- var to = toObject(target); // 2. If only one argument was passed, return to.
1133
+ if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Object.defineProperty&flags=always
1144
1134
 
1145
- if (arguments.length === 1) {
1146
- return to;
1147
- } // 3. Let sources be the List of argument values starting with the second argument
1135
+ (function (nativeDefineProperty) {
1136
+ var supportsAccessors = Object.prototype.hasOwnProperty('__defineGetter__');
1137
+ var ERR_ACCESSORS_NOT_SUPPORTED = 'Getters & setters cannot be defined on this javascript engine';
1138
+ var ERR_VALUE_ACCESSORS = 'A property cannot both have accessors and be writable or have a value';
1148
1139
 
1140
+ Object.defineProperty = function defineProperty(object, property, descriptor) {
1141
+ // Where native support exists, assume it
1142
+ if (nativeDefineProperty && (object === window || object === document || object === Element.prototype || object instanceof Element)) {
1143
+ return nativeDefineProperty(object, property, descriptor);
1144
+ }
1149
1145
 
1150
- var sources = Array.prototype.slice.call(arguments, 1); // 4. For each element nextSource of sources, in ascending index order, do
1146
+ if (object === null || !(object instanceof Object || typeof object === 'object')) {
1147
+ throw new TypeError('Object.defineProperty called on non-object');
1148
+ }
1151
1149
 
1152
- var index1;
1153
- var index2;
1154
- var keys;
1155
- var from;
1150
+ if (!(descriptor instanceof Object)) {
1151
+ throw new TypeError('Property description must be an object');
1152
+ }
1156
1153
 
1157
- for (index1 = 0; index1 < sources.length; index1++) {
1158
- var nextSource = sources[index1]; // 4a. If nextSource is undefined or null, let keys be a new empty List.
1154
+ var propertyString = String(property);
1155
+ var hasValueOrWritable = 'value' in descriptor || 'writable' in descriptor;
1156
+ var getterType = 'get' in descriptor && typeof descriptor.get;
1157
+ var setterType = 'set' in descriptor && typeof descriptor.set; // handle descriptor.get
1159
1158
 
1160
- if (nextSource === undefined || nextSource === null) {
1161
- keys = []; // 4b. Else,
1162
- } else {
1163
- // 4bi. Let from be ! ToObject(nextSource).
1164
- from = toObject(nextSource); // 4bii. Let keys be ? from.[[OwnPropertyKeys]]().
1159
+ if (getterType) {
1160
+ if (getterType !== 'function') {
1161
+ throw new TypeError('Getter must be a function');
1162
+ }
1165
1163
 
1166
- /*
1167
- This step in our polyfill is not complying with the specification.
1168
- [[OwnPropertyKeys]] is meant to return ALL keys, including non-enumerable and symbols.
1169
- TODO: When we have Reflect.ownKeys, use that instead as it is the userland equivalent of [[OwnPropertyKeys]].
1170
- */
1164
+ if (!supportsAccessors) {
1165
+ throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
1166
+ }
1171
1167
 
1172
- keys = Object.keys(from);
1173
- } // 4c. For each element nextKey of keys in List order, do
1168
+ if (hasValueOrWritable) {
1169
+ throw new TypeError(ERR_VALUE_ACCESSORS);
1170
+ }
1174
1171
 
1172
+ Object.__defineGetter__.call(object, propertyString, descriptor.get);
1173
+ } else {
1174
+ object[propertyString] = descriptor.value;
1175
+ } // handle descriptor.set
1175
1176
 
1176
- for (index2 = 0; index2 < keys.length; index2++) {
1177
- var nextKey = keys[index2]; // 4ci. Let desc be ? from.[[GetOwnProperty]](nextKey).
1178
1177
 
1179
- var desc = Object.getOwnPropertyDescriptor(from, nextKey); // 4cii. If desc is not undefined and desc.[[Enumerable]] is true, then
1178
+ if (setterType) {
1179
+ if (setterType !== 'function') {
1180
+ throw new TypeError('Setter must be a function');
1181
+ }
1180
1182
 
1181
- if (desc !== undefined && desc.enumerable) {
1182
- // 4cii1. Let propValue be ? Get(from, nextKey).
1183
- var propValue = from[nextKey]; // 4cii2. Perform ? Set(to, nextKey, propValue, true).
1183
+ if (!supportsAccessors) {
1184
+ throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
1185
+ }
1184
1186
 
1185
- to[nextKey] = propValue;
1186
- }
1187
+ if (hasValueOrWritable) {
1188
+ throw new TypeError(ERR_VALUE_ACCESSORS);
1187
1189
  }
1188
- } // 5. Return to.
1189
1190
 
1191
+ Object.__defineSetter__.call(object, propertyString, descriptor.set);
1192
+ } // OK to define value unconditionally - if a getter has been specified as well, an error would be thrown above
1190
1193
 
1191
- return to;
1192
- }
1193
- });
1194
- })();
1195
- }).call('object' === (typeof window === "undefined" ? "undefined" : _typeof(window)) && window || 'object' === (typeof self === "undefined" ? "undefined" : _typeof(self)) && self || 'object' === (typeof global === "undefined" ? "undefined" : _typeof(global)) && global || {});
1196
1194
 
1197
- (function (undefined) {
1198
- // Detection from https://github.com/Financial-Times/polyfill-library/blob/987630a085e29226da16b5dc542042c687560191/polyfills/Date/now/detect.js
1199
- var detect = 'Date' in this && 'now' in this.Date && 'getTime' in this.Date.prototype;
1200
- if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Array.prototype.forEach&flags=always
1195
+ if ('value' in descriptor) {
1196
+ object[propertyString] = descriptor.value;
1197
+ }
1201
1198
 
1202
- Date.now = function now() {
1203
- return new Date().getTime();
1204
- };
1205
- }).call('object' === (typeof window === "undefined" ? "undefined" : _typeof(window)) && window || 'object' === (typeof self === "undefined" ? "undefined" : _typeof(self)) && self || 'object' === (typeof global === "undefined" ? "undefined" : _typeof(global)) && global || {});
1199
+ return object;
1200
+ };
1201
+ })(Object.defineProperty);
1202
+ }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
1203
+ (function (undefined) {
1204
+ // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Event/detect.js
1205
+ var detect = function (global) {
1206
+ if (!('Event' in global)) return false;
1207
+ if (typeof global.Event === 'function') return true;
1206
1208
 
1207
- /**
1208
- * TODO: Ideally this would be a NodeList.prototype.forEach polyfill
1209
- * This seems to fail in IE8, requires more investigation.
1210
- * See: https://github.com/imagitama/nodelist-foreach-polyfill
1211
- */
1212
- // eslint-disable-next-line consistent-return
1213
- function nodeListForEach(nodes, callback) {
1214
- if (window.NodeList.prototype.forEach) {
1215
- return nodes.forEach(callback);
1216
- }
1209
+ try {
1210
+ // In IE 9-11, the Event object exists but cannot be instantiated
1211
+ new Event('click');
1212
+ return true;
1213
+ } catch (e) {
1214
+ return false;
1215
+ }
1216
+ }(this);
1217
1217
 
1218
- for (var i = 0; i < nodes.length; i += 1) {
1219
- callback.call(window, nodes[i], i, nodes);
1220
- }
1221
- } // eslint-disable-next-line import/prefer-default-export
1218
+ if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Event&flags=always
1222
1219
 
1223
- /* global ActiveXObject */
1224
- var _console = console,
1225
- warn = _console.warn;
1226
- var utils = {
1227
- generateDomElementFromString: function generateDomElementFromString(str) {
1228
- var abc = document.createElement('div');
1229
- abc.innerHTML = str;
1230
- return abc.firstChild;
1231
- },
1232
- generateDomElementFromStringAndAppendText: function generateDomElementFromStringAndAppendText(str, text) {
1233
- var $tmp = utils.generateDomElementFromString(str);
1234
- $tmp.innerText = text;
1235
- return $tmp;
1236
- },
1237
- hasClass: function hasClass(selector, className) {
1238
- return document.querySelector(selector).classList.contains(className);
1239
- },
1240
- addClass: function addClass(selector, className) {
1241
- var elements = document.querySelectorAll(selector);
1242
- nodeListForEach(elements, function (i) {
1243
- i.classList.add(className);
1244
- });
1245
- },
1246
- removeClass: function removeClass(selector, className) {
1247
- var elements = document.querySelectorAll(selector);
1248
- nodeListForEach(elements, function (i) {
1249
- i.classList.remove(className);
1250
- });
1251
- },
1252
- removeElement: function removeElement($elem) {
1253
- var parent = $elem.parentNode;
1220
+ (function () {
1221
+ var unlistenableWindowEvents = {
1222
+ click: 1,
1223
+ dblclick: 1,
1224
+ keyup: 1,
1225
+ keypress: 1,
1226
+ keydown: 1,
1227
+ mousedown: 1,
1228
+ mouseup: 1,
1229
+ mousemove: 1,
1230
+ mouseover: 1,
1231
+ mouseenter: 1,
1232
+ mouseleave: 1,
1233
+ mouseout: 1,
1234
+ storage: 1,
1235
+ storagecommit: 1,
1236
+ textinput: 1
1237
+ }; // This polyfill depends on availability of `document` so will not run in a worker
1238
+ // However, we asssume there are no browsers with worker support that lack proper
1239
+ // support for `Event` within the worker
1254
1240
 
1255
- if (parent) {
1256
- parent.removeChild($elem);
1257
- } else {
1258
- warn("couldn't find parent for elem", $elem);
1259
- }
1260
- },
1261
- ajaxGet: function ajaxGet(url, success) {
1262
- var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
1263
- xhr.open('GET', url);
1241
+ if (typeof document === 'undefined' || typeof window === 'undefined') return;
1264
1242
 
1265
- xhr.onreadystatechange = function () {
1266
- if (xhr.readyState > 3 && xhr.status === 200) success(xhr.responseText);
1267
- };
1243
+ function indexOf(array, element) {
1244
+ var index = -1,
1245
+ length = array.length;
1268
1246
 
1269
- xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
1270
- xhr.send();
1271
- return xhr;
1272
- }
1273
- };
1247
+ while (++index < length) {
1248
+ if (index in array && array[index] === element) {
1249
+ return index;
1250
+ }
1251
+ }
1274
1252
 
1275
- function displayDialog($elementToDisplay) {
1276
- var $dialog = utils.generateDomElementFromString('<div id="hmrc-timeout-dialog" tabindex="-1" role="dialog" aria-modal="true" class="hmrc-timeout-dialog">');
1277
- var $overlay = utils.generateDomElementFromString('<div id="hmrc-timeout-overlay" class="hmrc-timeout-overlay">');
1278
- var $preparedElementToDisplay = typeof $elementToDisplay === 'string' ? utils.generateDomElementFromString($elementToDisplay) : $elementToDisplay;
1279
- var resetElementsFunctionList = [];
1280
- var closeCallbacks = [];
1281
- $dialog.appendChild($preparedElementToDisplay);
1253
+ return -1;
1254
+ }
1282
1255
 
1283
- if (!utils.hasClass('html', 'noScroll')) {
1284
- utils.addClass('html', 'noScroll');
1285
- resetElementsFunctionList.push(function () {
1286
- utils.removeClass('html', 'noScroll');
1287
- });
1288
- }
1256
+ var existingProto = window.Event && window.Event.prototype || null;
1289
1257
 
1290
- document.body.appendChild($dialog);
1291
- document.body.appendChild($overlay);
1292
- resetElementsFunctionList.push(function () {
1293
- utils.removeElement($dialog);
1294
- utils.removeElement($overlay);
1295
- });
1258
+ window.Event = Window.prototype.Event = function Event(type, eventInitDict) {
1259
+ if (!type) {
1260
+ throw new Error('Not enough arguments');
1261
+ }
1296
1262
 
1297
- var setupFocusHandlerAndFocusDialog = function setupFocusHandlerAndFocusDialog() {
1298
- function keepFocus(event) {
1299
- var modalFocus = document.getElementById('hmrc-timeout-dialog');
1263
+ var event; // Shortcut if browser supports createEvent
1300
1264
 
1301
- if (modalFocus) {
1302
- if (event.target !== modalFocus && !modalFocus.contains(event.target)) {
1303
- event.stopPropagation();
1304
- modalFocus.focus();
1265
+ if ('createEvent' in document) {
1266
+ event = document.createEvent('Event');
1267
+ var bubbles = eventInitDict && eventInitDict.bubbles !== undefined ? eventInitDict.bubbles : false;
1268
+ var cancelable = eventInitDict && eventInitDict.cancelable !== undefined ? eventInitDict.cancelable : false;
1269
+ event.initEvent(type, bubbles, cancelable);
1270
+ return event;
1305
1271
  }
1272
+
1273
+ event = document.createEventObject();
1274
+ event.type = type;
1275
+ event.bubbles = eventInitDict && eventInitDict.bubbles !== undefined ? eventInitDict.bubbles : false;
1276
+ event.cancelable = eventInitDict && eventInitDict.cancelable !== undefined ? eventInitDict.cancelable : false;
1277
+ return event;
1278
+ };
1279
+
1280
+ if (existingProto) {
1281
+ Object.defineProperty(window.Event, 'prototype', {
1282
+ configurable: false,
1283
+ enumerable: false,
1284
+ writable: true,
1285
+ value: existingProto
1286
+ });
1306
1287
  }
1307
- }
1308
1288
 
1309
- var elemToFocusOnReset = document.activeElement;
1310
- $dialog.focus();
1311
- document.addEventListener('focus', keepFocus, true);
1312
- resetElementsFunctionList.push(function () {
1313
- document.removeEventListener('focus', keepFocus);
1314
- elemToFocusOnReset.focus();
1315
- });
1316
- }; // disable the non-dialog page to prevent confusion for VoiceOver users
1289
+ if (!('createEvent' in document)) {
1290
+ window.addEventListener = Window.prototype.addEventListener = Document.prototype.addEventListener = Element.prototype.addEventListener = function addEventListener() {
1291
+ var element = this,
1292
+ type = arguments[0],
1293
+ listener = arguments[1];
1317
1294
 
1295
+ if (element === window && type in unlistenableWindowEvents) {
1296
+ 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.');
1297
+ }
1318
1298
 
1319
- var selectors = ['#skiplink-container', 'body > header', '#global-cookie-message', 'main[role=main]', 'body > footer', 'body > .govuk-skip-link', '.cbanner-govuk-cookie-banner', 'body > .govuk-width-container'];
1320
- var elements = document.querySelectorAll(selectors.join(', '));
1299
+ if (!element._events) {
1300
+ element._events = {};
1301
+ }
1321
1302
 
1322
- var close = function close() {
1323
- while (resetElementsFunctionList.length > 0) {
1324
- var fn = resetElementsFunctionList.shift();
1325
- fn();
1326
- }
1327
- };
1303
+ if (!element._events[type]) {
1304
+ element._events[type] = function (event) {
1305
+ var list = element._events[event.type].list,
1306
+ events = list.slice(),
1307
+ index = -1,
1308
+ length = events.length,
1309
+ eventElement;
1328
1310
 
1329
- var closeAndInform = function closeAndInform() {
1330
- closeCallbacks.forEach(function (fn) {
1331
- fn();
1332
- });
1333
- close();
1334
- };
1311
+ event.preventDefault = function preventDefault() {
1312
+ if (event.cancelable !== false) {
1313
+ event.returnValue = false;
1314
+ }
1315
+ };
1335
1316
 
1336
- var setupKeydownHandler = function setupKeydownHandler() {
1337
- function keydownListener(e) {
1338
- if (e.keyCode === 27) {
1339
- closeAndInform();
1340
- }
1341
- }
1317
+ event.stopPropagation = function stopPropagation() {
1318
+ event.cancelBubble = true;
1319
+ };
1342
1320
 
1343
- document.addEventListener('keydown', keydownListener);
1344
- resetElementsFunctionList.push(function () {
1345
- document.removeEventListener('keydown', keydownListener);
1346
- });
1347
- };
1321
+ event.stopImmediatePropagation = function stopImmediatePropagation() {
1322
+ event.cancelBubble = true;
1323
+ event.cancelImmediate = true;
1324
+ };
1348
1325
 
1349
- var preventMobileScrollWhileAllowingPinchZoom = function preventMobileScrollWhileAllowingPinchZoom() {
1350
- var handleTouch = function handleTouch(e) {
1351
- var touches = e.touches || e.changedTouches || [];
1326
+ event.currentTarget = element;
1327
+ event.relatedTarget = event.fromElement || null;
1328
+ event.target = event.target || event.srcElement || element;
1329
+ event.timeStamp = new Date().getTime();
1352
1330
 
1353
- if (touches.length === 1) {
1354
- e.preventDefault();
1355
- }
1356
- };
1331
+ if (event.clientX) {
1332
+ event.pageX = event.clientX + document.documentElement.scrollLeft;
1333
+ event.pageY = event.clientY + document.documentElement.scrollTop;
1334
+ }
1357
1335
 
1358
- document.addEventListener('touchmove', handleTouch, true);
1359
- resetElementsFunctionList.push(function () {
1360
- document.removeEventListener('touchmove', handleTouch, true);
1361
- });
1362
- };
1336
+ while (++index < length && !event.cancelImmediate) {
1337
+ if (index in events) {
1338
+ eventElement = events[index];
1363
1339
 
1364
- nodeListForEach(elements, function ($elem) {
1365
- var value = $elem.getAttribute('aria-hidden');
1366
- $elem.setAttribute('aria-hidden', 'true');
1367
- resetElementsFunctionList.push(function () {
1368
- if (value) {
1369
- $elem.setAttribute('aria-hidden', value);
1370
- } else {
1371
- $elem.removeAttribute('aria-hidden');
1372
- }
1373
- });
1374
- }); //
1340
+ if (indexOf(list, eventElement) !== -1 && typeof eventElement === 'function') {
1341
+ eventElement.call(element, event);
1342
+ }
1343
+ }
1344
+ }
1345
+ };
1375
1346
 
1376
- setupFocusHandlerAndFocusDialog();
1377
- setupKeydownHandler();
1378
- preventMobileScrollWhileAllowingPinchZoom();
1379
- return {
1380
- closeDialog: function closeDialog() {
1381
- close();
1382
- },
1383
- setAriaLabelledBy: function setAriaLabelledBy(value) {
1384
- if (value) {
1385
- $dialog.setAttribute('aria-labelledby', value);
1386
- } else {
1387
- $dialog.removeAttribute('aria-labelledby');
1388
- }
1389
- },
1390
- addCloseHandler: function addCloseHandler(closeHandler) {
1391
- closeCallbacks.push(closeHandler);
1392
- }
1393
- };
1394
- }
1347
+ element._events[type].list = [];
1395
1348
 
1396
- var dialog = {
1397
- displayDialog: displayDialog
1398
- };
1349
+ if (element.attachEvent) {
1350
+ element.attachEvent('on' + type, element._events[type]);
1351
+ }
1352
+ }
1399
1353
 
1400
- // Polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN
1401
- Number.isNaN = Number.isNaN || function isNaN(input) {
1402
- return typeof input === 'number' && input !== input;
1403
- };
1354
+ element._events[type].list.push(listener);
1355
+ };
1404
1356
 
1405
- function ValidateInput() {}
1357
+ window.removeEventListener = Window.prototype.removeEventListener = Document.prototype.removeEventListener = Element.prototype.removeEventListener = function removeEventListener() {
1358
+ var element = this,
1359
+ type = arguments[0],
1360
+ listener = arguments[1],
1361
+ index;
1406
1362
 
1407
- ValidateInput["int"] = function (stringToValidate) {
1408
- var parsedInt = parseInt(stringToValidate, 10);
1409
- return Number.isNaN(parsedInt) ? undefined : parsedInt;
1410
- };
1363
+ if (element._events && element._events[type] && element._events[type].list) {
1364
+ index = indexOf(element._events[type].list, listener);
1411
1365
 
1412
- ValidateInput.string = function (stringToValidate) {
1413
- return typeof stringToValidate === 'string' ? stringToValidate : undefined;
1414
- };
1366
+ if (index !== -1) {
1367
+ element._events[type].list.splice(index, 1);
1415
1368
 
1416
- ValidateInput["boolean"] = function (stringToValidate) {
1417
- return String(stringToValidate).toLowerCase() === 'true';
1418
- };
1369
+ if (!element._events[type].list.length) {
1370
+ if (element.detachEvent) {
1371
+ element.detachEvent('on' + type, element._events[type]);
1372
+ }
1419
1373
 
1420
- function RedirectHelper() {}
1374
+ delete element._events[type];
1375
+ }
1376
+ }
1377
+ }
1378
+ };
1421
1379
 
1422
- RedirectHelper.redirectToUrl = function (url) {
1423
- // This exists to make redirects more testable
1424
- window.location.href = url;
1425
- };
1380
+ window.dispatchEvent = Window.prototype.dispatchEvent = Document.prototype.dispatchEvent = Element.prototype.dispatchEvent = function dispatchEvent(event) {
1381
+ if (!arguments.length) {
1382
+ throw new Error('Not enough arguments');
1383
+ }
1426
1384
 
1427
- function TimeoutDialog($module, $sessionActivityService) {
1428
- var options = {};
1429
- var settings = {};
1430
- var cleanupFunctions = [];
1431
- var currentTimer;
1432
- var sessionActivityService = $sessionActivityService;
1433
- cleanupFunctions.push(function () {
1434
- if (currentTimer) {
1435
- window.clearTimeout(currentTimer);
1436
- }
1437
- });
1385
+ if (!event || typeof event.type !== 'string') {
1386
+ throw new Error('DOM Events Exception 0');
1387
+ }
1438
1388
 
1439
- function init() {
1440
- var validate = ValidateInput;
1389
+ var element = this,
1390
+ type = event.type;
1441
1391
 
1442
- function lookupData(key) {
1443
- return ($module.attributes.getNamedItem(key) || {}).value;
1444
- }
1392
+ try {
1393
+ if (!event.bubbles) {
1394
+ event.cancelBubble = true;
1445
1395
 
1446
- var localisedDefaults = validate.string(lookupData('data-language')) === 'cy' ? {
1447
- title: 'Rydych ar fin cael eich allgofnodi',
1448
- message: 'Er eich diogelwch, byddwn yn eich allgofnodi cyn pen',
1449
- keepAliveButtonText: 'Parhau i fod wedi’ch mewngofnodi',
1450
- signOutButtonText: 'Allgofnodi',
1451
- properties: {
1452
- minutes: 'funud',
1453
- minute: 'funud',
1454
- seconds: 'eiliad',
1455
- second: 'eiliad'
1456
- }
1457
- } : {
1458
- title: 'You’re about to be signed out',
1459
- message: 'For your security, we will sign you out in',
1460
- keepAliveButtonText: 'Stay signed in',
1461
- signOutButtonText: 'Sign out',
1462
- properties: {
1463
- minutes: 'minutes',
1464
- minute: 'minute',
1465
- seconds: 'seconds',
1466
- second: 'second'
1467
- }
1468
- };
1469
- options = {
1470
- timeout: validate["int"](lookupData('data-timeout')),
1471
- countdown: validate["int"](lookupData('data-countdown')),
1472
- keepAliveUrl: validate.string(lookupData('data-keep-alive-url')),
1473
- signOutUrl: validate.string(lookupData('data-sign-out-url')),
1474
- timeoutUrl: validate.string(lookupData('data-timeout-url')),
1475
- title: validate.string(lookupData('data-title')),
1476
- message: validate.string(lookupData('data-message')),
1477
- messageSuffix: validate.string(lookupData('data-message-suffix')),
1478
- keepAliveButtonText: validate.string(lookupData('data-keep-alive-button-text')),
1479
- signOutButtonText: validate.string(lookupData('data-sign-out-button-text')),
1480
- synchroniseTabs: validate["boolean"](lookupData('data-synchronise-tabs') || false)
1481
- }; // Default timeoutUrl to signOutUrl if not set
1396
+ var cancelBubbleEvent = function (event) {
1397
+ event.cancelBubble = true;
1398
+ (element || window).detachEvent('on' + type, cancelBubbleEvent);
1399
+ };
1482
1400
 
1483
- options.timeoutUrl = options.timeoutUrl || options.signOutUrl;
1484
- validateInput(options);
1485
- settings = mergeOptionsWithDefaults(options, localisedDefaults);
1486
- setupDialogTimer();
1487
- listenForSessionActivityAndResetDialogTimer();
1488
- }
1401
+ this.attachEvent('on' + type, cancelBubbleEvent);
1402
+ }
1489
1403
 
1490
- var broadcastSessionActivity = function broadcastSessionActivity() {
1491
- sessionActivityService.logActivity();
1492
- };
1404
+ this.fireEvent('on' + type, event);
1405
+ } catch (error) {
1406
+ event.target = element;
1493
1407
 
1494
- var listenForSessionActivityAndResetDialogTimer = function listenForSessionActivityAndResetDialogTimer() {
1495
- if (settings.synchroniseTabs) {
1496
- sessionActivityService.onActivity(function (event) {
1497
- var timeOfActivity = event.timestamp;
1498
- cleanup();
1499
- setupDialogTimer(timeOfActivity);
1500
- });
1501
- }
1502
- };
1408
+ do {
1409
+ event.currentTarget = element;
1503
1410
 
1504
- var validateInput = function validateInput(config) {
1505
- var requiredConfig = ['timeout', 'countdown', 'keepAliveUrl', 'signOutUrl'];
1506
- var missingRequiredConfig = [];
1507
- requiredConfig.forEach(function (item) {
1508
- if (!config[item]) {
1509
- missingRequiredConfig.push("data-".concat(item.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()));
1510
- }
1511
- });
1411
+ if ('_events' in element && typeof element._events[type] === 'function') {
1412
+ element._events[type].call(element, event);
1413
+ }
1512
1414
 
1513
- if (missingRequiredConfig.length > 0) {
1514
- throw new Error("Missing config item(s): [".concat(missingRequiredConfig.join(', '), "]"));
1515
- }
1516
- };
1415
+ if (typeof element['on' + type] === 'function') {
1416
+ element['on' + type].call(element, event);
1417
+ }
1517
1418
 
1518
- var mergeOptionsWithDefaults = function mergeOptionsWithDefaults(theOptions, localisedDefaults) {
1519
- var clone = _objectSpread2({}, theOptions);
1419
+ element = element.nodeType === 9 ? element.parentWindow : element.parentNode;
1420
+ } while (element && !event.cancelBubble);
1421
+ }
1520
1422
 
1521
- Object.keys(localisedDefaults).forEach(function (key) {
1522
- if (_typeof(clone[key]) === 'object') {
1523
- clone[key] = mergeOptionsWithDefaults(theOptions[key], localisedDefaults[key]);
1524
- }
1423
+ return true;
1424
+ }; // Add the DOMContentLoaded Event
1525
1425
 
1526
- if (clone[key] === undefined || clone[key] === '') {
1527
- clone[key] = localisedDefaults[key];
1426
+
1427
+ document.attachEvent('onreadystatechange', function () {
1428
+ if (document.readyState === 'complete') {
1429
+ document.dispatchEvent(new Event('DOMContentLoaded', {
1430
+ bubbles: true
1431
+ }));
1432
+ }
1433
+ });
1528
1434
  }
1529
- });
1530
- return clone;
1531
- };
1435
+ })();
1436
+ }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
1437
+ });
1438
+ });
1532
1439
 
1533
- var setupDialogTimer = function setupDialogTimer() {
1534
- var timeOfLastActivity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getDateNow();
1535
- var signoutTime = timeOfLastActivity + settings.timeout * 1000;
1536
- var delta = getDateNow() - timeOfLastActivity;
1537
- var secondsUntilTimeoutDialog = settings.timeout - settings.countdown;
1538
- var timeout = window.setTimeout(function () {
1539
- setupDialog(signoutTime);
1540
- }, secondsUntilTimeoutDialog * 1000 - delta);
1541
- cleanupFunctions.push(function () {
1542
- window.clearTimeout(timeout);
1543
- });
1544
- };
1440
+ var classList = createCommonjsModule(function (module, exports) {
1441
+ (function (global, factory) {
1442
+ factory();
1443
+ })(commonjsGlobal, function () {
1545
1444
 
1546
- var wrapLink = function wrapLink($elem) {
1547
- var $wrapper = document.createElement('div');
1548
- $wrapper.classList.add('hmrc-timeout-dialog__link-wrapper');
1549
- $wrapper.appendChild($elem);
1550
- return $wrapper;
1551
- };
1445
+ (function (undefined) {
1446
+ // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Object/defineProperty/detect.js
1447
+ var detect = // In IE8, defineProperty could only act on DOM elements, so full support
1448
+ // for the feature requires the ability to set a property on an arbitrary object
1449
+ 'defineProperty' in Object && function () {
1450
+ try {
1451
+ var a = {};
1452
+ Object.defineProperty(a, 'test', {
1453
+ value: 42
1454
+ });
1455
+ return true;
1456
+ } catch (e) {
1457
+ return false;
1458
+ }
1459
+ }();
1552
1460
 
1553
- var setupDialog = function setupDialog(signoutTime) {
1554
- var $element = utils.generateDomElementFromString('<div>');
1461
+ if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Object.defineProperty&flags=always
1555
1462
 
1556
- if (settings.title) {
1557
- var $tmp = utils.generateDomElementFromStringAndAppendText('<h1 id="hmrc-timeout-heading" class="govuk-heading-m push--top">', settings.title);
1558
- $element.appendChild($tmp);
1559
- }
1463
+ (function (nativeDefineProperty) {
1464
+ var supportsAccessors = Object.prototype.hasOwnProperty('__defineGetter__');
1465
+ var ERR_ACCESSORS_NOT_SUPPORTED = 'Getters & setters cannot be defined on this javascript engine';
1466
+ var ERR_VALUE_ACCESSORS = 'A property cannot both have accessors and be writable or have a value';
1560
1467
 
1561
- var $countdownElement = utils.generateDomElementFromString('<span id="hmrc-timeout-countdown" class="hmrc-timeout-dialog__countdown">');
1562
- var $audibleMessage = utils.generateDomElementFromString('<p id="hmrc-timeout-message" class="govuk-visually-hidden screenreader-content" aria-live="assertive">');
1563
- var $visualMessge = utils.generateDomElementFromStringAndAppendText('<p class="govuk-body hmrc-timeout-dialog__message" aria-hidden="true">', settings.message);
1564
- $visualMessge.appendChild(document.createTextNode(' '));
1565
- $visualMessge.appendChild($countdownElement);
1566
- $visualMessge.appendChild(document.createTextNode('.'));
1468
+ Object.defineProperty = function defineProperty(object, property, descriptor) {
1469
+ // Where native support exists, assume it
1470
+ if (nativeDefineProperty && (object === window || object === document || object === Element.prototype || object instanceof Element)) {
1471
+ return nativeDefineProperty(object, property, descriptor);
1472
+ }
1567
1473
 
1568
- if (settings.messageSuffix) {
1569
- $visualMessge.appendChild(document.createTextNode(" ".concat(settings.messageSuffix)));
1570
- }
1474
+ if (object === null || !(object instanceof Object || typeof object === 'object')) {
1475
+ throw new TypeError('Object.defineProperty called on non-object');
1476
+ }
1571
1477
 
1572
- var $staySignedInButton = utils.generateDomElementFromStringAndAppendText('<button id="hmrc-timeout-keep-signin-btn" class="govuk-button">', settings.keepAliveButtonText);
1573
- var $signOutButton = utils.generateDomElementFromStringAndAppendText('<a id="hmrc-timeout-sign-out-link" class="govuk-link hmrc-timeout-dialog__link">', settings.signOutButtonText);
1574
- $staySignedInButton.addEventListener('click', keepAliveAndClose);
1575
- $signOutButton.addEventListener('click', signOut);
1576
- $signOutButton.setAttribute('href', settings.signOutUrl);
1577
- $element.appendChild($visualMessge);
1578
- $element.appendChild($audibleMessage);
1579
- $element.appendChild($staySignedInButton);
1580
- $element.appendChild(document.createTextNode(' '));
1581
- $element.appendChild(wrapLink($signOutButton));
1582
- var dialogControl = dialog.displayDialog($element);
1583
- cleanupFunctions.push(function () {
1584
- dialogControl.closeDialog();
1585
- });
1586
- dialogControl.addCloseHandler(keepAliveAndClose);
1587
- dialogControl.setAriaLabelledBy('hmrc-timeout-heading hmrc-timeout-message');
1478
+ if (!(descriptor instanceof Object)) {
1479
+ throw new TypeError('Property description must be an object');
1480
+ }
1588
1481
 
1589
- var getMillisecondsRemaining = function getMillisecondsRemaining() {
1590
- return signoutTime - getDateNow();
1591
- };
1482
+ var propertyString = String(property);
1483
+ var hasValueOrWritable = 'value' in descriptor || 'writable' in descriptor;
1484
+ var getterType = 'get' in descriptor && typeof descriptor.get;
1485
+ var setterType = 'set' in descriptor && typeof descriptor.set; // handle descriptor.get
1592
1486
 
1593
- var getSecondsRemaining = function getSecondsRemaining() {
1594
- return Math.round(getMillisecondsRemaining() / 1000);
1595
- };
1487
+ if (getterType) {
1488
+ if (getterType !== 'function') {
1489
+ throw new TypeError('Getter must be a function');
1490
+ }
1596
1491
 
1597
- var getHumanText = function getHumanText(counter) {
1598
- var minutes;
1599
- var visibleMessage;
1492
+ if (!supportsAccessors) {
1493
+ throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
1494
+ }
1600
1495
 
1601
- if (counter < 60) {
1602
- visibleMessage = "".concat(counter, " ").concat(settings.properties[counter !== 1 ? 'seconds' : 'second']);
1603
- } else {
1604
- minutes = Math.ceil(counter / 60);
1605
- visibleMessage = "".concat(minutes, " ").concat(settings.properties[minutes === 1 ? 'minute' : 'minutes']);
1606
- }
1496
+ if (hasValueOrWritable) {
1497
+ throw new TypeError(ERR_VALUE_ACCESSORS);
1498
+ }
1607
1499
 
1608
- return visibleMessage;
1609
- };
1500
+ Object.__defineGetter__.call(object, propertyString, descriptor.get);
1501
+ } else {
1502
+ object[propertyString] = descriptor.value;
1503
+ } // handle descriptor.set
1610
1504
 
1611
- var getAudibleHumanText = function getAudibleHumanText(counter) {
1612
- var humanText = getHumanText(roundSecondsUp(counter));
1613
- var messageParts = [settings.message, ' ', humanText, '.'];
1614
1505
 
1615
- if (settings.messageSuffix) {
1616
- messageParts.push(' ');
1617
- messageParts.push(settings.messageSuffix);
1618
- }
1506
+ if (setterType) {
1507
+ if (setterType !== 'function') {
1508
+ throw new TypeError('Setter must be a function');
1509
+ }
1619
1510
 
1620
- return messageParts.join('');
1621
- };
1511
+ if (!supportsAccessors) {
1512
+ throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
1513
+ }
1622
1514
 
1623
- var roundSecondsUp = function roundSecondsUp(counter) {
1624
- if (counter > 60) {
1625
- return counter;
1626
- }
1515
+ if (hasValueOrWritable) {
1516
+ throw new TypeError(ERR_VALUE_ACCESSORS);
1517
+ }
1627
1518
 
1628
- if (counter < 20) {
1629
- return 20;
1630
- }
1519
+ Object.__defineSetter__.call(object, propertyString, descriptor.set);
1520
+ } // OK to define value unconditionally - if a getter has been specified as well, an error would be thrown above
1631
1521
 
1632
- return Math.ceil(counter / 20) * 20;
1633
- };
1634
1522
 
1635
- var updateTextIfChanged = function updateTextIfChanged($elem, text) {
1636
- if ($elem.innerText !== text) {
1637
- // eslint-disable-next-line no-param-reassign
1638
- $elem.innerText = text;
1639
- }
1640
- };
1523
+ if ('value' in descriptor) {
1524
+ object[propertyString] = descriptor.value;
1525
+ }
1641
1526
 
1642
- var updateCountdown = function updateCountdown(counter) {
1643
- var visibleMessage = getHumanText(counter);
1644
- var audibleHumanText = getAudibleHumanText(counter);
1645
- updateTextIfChanged($countdownElement, visibleMessage);
1646
- updateTextIfChanged($audibleMessage, audibleHumanText);
1647
- };
1527
+ return object;
1528
+ };
1529
+ })(Object.defineProperty);
1530
+ }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
1531
+ (function (undefined) {
1532
+ // Detection from https://raw.githubusercontent.com/Financial-Times/polyfill-service/master/packages/polyfill-library/polyfills/DOMTokenList/detect.js
1533
+ var detect = 'DOMTokenList' in this && function (x) {
1534
+ return 'classList' in x ? !x.classList.toggle('x', false) && !x.className : true;
1535
+ }(document.createElement('x'));
1648
1536
 
1649
- var getNextTimeout = function getNextTimeout() {
1650
- var remaining = getMillisecondsRemaining();
1651
- var roundedRemaining = Math.floor(getMillisecondsRemaining() / 1000) * 1000;
1537
+ if (detect) return; // Polyfill from https://raw.githubusercontent.com/Financial-Times/polyfill-service/master/packages/polyfill-library/polyfills/DOMTokenList/polyfill.js
1652
1538
 
1653
- if (roundedRemaining <= 60000) {
1654
- return remaining - roundedRemaining || 1000;
1655
- }
1539
+ (function (global) {
1540
+ var nativeImpl = "DOMTokenList" in global && global.DOMTokenList;
1656
1541
 
1657
- return remaining - (roundedRemaining - (roundedRemaining % 60000 || 60000));
1658
- };
1542
+ if (!nativeImpl || !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg') && !(document.createElementNS("http://www.w3.org/2000/svg", "svg").classList instanceof DOMTokenList)) {
1543
+ global.DOMTokenList = function () {
1544
+ // eslint-disable-line no-unused-vars
1545
+ var dpSupport = true;
1659
1546
 
1660
- var runUpdate = function runUpdate() {
1661
- var counter = getSecondsRemaining();
1662
- updateCountdown(counter);
1547
+ var defineGetter = function (object, name, fn, configurable) {
1548
+ if (Object.defineProperty) Object.defineProperty(object, name, {
1549
+ configurable: false === dpSupport ? true : !!configurable,
1550
+ get: fn
1551
+ });else object.__defineGetter__(name, fn);
1552
+ };
1553
+ /** Ensure the browser allows Object.defineProperty to be used on native JavaScript objects. */
1663
1554
 
1664
- if (counter <= 0) {
1665
- timeout();
1666
- }
1667
1555
 
1668
- currentTimer = window.setTimeout(runUpdate, getNextTimeout());
1669
- };
1556
+ try {
1557
+ defineGetter({}, "support");
1558
+ } catch (e) {
1559
+ dpSupport = false;
1560
+ }
1670
1561
 
1671
- runUpdate();
1672
- };
1562
+ var _DOMTokenList = function (el, prop) {
1563
+ var that = this;
1564
+ var tokens = [];
1565
+ var tokenMap = {};
1566
+ var length = 0;
1567
+ var maxLength = 0;
1673
1568
 
1674
- var keepAliveAndClose = function keepAliveAndClose() {
1675
- cleanup();
1676
- setupDialogTimer();
1677
- utils.ajaxGet(settings.keepAliveUrl, function () {});
1678
- broadcastSessionActivity();
1679
- };
1569
+ var addIndexGetter = function (i) {
1570
+ defineGetter(that, i, function () {
1571
+ preop();
1572
+ return tokens[i];
1573
+ }, false);
1574
+ };
1680
1575
 
1681
- var getDateNow = function getDateNow() {
1682
- return Date.now();
1683
- };
1576
+ var reindex = function () {
1577
+ /** Define getter functions for array-like access to the tokenList's contents. */
1578
+ if (length >= maxLength) for (; maxLength < length; ++maxLength) {
1579
+ addIndexGetter(maxLength);
1580
+ }
1581
+ };
1582
+ /** Helper function called at the start of each class method. Internal use only. */
1684
1583
 
1685
- var signOut = function signOut() {
1686
- RedirectHelper.redirectToUrl(settings.signOutUrl);
1687
- };
1688
1584
 
1689
- var timeout = function timeout() {
1690
- RedirectHelper.redirectToUrl(settings.timeoutUrl);
1691
- };
1585
+ var preop = function () {
1586
+ var error;
1587
+ var i;
1588
+ var args = arguments;
1589
+ var rSpace = /\s+/;
1590
+ /** Validate the token/s passed to an instance method, if any. */
1692
1591
 
1693
- var cleanup = function cleanup() {
1694
- while (cleanupFunctions.length > 0) {
1695
- var fn = cleanupFunctions.shift();
1696
- fn();
1697
- }
1698
- };
1592
+ if (args.length) for (i = 0; i < args.length; ++i) if (rSpace.test(args[i])) {
1593
+ error = new SyntaxError('String "' + args[i] + '" ' + "contains" + ' an invalid character');
1594
+ error.code = 5;
1595
+ error.name = "InvalidCharacterError";
1596
+ throw error;
1597
+ }
1598
+ /** Split the new value apart by whitespace*/
1699
1599
 
1700
- return {
1701
- init: init,
1702
- cleanup: cleanup
1703
- };
1704
- }
1600
+ if (typeof el[prop] === "object") {
1601
+ tokens = ("" + el[prop].baseVal).replace(/^\s+|\s+$/g, "").split(rSpace);
1602
+ } else {
1603
+ tokens = ("" + el[prop]).replace(/^\s+|\s+$/g, "").split(rSpace);
1604
+ }
1605
+ /** Avoid treating blank strings as single-item token lists */
1705
1606
 
1706
- TimeoutDialog.dialog = dialog;
1707
- TimeoutDialog.redirectHelper = RedirectHelper;
1708
- TimeoutDialog.utils = utils;
1709
1607
 
1710
- // Based on https://github.com/alphagov/govuk_template_jinja
1711
- var setCookie = function setCookie(name, value) {
1712
- var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
1713
- var cookieString = "".concat(name, "=").concat(value, "; path=/");
1608
+ if ("" === tokens[0]) tokens = [];
1609
+ /** Repopulate the internal token lists */
1714
1610
 
1715
- if (options.days) {
1716
- var date = new Date();
1717
- date.setTime(date.getTime() + options.days * 24 * 60 * 60 * 1000);
1718
- cookieString = "".concat(cookieString, "; expires=").concat(date.toGMTString());
1719
- }
1611
+ tokenMap = {};
1720
1612
 
1721
- if (window.location.protocol === 'https:') {
1722
- cookieString += '; Secure';
1723
- }
1613
+ for (i = 0; i < tokens.length; ++i) tokenMap[tokens[i]] = true;
1724
1614
 
1725
- document.cookie = cookieString;
1726
- return cookieString;
1727
- };
1728
- var getCookie = function getCookie(name) {
1729
- var nameEQ = "".concat(name, "=");
1730
- var cookies = document.cookie.split(';');
1615
+ length = tokens.length;
1616
+ reindex();
1617
+ };
1618
+ /** Populate our internal token list if the targeted attribute of the subject element isn't empty. */
1731
1619
 
1732
- for (var i = 0, len = cookies.length; i < len; i += 1) {
1733
- var cookie = cookies[i];
1734
1620
 
1735
- while (cookie.charAt(0) === ' ') {
1736
- cookie = cookie.substring(1, cookie.length);
1737
- }
1621
+ preop();
1622
+ /** Return the number of tokens in the underlying string. Read-only. */
1738
1623
 
1739
- if (cookie.indexOf(nameEQ) === 0) {
1740
- return decodeURIComponent(cookie.substring(nameEQ.length));
1741
- }
1742
- }
1624
+ defineGetter(that, "length", function () {
1625
+ preop();
1626
+ return length;
1627
+ });
1628
+ /** Override the default toString/toLocaleString methods to return a space-delimited list of tokens when typecast. */
1743
1629
 
1744
- return null;
1745
- };
1630
+ that.toLocaleString = that.toString = function () {
1631
+ preop();
1632
+ return tokens.join(" ");
1633
+ };
1746
1634
 
1747
- function UserResearchBanner($module) {
1748
- this.$module = $module;
1749
- this.$closeLink = this.$module.querySelector('.hmrc-user-research-banner__close');
1750
- this.cookieName = 'mdtpurr';
1751
- this.cookieExpiryDays = 28;
1752
- }
1635
+ that.item = function (idx) {
1636
+ preop();
1637
+ return tokens[idx];
1638
+ };
1753
1639
 
1754
- UserResearchBanner.prototype.init = function init() {
1755
- var cookieData = getCookie(this.cookieName);
1640
+ that.contains = function (token) {
1641
+ preop();
1642
+ return !!tokenMap[token];
1643
+ };
1756
1644
 
1757
- if (cookieData == null) {
1758
- this.$module.classList.add('hmrc-user-research-banner--show');
1759
- this.$closeLink.addEventListener('click', this.eventHandlers.noThanksClick.bind(this));
1760
- }
1761
- };
1645
+ that.add = function () {
1646
+ preop.apply(that, args = arguments);
1762
1647
 
1763
- UserResearchBanner.prototype.eventHandlers = {
1764
- noThanksClick: function noThanksClick(event) {
1765
- event.preventDefault();
1766
- setCookie(this.cookieName, 'suppress_for_all_services', {
1767
- days: this.cookieExpiryDays
1768
- });
1769
- this.$module.classList.remove('hmrc-user-research-banner--show');
1770
- }
1771
- };
1648
+ for (var args, token, i = 0, l = args.length; i < l; ++i) {
1649
+ token = args[i];
1772
1650
 
1773
- var Event_1 = createCommonjsModule(function (module, exports) {
1774
- (function (global, factory) {
1775
- factory();
1776
- })(commonjsGlobal, function () {
1651
+ if (!tokenMap[token]) {
1652
+ tokens.push(token);
1653
+ tokenMap[token] = true;
1654
+ }
1655
+ }
1656
+ /** Update the targeted attribute of the attached element if the token list's changed. */
1777
1657
 
1778
- (function (undefined) {
1779
- // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Window/detect.js
1780
- var detect = ('Window' in this);
1781
- if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Window&flags=always
1782
1658
 
1783
- if (typeof WorkerGlobalScope === "undefined" && typeof importScripts !== "function") {
1784
- (function (global) {
1785
- if (global.constructor) {
1786
- global.Window = global.constructor;
1787
- } else {
1788
- (global.Window = global.constructor = new Function('return function Window() {}')()).prototype = this;
1789
- }
1790
- })(this);
1791
- }
1792
- }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
1793
- (function (undefined) {
1794
- // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Document/detect.js
1795
- var detect = ("Document" in this);
1796
- if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Document&flags=always
1659
+ if (length !== tokens.length) {
1660
+ length = tokens.length >>> 0;
1797
1661
 
1798
- if (typeof WorkerGlobalScope === "undefined" && typeof importScripts !== "function") {
1799
- if (this.HTMLDocument) {
1800
- // IE8
1801
- // HTMLDocument is an extension of Document. If the browser has HTMLDocument but not Document, the former will suffice as an alias for the latter.
1802
- this.Document = this.HTMLDocument;
1803
- } else {
1804
- // 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.
1805
- this.Document = this.HTMLDocument = document.constructor = new Function('return function Document() {}')();
1806
- this.Document.prototype = document;
1807
- }
1808
- }
1809
- }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
1810
- (function (undefined) {
1811
- // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Element/detect.js
1812
- var detect = 'Element' in this && 'HTMLElement' in this;
1813
- if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Element&flags=always
1662
+ if (typeof el[prop] === "object") {
1663
+ el[prop].baseVal = tokens.join(" ");
1664
+ } else {
1665
+ el[prop] = tokens.join(" ");
1666
+ }
1814
1667
 
1815
- (function () {
1816
- // IE8
1817
- if (window.Element && !window.HTMLElement) {
1818
- window.HTMLElement = window.Element;
1819
- return;
1668
+ reindex();
1669
+ }
1670
+ };
1671
+
1672
+ that.remove = function () {
1673
+ preop.apply(that, args = arguments);
1674
+ /** Build a hash of token names to compare against when recollecting our token list. */
1675
+
1676
+ for (var args, ignore = {}, i = 0, t = []; i < args.length; ++i) {
1677
+ ignore[args[i]] = true;
1678
+ delete tokenMap[args[i]];
1679
+ }
1680
+ /** Run through our tokens list and reassign only those that aren't defined in the hash declared above. */
1681
+
1682
+
1683
+ for (i = 0; i < tokens.length; ++i) if (!ignore[tokens[i]]) t.push(tokens[i]);
1684
+
1685
+ tokens = t;
1686
+ length = t.length >>> 0;
1687
+ /** Update the targeted attribute of the attached element. */
1688
+
1689
+ if (typeof el[prop] === "object") {
1690
+ el[prop].baseVal = tokens.join(" ");
1691
+ } else {
1692
+ el[prop] = tokens.join(" ");
1693
+ }
1694
+
1695
+ reindex();
1696
+ };
1697
+
1698
+ that.toggle = function (token, force) {
1699
+ preop.apply(that, [token]);
1700
+ /** Token state's being forced. */
1701
+
1702
+ if (undefined !== force) {
1703
+ if (force) {
1704
+ that.add(token);
1705
+ return true;
1706
+ } else {
1707
+ that.remove(token);
1708
+ return false;
1709
+ }
1710
+ }
1711
+ /** Token already exists in tokenList. Remove it, and return FALSE. */
1712
+
1713
+
1714
+ if (tokenMap[token]) {
1715
+ that.remove(token);
1716
+ return false;
1717
+ }
1718
+ /** Otherwise, add the token and return TRUE. */
1719
+
1720
+
1721
+ that.add(token);
1722
+ return true;
1723
+ };
1724
+
1725
+ return that;
1726
+ };
1727
+
1728
+ return _DOMTokenList;
1729
+ }();
1730
+ } // Add second argument to native DOMTokenList.toggle() if necessary
1731
+
1732
+
1733
+ (function () {
1734
+ var e = document.createElement('span');
1735
+ if (!('classList' in e)) return;
1736
+ e.classList.toggle('x', false);
1737
+ if (!e.classList.contains('x')) return;
1738
+
1739
+ e.classList.constructor.prototype.toggle = function toggle(token
1740
+ /*, force*/
1741
+ ) {
1742
+ var force = arguments[1];
1743
+
1744
+ if (force === undefined) {
1745
+ var add = !this.contains(token);
1746
+ this[add ? 'add' : 'remove'](token);
1747
+ return add;
1748
+ }
1749
+
1750
+ force = !!force;
1751
+ this[force ? 'add' : 'remove'](token);
1752
+ return force;
1753
+ };
1754
+ })(); // Add multiple arguments to native DOMTokenList.add() if necessary
1755
+
1756
+
1757
+ (function () {
1758
+ var e = document.createElement('span');
1759
+ if (!('classList' in e)) return;
1760
+ e.classList.add('a', 'b');
1761
+ if (e.classList.contains('b')) return;
1762
+ var native = e.classList.constructor.prototype.add;
1763
+
1764
+ e.classList.constructor.prototype.add = function () {
1765
+ var args = arguments;
1766
+ var l = arguments.length;
1767
+
1768
+ for (var i = 0; i < l; i++) {
1769
+ native.call(this, args[i]);
1770
+ }
1771
+ };
1772
+ })(); // Add multiple arguments to native DOMTokenList.remove() if necessary
1773
+
1774
+
1775
+ (function () {
1776
+ var e = document.createElement('span');
1777
+ if (!('classList' in e)) return;
1778
+ e.classList.add('a');
1779
+ e.classList.add('b');
1780
+ e.classList.remove('a', 'b');
1781
+ if (!e.classList.contains('b')) return;
1782
+ var native = e.classList.constructor.prototype.remove;
1783
+
1784
+ e.classList.constructor.prototype.remove = function () {
1785
+ var args = arguments;
1786
+ var l = arguments.length;
1787
+
1788
+ for (var i = 0; i < l; i++) {
1789
+ native.call(this, args[i]);
1790
+ }
1791
+ };
1792
+ })();
1793
+ })(this);
1794
+ }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
1795
+ (function (undefined) {
1796
+ // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Document/detect.js
1797
+ var detect = ("Document" in this);
1798
+ if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Document&flags=always
1799
+
1800
+ if (typeof WorkerGlobalScope === "undefined" && typeof importScripts !== "function") {
1801
+ if (this.HTMLDocument) {
1802
+ // IE8
1803
+ // HTMLDocument is an extension of Document. If the browser has HTMLDocument but not Document, the former will suffice as an alias for the latter.
1804
+ this.Document = this.HTMLDocument;
1805
+ } else {
1806
+ // 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.
1807
+ this.Document = this.HTMLDocument = document.constructor = new Function('return function Document() {}')();
1808
+ this.Document.prototype = document;
1809
+ }
1810
+ }
1811
+ }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
1812
+ (function (undefined) {
1813
+ // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Element/detect.js
1814
+ var detect = 'Element' in this && 'HTMLElement' in this;
1815
+ if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Element&flags=always
1816
+
1817
+ (function () {
1818
+ // IE8
1819
+ if (window.Element && !window.HTMLElement) {
1820
+ window.HTMLElement = window.Element;
1821
+ return;
1820
1822
  } // create Element constructor
1821
1823
 
1822
1824
 
@@ -1912,1144 +1914,1173 @@
1912
1914
  })();
1913
1915
  }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
1914
1916
  (function (undefined) {
1915
- // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Object/defineProperty/detect.js
1916
- var detect = // In IE8, defineProperty could only act on DOM elements, so full support
1917
- // for the feature requires the ability to set a property on an arbitrary object
1918
- 'defineProperty' in Object && function () {
1919
- try {
1920
- var a = {};
1921
- Object.defineProperty(a, 'test', {
1922
- value: 42
1923
- });
1924
- return true;
1925
- } catch (e) {
1926
- return false;
1927
- }
1917
+ // Detection from https://raw.githubusercontent.com/Financial-Times/polyfill-service/8717a9e04ac7aff99b4980fbedead98036b0929a/packages/polyfill-library/polyfills/Element/prototype/classList/detect.js
1918
+ var detect = 'document' in this && "classList" in document.documentElement && 'Element' in this && 'classList' in Element.prototype && function () {
1919
+ var e = document.createElement('span');
1920
+ e.classList.add('a', 'b');
1921
+ return e.classList.contains('b');
1928
1922
  }();
1929
1923
 
1930
- if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Object.defineProperty&flags=always
1924
+ if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Element.prototype.classList&flags=always
1931
1925
 
1932
- (function (nativeDefineProperty) {
1933
- var supportsAccessors = Object.prototype.hasOwnProperty('__defineGetter__');
1934
- var ERR_ACCESSORS_NOT_SUPPORTED = 'Getters & setters cannot be defined on this javascript engine';
1935
- var ERR_VALUE_ACCESSORS = 'A property cannot both have accessors and be writable or have a value';
1926
+ (function (global) {
1927
+ var dpSupport = true;
1936
1928
 
1937
- Object.defineProperty = function defineProperty(object, property, descriptor) {
1938
- // Where native support exists, assume it
1939
- if (nativeDefineProperty && (object === window || object === document || object === Element.prototype || object instanceof Element)) {
1940
- return nativeDefineProperty(object, property, descriptor);
1941
- }
1929
+ var defineGetter = function (object, name, fn, configurable) {
1930
+ if (Object.defineProperty) Object.defineProperty(object, name, {
1931
+ configurable: false === dpSupport ? true : !!configurable,
1932
+ get: fn
1933
+ });else object.__defineGetter__(name, fn);
1934
+ };
1935
+ /** Ensure the browser allows Object.defineProperty to be used on native JavaScript objects. */
1942
1936
 
1943
- if (object === null || !(object instanceof Object || typeof object === 'object')) {
1944
- throw new TypeError('Object.defineProperty called on non-object');
1945
- }
1946
1937
 
1947
- if (!(descriptor instanceof Object)) {
1948
- throw new TypeError('Property description must be an object');
1949
- }
1938
+ try {
1939
+ defineGetter({}, "support");
1940
+ } catch (e) {
1941
+ dpSupport = false;
1942
+ }
1943
+ /** Polyfills a property with a DOMTokenList */
1950
1944
 
1951
- var propertyString = String(property);
1952
- var hasValueOrWritable = 'value' in descriptor || 'writable' in descriptor;
1953
- var getterType = 'get' in descriptor && typeof descriptor.get;
1954
- var setterType = 'set' in descriptor && typeof descriptor.set; // handle descriptor.get
1955
1945
 
1956
- if (getterType) {
1957
- if (getterType !== 'function') {
1958
- throw new TypeError('Getter must be a function');
1959
- }
1946
+ var addProp = function (o, name, attr) {
1947
+ defineGetter(o.prototype, name, function () {
1948
+ var tokenList;
1949
+ var THIS = this,
1960
1950
 
1961
- if (!supportsAccessors) {
1962
- throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
1963
- }
1951
+ /** Prevent this from firing twice for some reason. What the hell, IE. */
1952
+ gibberishProperty = "__defineGetter__" + "DEFINE_PROPERTY" + name;
1953
+ if (THIS[gibberishProperty]) return tokenList;
1954
+ THIS[gibberishProperty] = true;
1955
+ /**
1956
+ * IE8 can't define properties on native JavaScript objects, so we'll use a dumb hack instead.
1957
+ *
1958
+ * What this is doing is creating a dummy element ("reflection") inside a detached phantom node ("mirror")
1959
+ * that serves as the target of Object.defineProperty instead. While we could simply use the subject HTML
1960
+ * element instead, this would conflict with element types which use indexed properties (such as forms and
1961
+ * select lists).
1962
+ */
1964
1963
 
1965
- if (hasValueOrWritable) {
1966
- throw new TypeError(ERR_VALUE_ACCESSORS);
1967
- }
1964
+ if (false === dpSupport) {
1965
+ var visage;
1966
+ var mirror = addProp.mirror || document.createElement("div");
1967
+ var reflections = mirror.childNodes;
1968
+ var l = reflections.length;
1968
1969
 
1969
- Object.__defineGetter__.call(object, propertyString, descriptor.get);
1970
- } else {
1971
- object[propertyString] = descriptor.value;
1972
- } // handle descriptor.set
1970
+ for (var i = 0; i < l; ++i) if (reflections[i]._R === THIS) {
1971
+ visage = reflections[i];
1972
+ break;
1973
+ }
1974
+ /** Couldn't find an element's reflection inside the mirror. Materialise one. */
1973
1975
 
1974
1976
 
1975
- if (setterType) {
1976
- if (setterType !== 'function') {
1977
- throw new TypeError('Setter must be a function');
1978
- }
1977
+ visage || (visage = mirror.appendChild(document.createElement("div")));
1978
+ tokenList = DOMTokenList.call(visage, THIS, attr);
1979
+ } else tokenList = new DOMTokenList(THIS, attr);
1979
1980
 
1980
- if (!supportsAccessors) {
1981
- throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
1982
- }
1983
-
1984
- if (hasValueOrWritable) {
1985
- throw new TypeError(ERR_VALUE_ACCESSORS);
1986
- }
1981
+ defineGetter(THIS, name, function () {
1982
+ return tokenList;
1983
+ });
1984
+ delete THIS[gibberishProperty];
1985
+ return tokenList;
1986
+ }, true);
1987
+ };
1987
1988
 
1988
- Object.__defineSetter__.call(object, propertyString, descriptor.set);
1989
- } // OK to define value unconditionally - if a getter has been specified as well, an error would be thrown above
1989
+ addProp(global.Element, "classList", "className");
1990
+ addProp(global.HTMLElement, "classList", "className");
1991
+ addProp(global.HTMLLinkElement, "relList", "rel");
1992
+ addProp(global.HTMLAnchorElement, "relList", "rel");
1993
+ addProp(global.HTMLAreaElement, "relList", "rel");
1994
+ })(this);
1995
+ }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
1996
+ });
1997
+ });
1990
1998
 
1999
+ // https://github.com/alphagov/govuk-frontend/blob/main/src/govuk/components/character-count/character-count.js
2000
+ // with the change to support Welsh language messages. At the moment, there is no ability to pass
2001
+ // in custom messages to the component for the dynamic count. If GDS release a version supporting
2002
+ // custom dynamic count messages, this version should be removed.
2003
+ // Linting is disabled to keep aligned with govuk-frontend
1991
2004
 
1992
- if ('value' in descriptor) {
1993
- object[propertyString] = descriptor.value;
1994
- }
2005
+ /* eslint-disable */
1995
2006
 
1996
- return object;
1997
- };
1998
- })(Object.defineProperty);
1999
- }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
2000
- (function (undefined) {
2001
- // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Event/detect.js
2002
- var detect = function (global) {
2003
- if (!('Event' in global)) return false;
2004
- if (typeof global.Event === 'function') return true;
2007
+ function CharacterCount($module) {
2008
+ this.$module = $module;
2009
+ this.$textarea = $module.querySelector('.hmrc-js-character-count');
2010
+ this.$visibleCountMessage = null;
2011
+ this.$screenReaderCountMessage = null;
2012
+ this.lastInputTimestamp = null;
2013
+ }
2005
2014
 
2006
- try {
2007
- // In IE 9-11, the Event object exists but cannot be instantiated
2008
- new Event('click');
2009
- return true;
2010
- } catch (e) {
2011
- return false;
2012
- }
2013
- }(this);
2015
+ CharacterCount.prototype.defaults = {
2016
+ characterCountAttribute: 'data-maxlength',
2017
+ wordCountAttribute: 'data-maxwords'
2018
+ }; // Initialize component
2014
2019
 
2015
- if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Event&flags=always
2020
+ CharacterCount.prototype.init = function () {
2021
+ // Check that required elements are present
2022
+ if (!this.$textarea) {
2023
+ return;
2024
+ } // Check for module
2016
2025
 
2017
- (function () {
2018
- var unlistenableWindowEvents = {
2019
- click: 1,
2020
- dblclick: 1,
2021
- keyup: 1,
2022
- keypress: 1,
2023
- keydown: 1,
2024
- mousedown: 1,
2025
- mouseup: 1,
2026
- mousemove: 1,
2027
- mouseover: 1,
2028
- mouseenter: 1,
2029
- mouseleave: 1,
2030
- mouseout: 1,
2031
- storage: 1,
2032
- storagecommit: 1,
2033
- textinput: 1
2034
- }; // This polyfill depends on availability of `document` so will not run in a worker
2035
- // However, we asssume there are no browsers with worker support that lack proper
2036
- // support for `Event` within the worker
2037
2026
 
2038
- if (typeof document === 'undefined' || typeof window === 'undefined') return;
2027
+ var $module = this.$module;
2028
+ var $textarea = this.$textarea;
2029
+ var $fallbackLimitMessage = document.getElementById($textarea.id + '-info'); // Move the fallback count message to be immediately after the textarea
2030
+ // Kept for backwards compatibility
2039
2031
 
2040
- function indexOf(array, element) {
2041
- var index = -1,
2042
- length = array.length;
2032
+ $textarea.insertAdjacentElement('afterend', $fallbackLimitMessage); // Create the *screen reader* specific live-updating counter
2033
+ // This doesn't need any styling classes, as it is never visible
2043
2034
 
2044
- while (++index < length) {
2045
- if (index in array && array[index] === element) {
2046
- return index;
2047
- }
2048
- }
2035
+ var $screenReaderCountMessage = document.createElement('div');
2036
+ $screenReaderCountMessage.className = 'hmrc-character-count__sr-status govuk-visually-hidden';
2037
+ $screenReaderCountMessage.setAttribute('aria-live', 'polite');
2038
+ this.$screenReaderCountMessage = $screenReaderCountMessage;
2039
+ $fallbackLimitMessage.insertAdjacentElement('afterend', $screenReaderCountMessage); // Create our live-updating counter element, copying the classes from the
2040
+ // fallback element for backwards compatibility as these may have been configured
2049
2041
 
2050
- return -1;
2051
- }
2042
+ var $visibleCountMessage = document.createElement('div');
2043
+ $visibleCountMessage.className = $fallbackLimitMessage.className;
2044
+ $visibleCountMessage.classList.add('hmrc-character-count__status');
2045
+ $visibleCountMessage.setAttribute('aria-hidden', 'true');
2046
+ this.$visibleCountMessage = $visibleCountMessage;
2047
+ $fallbackLimitMessage.insertAdjacentElement('afterend', $visibleCountMessage); // Hide the fallback limit message
2052
2048
 
2053
- var existingProto = window.Event && window.Event.prototype || null;
2049
+ $fallbackLimitMessage.classList.add('govuk-visually-hidden'); // Read options set using dataset ('data-' values)
2054
2050
 
2055
- window.Event = Window.prototype.Event = function Event(type, eventInitDict) {
2056
- if (!type) {
2057
- throw new Error('Not enough arguments');
2058
- }
2051
+ this.options = this.getDataset($module); // Determine the limit attribute (characters or words)
2059
2052
 
2060
- var event; // Shortcut if browser supports createEvent
2053
+ var countAttribute = this.defaults.characterCountAttribute;
2061
2054
 
2062
- if ('createEvent' in document) {
2063
- event = document.createEvent('Event');
2064
- var bubbles = eventInitDict && eventInitDict.bubbles !== undefined ? eventInitDict.bubbles : false;
2065
- var cancelable = eventInitDict && eventInitDict.cancelable !== undefined ? eventInitDict.cancelable : false;
2066
- event.initEvent(type, bubbles, cancelable);
2067
- return event;
2068
- }
2055
+ if (this.options.maxwords) {
2056
+ countAttribute = this.defaults.wordCountAttribute;
2057
+ } // Save the element limit
2069
2058
 
2070
- event = document.createEventObject();
2071
- event.type = type;
2072
- event.bubbles = eventInitDict && eventInitDict.bubbles !== undefined ? eventInitDict.bubbles : false;
2073
- event.cancelable = eventInitDict && eventInitDict.cancelable !== undefined ? eventInitDict.cancelable : false;
2074
- return event;
2075
- };
2076
2059
 
2077
- if (existingProto) {
2078
- Object.defineProperty(window.Event, 'prototype', {
2079
- configurable: false,
2080
- enumerable: false,
2081
- writable: true,
2082
- value: existingProto
2083
- });
2084
- }
2060
+ this.maxLength = $module.getAttribute(countAttribute); // Check for limit
2085
2061
 
2086
- if (!('createEvent' in document)) {
2087
- window.addEventListener = Window.prototype.addEventListener = Document.prototype.addEventListener = Element.prototype.addEventListener = function addEventListener() {
2088
- var element = this,
2089
- type = arguments[0],
2090
- listener = arguments[1];
2062
+ if (!this.maxLength) {
2063
+ return;
2064
+ } // Remove hard limit if set
2091
2065
 
2092
- if (element === window && type in unlistenableWindowEvents) {
2093
- 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.');
2094
- }
2095
2066
 
2096
- if (!element._events) {
2097
- element._events = {};
2098
- }
2067
+ $textarea.removeAttribute('maxlength');
2068
+ this.bindChangeEvents(); // When the page is restored after navigating 'back' in some browsers the
2069
+ // state of the character count is not restored until *after* the DOMContentLoaded
2070
+ // event is fired, so we need to manually update it after the pageshow event
2071
+ // in browsers that support it.
2099
2072
 
2100
- if (!element._events[type]) {
2101
- element._events[type] = function (event) {
2102
- var list = element._events[event.type].list,
2103
- events = list.slice(),
2104
- index = -1,
2105
- length = events.length,
2106
- eventElement;
2073
+ if ('onpageshow' in window) {
2074
+ window.addEventListener('pageshow', this.updateCountMessage.bind(this));
2075
+ } else {
2076
+ window.addEventListener('DOMContentLoaded', this.updateCountMessage.bind(this));
2077
+ }
2107
2078
 
2108
- event.preventDefault = function preventDefault() {
2109
- if (event.cancelable !== false) {
2110
- event.returnValue = false;
2111
- }
2112
- };
2079
+ this.updateCountMessage();
2080
+ }; // Read data attributes
2113
2081
 
2114
- event.stopPropagation = function stopPropagation() {
2115
- event.cancelBubble = true;
2116
- };
2117
2082
 
2118
- event.stopImmediatePropagation = function stopImmediatePropagation() {
2119
- event.cancelBubble = true;
2120
- event.cancelImmediate = true;
2121
- };
2083
+ CharacterCount.prototype.getDataset = function (element) {
2084
+ var dataset = {};
2085
+ var attributes = element.attributes;
2122
2086
 
2123
- event.currentTarget = element;
2124
- event.relatedTarget = event.fromElement || null;
2125
- event.target = event.target || event.srcElement || element;
2126
- event.timeStamp = new Date().getTime();
2087
+ if (attributes) {
2088
+ for (var i = 0; i < attributes.length; i++) {
2089
+ var attribute = attributes[i];
2090
+ var match = attribute.name.match(/^data-(.+)/);
2127
2091
 
2128
- if (event.clientX) {
2129
- event.pageX = event.clientX + document.documentElement.scrollLeft;
2130
- event.pageY = event.clientY + document.documentElement.scrollTop;
2131
- }
2092
+ if (match) {
2093
+ dataset[match[1]] = attribute.value;
2094
+ }
2095
+ }
2096
+ }
2132
2097
 
2133
- while (++index < length && !event.cancelImmediate) {
2134
- if (index in events) {
2135
- eventElement = events[index];
2098
+ return dataset;
2099
+ }; // Counts characters or words in text
2136
2100
 
2137
- if (indexOf(list, eventElement) !== -1 && typeof eventElement === 'function') {
2138
- eventElement.call(element, event);
2139
- }
2140
- }
2141
- }
2142
- };
2143
2101
 
2144
- element._events[type].list = [];
2102
+ CharacterCount.prototype.count = function (text) {
2103
+ var length;
2145
2104
 
2146
- if (element.attachEvent) {
2147
- element.attachEvent('on' + type, element._events[type]);
2148
- }
2149
- }
2105
+ if (this.options.maxwords) {
2106
+ var tokens = text.match(/\S+/g) || []; // Matches consecutive non-whitespace chars
2150
2107
 
2151
- element._events[type].list.push(listener);
2152
- };
2108
+ length = tokens.length;
2109
+ } else {
2110
+ length = text.length;
2111
+ }
2153
2112
 
2154
- window.removeEventListener = Window.prototype.removeEventListener = Document.prototype.removeEventListener = Element.prototype.removeEventListener = function removeEventListener() {
2155
- var element = this,
2156
- type = arguments[0],
2157
- listener = arguments[1],
2158
- index;
2113
+ return length;
2114
+ }; // Bind input propertychange to the elements and update based on the change
2159
2115
 
2160
- if (element._events && element._events[type] && element._events[type].list) {
2161
- index = indexOf(element._events[type].list, listener);
2162
2116
 
2163
- if (index !== -1) {
2164
- element._events[type].list.splice(index, 1);
2117
+ CharacterCount.prototype.bindChangeEvents = function () {
2118
+ var $textarea = this.$textarea;
2119
+ $textarea.addEventListener('keyup', this.handleKeyUp.bind(this)); // Bind focus/blur events to start/stop polling
2165
2120
 
2166
- if (!element._events[type].list.length) {
2167
- if (element.detachEvent) {
2168
- element.detachEvent('on' + type, element._events[type]);
2169
- }
2121
+ $textarea.addEventListener('focus', this.handleFocus.bind(this));
2122
+ $textarea.addEventListener('blur', this.handleBlur.bind(this));
2123
+ }; // Speech recognition software such as Dragon NaturallySpeaking will modify the
2124
+ // fields by directly changing its `value`. These changes don't trigger events
2125
+ // in JavaScript, so we need to poll to handle when and if they occur.
2170
2126
 
2171
- delete element._events[type];
2172
- }
2173
- }
2174
- }
2175
- };
2176
2127
 
2177
- window.dispatchEvent = Window.prototype.dispatchEvent = Document.prototype.dispatchEvent = Element.prototype.dispatchEvent = function dispatchEvent(event) {
2178
- if (!arguments.length) {
2179
- throw new Error('Not enough arguments');
2180
- }
2128
+ CharacterCount.prototype.checkIfValueChanged = function () {
2129
+ if (!this.$textarea.oldValue) this.$textarea.oldValue = '';
2181
2130
 
2182
- if (!event || typeof event.type !== 'string') {
2183
- throw new Error('DOM Events Exception 0');
2184
- }
2131
+ if (this.$textarea.value !== this.$textarea.oldValue) {
2132
+ this.$textarea.oldValue = this.$textarea.value;
2133
+ this.updateCountMessage();
2134
+ }
2135
+ }; // Helper function to update both the visible and screen reader-specific
2136
+ // counters simultaneously (e.g. on init)
2185
2137
 
2186
- var element = this,
2187
- type = event.type;
2188
2138
 
2189
- try {
2190
- if (!event.bubbles) {
2191
- event.cancelBubble = true;
2139
+ CharacterCount.prototype.updateCountMessage = function () {
2140
+ this.updateVisibleCountMessage();
2141
+ this.updateScreenReaderCountMessage();
2142
+ }; // Update visible counter
2192
2143
 
2193
- var cancelBubbleEvent = function (event) {
2194
- event.cancelBubble = true;
2195
- (element || window).detachEvent('on' + type, cancelBubbleEvent);
2196
- };
2197
2144
 
2198
- this.attachEvent('on' + type, cancelBubbleEvent);
2199
- }
2145
+ CharacterCount.prototype.updateVisibleCountMessage = function () {
2146
+ var $textarea = this.$textarea;
2147
+ var $visibleCountMessage = this.$visibleCountMessage;
2148
+ var remainingNumber = this.maxLength - this.count($textarea.value); // If input is over the threshold, remove the disabled class which renders the
2149
+ // counter invisible.
2200
2150
 
2201
- this.fireEvent('on' + type, event);
2202
- } catch (error) {
2203
- event.target = element;
2151
+ if (this.isOverThreshold()) {
2152
+ $visibleCountMessage.classList.remove('hmrc-character-count__message--disabled');
2153
+ } else {
2154
+ $visibleCountMessage.classList.add('hmrc-character-count__message--disabled');
2155
+ } // Update styles
2204
2156
 
2205
- do {
2206
- event.currentTarget = element;
2207
2157
 
2208
- if ('_events' in element && typeof element._events[type] === 'function') {
2209
- element._events[type].call(element, event);
2210
- }
2158
+ if (remainingNumber < 0) {
2159
+ $textarea.classList.add('govuk-textarea--error');
2160
+ $visibleCountMessage.classList.remove('govuk-hint');
2161
+ $visibleCountMessage.classList.add('govuk-error-message');
2162
+ } else {
2163
+ $textarea.classList.remove('govuk-textarea--error');
2164
+ $visibleCountMessage.classList.remove('govuk-error-message');
2165
+ $visibleCountMessage.classList.add('govuk-hint');
2166
+ } // Update message
2211
2167
 
2212
- if (typeof element['on' + type] === 'function') {
2213
- element['on' + type].call(element, event);
2214
- }
2215
2168
 
2216
- element = element.nodeType === 9 ? element.parentWindow : element.parentNode;
2217
- } while (element && !event.cancelBubble);
2218
- }
2169
+ $visibleCountMessage.innerHTML = this.formattedUpdateMessage();
2170
+ }; // Update screen reader-specific counter
2219
2171
 
2220
- return true;
2221
- }; // Add the DOMContentLoaded Event
2222
2172
 
2173
+ CharacterCount.prototype.updateScreenReaderCountMessage = function () {
2174
+ var $screenReaderCountMessage = this.$screenReaderCountMessage; // If over the threshold, remove the aria-hidden attribute, allowing screen
2175
+ // readers to announce the content of the element.
2223
2176
 
2224
- document.attachEvent('onreadystatechange', function () {
2225
- if (document.readyState === 'complete') {
2226
- document.dispatchEvent(new Event('DOMContentLoaded', {
2227
- bubbles: true
2228
- }));
2229
- }
2230
- });
2231
- }
2232
- })();
2233
- }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
2234
- });
2235
- });
2177
+ if (this.isOverThreshold()) {
2178
+ $screenReaderCountMessage.removeAttribute('aria-hidden');
2179
+ } else {
2180
+ $screenReaderCountMessage.setAttribute('aria-hidden', true);
2181
+ } // Update message
2236
2182
 
2237
- var classList = createCommonjsModule(function (module, exports) {
2238
- (function (global, factory) {
2239
- factory();
2240
- })(commonjsGlobal, function () {
2241
2183
 
2242
- (function (undefined) {
2243
- // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Object/defineProperty/detect.js
2244
- var detect = // In IE8, defineProperty could only act on DOM elements, so full support
2245
- // for the feature requires the ability to set a property on an arbitrary object
2246
- 'defineProperty' in Object && function () {
2247
- try {
2248
- var a = {};
2249
- Object.defineProperty(a, 'test', {
2250
- value: 42
2251
- });
2252
- return true;
2253
- } catch (e) {
2254
- return false;
2255
- }
2256
- }();
2184
+ $screenReaderCountMessage.innerHTML = this.formattedUpdateMessage();
2185
+ }; // Format update message
2257
2186
 
2258
- if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Object.defineProperty&flags=always
2259
2187
 
2260
- (function (nativeDefineProperty) {
2261
- var supportsAccessors = Object.prototype.hasOwnProperty('__defineGetter__');
2262
- var ERR_ACCESSORS_NOT_SUPPORTED = 'Getters & setters cannot be defined on this javascript engine';
2263
- var ERR_VALUE_ACCESSORS = 'A property cannot both have accessors and be writable or have a value';
2188
+ CharacterCount.prototype.formattedUpdateMessage = function () {
2189
+ var $textarea = this.$textarea;
2190
+ var options = this.options;
2191
+ var remainingNumber = this.maxLength - this.count($textarea.value);
2192
+ var isWelsh = this.options.language === 'cy';
2193
+ var charVerb;
2194
+ var charNoun;
2195
+ var charStartMessage = isWelsh ? 'Mae gennych ' : 'You have ';
2264
2196
 
2265
- Object.defineProperty = function defineProperty(object, property, descriptor) {
2266
- // Where native support exists, assume it
2267
- if (nativeDefineProperty && (object === window || object === document || object === Element.prototype || object instanceof Element)) {
2268
- return nativeDefineProperty(object, property, descriptor);
2269
- }
2197
+ if (options.maxwords) {
2198
+ if (remainingNumber === -1 || remainingNumber === 1) {
2199
+ charNoun = isWelsh ? 'gair' : 'word';
2200
+ } else {
2201
+ charNoun = isWelsh ? 'o eiriau' : 'words';
2202
+ }
2203
+ } else if (remainingNumber === -1 || remainingNumber === 1) {
2204
+ charNoun = isWelsh ? 'cymeriad' : 'character';
2205
+ } else {
2206
+ charNoun = isWelsh ? 'o gymeriadau' : 'characters';
2207
+ }
2270
2208
 
2271
- if (object === null || !(object instanceof Object || typeof object === 'object')) {
2272
- throw new TypeError('Object.defineProperty called on non-object');
2273
- }
2209
+ if (remainingNumber < 0) {
2210
+ charVerb = isWelsh ? 'yn ormod' : 'too many';
2211
+ } else {
2212
+ charVerb = isWelsh ? 'yn weddill' : 'remaining';
2213
+ }
2274
2214
 
2275
- if (!(descriptor instanceof Object)) {
2276
- throw new TypeError('Property description must be an object');
2277
- }
2215
+ var displayNumber = Math.abs(remainingNumber);
2216
+ return charStartMessage + displayNumber + ' ' + charNoun + ' ' + charVerb;
2217
+ }; // Checks whether the value is over the configured threshold for the input.
2218
+ // If there is no configured threshold, it is set to 0 and this function will
2219
+ // always return true.
2278
2220
 
2279
- var propertyString = String(property);
2280
- var hasValueOrWritable = 'value' in descriptor || 'writable' in descriptor;
2281
- var getterType = 'get' in descriptor && typeof descriptor.get;
2282
- var setterType = 'set' in descriptor && typeof descriptor.set; // handle descriptor.get
2283
2221
 
2284
- if (getterType) {
2285
- if (getterType !== 'function') {
2286
- throw new TypeError('Getter must be a function');
2287
- }
2222
+ CharacterCount.prototype.isOverThreshold = function () {
2223
+ var $textarea = this.$textarea;
2224
+ var options = this.options; // Determine the remaining number of characters/words
2288
2225
 
2289
- if (!supportsAccessors) {
2290
- throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
2291
- }
2226
+ var currentLength = this.count($textarea.value);
2227
+ var maxLength = this.maxLength; // Set threshold if presented in options
2292
2228
 
2293
- if (hasValueOrWritable) {
2294
- throw new TypeError(ERR_VALUE_ACCESSORS);
2295
- }
2229
+ var thresholdPercent = options.threshold ? options.threshold : 0;
2230
+ var thresholdValue = maxLength * thresholdPercent / 100;
2231
+ return thresholdValue <= currentLength;
2232
+ }; // Update the visible character counter and keep track of when the last update
2233
+ // happened for each keypress
2296
2234
 
2297
- Object.__defineGetter__.call(object, propertyString, descriptor.get);
2298
- } else {
2299
- object[propertyString] = descriptor.value;
2300
- } // handle descriptor.set
2301
2235
 
2236
+ CharacterCount.prototype.handleKeyUp = function () {
2237
+ this.updateVisibleCountMessage();
2238
+ this.lastInputTimestamp = Date.now();
2239
+ };
2302
2240
 
2303
- if (setterType) {
2304
- if (setterType !== 'function') {
2305
- throw new TypeError('Setter must be a function');
2306
- }
2241
+ CharacterCount.prototype.handleFocus = function () {
2242
+ // If the field is focused, and a keyup event hasn't been detected for at
2243
+ // least 1000 ms (1 second), then run the manual change check.
2244
+ // This is so that the update triggered by the manual comparison doesn't
2245
+ // conflict with debounced KeyboardEvent updates.
2246
+ this.valueChecker = setInterval(function () {
2247
+ if (!this.lastInputTimestamp || Date.now() - 500 >= this.lastInputTimestamp) {
2248
+ this.checkIfValueChanged();
2249
+ }
2250
+ }.bind(this), 1000);
2251
+ };
2307
2252
 
2308
- if (!supportsAccessors) {
2309
- throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
2310
- }
2253
+ CharacterCount.prototype.handleBlur = function () {
2254
+ // Cancel value checking on blur
2255
+ clearInterval(this.valueChecker);
2256
+ };
2311
2257
 
2312
- if (hasValueOrWritable) {
2313
- throw new TypeError(ERR_VALUE_ACCESSORS);
2314
- }
2258
+ (function (undefined) {
2259
+ // Detection from https://github.com/Financial-Times/polyfill-library/blob/987630a085e29226da16b5dc542042c687560191/polyfills/Array/prototype/forEach/detect.js
2260
+ var detect = ('forEach' in Array.prototype);
2261
+ if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Array.prototype.forEach&flags=always
2315
2262
 
2316
- Object.__defineSetter__.call(object, propertyString, descriptor.set);
2317
- } // OK to define value unconditionally - if a getter has been specified as well, an error would be thrown above
2263
+ (function () {
2264
+ Array.prototype.forEach = function forEach(callback) {
2265
+ if (this === undefined || this === null) {
2266
+ throw new TypeError(this + " is not an object");
2267
+ }
2318
2268
 
2269
+ if (typeof callback !== "function") {
2270
+ throw new TypeError(callback + " is not a function");
2271
+ }
2319
2272
 
2320
- if ('value' in descriptor) {
2321
- object[propertyString] = descriptor.value;
2273
+ var object = Object(this),
2274
+ scope = arguments[1],
2275
+ arraylike = object instanceof String ? object.split("") : object,
2276
+ length = Math.max(Math.min(arraylike.length, 9007199254740991), 0) || 0,
2277
+ index = -1;
2278
+
2279
+ while (++index < length) {
2280
+ if (index in arraylike) {
2281
+ callback.call(scope, arraylike[index], index, object);
2322
2282
  }
2283
+ }
2284
+ };
2285
+ })();
2286
+ }).call('object' === (typeof window === "undefined" ? "undefined" : _typeof(window)) && window || 'object' === (typeof self === "undefined" ? "undefined" : _typeof(self)) && self || 'object' === (typeof global === "undefined" ? "undefined" : _typeof(global)) && global || {});
2323
2287
 
2324
- return object;
2325
- };
2326
- })(Object.defineProperty);
2327
- }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
2328
- (function (undefined) {
2329
- // Detection from https://raw.githubusercontent.com/Financial-Times/polyfill-service/master/packages/polyfill-library/polyfills/DOMTokenList/detect.js
2330
- var detect = 'DOMTokenList' in this && function (x) {
2331
- return 'classList' in x ? !x.classList.toggle('x', false) && !x.className : true;
2332
- }(document.createElement('x'));
2288
+ (function (undefined) {
2289
+ // Detection from https://github.com/Financial-Times/polyfill-library/blob/987630a085e29226da16b5dc542042c687560191/polyfills/Object/keys/detect.js
2290
+ var detect = 'keys' in Object && function () {
2291
+ // Safari 5.0 bug where Object.keys doesn't work with arguments
2292
+ return Object.keys(arguments).length === 2;
2293
+ }(1, 2) && function () {
2294
+ try {
2295
+ return true;
2296
+ } catch (e) {
2297
+ return false;
2298
+ }
2299
+ }();
2333
2300
 
2334
- if (detect) return; // Polyfill from https://raw.githubusercontent.com/Financial-Times/polyfill-service/master/packages/polyfill-library/polyfills/DOMTokenList/polyfill.js
2301
+ if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Object.assign&flags=always
2335
2302
 
2336
- (function (global) {
2337
- var nativeImpl = "DOMTokenList" in global && global.DOMTokenList;
2303
+ Object.keys = function () {
2338
2304
 
2339
- if (!nativeImpl || !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg') && !(document.createElementNS("http://www.w3.org/2000/svg", "svg").classList instanceof DOMTokenList)) {
2340
- global.DOMTokenList = function () {
2341
- // eslint-disable-line no-unused-vars
2342
- var dpSupport = true;
2305
+ var has = Object.prototype.hasOwnProperty;
2306
+ var toStr = Object.prototype.toString;
2307
+ var isEnumerable = Object.prototype.propertyIsEnumerable;
2308
+ var hasDontEnumBug = !isEnumerable.call({
2309
+ toString: null
2310
+ }, "toString");
2311
+ var hasProtoEnumBug = isEnumerable.call(function () {}, "prototype");
2312
+ var dontEnums = ["toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "constructor"];
2343
2313
 
2344
- var defineGetter = function (object, name, fn, configurable) {
2345
- if (Object.defineProperty) Object.defineProperty(object, name, {
2346
- configurable: false === dpSupport ? true : !!configurable,
2347
- get: fn
2348
- });else object.__defineGetter__(name, fn);
2349
- };
2350
- /** Ensure the browser allows Object.defineProperty to be used on native JavaScript objects. */
2314
+ var equalsConstructorPrototype = function equalsConstructorPrototype(o) {
2315
+ var ctor = o.constructor;
2316
+ return ctor && ctor.prototype === o;
2317
+ };
2318
+
2319
+ var excludedKeys = {
2320
+ $console: true,
2321
+ $external: true,
2322
+ $frame: true,
2323
+ $frameElement: true,
2324
+ $frames: true,
2325
+ $innerHeight: true,
2326
+ $innerWidth: true,
2327
+ $outerHeight: true,
2328
+ $outerWidth: true,
2329
+ $pageXOffset: true,
2330
+ $pageYOffset: true,
2331
+ $parent: true,
2332
+ $scrollLeft: true,
2333
+ $scrollTop: true,
2334
+ $scrollX: true,
2335
+ $scrollY: true,
2336
+ $self: true,
2337
+ $webkitIndexedDB: true,
2338
+ $webkitStorageInfo: true,
2339
+ $window: true
2340
+ };
2351
2341
 
2342
+ var hasAutomationEqualityBug = function () {
2343
+ /* global window */
2344
+ if (typeof window === "undefined") {
2345
+ return false;
2346
+ }
2352
2347
 
2353
- try {
2354
- defineGetter({}, "support");
2355
- } catch (e) {
2356
- dpSupport = false;
2348
+ for (var k in window) {
2349
+ try {
2350
+ if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && _typeof(window[k]) === 'object') {
2351
+ try {
2352
+ equalsConstructorPrototype(window[k]);
2353
+ } catch (e) {
2354
+ return true;
2355
+ }
2357
2356
  }
2357
+ } catch (e) {
2358
+ return true;
2359
+ }
2360
+ }
2358
2361
 
2359
- var _DOMTokenList = function (el, prop) {
2360
- var that = this;
2361
- var tokens = [];
2362
- var tokenMap = {};
2363
- var length = 0;
2364
- var maxLength = 0;
2362
+ return false;
2363
+ }();
2365
2364
 
2366
- var addIndexGetter = function (i) {
2367
- defineGetter(that, i, function () {
2368
- preop();
2369
- return tokens[i];
2370
- }, false);
2371
- };
2365
+ var equalsConstructorPrototypeIfNotBuggy = function equalsConstructorPrototypeIfNotBuggy(o) {
2366
+ /* global window */
2367
+ if (typeof window === "undefined" || !hasAutomationEqualityBug) {
2368
+ return equalsConstructorPrototype(o);
2369
+ }
2372
2370
 
2373
- var reindex = function () {
2374
- /** Define getter functions for array-like access to the tokenList's contents. */
2375
- if (length >= maxLength) for (; maxLength < length; ++maxLength) {
2376
- addIndexGetter(maxLength);
2377
- }
2378
- };
2379
- /** Helper function called at the start of each class method. Internal use only. */
2371
+ try {
2372
+ return equalsConstructorPrototype(o);
2373
+ } catch (e) {
2374
+ return false;
2375
+ }
2376
+ };
2380
2377
 
2378
+ function isArgumentsObject(value) {
2379
+ var str = toStr.call(value);
2380
+ var isArgs = str === "[object Arguments]";
2381
2381
 
2382
- var preop = function () {
2383
- var error;
2384
- var i;
2385
- var args = arguments;
2386
- var rSpace = /\s+/;
2387
- /** Validate the token/s passed to an instance method, if any. */
2382
+ if (!isArgs) {
2383
+ isArgs = str !== "[object Array]" && value !== null && _typeof(value) === "object" && typeof value.length === "number" && value.length >= 0 && toStr.call(value.callee) === "[object Function]";
2384
+ }
2388
2385
 
2389
- if (args.length) for (i = 0; i < args.length; ++i) if (rSpace.test(args[i])) {
2390
- error = new SyntaxError('String "' + args[i] + '" ' + "contains" + ' an invalid character');
2391
- error.code = 5;
2392
- error.name = "InvalidCharacterError";
2393
- throw error;
2394
- }
2395
- /** Split the new value apart by whitespace*/
2386
+ return isArgs;
2387
+ }
2396
2388
 
2397
- if (typeof el[prop] === "object") {
2398
- tokens = ("" + el[prop].baseVal).replace(/^\s+|\s+$/g, "").split(rSpace);
2399
- } else {
2400
- tokens = ("" + el[prop]).replace(/^\s+|\s+$/g, "").split(rSpace);
2401
- }
2402
- /** Avoid treating blank strings as single-item token lists */
2389
+ return function keys(object) {
2390
+ var isFunction = toStr.call(object) === "[object Function]";
2391
+ var isArguments = isArgumentsObject(object);
2392
+ var isString = toStr.call(object) === "[object String]";
2393
+ var theKeys = [];
2403
2394
 
2395
+ if (object === undefined || object === null) {
2396
+ throw new TypeError("Cannot convert undefined or null to object");
2397
+ }
2404
2398
 
2405
- if ("" === tokens[0]) tokens = [];
2406
- /** Repopulate the internal token lists */
2399
+ var skipProto = hasProtoEnumBug && isFunction;
2407
2400
 
2408
- tokenMap = {};
2401
+ if (isString && object.length > 0 && !has.call(object, 0)) {
2402
+ for (var i = 0; i < object.length; ++i) {
2403
+ theKeys.push(String(i));
2404
+ }
2405
+ }
2409
2406
 
2410
- for (i = 0; i < tokens.length; ++i) tokenMap[tokens[i]] = true;
2407
+ if (isArguments && object.length > 0) {
2408
+ for (var j = 0; j < object.length; ++j) {
2409
+ theKeys.push(String(j));
2410
+ }
2411
+ } else {
2412
+ for (var name in object) {
2413
+ if (!(skipProto && name === "prototype") && has.call(object, name)) {
2414
+ theKeys.push(String(name));
2415
+ }
2416
+ }
2417
+ }
2411
2418
 
2412
- length = tokens.length;
2413
- reindex();
2414
- };
2415
- /** Populate our internal token list if the targeted attribute of the subject element isn't empty. */
2419
+ if (hasDontEnumBug) {
2420
+ var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object);
2416
2421
 
2422
+ for (var k = 0; k < dontEnums.length; ++k) {
2423
+ if (!(skipConstructor && dontEnums[k] === "constructor") && has.call(object, dontEnums[k])) {
2424
+ theKeys.push(dontEnums[k]);
2425
+ }
2426
+ }
2427
+ }
2417
2428
 
2418
- preop();
2419
- /** Return the number of tokens in the underlying string. Read-only. */
2429
+ return theKeys;
2430
+ };
2431
+ }();
2432
+ }).call("object" === (typeof window === "undefined" ? "undefined" : _typeof(window)) && window || "object" === (typeof self === "undefined" ? "undefined" : _typeof(self)) && self || "object" === (typeof global === "undefined" ? "undefined" : _typeof(global)) && global || {});
2420
2433
 
2421
- defineGetter(that, "length", function () {
2422
- preop();
2423
- return length;
2424
- });
2425
- /** Override the default toString/toLocaleString methods to return a space-delimited list of tokens when typecast. */
2434
+ (function (undefined) {
2435
+ // Detection from https://github.com/Financial-Times/polyfill-library/blob/987630a085e29226da16b5dc542042c687560191/polyfills/Object/assign/detect.js
2436
+ var detect = ('assign' in Object);
2437
+ if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Object.assign&flags=always
2426
2438
 
2427
- that.toLocaleString = that.toString = function () {
2428
- preop();
2429
- return tokens.join(" ");
2430
- };
2439
+ (function () {
2440
+ // 7.1.13 ToObject ( argument )
2441
+ function toObject(argument) {
2442
+ if (argument === null || argument === undefined) {
2443
+ throw new TypeError('Cannot call method on ' + argument);
2444
+ }
2431
2445
 
2432
- that.item = function (idx) {
2433
- preop();
2434
- return tokens[idx];
2435
- };
2446
+ return Object(argument);
2447
+ }
2436
2448
 
2437
- that.contains = function (token) {
2438
- preop();
2439
- return !!tokenMap[token];
2440
- };
2449
+ Object.defineProperty(Object, 'assign', {
2450
+ enumerable: false,
2451
+ configurable: true,
2452
+ writable: true,
2453
+ value: function assign(target, source) {
2454
+ // eslint-disable-line no-unused-vars
2455
+ // 1. Let to be ? ToObject(target).
2456
+ var to = toObject(target); // 2. If only one argument was passed, return to.
2441
2457
 
2442
- that.add = function () {
2443
- preop.apply(that, args = arguments);
2458
+ if (arguments.length === 1) {
2459
+ return to;
2460
+ } // 3. Let sources be the List of argument values starting with the second argument
2444
2461
 
2445
- for (var args, token, i = 0, l = args.length; i < l; ++i) {
2446
- token = args[i];
2447
2462
 
2448
- if (!tokenMap[token]) {
2449
- tokens.push(token);
2450
- tokenMap[token] = true;
2451
- }
2452
- }
2453
- /** Update the targeted attribute of the attached element if the token list's changed. */
2463
+ var sources = Array.prototype.slice.call(arguments, 1); // 4. For each element nextSource of sources, in ascending index order, do
2454
2464
 
2465
+ var index1;
2466
+ var index2;
2467
+ var keys;
2468
+ var from;
2455
2469
 
2456
- if (length !== tokens.length) {
2457
- length = tokens.length >>> 0;
2470
+ for (index1 = 0; index1 < sources.length; index1++) {
2471
+ var nextSource = sources[index1]; // 4a. If nextSource is undefined or null, let keys be a new empty List.
2458
2472
 
2459
- if (typeof el[prop] === "object") {
2460
- el[prop].baseVal = tokens.join(" ");
2461
- } else {
2462
- el[prop] = tokens.join(" ");
2463
- }
2473
+ if (nextSource === undefined || nextSource === null) {
2474
+ keys = []; // 4b. Else,
2475
+ } else {
2476
+ // 4bi. Let from be ! ToObject(nextSource).
2477
+ from = toObject(nextSource); // 4bii. Let keys be ? from.[[OwnPropertyKeys]]().
2464
2478
 
2465
- reindex();
2466
- }
2467
- };
2479
+ /*
2480
+ This step in our polyfill is not complying with the specification.
2481
+ [[OwnPropertyKeys]] is meant to return ALL keys, including non-enumerable and symbols.
2482
+ TODO: When we have Reflect.ownKeys, use that instead as it is the userland equivalent of [[OwnPropertyKeys]].
2483
+ */
2468
2484
 
2469
- that.remove = function () {
2470
- preop.apply(that, args = arguments);
2471
- /** Build a hash of token names to compare against when recollecting our token list. */
2485
+ keys = Object.keys(from);
2486
+ } // 4c. For each element nextKey of keys in List order, do
2472
2487
 
2473
- for (var args, ignore = {}, i = 0, t = []; i < args.length; ++i) {
2474
- ignore[args[i]] = true;
2475
- delete tokenMap[args[i]];
2476
- }
2477
- /** Run through our tokens list and reassign only those that aren't defined in the hash declared above. */
2478
2488
 
2489
+ for (index2 = 0; index2 < keys.length; index2++) {
2490
+ var nextKey = keys[index2]; // 4ci. Let desc be ? from.[[GetOwnProperty]](nextKey).
2479
2491
 
2480
- for (i = 0; i < tokens.length; ++i) if (!ignore[tokens[i]]) t.push(tokens[i]);
2492
+ var desc = Object.getOwnPropertyDescriptor(from, nextKey); // 4cii. If desc is not undefined and desc.[[Enumerable]] is true, then
2481
2493
 
2482
- tokens = t;
2483
- length = t.length >>> 0;
2484
- /** Update the targeted attribute of the attached element. */
2494
+ if (desc !== undefined && desc.enumerable) {
2495
+ // 4cii1. Let propValue be ? Get(from, nextKey).
2496
+ var propValue = from[nextKey]; // 4cii2. Perform ? Set(to, nextKey, propValue, true).
2485
2497
 
2486
- if (typeof el[prop] === "object") {
2487
- el[prop].baseVal = tokens.join(" ");
2488
- } else {
2489
- el[prop] = tokens.join(" ");
2490
- }
2498
+ to[nextKey] = propValue;
2499
+ }
2500
+ }
2501
+ } // 5. Return to.
2491
2502
 
2492
- reindex();
2493
- };
2494
2503
 
2495
- that.toggle = function (token, force) {
2496
- preop.apply(that, [token]);
2497
- /** Token state's being forced. */
2504
+ return to;
2505
+ }
2506
+ });
2507
+ })();
2508
+ }).call('object' === (typeof window === "undefined" ? "undefined" : _typeof(window)) && window || 'object' === (typeof self === "undefined" ? "undefined" : _typeof(self)) && self || 'object' === (typeof global === "undefined" ? "undefined" : _typeof(global)) && global || {});
2498
2509
 
2499
- if (undefined !== force) {
2500
- if (force) {
2501
- that.add(token);
2502
- return true;
2503
- } else {
2504
- that.remove(token);
2505
- return false;
2506
- }
2507
- }
2508
- /** Token already exists in tokenList. Remove it, and return FALSE. */
2510
+ (function (undefined) {
2511
+ // Detection from https://github.com/Financial-Times/polyfill-library/blob/987630a085e29226da16b5dc542042c687560191/polyfills/Date/now/detect.js
2512
+ var detect = 'Date' in this && 'now' in this.Date && 'getTime' in this.Date.prototype;
2513
+ if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Array.prototype.forEach&flags=always
2509
2514
 
2515
+ Date.now = function now() {
2516
+ return new Date().getTime();
2517
+ };
2518
+ }).call('object' === (typeof window === "undefined" ? "undefined" : _typeof(window)) && window || 'object' === (typeof self === "undefined" ? "undefined" : _typeof(self)) && self || 'object' === (typeof global === "undefined" ? "undefined" : _typeof(global)) && global || {});
2510
2519
 
2511
- if (tokenMap[token]) {
2512
- that.remove(token);
2513
- return false;
2514
- }
2515
- /** Otherwise, add the token and return TRUE. */
2520
+ /**
2521
+ * TODO: Ideally this would be a NodeList.prototype.forEach polyfill
2522
+ * This seems to fail in IE8, requires more investigation.
2523
+ * See: https://github.com/imagitama/nodelist-foreach-polyfill
2524
+ */
2525
+ // eslint-disable-next-line consistent-return
2526
+ function nodeListForEach(nodes, callback) {
2527
+ if (window.NodeList.prototype.forEach) {
2528
+ return nodes.forEach(callback);
2529
+ }
2516
2530
 
2531
+ for (var i = 0; i < nodes.length; i += 1) {
2532
+ callback.call(window, nodes[i], i, nodes);
2533
+ }
2534
+ } // eslint-disable-next-line import/prefer-default-export
2517
2535
 
2518
- that.add(token);
2519
- return true;
2520
- };
2536
+ /* global ActiveXObject */
2537
+ var _console = console,
2538
+ warn = _console.warn;
2539
+ var utils = {
2540
+ generateDomElementFromString: function generateDomElementFromString(str) {
2541
+ var abc = document.createElement('div');
2542
+ abc.innerHTML = str;
2543
+ return abc.firstChild;
2544
+ },
2545
+ generateDomElementFromStringAndAppendText: function generateDomElementFromStringAndAppendText(str, text) {
2546
+ var $tmp = utils.generateDomElementFromString(str);
2547
+ $tmp.innerText = text;
2548
+ return $tmp;
2549
+ },
2550
+ hasClass: function hasClass(selector, className) {
2551
+ return document.querySelector(selector).classList.contains(className);
2552
+ },
2553
+ addClass: function addClass(selector, className) {
2554
+ var elements = document.querySelectorAll(selector);
2555
+ nodeListForEach(elements, function (i) {
2556
+ i.classList.add(className);
2557
+ });
2558
+ },
2559
+ removeClass: function removeClass(selector, className) {
2560
+ var elements = document.querySelectorAll(selector);
2561
+ nodeListForEach(elements, function (i) {
2562
+ i.classList.remove(className);
2563
+ });
2564
+ },
2565
+ removeElement: function removeElement($elem) {
2566
+ var parent = $elem.parentNode;
2521
2567
 
2522
- return that;
2523
- };
2568
+ if (parent) {
2569
+ parent.removeChild($elem);
2570
+ } else {
2571
+ warn("couldn't find parent for elem", $elem);
2572
+ }
2573
+ },
2574
+ ajaxGet: function ajaxGet(url, success) {
2575
+ var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
2576
+ xhr.open('GET', url);
2524
2577
 
2525
- return _DOMTokenList;
2526
- }();
2527
- } // Add second argument to native DOMTokenList.toggle() if necessary
2578
+ xhr.onreadystatechange = function () {
2579
+ if (xhr.readyState > 3 && xhr.status === 200) success(xhr.responseText);
2580
+ };
2528
2581
 
2582
+ xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
2583
+ xhr.send();
2584
+ return xhr;
2585
+ }
2586
+ };
2529
2587
 
2530
- (function () {
2531
- var e = document.createElement('span');
2532
- if (!('classList' in e)) return;
2533
- e.classList.toggle('x', false);
2534
- if (!e.classList.contains('x')) return;
2588
+ function displayDialog($elementToDisplay) {
2589
+ var $dialog = utils.generateDomElementFromString('<div id="hmrc-timeout-dialog" tabindex="-1" role="dialog" aria-modal="true" class="hmrc-timeout-dialog">');
2590
+ var $overlay = utils.generateDomElementFromString('<div id="hmrc-timeout-overlay" class="hmrc-timeout-overlay">');
2591
+ var $preparedElementToDisplay = typeof $elementToDisplay === 'string' ? utils.generateDomElementFromString($elementToDisplay) : $elementToDisplay;
2592
+ var resetElementsFunctionList = [];
2593
+ var closeCallbacks = [];
2594
+ $dialog.appendChild($preparedElementToDisplay);
2535
2595
 
2536
- e.classList.constructor.prototype.toggle = function toggle(token
2537
- /*, force*/
2538
- ) {
2539
- var force = arguments[1];
2596
+ if (!utils.hasClass('html', 'noScroll')) {
2597
+ utils.addClass('html', 'noScroll');
2598
+ resetElementsFunctionList.push(function () {
2599
+ utils.removeClass('html', 'noScroll');
2600
+ });
2601
+ }
2540
2602
 
2541
- if (force === undefined) {
2542
- var add = !this.contains(token);
2543
- this[add ? 'add' : 'remove'](token);
2544
- return add;
2545
- }
2603
+ document.body.appendChild($dialog);
2604
+ document.body.appendChild($overlay);
2605
+ resetElementsFunctionList.push(function () {
2606
+ utils.removeElement($dialog);
2607
+ utils.removeElement($overlay);
2608
+ });
2546
2609
 
2547
- force = !!force;
2548
- this[force ? 'add' : 'remove'](token);
2549
- return force;
2550
- };
2551
- })(); // Add multiple arguments to native DOMTokenList.add() if necessary
2610
+ var setupFocusHandlerAndFocusDialog = function setupFocusHandlerAndFocusDialog() {
2611
+ function keepFocus(event) {
2612
+ var modalFocus = document.getElementById('hmrc-timeout-dialog');
2552
2613
 
2614
+ if (modalFocus) {
2615
+ if (event.target !== modalFocus && !modalFocus.contains(event.target)) {
2616
+ event.stopPropagation();
2617
+ modalFocus.focus();
2618
+ }
2619
+ }
2620
+ }
2553
2621
 
2554
- (function () {
2555
- var e = document.createElement('span');
2556
- if (!('classList' in e)) return;
2557
- e.classList.add('a', 'b');
2558
- if (e.classList.contains('b')) return;
2559
- var native = e.classList.constructor.prototype.add;
2622
+ var elemToFocusOnReset = document.activeElement;
2623
+ $dialog.focus();
2624
+ document.addEventListener('focus', keepFocus, true);
2625
+ resetElementsFunctionList.push(function () {
2626
+ document.removeEventListener('focus', keepFocus);
2627
+ elemToFocusOnReset.focus();
2628
+ });
2629
+ }; // disable the non-dialog page to prevent confusion for VoiceOver users
2560
2630
 
2561
- e.classList.constructor.prototype.add = function () {
2562
- var args = arguments;
2563
- var l = arguments.length;
2564
2631
 
2565
- for (var i = 0; i < l; i++) {
2566
- native.call(this, args[i]);
2567
- }
2568
- };
2569
- })(); // Add multiple arguments to native DOMTokenList.remove() if necessary
2632
+ var selectors = ['#skiplink-container', 'body > header', '#global-cookie-message', 'main[role=main]', 'body > footer', 'body > .govuk-skip-link', '.cbanner-govuk-cookie-banner', 'body > .govuk-width-container'];
2633
+ var elements = document.querySelectorAll(selectors.join(', '));
2570
2634
 
2635
+ var close = function close() {
2636
+ while (resetElementsFunctionList.length > 0) {
2637
+ var fn = resetElementsFunctionList.shift();
2638
+ fn();
2639
+ }
2640
+ };
2571
2641
 
2572
- (function () {
2573
- var e = document.createElement('span');
2574
- if (!('classList' in e)) return;
2575
- e.classList.add('a');
2576
- e.classList.add('b');
2577
- e.classList.remove('a', 'b');
2578
- if (!e.classList.contains('b')) return;
2579
- var native = e.classList.constructor.prototype.remove;
2642
+ var closeAndInform = function closeAndInform() {
2643
+ closeCallbacks.forEach(function (fn) {
2644
+ fn();
2645
+ });
2646
+ close();
2647
+ };
2580
2648
 
2581
- e.classList.constructor.prototype.remove = function () {
2582
- var args = arguments;
2583
- var l = arguments.length;
2649
+ var setupKeydownHandler = function setupKeydownHandler() {
2650
+ function keydownListener(e) {
2651
+ if (e.keyCode === 27) {
2652
+ closeAndInform();
2653
+ }
2654
+ }
2584
2655
 
2585
- for (var i = 0; i < l; i++) {
2586
- native.call(this, args[i]);
2587
- }
2588
- };
2589
- })();
2590
- })(this);
2591
- }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
2592
- (function (undefined) {
2593
- // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Document/detect.js
2594
- var detect = ("Document" in this);
2595
- if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Document&flags=always
2596
-
2597
- if (typeof WorkerGlobalScope === "undefined" && typeof importScripts !== "function") {
2598
- if (this.HTMLDocument) {
2599
- // IE8
2600
- // HTMLDocument is an extension of Document. If the browser has HTMLDocument but not Document, the former will suffice as an alias for the latter.
2601
- this.Document = this.HTMLDocument;
2602
- } else {
2603
- // 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.
2604
- this.Document = this.HTMLDocument = document.constructor = new Function('return function Document() {}')();
2605
- this.Document.prototype = document;
2606
- }
2607
- }
2608
- }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
2609
- (function (undefined) {
2610
- // Detection from https://github.com/Financial-Times/polyfill-service/blob/master/packages/polyfill-library/polyfills/Element/detect.js
2611
- var detect = 'Element' in this && 'HTMLElement' in this;
2612
- if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Element&flags=always
2613
-
2614
- (function () {
2615
- // IE8
2616
- if (window.Element && !window.HTMLElement) {
2617
- window.HTMLElement = window.Element;
2618
- return;
2619
- } // create Element constructor
2620
-
2621
-
2622
- window.Element = window.HTMLElement = new Function('return function Element() {}')(); // generate sandboxed iframe
2623
-
2624
- var vbody = document.appendChild(document.createElement('body'));
2625
- var frame = vbody.appendChild(document.createElement('iframe')); // use sandboxed iframe to replicate Element functionality
2626
-
2627
- var frameDocument = frame.contentWindow.document;
2628
- var prototype = Element.prototype = frameDocument.appendChild(frameDocument.createElement('*'));
2629
- var cache = {}; // polyfill Element.prototype on an element
2630
-
2631
- var shiv = function (element, deep) {
2632
- var childNodes = element.childNodes || [],
2633
- index = -1,
2634
- key,
2635
- value,
2636
- childNode;
2637
-
2638
- if (element.nodeType === 1 && element.constructor !== Element) {
2639
- element.constructor = Element;
2640
-
2641
- for (key in cache) {
2642
- value = cache[key];
2643
- element[key] = value;
2644
- }
2645
- }
2646
-
2647
- while (childNode = deep && childNodes[++index]) {
2648
- shiv(childNode, deep);
2649
- }
2650
-
2651
- return element;
2652
- };
2653
-
2654
- var elements = document.getElementsByTagName('*');
2655
- var nativeCreateElement = document.createElement;
2656
- var interval;
2657
- var loopLimit = 100;
2658
- prototype.attachEvent('onpropertychange', function (event) {
2659
- var propertyName = event.propertyName,
2660
- nonValue = !cache.hasOwnProperty(propertyName),
2661
- newValue = prototype[propertyName],
2662
- oldValue = cache[propertyName],
2663
- index = -1,
2664
- element;
2665
-
2666
- while (element = elements[++index]) {
2667
- if (element.nodeType === 1) {
2668
- if (nonValue || element[propertyName] === oldValue) {
2669
- element[propertyName] = newValue;
2670
- }
2671
- }
2672
- }
2673
-
2674
- cache[propertyName] = newValue;
2675
- });
2676
- prototype.constructor = Element;
2677
-
2678
- if (!prototype.hasAttribute) {
2679
- // <Element>.hasAttribute
2680
- prototype.hasAttribute = function hasAttribute(name) {
2681
- return this.getAttribute(name) !== null;
2682
- };
2683
- } // Apply Element prototype to the pre-existing DOM as soon as the body element appears.
2684
-
2685
-
2686
- function bodyCheck() {
2687
- if (!loopLimit--) clearTimeout(interval);
2656
+ document.addEventListener('keydown', keydownListener);
2657
+ resetElementsFunctionList.push(function () {
2658
+ document.removeEventListener('keydown', keydownListener);
2659
+ });
2660
+ };
2688
2661
 
2689
- if (document.body && !document.body.prototype && /(complete|interactive)/.test(document.readyState)) {
2690
- shiv(document, true);
2691
- if (interval && document.body.prototype) clearTimeout(interval);
2692
- return !!document.body.prototype;
2693
- }
2662
+ var preventMobileScrollWhileAllowingPinchZoom = function preventMobileScrollWhileAllowingPinchZoom() {
2663
+ var handleTouch = function handleTouch(e) {
2664
+ var touches = e.touches || e.changedTouches || [];
2694
2665
 
2695
- return false;
2666
+ if (touches.length === 1) {
2667
+ e.preventDefault();
2696
2668
  }
2669
+ };
2697
2670
 
2698
- if (!bodyCheck()) {
2699
- document.onreadystatechange = bodyCheck;
2700
- interval = setInterval(bodyCheck, 25);
2701
- } // Apply to any new elements created after load
2702
-
2703
-
2704
- document.createElement = function createElement(nodeName) {
2705
- var element = nativeCreateElement(String(nodeName).toLowerCase());
2706
- return shiv(element);
2707
- }; // remove sandboxed iframe
2708
-
2709
-
2710
- document.removeChild(vbody);
2711
- })();
2712
- }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
2713
- (function (undefined) {
2714
- // Detection from https://raw.githubusercontent.com/Financial-Times/polyfill-service/8717a9e04ac7aff99b4980fbedead98036b0929a/packages/polyfill-library/polyfills/Element/prototype/classList/detect.js
2715
- var detect = 'document' in this && "classList" in document.documentElement && 'Element' in this && 'classList' in Element.prototype && function () {
2716
- var e = document.createElement('span');
2717
- e.classList.add('a', 'b');
2718
- return e.classList.contains('b');
2719
- }();
2720
-
2721
- if (detect) return; // Polyfill from https://cdn.polyfill.io/v2/polyfill.js?features=Element.prototype.classList&flags=always
2722
-
2723
- (function (global) {
2724
- var dpSupport = true;
2725
-
2726
- var defineGetter = function (object, name, fn, configurable) {
2727
- if (Object.defineProperty) Object.defineProperty(object, name, {
2728
- configurable: false === dpSupport ? true : !!configurable,
2729
- get: fn
2730
- });else object.__defineGetter__(name, fn);
2731
- };
2732
- /** Ensure the browser allows Object.defineProperty to be used on native JavaScript objects. */
2733
-
2671
+ document.addEventListener('touchmove', handleTouch, true);
2672
+ resetElementsFunctionList.push(function () {
2673
+ document.removeEventListener('touchmove', handleTouch, true);
2674
+ });
2675
+ };
2734
2676
 
2735
- try {
2736
- defineGetter({}, "support");
2737
- } catch (e) {
2738
- dpSupport = false;
2677
+ nodeListForEach(elements, function ($elem) {
2678
+ var value = $elem.getAttribute('aria-hidden');
2679
+ $elem.setAttribute('aria-hidden', 'true');
2680
+ resetElementsFunctionList.push(function () {
2681
+ if (value) {
2682
+ $elem.setAttribute('aria-hidden', value);
2683
+ } else {
2684
+ $elem.removeAttribute('aria-hidden');
2739
2685
  }
2740
- /** Polyfills a property with a DOMTokenList */
2741
-
2742
-
2743
- var addProp = function (o, name, attr) {
2744
- defineGetter(o.prototype, name, function () {
2745
- var tokenList;
2746
- var THIS = this,
2747
-
2748
- /** Prevent this from firing twice for some reason. What the hell, IE. */
2749
- gibberishProperty = "__defineGetter__" + "DEFINE_PROPERTY" + name;
2750
- if (THIS[gibberishProperty]) return tokenList;
2751
- THIS[gibberishProperty] = true;
2752
- /**
2753
- * IE8 can't define properties on native JavaScript objects, so we'll use a dumb hack instead.
2754
- *
2755
- * What this is doing is creating a dummy element ("reflection") inside a detached phantom node ("mirror")
2756
- * that serves as the target of Object.defineProperty instead. While we could simply use the subject HTML
2757
- * element instead, this would conflict with element types which use indexed properties (such as forms and
2758
- * select lists).
2759
- */
2760
-
2761
- if (false === dpSupport) {
2762
- var visage;
2763
- var mirror = addProp.mirror || document.createElement("div");
2764
- var reflections = mirror.childNodes;
2765
- var l = reflections.length;
2766
-
2767
- for (var i = 0; i < l; ++i) if (reflections[i]._R === THIS) {
2768
- visage = reflections[i];
2769
- break;
2770
- }
2771
- /** Couldn't find an element's reflection inside the mirror. Materialise one. */
2772
-
2773
-
2774
- visage || (visage = mirror.appendChild(document.createElement("div")));
2775
- tokenList = DOMTokenList.call(visage, THIS, attr);
2776
- } else tokenList = new DOMTokenList(THIS, attr);
2686
+ });
2687
+ }); //
2777
2688
 
2778
- defineGetter(THIS, name, function () {
2779
- return tokenList;
2780
- });
2781
- delete THIS[gibberishProperty];
2782
- return tokenList;
2783
- }, true);
2784
- };
2689
+ setupFocusHandlerAndFocusDialog();
2690
+ setupKeydownHandler();
2691
+ preventMobileScrollWhileAllowingPinchZoom();
2692
+ return {
2693
+ closeDialog: function closeDialog() {
2694
+ close();
2695
+ },
2696
+ setAriaLabelledBy: function setAriaLabelledBy(value) {
2697
+ if (value) {
2698
+ $dialog.setAttribute('aria-labelledby', value);
2699
+ } else {
2700
+ $dialog.removeAttribute('aria-labelledby');
2701
+ }
2702
+ },
2703
+ addCloseHandler: function addCloseHandler(closeHandler) {
2704
+ closeCallbacks.push(closeHandler);
2705
+ }
2706
+ };
2707
+ }
2785
2708
 
2786
- addProp(global.Element, "classList", "className");
2787
- addProp(global.HTMLElement, "classList", "className");
2788
- addProp(global.HTMLLinkElement, "relList", "rel");
2789
- addProp(global.HTMLAnchorElement, "relList", "rel");
2790
- addProp(global.HTMLAreaElement, "relList", "rel");
2791
- })(this);
2792
- }).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof commonjsGlobal && commonjsGlobal || {});
2793
- });
2794
- });
2709
+ var dialog = {
2710
+ displayDialog: displayDialog
2711
+ };
2795
2712
 
2796
- // https://github.com/alphagov/govuk-frontend/blob/main/src/govuk/components/character-count/character-count.js
2797
- // with the change to support Welsh language messages. At the moment, there is no ability to pass
2798
- // in custom messages to the component for the dynamic count. If GDS release a version supporting
2799
- // custom dynamic count messages, this version should be removed.
2800
- // Linting is disabled to keep aligned with govuk-frontend
2713
+ // Polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN
2714
+ Number.isNaN = Number.isNaN || function isNaN(input) {
2715
+ return typeof input === 'number' && input !== input;
2716
+ };
2801
2717
 
2802
- /* eslint-disable */
2718
+ function ValidateInput() {}
2803
2719
 
2804
- function CharacterCount($module) {
2805
- this.$module = $module;
2806
- this.$textarea = $module.querySelector('.hmrc-js-character-count');
2807
- this.$visibleCountMessage = null;
2808
- this.$screenReaderCountMessage = null;
2809
- this.lastInputTimestamp = null;
2810
- }
2720
+ ValidateInput["int"] = function (stringToValidate) {
2721
+ var parsedInt = parseInt(stringToValidate, 10);
2722
+ return Number.isNaN(parsedInt) ? undefined : parsedInt;
2723
+ };
2811
2724
 
2812
- CharacterCount.prototype.defaults = {
2813
- characterCountAttribute: 'data-maxlength',
2814
- wordCountAttribute: 'data-maxwords'
2815
- }; // Initialize component
2725
+ ValidateInput.string = function (stringToValidate) {
2726
+ return typeof stringToValidate === 'string' ? stringToValidate : undefined;
2727
+ };
2816
2728
 
2817
- CharacterCount.prototype.init = function () {
2818
- // Check that required elements are present
2819
- if (!this.$textarea) {
2820
- return;
2821
- } // Check for module
2729
+ ValidateInput["boolean"] = function (stringToValidate) {
2730
+ return String(stringToValidate).toLowerCase() === 'true';
2731
+ };
2822
2732
 
2733
+ function RedirectHelper() {}
2823
2734
 
2824
- var $module = this.$module;
2825
- var $textarea = this.$textarea;
2826
- var $fallbackLimitMessage = document.getElementById($textarea.id + '-info'); // Move the fallback count message to be immediately after the textarea
2827
- // Kept for backwards compatibility
2735
+ RedirectHelper.redirectToUrl = function (url) {
2736
+ // This exists to make redirects more testable
2737
+ window.location.href = url;
2738
+ };
2828
2739
 
2829
- $textarea.insertAdjacentElement('afterend', $fallbackLimitMessage); // Create the *screen reader* specific live-updating counter
2830
- // This doesn't need any styling classes, as it is never visible
2740
+ function TimeoutDialog($module, $sessionActivityService) {
2741
+ var options = {};
2742
+ var settings = {};
2743
+ var cleanupFunctions = [];
2744
+ var currentTimer;
2745
+ var sessionActivityService = $sessionActivityService;
2746
+ cleanupFunctions.push(function () {
2747
+ if (currentTimer) {
2748
+ window.clearTimeout(currentTimer);
2749
+ }
2750
+ });
2831
2751
 
2832
- var $screenReaderCountMessage = document.createElement('div');
2833
- $screenReaderCountMessage.className = 'hmrc-character-count__sr-status govuk-visually-hidden';
2834
- $screenReaderCountMessage.setAttribute('aria-live', 'polite');
2835
- this.$screenReaderCountMessage = $screenReaderCountMessage;
2836
- $fallbackLimitMessage.insertAdjacentElement('afterend', $screenReaderCountMessage); // Create our live-updating counter element, copying the classes from the
2837
- // fallback element for backwards compatibility as these may have been configured
2752
+ function init() {
2753
+ var validate = ValidateInput;
2838
2754
 
2839
- var $visibleCountMessage = document.createElement('div');
2840
- $visibleCountMessage.className = $fallbackLimitMessage.className;
2841
- $visibleCountMessage.classList.add('hmrc-character-count__status');
2842
- $visibleCountMessage.setAttribute('aria-hidden', 'true');
2843
- this.$visibleCountMessage = $visibleCountMessage;
2844
- $fallbackLimitMessage.insertAdjacentElement('afterend', $visibleCountMessage); // Hide the fallback limit message
2755
+ function lookupData(key) {
2756
+ return ($module.attributes.getNamedItem(key) || {}).value;
2757
+ }
2845
2758
 
2846
- $fallbackLimitMessage.classList.add('govuk-visually-hidden'); // Read options set using dataset ('data-' values)
2759
+ var localisedDefaults = validate.string(lookupData('data-language')) === 'cy' ? {
2760
+ title: 'Rydych ar fin cael eich allgofnodi',
2761
+ message: 'Er eich diogelwch, byddwn yn eich allgofnodi cyn pen',
2762
+ keepAliveButtonText: 'Parhau i fod wedi’ch mewngofnodi',
2763
+ signOutButtonText: 'Allgofnodi',
2764
+ properties: {
2765
+ minutes: 'funud',
2766
+ minute: 'funud',
2767
+ seconds: 'eiliad',
2768
+ second: 'eiliad'
2769
+ }
2770
+ } : {
2771
+ title: 'You’re about to be signed out',
2772
+ message: 'For your security, we will sign you out in',
2773
+ keepAliveButtonText: 'Stay signed in',
2774
+ signOutButtonText: 'Sign out',
2775
+ properties: {
2776
+ minutes: 'minutes',
2777
+ minute: 'minute',
2778
+ seconds: 'seconds',
2779
+ second: 'second'
2780
+ }
2781
+ };
2782
+ options = {
2783
+ timeout: validate["int"](lookupData('data-timeout')),
2784
+ countdown: validate["int"](lookupData('data-countdown')),
2785
+ keepAliveUrl: validate.string(lookupData('data-keep-alive-url')),
2786
+ signOutUrl: validate.string(lookupData('data-sign-out-url')),
2787
+ timeoutUrl: validate.string(lookupData('data-timeout-url')),
2788
+ title: validate.string(lookupData('data-title')),
2789
+ message: validate.string(lookupData('data-message')),
2790
+ messageSuffix: validate.string(lookupData('data-message-suffix')),
2791
+ keepAliveButtonText: validate.string(lookupData('data-keep-alive-button-text')),
2792
+ signOutButtonText: validate.string(lookupData('data-sign-out-button-text')),
2793
+ synchroniseTabs: validate["boolean"](lookupData('data-synchronise-tabs') || false)
2794
+ }; // Default timeoutUrl to signOutUrl if not set
2847
2795
 
2848
- this.options = this.getDataset($module); // Determine the limit attribute (characters or words)
2796
+ options.timeoutUrl = options.timeoutUrl || options.signOutUrl;
2797
+ validateInput(options);
2798
+ settings = mergeOptionsWithDefaults(options, localisedDefaults);
2799
+ setupDialogTimer();
2800
+ listenForSessionActivityAndResetDialogTimer();
2801
+ }
2849
2802
 
2850
- var countAttribute = this.defaults.characterCountAttribute;
2803
+ var broadcastSessionActivity = function broadcastSessionActivity() {
2804
+ sessionActivityService.logActivity();
2805
+ };
2851
2806
 
2852
- if (this.options.maxwords) {
2853
- countAttribute = this.defaults.wordCountAttribute;
2854
- } // Save the element limit
2807
+ var listenForSessionActivityAndResetDialogTimer = function listenForSessionActivityAndResetDialogTimer() {
2808
+ if (settings.synchroniseTabs) {
2809
+ sessionActivityService.onActivity(function (event) {
2810
+ var timeOfActivity = event.timestamp;
2811
+ cleanup();
2812
+ setupDialogTimer(timeOfActivity);
2813
+ });
2814
+ }
2815
+ };
2855
2816
 
2817
+ var validateInput = function validateInput(config) {
2818
+ var requiredConfig = ['timeout', 'countdown', 'keepAliveUrl', 'signOutUrl'];
2819
+ var missingRequiredConfig = [];
2820
+ requiredConfig.forEach(function (item) {
2821
+ if (!config[item]) {
2822
+ missingRequiredConfig.push("data-".concat(item.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()));
2823
+ }
2824
+ });
2856
2825
 
2857
- this.maxLength = $module.getAttribute(countAttribute); // Check for limit
2826
+ if (missingRequiredConfig.length > 0) {
2827
+ throw new Error("Missing config item(s): [".concat(missingRequiredConfig.join(', '), "]"));
2828
+ }
2829
+ };
2858
2830
 
2859
- if (!this.maxLength) {
2860
- return;
2861
- } // Remove hard limit if set
2831
+ var mergeOptionsWithDefaults = function mergeOptionsWithDefaults(theOptions, localisedDefaults) {
2832
+ var clone = _objectSpread2({}, theOptions);
2862
2833
 
2834
+ Object.keys(localisedDefaults).forEach(function (key) {
2835
+ if (_typeof(clone[key]) === 'object') {
2836
+ clone[key] = mergeOptionsWithDefaults(theOptions[key], localisedDefaults[key]);
2837
+ }
2863
2838
 
2864
- $textarea.removeAttribute('maxlength');
2865
- this.bindChangeEvents(); // When the page is restored after navigating 'back' in some browsers the
2866
- // state of the character count is not restored until *after* the DOMContentLoaded
2867
- // event is fired, so we need to manually update it after the pageshow event
2868
- // in browsers that support it.
2839
+ if (clone[key] === undefined || clone[key] === '') {
2840
+ clone[key] = localisedDefaults[key];
2841
+ }
2842
+ });
2843
+ return clone;
2844
+ };
2869
2845
 
2870
- if ('onpageshow' in window) {
2871
- window.addEventListener('pageshow', this.updateCountMessage.bind(this));
2872
- } else {
2873
- window.addEventListener('DOMContentLoaded', this.updateCountMessage.bind(this));
2874
- }
2846
+ var setupDialogTimer = function setupDialogTimer() {
2847
+ var timeOfLastActivity = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getDateNow();
2848
+ var signoutTime = timeOfLastActivity + settings.timeout * 1000;
2849
+ var delta = getDateNow() - timeOfLastActivity;
2850
+ var secondsUntilTimeoutDialog = settings.timeout - settings.countdown;
2851
+ var timeout = window.setTimeout(function () {
2852
+ setupDialog(signoutTime);
2853
+ }, secondsUntilTimeoutDialog * 1000 - delta);
2854
+ cleanupFunctions.push(function () {
2855
+ window.clearTimeout(timeout);
2856
+ });
2857
+ };
2875
2858
 
2876
- this.updateCountMessage();
2877
- }; // Read data attributes
2859
+ var wrapLink = function wrapLink($elem) {
2860
+ var $wrapper = document.createElement('div');
2861
+ $wrapper.classList.add('hmrc-timeout-dialog__link-wrapper');
2862
+ $wrapper.appendChild($elem);
2863
+ return $wrapper;
2864
+ };
2878
2865
 
2866
+ var setupDialog = function setupDialog(signoutTime) {
2867
+ var $element = utils.generateDomElementFromString('<div>');
2879
2868
 
2880
- CharacterCount.prototype.getDataset = function (element) {
2881
- var dataset = {};
2882
- var attributes = element.attributes;
2869
+ if (settings.title) {
2870
+ var $tmp = utils.generateDomElementFromStringAndAppendText('<h1 id="hmrc-timeout-heading" class="govuk-heading-m push--top">', settings.title);
2871
+ $element.appendChild($tmp);
2872
+ }
2883
2873
 
2884
- if (attributes) {
2885
- for (var i = 0; i < attributes.length; i++) {
2886
- var attribute = attributes[i];
2887
- var match = attribute.name.match(/^data-(.+)/);
2874
+ var $countdownElement = utils.generateDomElementFromString('<span id="hmrc-timeout-countdown" class="hmrc-timeout-dialog__countdown">');
2875
+ var $audibleMessage = utils.generateDomElementFromString('<p id="hmrc-timeout-message" class="govuk-visually-hidden screenreader-content" aria-live="assertive">');
2876
+ var $visualMessge = utils.generateDomElementFromStringAndAppendText('<p class="govuk-body hmrc-timeout-dialog__message" aria-hidden="true">', settings.message);
2877
+ $visualMessge.appendChild(document.createTextNode(' '));
2878
+ $visualMessge.appendChild($countdownElement);
2879
+ $visualMessge.appendChild(document.createTextNode('.'));
2888
2880
 
2889
- if (match) {
2890
- dataset[match[1]] = attribute.value;
2891
- }
2881
+ if (settings.messageSuffix) {
2882
+ $visualMessge.appendChild(document.createTextNode(" ".concat(settings.messageSuffix)));
2892
2883
  }
2893
- }
2894
2884
 
2895
- return dataset;
2896
- }; // Counts characters or words in text
2885
+ var $staySignedInButton = utils.generateDomElementFromStringAndAppendText('<button id="hmrc-timeout-keep-signin-btn" class="govuk-button">', settings.keepAliveButtonText);
2886
+ var $signOutButton = utils.generateDomElementFromStringAndAppendText('<a id="hmrc-timeout-sign-out-link" class="govuk-link hmrc-timeout-dialog__link">', settings.signOutButtonText);
2887
+ $staySignedInButton.addEventListener('click', keepAliveAndClose);
2888
+ $signOutButton.addEventListener('click', signOut);
2889
+ $signOutButton.setAttribute('href', settings.signOutUrl);
2890
+ $element.appendChild($visualMessge);
2891
+ $element.appendChild($audibleMessage);
2892
+ $element.appendChild($staySignedInButton);
2893
+ $element.appendChild(document.createTextNode(' '));
2894
+ $element.appendChild(wrapLink($signOutButton));
2895
+ var dialogControl = dialog.displayDialog($element);
2896
+ cleanupFunctions.push(function () {
2897
+ dialogControl.closeDialog();
2898
+ });
2899
+ dialogControl.addCloseHandler(keepAliveAndClose);
2900
+ dialogControl.setAriaLabelledBy('hmrc-timeout-heading hmrc-timeout-message');
2901
+
2902
+ var getMillisecondsRemaining = function getMillisecondsRemaining() {
2903
+ return signoutTime - getDateNow();
2904
+ };
2897
2905
 
2906
+ var getSecondsRemaining = function getSecondsRemaining() {
2907
+ return Math.round(getMillisecondsRemaining() / 1000);
2908
+ };
2898
2909
 
2899
- CharacterCount.prototype.count = function (text) {
2900
- var length;
2910
+ var getHumanText = function getHumanText(counter) {
2911
+ var minutes;
2912
+ var visibleMessage;
2901
2913
 
2902
- if (this.options.maxwords) {
2903
- var tokens = text.match(/\S+/g) || []; // Matches consecutive non-whitespace chars
2914
+ if (counter < 60) {
2915
+ visibleMessage = "".concat(counter, " ").concat(settings.properties[counter !== 1 ? 'seconds' : 'second']);
2916
+ } else {
2917
+ minutes = Math.ceil(counter / 60);
2918
+ visibleMessage = "".concat(minutes, " ").concat(settings.properties[minutes === 1 ? 'minute' : 'minutes']);
2919
+ }
2904
2920
 
2905
- length = tokens.length;
2906
- } else {
2907
- length = text.length;
2908
- }
2921
+ return visibleMessage;
2922
+ };
2909
2923
 
2910
- return length;
2911
- }; // Bind input propertychange to the elements and update based on the change
2924
+ var getAudibleHumanText = function getAudibleHumanText(counter) {
2925
+ var humanText = getHumanText(roundSecondsUp(counter));
2926
+ var messageParts = [settings.message, ' ', humanText, '.'];
2912
2927
 
2928
+ if (settings.messageSuffix) {
2929
+ messageParts.push(' ');
2930
+ messageParts.push(settings.messageSuffix);
2931
+ }
2913
2932
 
2914
- CharacterCount.prototype.bindChangeEvents = function () {
2915
- var $textarea = this.$textarea;
2916
- $textarea.addEventListener('keyup', this.handleKeyUp.bind(this)); // Bind focus/blur events to start/stop polling
2933
+ return messageParts.join('');
2934
+ };
2917
2935
 
2918
- $textarea.addEventListener('focus', this.handleFocus.bind(this));
2919
- $textarea.addEventListener('blur', this.handleBlur.bind(this));
2920
- }; // Speech recognition software such as Dragon NaturallySpeaking will modify the
2921
- // fields by directly changing its `value`. These changes don't trigger events
2922
- // in JavaScript, so we need to poll to handle when and if they occur.
2936
+ var roundSecondsUp = function roundSecondsUp(counter) {
2937
+ if (counter > 60) {
2938
+ return counter;
2939
+ }
2923
2940
 
2941
+ if (counter < 20) {
2942
+ return 20;
2943
+ }
2924
2944
 
2925
- CharacterCount.prototype.checkIfValueChanged = function () {
2926
- if (!this.$textarea.oldValue) this.$textarea.oldValue = '';
2945
+ return Math.ceil(counter / 20) * 20;
2946
+ };
2927
2947
 
2928
- if (this.$textarea.value !== this.$textarea.oldValue) {
2929
- this.$textarea.oldValue = this.$textarea.value;
2930
- this.updateCountMessage();
2931
- }
2932
- }; // Helper function to update both the visible and screen reader-specific
2933
- // counters simultaneously (e.g. on init)
2948
+ var updateTextIfChanged = function updateTextIfChanged($elem, text) {
2949
+ if ($elem.innerText !== text) {
2950
+ // eslint-disable-next-line no-param-reassign
2951
+ $elem.innerText = text;
2952
+ }
2953
+ };
2934
2954
 
2955
+ var updateCountdown = function updateCountdown(counter) {
2956
+ var visibleMessage = getHumanText(counter);
2957
+ var audibleHumanText = getAudibleHumanText(counter);
2958
+ updateTextIfChanged($countdownElement, visibleMessage);
2959
+ updateTextIfChanged($audibleMessage, audibleHumanText);
2960
+ };
2935
2961
 
2936
- CharacterCount.prototype.updateCountMessage = function () {
2937
- this.updateVisibleCountMessage();
2938
- this.updateScreenReaderCountMessage();
2939
- }; // Update visible counter
2962
+ var getNextTimeout = function getNextTimeout() {
2963
+ var remaining = getMillisecondsRemaining();
2964
+ var roundedRemaining = Math.floor(getMillisecondsRemaining() / 1000) * 1000;
2940
2965
 
2966
+ if (roundedRemaining <= 60000) {
2967
+ return remaining - roundedRemaining || 1000;
2968
+ }
2941
2969
 
2942
- CharacterCount.prototype.updateVisibleCountMessage = function () {
2943
- var $textarea = this.$textarea;
2944
- var $visibleCountMessage = this.$visibleCountMessage;
2945
- var remainingNumber = this.maxLength - this.count($textarea.value); // If input is over the threshold, remove the disabled class which renders the
2946
- // counter invisible.
2970
+ return remaining - (roundedRemaining - (roundedRemaining % 60000 || 60000));
2971
+ };
2947
2972
 
2948
- if (this.isOverThreshold()) {
2949
- $visibleCountMessage.classList.remove('hmrc-character-count__message--disabled');
2950
- } else {
2951
- $visibleCountMessage.classList.add('hmrc-character-count__message--disabled');
2952
- } // Update styles
2973
+ var runUpdate = function runUpdate() {
2974
+ var counter = getSecondsRemaining();
2975
+ updateCountdown(counter);
2953
2976
 
2977
+ if (counter <= 0) {
2978
+ timeout();
2979
+ }
2954
2980
 
2955
- if (remainingNumber < 0) {
2956
- $textarea.classList.add('govuk-textarea--error');
2957
- $visibleCountMessage.classList.remove('govuk-hint');
2958
- $visibleCountMessage.classList.add('govuk-error-message');
2959
- } else {
2960
- $textarea.classList.remove('govuk-textarea--error');
2961
- $visibleCountMessage.classList.remove('govuk-error-message');
2962
- $visibleCountMessage.classList.add('govuk-hint');
2963
- } // Update message
2981
+ currentTimer = window.setTimeout(runUpdate, getNextTimeout());
2982
+ };
2964
2983
 
2984
+ runUpdate();
2985
+ };
2965
2986
 
2966
- $visibleCountMessage.innerHTML = this.formattedUpdateMessage();
2967
- }; // Update screen reader-specific counter
2987
+ var keepAliveAndClose = function keepAliveAndClose() {
2988
+ cleanup();
2989
+ setupDialogTimer();
2990
+ utils.ajaxGet(settings.keepAliveUrl, function () {});
2991
+ broadcastSessionActivity();
2992
+ };
2968
2993
 
2994
+ var getDateNow = function getDateNow() {
2995
+ return Date.now();
2996
+ };
2969
2997
 
2970
- CharacterCount.prototype.updateScreenReaderCountMessage = function () {
2971
- var $screenReaderCountMessage = this.$screenReaderCountMessage; // If over the threshold, remove the aria-hidden attribute, allowing screen
2972
- // readers to announce the content of the element.
2998
+ var signOut = function signOut() {
2999
+ RedirectHelper.redirectToUrl(settings.signOutUrl);
3000
+ };
2973
3001
 
2974
- if (this.isOverThreshold()) {
2975
- $screenReaderCountMessage.removeAttribute('aria-hidden');
2976
- } else {
2977
- $screenReaderCountMessage.setAttribute('aria-hidden', true);
2978
- } // Update message
3002
+ var timeout = function timeout() {
3003
+ RedirectHelper.redirectToUrl(settings.timeoutUrl);
3004
+ };
2979
3005
 
3006
+ var cleanup = function cleanup() {
3007
+ while (cleanupFunctions.length > 0) {
3008
+ var fn = cleanupFunctions.shift();
3009
+ fn();
3010
+ }
3011
+ };
2980
3012
 
2981
- $screenReaderCountMessage.innerHTML = this.formattedUpdateMessage();
2982
- }; // Format update message
3013
+ return {
3014
+ init: init,
3015
+ cleanup: cleanup
3016
+ };
3017
+ }
2983
3018
 
3019
+ TimeoutDialog.dialog = dialog;
3020
+ TimeoutDialog.redirectHelper = RedirectHelper;
3021
+ TimeoutDialog.utils = utils;
2984
3022
 
2985
- CharacterCount.prototype.formattedUpdateMessage = function () {
2986
- var $textarea = this.$textarea;
2987
- var options = this.options;
2988
- var remainingNumber = this.maxLength - this.count($textarea.value);
2989
- var isWelsh = this.options.language === 'cy';
2990
- var charVerb;
2991
- var charNoun;
2992
- var charStartMessage = isWelsh ? 'Mae gennych ' : 'You have ';
3023
+ // Based on https://github.com/alphagov/govuk_template_jinja
3024
+ var setCookie = function setCookie(name, value) {
3025
+ var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
3026
+ var cookieString = "".concat(name, "=").concat(value, "; path=/");
2993
3027
 
2994
- if (options.maxwords) {
2995
- if (remainingNumber === -1 || remainingNumber === 1) {
2996
- charNoun = isWelsh ? 'gair' : 'word';
2997
- } else {
2998
- charNoun = isWelsh ? 'o eiriau' : 'words';
2999
- }
3000
- } else if (remainingNumber === -1 || remainingNumber === 1) {
3001
- charNoun = isWelsh ? 'cymeriad' : 'character';
3002
- } else {
3003
- charNoun = isWelsh ? 'o gymeriadau' : 'characters';
3028
+ if (options.days) {
3029
+ var date = new Date();
3030
+ date.setTime(date.getTime() + options.days * 24 * 60 * 60 * 1000);
3031
+ cookieString = "".concat(cookieString, "; expires=").concat(date.toGMTString());
3004
3032
  }
3005
3033
 
3006
- if (remainingNumber < 0) {
3007
- charVerb = isWelsh ? 'yn ormod' : 'too many';
3008
- } else {
3009
- charVerb = isWelsh ? 'yn weddill' : 'remaining';
3034
+ if (window.location.protocol === 'https:') {
3035
+ cookieString += '; Secure';
3010
3036
  }
3011
3037
 
3012
- var displayNumber = Math.abs(remainingNumber);
3013
- return charStartMessage + displayNumber + ' ' + charNoun + ' ' + charVerb;
3014
- }; // Checks whether the value is over the configured threshold for the input.
3015
- // If there is no configured threshold, it is set to 0 and this function will
3016
- // always return true.
3038
+ document.cookie = cookieString;
3039
+ return cookieString;
3040
+ };
3041
+ var getCookie = function getCookie(name) {
3042
+ var nameEQ = "".concat(name, "=");
3043
+ var cookies = document.cookie.split(';');
3017
3044
 
3045
+ for (var i = 0, len = cookies.length; i < len; i += 1) {
3046
+ var cookie = cookies[i];
3018
3047
 
3019
- CharacterCount.prototype.isOverThreshold = function () {
3020
- var $textarea = this.$textarea;
3021
- var options = this.options; // Determine the remaining number of characters/words
3048
+ while (cookie.charAt(0) === ' ') {
3049
+ cookie = cookie.substring(1, cookie.length);
3050
+ }
3022
3051
 
3023
- var currentLength = this.count($textarea.value);
3024
- var maxLength = this.maxLength; // Set threshold if presented in options
3052
+ if (cookie.indexOf(nameEQ) === 0) {
3053
+ return decodeURIComponent(cookie.substring(nameEQ.length));
3054
+ }
3055
+ }
3025
3056
 
3026
- var thresholdPercent = options.threshold ? options.threshold : 0;
3027
- var thresholdValue = maxLength * thresholdPercent / 100;
3028
- return thresholdValue <= currentLength;
3029
- }; // Update the visible character counter and keep track of when the last update
3030
- // happened for each keypress
3057
+ return null;
3058
+ };
3031
3059
 
3060
+ function UserResearchBanner($module) {
3061
+ this.$module = $module;
3062
+ this.$closeLink = this.$module.querySelector('.hmrc-user-research-banner__close');
3063
+ this.cookieName = 'mdtpurr';
3064
+ this.cookieExpiryDays = 28;
3065
+ }
3032
3066
 
3033
- CharacterCount.prototype.handleKeyUp = function () {
3034
- this.updateVisibleCountMessage();
3035
- this.lastInputTimestamp = Date.now();
3036
- };
3067
+ UserResearchBanner.prototype.init = function init() {
3068
+ var cookieData = getCookie(this.cookieName);
3037
3069
 
3038
- CharacterCount.prototype.handleFocus = function () {
3039
- // If the field is focused, and a keyup event hasn't been detected for at
3040
- // least 1000 ms (1 second), then run the manual change check.
3041
- // This is so that the update triggered by the manual comparison doesn't
3042
- // conflict with debounced KeyboardEvent updates.
3043
- this.valueChecker = setInterval(function () {
3044
- if (!this.lastInputTimestamp || Date.now() - 500 >= this.lastInputTimestamp) {
3045
- this.checkIfValueChanged();
3046
- }
3047
- }.bind(this), 1000);
3070
+ if (cookieData == null) {
3071
+ this.$module.classList.add('hmrc-user-research-banner--show');
3072
+ this.$closeLink.addEventListener('click', this.eventHandlers.noThanksClick.bind(this));
3073
+ }
3048
3074
  };
3049
3075
 
3050
- CharacterCount.prototype.handleBlur = function () {
3051
- // Cancel value checking on blur
3052
- clearInterval(this.valueChecker);
3076
+ UserResearchBanner.prototype.eventHandlers = {
3077
+ noThanksClick: function noThanksClick(event) {
3078
+ event.preventDefault();
3079
+ setCookie(this.cookieName, 'suppress_for_all_services', {
3080
+ days: this.cookieExpiryDays
3081
+ });
3082
+ this.$module.classList.remove('hmrc-user-research-banner--show');
3083
+ }
3053
3084
  };
3054
3085
 
3055
3086
  var SessionActivityService = /*#__PURE__*/function () {
@@ -3104,6 +3135,10 @@
3104
3135
  new UserResearchBanner($UserResearchBanner).init();
3105
3136
  }
3106
3137
 
3138
+ var $BackLinks = document.querySelectorAll('[data-module="hmrc-back-link"]');
3139
+ nodeListForEach($BackLinks, function ($BackLink) {
3140
+ new BackLinkHelper($BackLink, window, document).init();
3141
+ });
3107
3142
  var $CharacterCounts = document.querySelectorAll('[data-module="hmrc-character-count"]');
3108
3143
  nodeListForEach($CharacterCounts, function ($CharacterCount) {
3109
3144
  new CharacterCount($CharacterCount).init();
@@ -3115,7 +3150,8 @@
3115
3150
  AccountMenu: AccountMenu,
3116
3151
  TimeoutDialog: TimeoutDialog,
3117
3152
  UserResearchBanner: UserResearchBanner,
3118
- CharacterCount: CharacterCount
3153
+ CharacterCount: CharacterCount,
3154
+ BackLinkHelper: BackLinkHelper
3119
3155
  };
3120
3156
 
3121
3157
  return all;