Skip to content

Commit

Permalink
Merge pull request #1523 from alphagov/simplify-details-polyfilling
Browse files Browse the repository at this point in the history
Improve accessibility of details component by polyfilling only where the native element is not available
  • Loading branch information
NickColley committed Aug 28, 2019
2 parents 94c9b9b + e4ed929 commit a980a67
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 104 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ govukInput({

### Fixes

- [Pull request #1523: Improve accessibility of details component by polyfilling only where the native element is not available](https://github.com/alphagov/govuk-frontend/pull/1523).
- [Pull request #1512: Update components to only output items when they are defined](https://github.com/alphagov/govuk-frontend/pull/1512).
- [Pull request #1538: Simplify button types to avoid unnecessary type attribute](https://github.com/alphagov/govuk-frontend/pull/1538).

Expand Down
56 changes: 56 additions & 0 deletions app/views/examples/details-polyfill/index.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{% from "back-link/macro.njk" import govukBackLink %}

{% extends "layout.njk" %}

{% block beforeContent %}
{{ govukBackLink({
"href": "/"
}) }}
{% endblock %}

{% block content %}
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">

<h1 class="govuk-heading-xl">
Details polyfill examples
</h1>

<p class="govuk-body">
In order to test our polyfill code for details we need to have examples that do not use the native elements.
</p>


<h2 class="govuk-heading-m">
Default
</h2>

<div class="govuk-details" data-module="govuk-details" id="default">
<summary class="govuk-details__summary">
<span class="govuk-details__summary-text">
Help with nationality
</span>
</summary>
<div class="govuk-details__text">
We need to know your nationality so we can work out which elections you’re entitled to vote in. If you cannot provide your nationality, you’ll have to send copies of identity documents through the post.
</div>
</div>

<h2 class="govuk-heading-m">
Expanded
</h2>

<div class="govuk-details" data-module="govuk-details" open id="expanded">
<summary class="govuk-details__summary">
<span class="govuk-details__summary-text">
Help with nationality
</span>
</summary>
<div class="govuk-details__text">
We need to know your nationality so we can work out which elections you’re entitled to vote in. If you cannot provide your nationality, you’ll have to send copies of identity documents through the post.
</div>
</div>

</div>
</div>
{% endblock %}
119 changes: 56 additions & 63 deletions src/govuk/components/details/details.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,58 +11,28 @@ import { generateUniqueID } from '../../common.js'
var KEY_ENTER = 13
var KEY_SPACE = 32

// Create a flag to know if the browser supports navtive details
var NATIVE_DETAILS = typeof document.createElement('details').open === 'boolean'

function Details ($module) {
this.$module = $module
}

/**
* Handle cross-modal click events
* @param {object} node element
* @param {function} callback function
*/
Details.prototype.handleInputs = function (node, callback) {
node.addEventListener('keypress', function (event) {
var target = event.target
// When the key gets pressed - check if it is enter or space
if (event.keyCode === KEY_ENTER || event.keyCode === KEY_SPACE) {
if (target.nodeName.toLowerCase() === 'summary') {
// Prevent space from scrolling the page
// and enter from submitting a form
event.preventDefault()
// Click to let the click event do all the necessary action
if (target.click) {
target.click()
} else {
// except Safari 5.1 and under don't support .click() here
callback(event)
}
}
}
})
Details.prototype.init = function () {
if (!this.$module) {
return
}

// Prevent keyup to prevent clicking twice in Firefox when using space key
node.addEventListener('keyup', function (event) {
var target = event.target
if (event.keyCode === KEY_SPACE) {
if (target.nodeName.toLowerCase() === 'summary') {
event.preventDefault()
}
}
})
// If there is native details support, we want to avoid running code to polyfill native behaviour.
var hasNativeDetails = typeof this.$module.open === 'boolean'

node.addEventListener('click', callback)
if (hasNativeDetails) {
return
}

this.polyfillDetails()
}

Details.prototype.init = function () {
Details.prototype.polyfillDetails = function () {
var $module = this.$module

if (!$module) {
return
}

// Save shortcuts to the inner summary and content elements
var $summary = this.$summary = $module.getElementsByTagName('summary').item(0)
var $content = this.$content = $module.getElementsByTagName('div').item(0)
Expand Down Expand Up @@ -92,9 +62,7 @@ Details.prototype.init = function () {
//
// We have to use the camelcase `tabIndex` property as there is a bug in IE6/IE7 when we set the correct attribute lowercase:
// See http://web.archive.org/web/20170120194036/http://www.saliences.com/browserBugs/tabIndex.html for more information.
if (!NATIVE_DETAILS) {
$summary.tabIndex = 0
}
$summary.tabIndex = 0

// Detect initial open state
var openAttr = $module.getAttribute('open') !== null
Expand All @@ -104,20 +72,18 @@ Details.prototype.init = function () {
} else {
$summary.setAttribute('aria-expanded', 'false')
$content.setAttribute('aria-hidden', 'true')
if (!NATIVE_DETAILS) {
$content.style.display = 'none'
}
$content.style.display = 'none'
}

// Bind an event to handle summary elements
this.handleInputs($summary, this.setAttributes.bind(this))
this.polyfillHandleInputs($summary, this.polyfillSetAttributes.bind(this))
}

/**
* Define a statechange function that updates aria-expanded and style.display
* @param {object} summary element
*/
Details.prototype.setAttributes = function () {
Details.prototype.polyfillSetAttributes = function () {
var $module = this.$module
var $summary = this.$summary
var $content = this.$content
Expand All @@ -128,27 +94,54 @@ Details.prototype.setAttributes = function () {
$summary.setAttribute('aria-expanded', (expanded ? 'false' : 'true'))
$content.setAttribute('aria-hidden', (hidden ? 'false' : 'true'))

if (!NATIVE_DETAILS) {
$content.style.display = (expanded ? 'none' : '')
$content.style.display = (expanded ? 'none' : '')

var hasOpenAttr = $module.getAttribute('open') !== null
if (!hasOpenAttr) {
$module.setAttribute('open', 'open')
} else {
$module.removeAttribute('open')
}
var hasOpenAttr = $module.getAttribute('open') !== null
if (!hasOpenAttr) {
$module.setAttribute('open', 'open')
} else {
$module.removeAttribute('open')
}

return true
}

/**
* Remove the click event from the node element
* Handle cross-modal click events
* @param {object} node element
* @param {function} callback function
*/
Details.prototype.destroy = function (node) {
node.removeEventListener('keypress')
node.removeEventListener('keyup')
node.removeEventListener('click')
Details.prototype.polyfillHandleInputs = function (node, callback) {
node.addEventListener('keypress', function (event) {
var target = event.target
// When the key gets pressed - check if it is enter or space
if (event.keyCode === KEY_ENTER || event.keyCode === KEY_SPACE) {
if (target.nodeName.toLowerCase() === 'summary') {
// Prevent space from scrolling the page
// and enter from submitting a form
event.preventDefault()
// Click to let the click event do all the necessary action
if (target.click) {
target.click()
} else {
// except Safari 5.1 and under don't support .click() here
callback(event)
}
}
}
})

// Prevent keyup to prevent clicking twice in Firefox when using space key
node.addEventListener('keyup', function (event) {
var target = event.target
if (event.keyCode === KEY_SPACE) {
if (target.nodeName.toLowerCase() === 'summary') {
event.preventDefault()
}
}
})

node.addEventListener('click', callback)
}

export default Details
Loading

0 comments on commit a980a67

Please sign in to comment.