digitalmarketplace-frontend
Version:
Digital Marketplace Frontend contains assets and components used in Digital Marketplace projects
1,259 lines (1,241 loc) • 223 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.DigitalMarketplaceFrontend = {}));
})(this, (function (exports) { 'use strict';
/*
* This variable is automatically overwritten during builds and releases.
* It doesn't need to be updated manually.
*/
/**
* Digital Marketplace Frontend release version
*
* {@link https://github.com/Crown-Commercial-Service/ccs-digitalmarketplace-govuk-frontend/releases}
*/
const version = '3.8.0';
const GOOGLE_TAG_MANAGER_ID = 'GTM-WCGFX3GW';
const googleTagManagerInit = (w, d, s, l, i) => {
w[l] = w[l] || [];
w[l].push({
'gtm.start': new Date().getTime(),
event: 'gtm.js'
});
const f = d.getElementsByTagName(s)[0];
const j = d.createElement(s);
const dl = '';
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
f.parentNode.insertBefore(j, f);
};
const loadGoogleTagManager = () => googleTagManagerInit(window, document, 'script', 'dataLayer', GOOGLE_TAG_MANAGER_ID);
function assign(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
target[key] = source[key];
}
}
return target;
}
var defaultConverter = {
read: function read(value) {
if (value[0] === '"') {
value = value.slice(1, -1);
}
return value.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent);
},
write: function write(value) {
return encodeURIComponent(value).replace(/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g, decodeURIComponent);
}
};
function init(converter, defaultAttributes) {
function set(name, value, attributes) {
if (typeof document === 'undefined') {
return;
}
attributes = assign({}, defaultAttributes, attributes);
if (typeof attributes.expires === 'number') {
attributes.expires = new Date(Date.now() + attributes.expires * 864e5);
}
if (attributes.expires) {
attributes.expires = attributes.expires.toUTCString();
}
name = encodeURIComponent(name).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent).replace(/[()]/g, escape);
var stringifiedAttributes = '';
for (var attributeName in attributes) {
if (!attributes[attributeName]) {
continue;
}
stringifiedAttributes += '; ' + attributeName;
if (attributes[attributeName] === true) {
continue;
}
stringifiedAttributes += '=' + attributes[attributeName].split(';')[0];
}
return document.cookie = name + '=' + converter.write(value, name) + stringifiedAttributes;
}
function get(name) {
if (typeof document === 'undefined' || arguments.length && !name) {
return;
}
var cookies = document.cookie ? document.cookie.split('; ') : [];
var jar = {};
for (var i = 0; i < cookies.length; i++) {
var parts = cookies[i].split('=');
var value = parts.slice(1).join('=');
try {
var found = decodeURIComponent(parts[0]);
jar[found] = converter.read(value, found);
if (name === found) {
break;
}
} catch (e) {}
}
return name ? jar[name] : jar;
}
return Object.create({
set: set,
get: get,
remove: function remove(name, attributes) {
set(name, '', assign({}, attributes, {
expires: -1
}));
},
withAttributes: function withAttributes(attributes) {
return init(this.converter, assign({}, this.attributes, attributes));
},
withConverter: function withConverter(converter) {
return init(assign({}, this.converter, converter), this.attributes);
}
}, {
attributes: {
value: Object.freeze(defaultAttributes)
},
converter: {
value: Object.freeze(converter)
}
});
}
var api = init(defaultConverter, {
path: '/'
});
var GrantType;
(function (GrantType) {
GrantType["GRANTED"] = "granted";
GrantType["NOT_GRANTED"] = "not granted";
})(GrantType || (GrantType = {}));
const getGrantedText = (state) => state ? GrantType.GRANTED : GrantType.NOT_GRANTED;
const updateDataLayer = (cookiePreferences) => {
window.dataLayer.push({
event: 'gtm_consent_update',
usage_consent: getGrantedText(cookiePreferences.usage),
glassbox_consent: getGrantedText(cookiePreferences.glassbox),
marketing_consent: GrantType.NOT_GRANTED
});
};
const cookieUpdateOptions = [
{
cookieName: 'usage',
cookiePrefixes: ['_ga', '_gi']
},
{
cookieName: 'glassbox',
cookiePrefixes: ['_cls']
}
];
const DOMAINS = [
'.marketplace.team',
'.digitalmarketplace.service.gov.uk',
'www.applytosupply.digitalmarketplace.service.gov.uk'
];
// When not in production we want to delete cookies in localhost too
const getDomains = () => {
if (window.location.hostname === 'localhost') {
return DOMAINS.concat(['localhost']);
}
return DOMAINS;
};
const getCookiePreferences = () => {
const defaultCookieSettings = '{"usage":false,"glassbox":false}';
return JSON.parse(api.get('cookie_preferences_dmp') ?? defaultCookieSettings);
};
const setCookiePreferences = (usage) => {
const cookiePreferences = getCookiePreferences();
cookiePreferences.usage = usage;
cookiePreferences.settings_viewed = true;
api.set('cookie_preferences_dmp', JSON.stringify(cookiePreferences), { expires: 365 });
updateDataLayer(cookiePreferences);
removeUnwantedCookies();
};
const removeUnwantedCookies = () => {
const cookieList = Object.keys(api.get());
const cookiesToRemove = ['digitalmarketplace_cookie_settings_viewed', 'digitalmarketplace_google_analytics_enabled', 'digitalmarketplace_cookie_options_v1', 'dm_cookies_policy'];
const cookiePreferences = getCookiePreferences();
const cookiePrefixes = [];
cookieUpdateOptions.forEach((cookieUpdateOption) => {
if (!cookiePreferences[cookieUpdateOption.cookieName])
cookiePrefixes.push(...cookieUpdateOption.cookiePrefixes);
});
for (let i = 0; i < cookieList.length; i++) {
const cookieName = cookieList[i];
if (cookiePrefixes.some((cookiePrefix) => cookieName.startsWith(cookiePrefix)))
cookiesToRemove.push(cookieName);
}
getDomains().forEach((domain) => {
cookiesToRemove.forEach((cookieName) => { api.remove(cookieName, { path: '/', domain: domain }); });
});
};
const initGoogleAnalytics = () => {
loadGoogleTagManager();
removeUnwantedCookies();
};
function _arrayLikeToArray(r, a) {
(null == a || a > r.length) && (a = r.length);
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
return n;
}
function _construct(t, e, r) {
if (_isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments);
var o = [null];
o.push.apply(o, e);
var p = new (t.bind.apply(t, o))();
return r && _setPrototypeOf(p, r.prototype), p;
}
function _defineProperties(e, r) {
for (var t = 0; t < r.length; t++) {
var o = r[t];
o.enumerable = o.enumerable || false, o.configurable = true, "value" in o && (o.writable = true), Object.defineProperty(e, _toPropertyKey(o.key), o);
}
}
function _createClass(e, r, t) {
return r && _defineProperties(e.prototype, r), Object.defineProperty(e, "prototype", {
writable: false
}), e;
}
function _createForOfIteratorHelperLoose(r, e) {
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (t) return (t = t.call(r)).next.bind(t);
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) {
t && (r = t);
var o = 0;
return function () {
return o >= r.length ? {
done: true
} : {
done: false,
value: r[o++]
};
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _getPrototypeOf(t) {
return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) {
return t.__proto__ || Object.getPrototypeOf(t);
}, _getPrototypeOf(t);
}
function _inheritsLoose(t, o) {
t.prototype = Object.create(o.prototype), t.prototype.constructor = t, _setPrototypeOf(t, o);
}
function _isNativeFunction(t) {
try {
return -1 !== Function.toString.call(t).indexOf("[native code]");
} catch (n) {
return "function" == typeof t;
}
}
function _isNativeReflectConstruct() {
try {
var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
} catch (t) {}
return (_isNativeReflectConstruct = function () {
return !!t;
})();
}
function _setPrototypeOf(t, e) {
return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {
return t.__proto__ = e, t;
}, _setPrototypeOf(t, e);
}
function _toPrimitive(t, r) {
if ("object" != typeof t || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r);
if ("object" != typeof i) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return (String )(t);
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == typeof i ? i : i + "";
}
function _unsupportedIterableToArray(r, a) {
if (r) {
if ("string" == typeof r) return _arrayLikeToArray(r, a);
var t = {}.toString.call(r).slice(8, -1);
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
}
}
function _wrapNativeSuper(t) {
var r = "function" == typeof Map ? new Map() : void 0;
return _wrapNativeSuper = function (t) {
if (null === t || !_isNativeFunction(t)) return t;
if ("function" != typeof t) throw new TypeError("Super expression must either be null or a function");
if (void 0 !== r) {
if (r.has(t)) return r.get(t);
r.set(t, Wrapper);
}
function Wrapper() {
return _construct(t, arguments, _getPrototypeOf(this).constructor);
}
return Wrapper.prototype = Object.create(t.prototype, {
constructor: {
value: Wrapper,
enumerable: false,
writable: true,
configurable: true
}
}), _setPrototypeOf(Wrapper, t);
}, _wrapNativeSuper(t);
}
function isInitialised($root, moduleName) {
return $root instanceof HTMLElement && $root.hasAttribute("data-" + moduleName + "-init");
}
/**
* Checks if GOV.UK Frontend is supported on this page
*
* Some browsers will load and run our JavaScript but GOV.UK Frontend
* won't be supported.
*
* @param {HTMLElement | null} [$scope] - (internal) `<body>` HTML element checked for browser support
* @returns {boolean} Whether GOV.UK Frontend is supported on this page
*/
function isSupported($scope) {
if ($scope === void 0) {
$scope = document.body;
}
if (!$scope) {
return false;
}
return $scope.classList.contains('govuk-frontend-supported');
}
function isArray(option) {
return Array.isArray(option);
}
function isObject(option) {
return !!option && typeof option === 'object' && !isArray(option);
}
function formatErrorMessage(Component, message) {
return Component.moduleName + ": " + message;
}
var GOVUKFrontendError = function (_Error) {
function GOVUKFrontendError() {
var _this;
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = _Error.call.apply(_Error, [this].concat(args)) || this;
_this.name = 'GOVUKFrontendError';
return _this;
}
_inheritsLoose(GOVUKFrontendError, _Error);
return GOVUKFrontendError;
}(_wrapNativeSuper(Error));
var SupportError = function (_GOVUKFrontendError) {
/**
* Checks if GOV.UK Frontend is supported on this page
*
* @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support
*/
function SupportError($scope) {
var _this2;
if ($scope === void 0) {
$scope = document.body;
}
var supportMessage = 'noModule' in HTMLScriptElement.prototype ? 'GOV.UK Frontend initialised without `<body class="govuk-frontend-supported">` from template `<script>` snippet' : 'GOV.UK Frontend is not supported in this browser';
_this2 = _GOVUKFrontendError.call(this, $scope ? supportMessage : 'GOV.UK Frontend initialised without `<script type="module">`') || this;
_this2.name = 'SupportError';
return _this2;
}
_inheritsLoose(SupportError, _GOVUKFrontendError);
return SupportError;
}(GOVUKFrontendError);
var ConfigError = function (_GOVUKFrontendError2) {
function ConfigError() {
var _this3;
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
_this3 = _GOVUKFrontendError2.call.apply(_GOVUKFrontendError2, [this].concat(args)) || this;
_this3.name = 'ConfigError';
return _this3;
}
_inheritsLoose(ConfigError, _GOVUKFrontendError2);
return ConfigError;
}(GOVUKFrontendError);
var ElementError = function (_GOVUKFrontendError3) {
function ElementError(messageOrOptions) {
var _this4;
var message = typeof messageOrOptions === 'string' ? messageOrOptions : '';
if (typeof messageOrOptions === 'object') {
var component = messageOrOptions.component,
identifier = messageOrOptions.identifier,
element = messageOrOptions.element,
expectedType = messageOrOptions.expectedType;
message = identifier;
message += element ? " is not of type " + (expectedType != null ? expectedType : 'HTMLElement') : ' not found';
message = formatErrorMessage(component, message);
}
_this4 = _GOVUKFrontendError3.call(this, message) || this;
_this4.name = 'ElementError';
return _this4;
}
_inheritsLoose(ElementError, _GOVUKFrontendError3);
return ElementError;
}(GOVUKFrontendError);
var InitError = function (_GOVUKFrontendError4) {
function InitError(componentOrMessage) {
var _this5;
var message = typeof componentOrMessage === 'string' ? componentOrMessage : formatErrorMessage(componentOrMessage, "Root element (`$root`) already initialised");
_this5 = _GOVUKFrontendError4.call(this, message) || this;
_this5.name = 'InitError';
return _this5;
}
_inheritsLoose(InitError, _GOVUKFrontendError4);
return InitError;
}(GOVUKFrontendError);
var Component = function () {
function Component($root) {
this._$root = void 0;
var childConstructor = this.constructor;
if (typeof childConstructor.moduleName !== 'string') {
throw new InitError("`moduleName` not defined in component");
}
if (!($root instanceof childConstructor.elementType)) {
throw new ElementError({
element: $root,
component: childConstructor,
identifier: 'Root element (`$root`)',
expectedType: childConstructor.elementType.name
});
} else {
this._$root = $root;
}
childConstructor.checkSupport();
this.checkInitialised();
var moduleName = childConstructor.moduleName;
this.$root.setAttribute("data-" + moduleName + "-init", '');
}
var _proto = Component.prototype;
_proto.checkInitialised = function checkInitialised() {
var constructor = this.constructor;
var moduleName = constructor.moduleName;
if (moduleName && isInitialised(this.$root, moduleName)) {
throw new InitError(constructor);
}
};
Component.checkSupport = function checkSupport() {
if (!isSupported()) {
throw new SupportError();
}
};
return _createClass(Component, [{
key: "$root",
get:
/**
* Returns the root element of the component
*
* @protected
* @returns {RootElementType} - the root element of component
*/
function get() {
return this._$root;
}
}]);
}();
/**
* @typedef ChildClass
* @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component
*/
/**
* @typedef {typeof Component & ChildClass} ChildClassConstructor
*/
Component.elementType = HTMLElement;
var configOverride = Symbol["for"]('configOverride');
var ConfigurableComponent = function (_Component) {
function ConfigurableComponent($root, config) {
var _this;
_this = _Component.call(this, $root) || this;
_this._config = void 0;
var childConstructor = _this.constructor;
if (!isObject(childConstructor.defaults)) {
throw new ConfigError(formatErrorMessage(childConstructor, 'Config passed as parameter into constructor but no defaults defined'));
}
var datasetConfig = normaliseDataset(childConstructor, _this._$root.dataset);
_this._config = mergeConfigs(childConstructor.defaults, config != null ? config : {}, _this[configOverride](datasetConfig), datasetConfig);
return _this;
}
_inheritsLoose(ConfigurableComponent, _Component);
var _proto = ConfigurableComponent.prototype;
_proto[configOverride] = function (param) {
return {};
}
/**
* Returns the root element of the component
*
* @protected
* @returns {ConfigurationType} - the root element of component
*/;
return _createClass(ConfigurableComponent, [{
key: "config",
get: function get() {
return this._config;
}
}]);
}(Component);
function normaliseString(value, property) {
var trimmedValue = value ? value.trim() : '';
var output;
var outputType = property == null ? void 0 : property.type;
if (!outputType) {
if (['true', 'false'].includes(trimmedValue)) {
outputType = 'boolean';
}
if (trimmedValue.length > 0 && isFinite(Number(trimmedValue))) {
outputType = 'number';
}
}
switch (outputType) {
case 'boolean':
output = trimmedValue === 'true';
break;
case 'number':
output = Number(trimmedValue);
break;
default:
output = value;
}
return output;
}
function normaliseDataset(Component, dataset) {
if (!isObject(Component.schema)) {
throw new ConfigError(formatErrorMessage(Component, 'Config passed as parameter into constructor but no schema defined'));
}
var out = {};
var entries = Object.entries(Component.schema.properties);
for (var _i = 0, _entries = entries; _i < _entries.length; _i++) {
var entry = _entries[_i];
var namespace = entry[0],
property = entry[1];
var field = namespace.toString();
if (field in dataset) {
out[field] = normaliseString(dataset[field], property);
}
if ((property == null ? void 0 : property.type) === 'object') {
out[field] = extractConfigByNamespace(Component.schema, dataset, namespace);
}
}
return out;
}
function mergeConfigs() {
var formattedConfigObject = {};
for (var _len = arguments.length, configObjects = new Array(_len), _key = 0; _key < _len; _key++) {
configObjects[_key] = arguments[_key];
}
for (var _i2 = 0, _configObjects = configObjects; _i2 < _configObjects.length; _i2++) {
var configObject = _configObjects[_i2];
for (var _i3 = 0, _Object$keys = Object.keys(configObject); _i3 < _Object$keys.length; _i3++) {
var key = _Object$keys[_i3];
var option = formattedConfigObject[key];
var override = configObject[key];
if (isObject(option) && isObject(override)) {
formattedConfigObject[key] = mergeConfigs(option, override);
} else {
formattedConfigObject[key] = override;
}
}
}
return formattedConfigObject;
}
function extractConfigByNamespace(schema, dataset, namespace) {
var _newObject;
var property = schema.properties[namespace];
if ((property == null ? void 0 : property.type) !== 'object') {
return;
}
var newObject = (_newObject = {}, _newObject[namespace] = {}, _newObject);
for (var _i5 = 0, _Object$entries2 = Object.entries(dataset); _i5 < _Object$entries2.length; _i5++) {
var _Object$entries2$_i = _Object$entries2[_i5],
key = _Object$entries2$_i[0],
value = _Object$entries2$_i[1];
var current = newObject;
var keyParts = key.split('.');
for (var _iterator2 = _createForOfIteratorHelperLoose(keyParts.entries()), _step2; !(_step2 = _iterator2()).done;) {
var _step2$value = _step2.value,
index = _step2$value[0],
name = _step2$value[1];
if (isObject(current)) {
if (index < keyParts.length - 1) {
if (!isObject(current[name])) {
current[name] = {};
}
current = current[name];
} else if (key !== namespace) {
current[name] = normaliseString(value);
}
}
}
}
return newObject[namespace];
}
var I18n = function () {
function I18n(translations, config) {
if (translations === void 0) {
translations = {};
}
if (config === void 0) {
config = {};
}
var _config$locale;
this.translations = void 0;
this.locale = void 0;
this.translations = translations;
this.locale = (_config$locale = config.locale) != null ? _config$locale : document.documentElement.lang || 'en';
}
var _proto = I18n.prototype;
_proto.t = function t(lookupKey, options) {
if (!lookupKey) {
throw new Error('i18n: lookup key missing');
}
var translation = this.translations[lookupKey];
if (typeof (options == null ? void 0 : options.count) === 'number' && typeof translation === 'object') {
var translationPluralForm = translation[this.getPluralSuffix(lookupKey, options.count)];
if (translationPluralForm) {
translation = translationPluralForm;
}
}
if (typeof translation === 'string') {
if (translation.match(/%{(.\S+)}/)) {
if (!options) {
throw new Error('i18n: cannot replace placeholders in string if no option data provided');
}
return this.replacePlaceholders(translation, options);
}
return translation;
}
return lookupKey;
};
_proto.replacePlaceholders = function replacePlaceholders(translationString, options) {
var formatter = Intl.NumberFormat.supportedLocalesOf(this.locale).length ? new Intl.NumberFormat(this.locale) : undefined;
return translationString.replace(/%{(.\S+)}/g, function (placeholderWithBraces, placeholderKey) {
if (Object.prototype.hasOwnProperty.call(options, placeholderKey)) {
var placeholderValue = options[placeholderKey];
if (placeholderValue === false || typeof placeholderValue !== 'number' && typeof placeholderValue !== 'string') {
return '';
}
if (typeof placeholderValue === 'number') {
return formatter ? formatter.format(placeholderValue) : "" + placeholderValue;
}
return placeholderValue;
}
throw new Error("i18n: no data found to replace " + placeholderWithBraces + " placeholder in string");
});
};
_proto.hasIntlPluralRulesSupport = function hasIntlPluralRulesSupport() {
return Boolean('PluralRules' in window.Intl && Intl.PluralRules.supportedLocalesOf(this.locale).length);
};
_proto.getPluralSuffix = function getPluralSuffix(lookupKey, count) {
count = Number(count);
if (!isFinite(count)) {
return 'other';
}
var translation = this.translations[lookupKey];
var preferredForm = this.hasIntlPluralRulesSupport() ? new Intl.PluralRules(this.locale).select(count) : this.selectPluralFormUsingFallbackRules(count);
if (typeof translation === 'object') {
if (preferredForm in translation) {
return preferredForm;
} else if ('other' in translation) {
console.warn("i18n: Missing plural form \"." + preferredForm + "\" for \"" + this.locale + "\" locale. Falling back to \".other\".");
return 'other';
}
}
throw new Error("i18n: Plural form \".other\" is required for \"" + this.locale + "\" locale");
};
_proto.selectPluralFormUsingFallbackRules = function selectPluralFormUsingFallbackRules(count) {
count = Math.abs(Math.floor(count));
var ruleset = this.getPluralRulesForLocale();
if (ruleset) {
return I18n.pluralRules[ruleset](count);
}
return 'other';
};
_proto.getPluralRulesForLocale = function getPluralRulesForLocale() {
var localeShort = this.locale.split('-')[0];
for (var pluralRule in I18n.pluralRulesMap) {
var languages = I18n.pluralRulesMap[pluralRule];
if (languages.includes(this.locale) || languages.includes(localeShort)) {
return pluralRule;
}
}
};
return I18n;
}();
I18n.pluralRulesMap = {
arabic: ['ar'],
chinese: ['my', 'zh', 'id', 'ja', 'jv', 'ko', 'ms', 'th', 'vi'],
french: ['hy', 'bn', 'fr', 'gu', 'hi', 'fa', 'pa', 'zu'],
german: ['af', 'sq', 'az', 'eu', 'bg', 'ca', 'da', 'nl', 'en', 'et', 'fi', 'ka', 'de', 'el', 'hu', 'lb', 'no', 'so', 'sw', 'sv', 'ta', 'te', 'tr', 'ur'],
irish: ['ga'],
russian: ['ru', 'uk'],
scottish: ['gd'],
spanish: ['pt-PT', 'it', 'es'],
welsh: ['cy']
};
I18n.pluralRules = {
arabic: function arabic(n) {
if (n === 0) {
return 'zero';
}
if (n === 1) {
return 'one';
}
if (n === 2) {
return 'two';
}
if (n % 100 >= 3 && n % 100 <= 10) {
return 'few';
}
if (n % 100 >= 11 && n % 100 <= 99) {
return 'many';
}
return 'other';
},
chinese: function chinese() {
return 'other';
},
french: function french(n) {
return n === 0 || n === 1 ? 'one' : 'other';
},
german: function german(n) {
return n === 1 ? 'one' : 'other';
},
irish: function irish(n) {
if (n === 1) {
return 'one';
}
if (n === 2) {
return 'two';
}
if (n >= 3 && n <= 6) {
return 'few';
}
if (n >= 7 && n <= 10) {
return 'many';
}
return 'other';
},
russian: function russian(n) {
var lastTwo = n % 100;
var last = lastTwo % 10;
if (last === 1 && lastTwo !== 11) {
return 'one';
}
if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) {
return 'few';
}
if (last === 0 || last >= 5 && last <= 9 || lastTwo >= 11 && lastTwo <= 14) {
return 'many';
}
return 'other';
},
scottish: function scottish(n) {
if (n === 1 || n === 11) {
return 'one';
}
if (n === 2 || n === 12) {
return 'two';
}
if (n >= 3 && n <= 10 || n >= 13 && n <= 19) {
return 'few';
}
return 'other';
},
spanish: function spanish(n) {
if (n === 1) {
return 'one';
}
if (n % 1000000 === 0 && n !== 0) {
return 'many';
}
return 'other';
},
welsh: function welsh(n) {
if (n === 0) {
return 'zero';
}
if (n === 1) {
return 'one';
}
if (n === 2) {
return 'two';
}
if (n === 3) {
return 'few';
}
if (n === 6) {
return 'many';
}
return 'other';
}
};
function closestAttributeValue($element, attributeName) {
var $closestElementWithAttribute = $element.closest("[" + attributeName + "]");
return $closestElementWithAttribute ? $closestElementWithAttribute.getAttribute(attributeName) : null;
}
/**
* File upload component
*
* @preserve
* @augments ConfigurableComponent<FileUploadConfig>
*/
var FileUpload = function (_ConfigurableComponen) {
/**
* @param {Element | null} $root - File input element
* @param {FileUploadConfig} [config] - File Upload config
*/
function FileUpload($root, config) {
var _this;
if (config === void 0) {
config = {};
}
_this = _ConfigurableComponen.call(this, $root, config) || this;
_this.$input = void 0;
_this.$button = void 0;
_this.$status = void 0;
_this.i18n = void 0;
_this.id = void 0;
_this.$announcements = void 0;
_this.enteredAnotherElement = void 0;
var $input = _this.$root.querySelector('input');
if ($input === null) {
throw new ElementError({
component: FileUpload,
identifier: 'File inputs (`<input type="file">`)'
});
}
if ($input.type !== 'file') {
throw new ElementError(formatErrorMessage(FileUpload, 'File input (`<input type="file">`) attribute (`type`) is not `file`'));
}
_this.$input = $input;
_this.$input.setAttribute('hidden', 'true');
if (!_this.$input.id) {
throw new ElementError({
component: FileUpload,
identifier: 'File input (`<input type="file">`) attribute (`id`)'
});
}
_this.id = _this.$input.id;
_this.i18n = new I18n(_this.config.i18n, {
locale: closestAttributeValue(_this.$root, 'lang')
});
var $label = _this.findLabel();
if (!$label.id) {
$label.id = _this.id + "-label";
}
_this.$input.id = _this.id + "-input";
var $button = document.createElement('button');
$button.classList.add('govuk-file-upload-button');
$button.type = 'button';
$button.id = _this.id;
$button.classList.add('govuk-file-upload-button--empty');
var ariaDescribedBy = _this.$input.getAttribute('aria-describedby');
if (ariaDescribedBy) {
$button.setAttribute('aria-describedby', ariaDescribedBy);
}
var $status = document.createElement('span');
$status.className = 'govuk-body govuk-file-upload-button__status';
$status.setAttribute('aria-live', 'polite');
$status.innerText = _this.i18n.t('noFileChosen');
$button.appendChild($status);
var commaSpan = document.createElement('span');
commaSpan.className = 'govuk-visually-hidden';
commaSpan.innerText = ', ';
commaSpan.id = _this.id + "-comma";
$button.appendChild(commaSpan);
var containerSpan = document.createElement('span');
containerSpan.className = 'govuk-file-upload-button__pseudo-button-container';
var buttonSpan = document.createElement('span');
buttonSpan.className = 'govuk-button govuk-button--secondary govuk-file-upload-button__pseudo-button';
buttonSpan.innerText = _this.i18n.t('chooseFilesButton');
containerSpan.appendChild(buttonSpan);
containerSpan.insertAdjacentText('beforeend', ' ');
var instructionSpan = document.createElement('span');
instructionSpan.className = 'govuk-body govuk-file-upload-button__instruction';
instructionSpan.innerText = _this.i18n.t('dropInstruction');
containerSpan.appendChild(instructionSpan);
$button.appendChild(containerSpan);
$button.setAttribute('aria-labelledby', $label.id + " " + commaSpan.id + " " + $button.id);
$button.addEventListener('click', _this.onClick.bind(_this));
$button.addEventListener('dragover', function (event) {
event.preventDefault();
});
_this.$root.insertAdjacentElement('afterbegin', $button);
_this.$input.setAttribute('tabindex', '-1');
_this.$input.setAttribute('aria-hidden', 'true');
_this.$button = $button;
_this.$status = $status;
_this.$input.addEventListener('change', _this.onChange.bind(_this));
_this.updateDisabledState();
_this.observeDisabledState();
_this.$announcements = document.createElement('span');
_this.$announcements.classList.add('govuk-file-upload-announcements');
_this.$announcements.classList.add('govuk-visually-hidden');
_this.$announcements.setAttribute('aria-live', 'assertive');
_this.$root.insertAdjacentElement('afterend', _this.$announcements);
_this.$button.addEventListener('drop', _this.onDrop.bind(_this));
document.addEventListener('dragenter', _this.updateDropzoneVisibility.bind(_this));
document.addEventListener('dragenter', function () {
_this.enteredAnotherElement = true;
});
document.addEventListener('dragleave', function () {
if (!_this.enteredAnotherElement && !_this.$button.disabled) {
_this.hideDraggingState();
_this.$announcements.innerText = _this.i18n.t('leftDropZone');
}
_this.enteredAnotherElement = false;
});
return _this;
}
_inheritsLoose(FileUpload, _ConfigurableComponen);
var _proto = FileUpload.prototype;
_proto.updateDropzoneVisibility = function updateDropzoneVisibility(event) {
if (this.$button.disabled) return;
if (event.target instanceof Node) {
if (this.$root.contains(event.target)) {
if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
if (!this.$button.classList.contains('govuk-file-upload-button--dragging')) {
this.showDraggingState();
this.$announcements.innerText = this.i18n.t('enteredDropZone');
}
}
} else {
if (this.$button.classList.contains('govuk-file-upload-button--dragging')) {
this.hideDraggingState();
this.$announcements.innerText = this.i18n.t('leftDropZone');
}
}
}
};
_proto.showDraggingState = function showDraggingState() {
this.$button.classList.add('govuk-file-upload-button--dragging');
};
_proto.hideDraggingState = function hideDraggingState() {
this.$button.classList.remove('govuk-file-upload-button--dragging');
};
_proto.onDrop = function onDrop(event) {
event.preventDefault();
if (event.dataTransfer && isContainingFiles(event.dataTransfer)) {
this.$input.files = event.dataTransfer.files;
this.$input.dispatchEvent(new CustomEvent('change'));
this.hideDraggingState();
}
};
_proto.onChange = function onChange() {
var fileCount = this.$input.files.length;
if (fileCount === 0) {
this.$status.innerText = this.i18n.t('noFileChosen');
this.$button.classList.add('govuk-file-upload-button--empty');
} else {
if (fileCount === 1) {
this.$status.innerText = this.$input.files[0].name;
} else {
this.$status.innerText = this.i18n.t('multipleFilesChosen', {
count: fileCount
});
}
this.$button.classList.remove('govuk-file-upload-button--empty');
}
};
_proto.findLabel = function findLabel() {
var $label = document.querySelector("label[for=\"" + this.$input.id + "\"]");
if (!$label) {
throw new ElementError({
component: FileUpload,
identifier: "Field label (`<label for=" + this.$input.id + ">`)"
});
}
return $label;
};
_proto.onClick = function onClick() {
this.$input.click();
};
_proto.observeDisabledState = function observeDisabledState() {
var _this2 = this;
var observer = new MutationObserver(function (mutationList) {
for (var _iterator = _createForOfIteratorHelperLoose(mutationList), _step; !(_step = _iterator()).done;) {
var mutation = _step.value;
if (mutation.type === 'attributes' && mutation.attributeName === 'disabled') {
_this2.updateDisabledState();
}
}
});
observer.observe(this.$input, {
attributes: true
});
};
_proto.updateDisabledState = function updateDisabledState() {
this.$button.disabled = this.$input.disabled;
this.$root.classList.toggle('govuk-drop-zone--disabled', this.$button.disabled);
};
return FileUpload;
}(ConfigurableComponent);
FileUpload.moduleName = 'govuk-file-upload';
FileUpload.defaults = Object.freeze({
i18n: {
chooseFilesButton: 'Choose file',
dropInstruction: 'or drop file',
noFileChosen: 'No file chosen',
multipleFilesChosen: {
one: '%{count} file chosen',
other: '%{count} files chosen'
},
enteredDropZone: 'Entered drop zone',
leftDropZone: 'Left drop zone'
}
});
FileUpload.schema = Object.freeze({
properties: {
i18n: {
type: 'object'
}
}
});
function isContainingFiles(dataTransfer) {
var hasNoTypesInfo = dataTransfer.types.length === 0;
var isDraggingFiles = dataTransfer.types.some(function (type) {
return type === 'Files';
});
return hasNoTypesInfo || isDraggingFiles;
}
class ComplianceCommunicationAttachmentListRowFileInput {
$dropZone;
$input;
$label;
$hint;
$button;
$comma;
$announcements;
constructor($row, column) {
const $column = $row.find(`.govuk-grid-column-one-half:nth-of-type(${column})`);
this.$dropZone = $column.find('.govuk-drop-zone');
this.$input = $column.find('input');
this.$label = $column.find('.govuk-label');
this.$hint = $column.find('div.govuk-hint');
this.$button = $column.find('button');
this.$comma = $column.find('button > span.govuk-visually-hidden');
this.$announcements = $column.find('span.govuk-file-upload-announcements');
}
updateIndex(newIndex) {
const newName = this.$input.attr('name').replace(/\d+/, newIndex.toString());
const newId = `input-${newName}`;
if (this.$button.length) {
this.$label.attr('for', newId);
this.$label.attr('id', `${newId}-label`);
this.$hint.attr('id', `${newId}-hint`);
this.$input.attr('id', `${newId}-input`);
this.$input.attr('name', newName);
this.$input.attr('aria-describedby', `${newId}-hint`);
this.$button.attr('id', newId);
this.$button.attr('aria-describedby', `${newId}-hint`);
this.$button.attr('aria-labelledby', `${newId}-label ${newId}-comma ${newId}`);
this.$comma.attr('id', `${newId}-comma`);
}
else {
this.$label.attr('for', newId);
this.$hint.attr('id', `${newId}-hint`);
this.$input.attr('id', newId);
this.$input.attr('name', newName);
this.$input.attr('aria-describedby', `${newId}-hint`);
}
}
makeInteractable() {
if (!this.$button.length) {
return new FileUpload(this.$dropZone.get(0));
}
}
resetHtml() {
this.$label.removeAttr('id');
this.$dropZone.removeAttr('data-govuk-file-upload-init');
this.$button.remove();
const id = this.$input.attr('id');
this.$input.removeAttr('hidden');
this.$input.removeAttr('aria-hidden');
this.$input.attr('id', id.substring(0, id.length - 6));
this.$announcements.remove();
}
}
class ComplianceCommunicationAttachmentListRequiredInput {
$requiredSection;
$input;
$label;
constructor($row) {
this.$requiredSection = $row.find('.dm-compliance-communication__attachments-item-required');
this.$input = this.$requiredSection.find('.govuk-checkboxes__item > input');
this.$label = this.$requiredSection.find('.govuk-checkboxes__item > .govuk-label');
}
isChecked() {
return this.$input.is(':checked');
}
updateIndex(newIndex) {
const newName = this.$input.attr('name').replace(/\d+/, newIndex.toString());
const newId = `input-${newName}`;
this.$label.attr('for', newId);
this.$input.attr('id', newId);
this.$input.attr('name', newName);
}
checkRow() {
this.$requiredSection.toggleClass('govuk-visually-hidden', true);
this.$input.prop('checked', true);
this.$input.attr('tabindex', -1);
this.$input.attr('tabindex', -1);
}
}
class ComplianceCommunicationAttachmentListRowRemoveButton {
attachmentListRow;
$button;
$removeButtonCounter;
constructor(attachmentListRow, $row) {
this.attachmentListRow = attachmentListRow;
this.$button = $row.find('.dm-compliance-communication__attachments-item-remove');
this.$removeButtonCounter = this.$button.find('.dm-compliance-communication__attachments-item-remove-counter');
}
init() {
this.toggleVisibility(true);
this.$button.on('click', () => {
this.attachmentListRow.removeRow();
});
}
toggleVisibility(isShown) {
this.$button.toggleClass('govuk-visually-hidden', !isShown);
if (isShown) {
this.$button.removeAttr('tabindex');
}
else {
this.$button.attr('tabindex', -1);
}
}
updateIndex(newIndex) {
this.$removeButtonCounter.text(newIndex + 1);
}
}
class ComplianceCommunicationAttachmentListRow {
$row;
attachmentList;
index;
$legendCounter;
attachmentListRowFileInput;
attachmentListRowRequiredInput;
attachmentListRowRemoveButton;
constructor(attachmentList, index, $row) {
this.$row = $row;
this.attachmentList = attachmentList;
this.index = index;
this.$legendCounter = this.$row.find('.dm-compliance-communication__attachments-item-legend-counter');
this.attachmentListRowFileInput = new ComplianceCommunicationAttachmentListRowFileInput($row, 1);
this.attachmentListRowRequiredInput = new ComplianceCommunicationAttachmentListRequiredInput($row);
this.attachmentListRowRemoveButton = new ComplianceCommunicationAttachmentListRowRemoveButton(this, $row);
}
init() {
this.attachmentListRowRemoveButton.init();
this.attachmentListRowFileInput.makeInteractable();
this.attachmentListRowRequiredInput.checkRow();
}
updateIndex(newIndex) {
this.index = newIndex;
this.attachmentListRowFileInput.updateIndex(newIndex);
this.attachmentListRowRequiredInput.updateIndex(newIndex);
this.attachmentListRowRemoveButton.updateIndex(newIndex);
this.$legendCounter.text(newIndex + 1);
}
removeRow() {
this.attachmentList.removeRow(this.index);
this.deleteRow();
}
deleteRow() {
this.$row.remove();
}
toggleRemoveButtonVisibility(isShown) {
this.attachmentListRowRemoveButton.toggleVisibility(isShown);
}
isRowChecked() {
return this.attachmentListRowRequiredInput.isChecked();
}
}
class ComplianceCommunicationAttachmentListAddButton {
attachmentList;
$button;
$buttonCounter;
constructor(attachmentList, $button) {
this.attachmentList = attachmentList;
this.$button = $button;
this.$buttonCounter = $button.find('.dm-compliance-communication__attachments__js-remaining-counter');
}
init(numberOfRows) {
this.$button.on('click', () => {
this.attachmentList.addRow();
});
this.updateButtonText(this.attachmentList.maxNumberOfAttachments - numberOfRows);
}
updateButtonText(numberRemaining) {
this.$buttonCounter.text(numberRemaining);
}
toggleVisibility(isShown) {
this.$button.toggleClass('govuk-visually-hidden', !isShown);
if (isShown) {
this.$button.removeAttr('tabindex');
}
else {
this.$button.attr('tabindex', -1);
}
}
}
class ComplianceCommunicationAttachments {
static moduleName = 'dm-compliance-communication-attachments';
$attachmentList;
$attachmentListItems;
attachmentListRows;
attachmentListTemplateRow;
attachmentListAddButton;
maxNumberOfAttachments;
constructor($attachmentList) {
this.$attachmentList = $attachmentList;
this.$attachmentListItems = this.$attachmentList.find('.dm-compliance-communication__attachments-items');
this.attachmentListRows = this.$attachmentListItems.find('.dm-compliance-communication__attachments-item').get().map((row, index) => new ComplianceCommunicationAttachmentListRow(this, index, $(row)));
this.attachmentListTemplateRow = new ComplianceCommunicationAttachmentListRow(this, 99, this.$attachmentList.find('.dm-compliance-communication__attachments-item-template > .dm-compliance-communication__attachments-item'));
this.attachmentListAddButton = new ComplianceCommunicationAttachmentListAddButton(this, this.$attachmentList.find('.dm-compliance-communication__attachments-add'));
this.maxNumberOfAttachments = this.$attachmentList.data('maxNumberOfAttachments');
}
init() {
const rowsChecked = this.attachmentListRows.map((attachmentListRow) => attachmentListRow.isRowChecked());
let indexToDeleteFrom;
if (rowsChecked.every((rowChecked) => !rowChecked)) {
indexToDeleteFrom = 0;
}
else {
indexToDeleteFrom = rowsChecked.indexOf(false);
}
if (indexToDeleteFrom >= 0) {
this.attachmentListRows.slice(indexToDeleteFrom).forEach((attachmentListRow) => attachmentListRow.deleteRow());
this.attachmentListRows.splice(indexToDeleteFrom);
}
this.attachmentListAddButton.init(this.attachmentListRows.length);
this.attachmentListRows.forEach((attachmentListRow) => attachmentListRow.init());
this.attachmentListTemplateRow.attachmentListRowFileInput.resetHtml();
this.updateIfMinRows();
this.updateAttachmentButton();
}
removeRow(indexToRemove) {
this.attachmentListRows.splice(indexToRemove, 1);
this.attachmentListRows.slice(indexT