and a representing the content\n // it means the required HTML structure is not met so the script will stop\n if (!$summary || !$content) {\n return\n }\n\n // If the content doesn't have an ID, assign it one now\n // which we'll need for the summary's aria-controls assignment\n if (!$content.id) {\n $content.id = 'details-content-' + generateUniqueID()\n }\n\n // Add ARIA role=\"group\" to details\n $module.setAttribute('role', 'group')\n\n // Add role=button to summary\n $summary.setAttribute('role', 'button')\n\n // Add aria-controls\n $summary.setAttribute('aria-controls', $content.id)\n\n // Set tabIndex so the summary is keyboard accessible for non-native elements\n //\n // We have to use the camelcase `tabIndex` property as there is a bug in IE6/IE7 when we set the correct attribute lowercase:\n // See http://web.archive.org/web/20170120194036/http://www.saliences.com/browserBugs/tabIndex.html for more information.\n $summary.tabIndex = 0\n\n // Detect initial open state\n if (this.$module.hasAttribute('open')) {\n $summary.setAttribute('aria-expanded', 'true')\n } else {\n $summary.setAttribute('aria-expanded', 'false')\n $content.style.display = 'none'\n }\n\n // Bind an event to handle summary elements\n this.polyfillHandleInputs(this.polyfillSetAttributes.bind(this))\n}\n\n/**\n * Define a statechange function that updates aria-expanded and style.display\n *\n * @deprecated Will be made private in v5.0\n * @returns {boolean} Returns true\n */\nDetails.prototype.polyfillSetAttributes = function () {\n if (this.$module.hasAttribute('open')) {\n this.$module.removeAttribute('open')\n this.$summary.setAttribute('aria-expanded', 'false')\n this.$content.style.display = 'none'\n } else {\n this.$module.setAttribute('open', 'open')\n this.$summary.setAttribute('aria-expanded', 'true')\n this.$content.style.display = ''\n }\n\n return true\n}\n\n/**\n * Handle cross-modal click events\n *\n * @deprecated Will be made private in v5.0\n * @param {polyfillHandleInputsCallback} callback - function\n */\nDetails.prototype.polyfillHandleInputs = function (callback) {\n this.$summary.addEventListener('keypress', function (event) {\n var $target = event.target\n // When the key gets pressed - check if it is enter or space\n if (event.keyCode === KEY_ENTER || event.keyCode === KEY_SPACE) {\n if ($target instanceof HTMLElement && $target.nodeName.toLowerCase() === 'summary') {\n // Prevent space from scrolling the page\n // and enter from submitting a form\n event.preventDefault()\n // Click to let the click event do all the necessary action\n if ($target.click) {\n $target.click()\n } else {\n // except Safari 5.1 and under don't support .click() here\n callback(event)\n }\n }\n }\n })\n\n // Prevent keyup to prevent clicking twice in Firefox when using space key\n this.$summary.addEventListener('keyup', function (event) {\n var $target = event.target\n if (event.keyCode === KEY_SPACE) {\n if ($target instanceof HTMLElement && $target.nodeName.toLowerCase() === 'summary') {\n event.preventDefault()\n }\n }\n })\n\n this.$summary.addEventListener('click', callback)\n}\n\nexport default Details\n\n/**\n * @callback polyfillHandleInputsCallback\n * @param {UIEvent} event - Keyboard or mouse event\n * @returns {void}\n */\n","/* eslint-disable es-x/no-function-prototype-bind -- Polyfill imported */\n\nimport { mergeConfigs } from '../../common/index.mjs'\nimport { normaliseDataset } from '../../common/normalise-dataset.mjs'\nimport '../../vendor/polyfills/Element/prototype/closest.mjs'\nimport '../../vendor/polyfills/Event.mjs' // addEventListener, event.target normalization and DOMContentLoaded\nimport '../../vendor/polyfills/Function/prototype/bind.mjs'\n\n/**\n * JavaScript enhancements for the ErrorSummary\n *\n * Takes focus on initialisation for accessible announcement, unless disabled in configuration.\n *\n * @class\n * @param {Element} $module - HTML element to use for error summary\n * @param {ErrorSummaryConfig} [config] - Error summary config\n */\nfunction ErrorSummary ($module, config) {\n // Some consuming code may not be passing a module,\n // for example if they initialise the component\n // on their own by directly passing the result\n // of `document.querySelector`.\n // To avoid breaking further JavaScript initialisation\n // we need to safeguard against this so things keep\n // working the same now we read the elements data attributes\n if (!($module instanceof HTMLElement)) {\n // Little safety in case code gets ported as-is\n // into and ES6 class constructor, where the return value matters\n return this\n }\n\n /** @deprecated Will be made private in v5.0 */\n this.$module = $module\n\n var defaultConfig = {\n disableAutoFocus: false\n }\n\n /**\n * @deprecated Will be made private in v5.0\n * @type {ErrorSummaryConfig}\n */\n this.config = mergeConfigs(\n defaultConfig,\n config || {},\n normaliseDataset($module.dataset)\n )\n}\n\n/**\n * Initialise component\n */\nErrorSummary.prototype.init = function () {\n // Check that required elements are present\n if (!this.$module) {\n return\n }\n\n var $module = this.$module\n\n this.setFocus()\n $module.addEventListener('click', this.handleClick.bind(this))\n}\n\n/**\n * Focus the error summary\n *\n * @deprecated Will be made private in v5.0\n */\nErrorSummary.prototype.setFocus = function () {\n var $module = this.$module\n\n if (this.config.disableAutoFocus) {\n return\n }\n\n // Set tabindex to -1 to make the element programmatically focusable, but\n // remove it on blur as the error summary doesn't need to be focused again.\n $module.setAttribute('tabindex', '-1')\n\n $module.addEventListener('blur', function () {\n $module.removeAttribute('tabindex')\n })\n\n $module.focus()\n}\n\n/**\n * Click event handler\n *\n * @deprecated Will be made private in v5.0\n * @param {MouseEvent} event - Click event\n */\nErrorSummary.prototype.handleClick = function (event) {\n var $target = event.target\n if (this.focusTarget($target)) {\n event.preventDefault()\n }\n}\n\n/**\n * Focus the target element\n *\n * By default, the browser will scroll the target into view. Because our labels\n * or legends appear above the input, this means the user will be presented with\n * an input without any context, as the label or legend will be off the top of\n * the screen.\n *\n * Manually handling the click event, scrolling the question into view and then\n * focussing the element solves this.\n *\n * This also results in the label and/or legend being announced correctly in\n * NVDA (as tested in 2018.3.2) - without this only the field type is announced\n * (e.g. \"Edit, has autocomplete\").\n *\n * @deprecated Will be made private in v5.0\n * @param {EventTarget} $target - Event target\n * @returns {boolean} True if the target was able to be focussed\n */\nErrorSummary.prototype.focusTarget = function ($target) {\n // If the element that was clicked was not a link, return early\n if (!($target instanceof HTMLAnchorElement)) {\n return false\n }\n\n var inputId = this.getFragmentFromUrl($target.href)\n if (!inputId) {\n return false\n }\n\n var $input = document.getElementById(inputId)\n if (!$input) {\n return false\n }\n\n var $legendOrLabel = this.getAssociatedLegendOrLabel($input)\n if (!$legendOrLabel) {\n return false\n }\n\n // Scroll the legend or label into view *before* calling focus on the input to\n // avoid extra scrolling in browsers that don't support `preventScroll` (which\n // at time of writing is most of them...)\n $legendOrLabel.scrollIntoView()\n $input.focus({ preventScroll: true })\n\n return true\n}\n\n/**\n * Get fragment from URL\n *\n * Extract the fragment (everything after the hash) from a URL, but not including\n * the hash.\n *\n * @deprecated Will be made private in v5.0\n * @param {string} url - URL\n * @returns {string | undefined} Fragment from URL, without the hash\n */\nErrorSummary.prototype.getFragmentFromUrl = function (url) {\n if (url.indexOf('#') === -1) {\n return undefined\n }\n\n return url.split('#').pop()\n}\n\n/**\n * Get associated legend or label\n *\n * Returns the first element that exists from this list:\n *\n * - The `