diff --git a/app/__init__.py b/app/__init__.py index 59b918f81..4c24d5b28 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -743,7 +743,6 @@ def add_template_filters(application): format_phone_number_human_readable, format_thousands, id_safe, - convert_to_boolean, ]: application.add_template_filter(fn) diff --git a/app/assets/javascripts/detailsPolyfill.js b/app/assets/javascripts/detailsPolyfill.js new file mode 100644 index 000000000..ce0692195 --- /dev/null +++ b/app/assets/javascripts/detailsPolyfill.js @@ -0,0 +1,196 @@ +// From +// https://github.com/alphagov/govuk_elements/blob/4926897dc7734db2fc5e5ebb6acdc97f86e22e50/public/javascripts/vendor/details.polyfill.js +// +// --- +// +//
polyfill +// http://caniuse.com/#feat=details + +// FF Support for HTML5's
and +// https://bugzilla.mozilla.org/show_bug.cgi?id=591737 + +// http://www.sitepoint.com/fixing-the-details-element/ + +(function () { + 'use strict'; + + var NATIVE_DETAILS = typeof document.createElement('details').open === 'boolean'; + + // Add event construct for modern browsers or IE + // which fires the callback with a pre-converted target reference + function addEvent(node, type, callback) { + if (node.addEventListener) { + node.addEventListener(type, function (e) { + callback(e, e.target); + }, false); + } else if (node.attachEvent) { + node.attachEvent('on' + type, function (e) { + callback(e, e.srcElement); + }); + } + } + + // Handle cross-modal click events + function addClickEvent(node, callback) { + // Prevent space(32) from scrolling the page + addEvent(node, 'keypress', function (e, target) { + if (target.nodeName === 'SUMMARY') { + if (e.keyCode === 32) { + if (e.preventDefault) { + e.preventDefault(); + } else { + e.returnValue = false; + } + } + } + }); + // When the key comes up - check if it is enter(13) or space(32) + addEvent(node, 'keyup', function (e, target) { + if (e.keyCode === 13 || e.keyCode === 32) { callback(e, target); } + }); + addEvent(node, 'mouseup', function (e, target) { + callback(e, target); + }); + } + + // Get the nearest ancestor element of a node that matches a given tag name + function getAncestor(node, match) { + do { + if (!node || node.nodeName.toLowerCase() === match) { + break; + } + } while ((node = node.parentNode)); + + return node; + } + + // Create a started flag so we can prevent the initialisation + // function firing from both DOMContentLoaded and window.onload + var started = false; + + // Initialisation function + function addDetailsPolyfill(list) { + + // If this has already happened, just return + // else set the flag so it doesn't happen again + if (started) { + return; + } + started = true; + + // Get the collection of details elements, but if that's empty + // then we don't need to bother with the rest of the scripting + if ((list = document.getElementsByTagName('details')).length === 0) { + return; + } + + // else iterate through them to apply their initial state + var n = list.length, i = 0; + for (i; i < n; i++) { + var details = list[i]; + + // Save shortcuts to the inner summary and content elements + details.__summary = details.getElementsByTagName('summary').item(0); + details.__content = details.getElementsByTagName('div').item(0); + + // If the content doesn't have an ID, assign it one now + // which we'll need for the summary's aria-controls assignment + if (!details.__content.id) { + details.__content.id = 'details-content-' + i; + } + + // Add ARIA role="group" to details + details.setAttribute('role', 'group'); + + // Add role=button to summary + details.__summary.setAttribute('role', 'button'); + + // Add aria-controls + details.__summary.setAttribute('aria-controls', details.__content.id); + + // Set tabIndex so the summary is keyboard accessible for non-native elements + // http://www.saliences.com/browserBugs/tabIndex.html + if (!NATIVE_DETAILS) { + details.__summary.tabIndex = 0; + } + + // Detect initial open state + var openAttr = details.getAttribute('open') !== null; + if (openAttr === true) { + details.__summary.setAttribute('aria-expanded', 'true'); + details.__content.setAttribute('aria-hidden', 'false'); + } else { + details.__summary.setAttribute('aria-expanded', 'false'); + details.__content.setAttribute('aria-hidden', 'true'); + if (!NATIVE_DETAILS) { + details.__content.style.display = 'none'; + } + } + + // Create a circular reference from the summary back to its + // parent details element, for convenience in the click handler + details.__summary.__details = details; + + // If this is not a native implementation, create an arrow + // inside the summary + + var twisty = document.createElement('i'); + + if (openAttr === true) { + twisty.className = 'arrow arrow-open'; + twisty.appendChild(document.createTextNode('\u25bc')); + } else { + twisty.className = 'arrow arrow-closed'; + twisty.appendChild(document.createTextNode('\u25ba')); + } + + details.__summary.__twisty = details.__summary.insertBefore(twisty, details.__summary.firstChild); + details.__summary.__twisty.setAttribute('aria-hidden', 'true'); + + } + + // Define a statechange function that updates aria-expanded and style.display + // Also update the arrow position + function statechange(summary) { + + var expanded = summary.__details.__summary.getAttribute('aria-expanded') === 'true'; + var hidden = summary.__details.__content.getAttribute('aria-hidden') === 'true'; + + summary.__details.__summary.setAttribute('aria-expanded', (expanded ? 'false' : 'true')); + summary.__details.__content.setAttribute('aria-hidden', (hidden ? 'false' : 'true')); + + if (!NATIVE_DETAILS) { + summary.__details.__content.style.display = (expanded ? 'none' : ''); + + var hasOpenAttr = summary.__details.getAttribute('open') !== null; + if (!hasOpenAttr) { + summary.__details.setAttribute('open', 'open'); + } else { + summary.__details.removeAttribute('open'); + } + } + + if (summary.__twisty) { + summary.__twisty.firstChild.nodeValue = (expanded ? '\u25ba' : '\u25bc'); + summary.__twisty.setAttribute('class', (expanded ? 'arrow arrow-closed' : 'arrow arrow-open')); + } + + return true; + } + + // Bind a click event to handle summary elements + addClickEvent(document, function(e, summary) { + if (!(summary = getAncestor(summary, 'summary'))) { + return true; + } + return statechange(summary); + }); + } + + // Bind two load events for modern and older browsers + // If the first one fires it will set a flag to block the second one + // but if it's not supported then the second one will fire + addEvent(document, 'DOMContentLoaded', addDetailsPolyfill); + addEvent(window, 'load', addDetailsPolyfill); + +})(); diff --git a/app/assets/stylesheets/govuk-frontend/_all.scss b/app/assets/stylesheets/govuk-frontend/_all.scss index 9ecefd894..760d837cc 100644 --- a/app/assets/stylesheets/govuk-frontend/_all.scss +++ b/app/assets/stylesheets/govuk-frontend/_all.scss @@ -17,7 +17,6 @@ $govuk-assets-path: "/static/"; @import 'components/header/_header'; @import 'components/footer/_footer'; @import 'components/back-link/_back-link'; -@import 'components/details/_details'; @import "utilities/all"; @import "overrides/all"; diff --git a/app/assets/stylesheets/views/api.scss b/app/assets/stylesheets/views/api.scss index 4049c43c5..98e21685e 100644 --- a/app/assets/stylesheets/views/api.scss +++ b/app/assets/stylesheets/views/api.scss @@ -1,8 +1,6 @@ .api-notifications { font-family: monospace; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; border-bottom: 1px solid $border-colour; &-item { @@ -10,59 +8,38 @@ border-top: 1px solid $border-colour; padding: 10px 0 0 0; - &__heading, - &__data, - &__view { - font-family: monospace; - } - - &__heading { + &-title { + color: $link-colour; + text-decoration: none; display: block; - margin-bottom: $gutter-half; - - &::before { - top: -1.3em; - } } - &__meta { + &-recipient { + display: inline; + } + &-meta { display: block; color: $secondary-text-colour; - text-decoration: none; - - &-key, - &-time { - color: $secondary-text-colour; - display: inline-block; - width: auto; - } - - @include govuk-media-query($from: tablet) { - &-key, - &-time { - width: 50%; - } - - &-time { - text-align: right; - } - } - } - &__data { + &-time { + text-align: right; + } - border-left: none; - padding-left: 25px; + &-key { + display: inline-block; + padding-left: 46px; + } - &-name { - color: $secondary-text-colour; - } + &-data { - &-value { - color: $text-colour; + padding-left: 31px; + color: $secondary-text-colour; + + &-item { padding-bottom: 15px; + color: $text-colour; } } diff --git a/app/templates/views/api/index.html b/app/templates/views/api/index.html index cebb5442d..9397a97b5 100644 --- a/app/templates/views/api/index.html +++ b/app/templates/views/api/index.html @@ -39,45 +39,43 @@
{% if not api_notifications.notifications %}
-

+

When you send messages via the API they’ll appear here.

-

+

Notify deletes messages after 7 days.

{% endif %} {% for notification in api_notifications.notifications %} -
- -

- +
+ +

{{ notification.to }} - - - - {{notification.key_name}} - - - - -

+ + + {{notification.key_name}} + + + + +
-
-
+
+
{% for key in [ 'id', 'client_reference', 'notification_type', 'created_at', 'updated_at', 'sent_at', 'status' ] %} {% if notification[key] %} -
{{ key }}:
-
{{ notification[key] }}
+
{{ key }}:
+
{{ notification[key] }}
{% endif %} {% endfor %} {% if notification.status not in ('pending-virus-check', 'virus-scan-failed') %} - View {{ message_count_label(1, notification.template.template_type, suffix='') }} + View {{ message_count_label(1, notification.template.template_type, suffix='') }} {% endif %}
@@ -86,11 +84,11 @@ {% if api_notifications.notifications %}
{% if api_notifications.notifications|length == 50 %} -

+

Only showing the first 50 messages.

{% endif %} -

+

Notify deletes messages after 7 days.

diff --git a/app/templates/views/get-started.html b/app/templates/views/get-started.html index 0d20b17b9..09e165a8d 100644 --- a/app/templates/views/get-started.html +++ b/app/templates/views/get-started.html @@ -1,7 +1,6 @@ {% extends "content_template.html" %} {% from "components/table.html" import mapping_table, row, text_field, edit_field, field with context %} {% from "components/sub-navigation.html" import sub_navigation %} -{% from "components/details/macro.njk" import govukDetails %} {% block per_page_title %} Get started @@ -15,22 +14,21 @@
  • Check if GOV.UK Notify is right for you

    Read about our features, pricing and roadmap.

    - {{ govukDetails({ - "summaryText": "Organisations that can use Notify", - "html": ''' -
    -

    Notify is available to:

    -
      -
    • central government departments
    • -
    • local authorities
    • -
    • state-funded schools
    • -
    • housing associations
    • -
    • the NHS
    • -
    • companies owned by local or central government that deliver services on their behalf
    • -
    -

    Notify is not currently available to charities.

    -
    ''' - }) }} +
    + Organisations that can use Notify +
    +

    Notify is available to:

    +
      +
    • central government departments
    • +
    • local authorities
    • +
    • state-funded schools
    • +
    • housing associations
    • +
    • the NHS
    • +
    • companies owned by local or central government that deliver services on their behalf
    • +
    +

    Notify is not currently available to charities.

    +
    +
  • diff --git a/app/templates/views/platform-admin/index.html b/app/templates/views/platform-admin/index.html index c404f78c3..6da4e87d2 100644 --- a/app/templates/views/platform-admin/index.html +++ b/app/templates/views/platform-admin/index.html @@ -4,7 +4,6 @@ {% from "components/message-count-label.html" import message_count_label %} {% from "components/status-box.html" import status_box %} {% from "components/form.html" import form_wrapper %} -{% from "components/details/macro.njk" import govukDetails %} {% block per_page_title %} Platform admin @@ -15,21 +14,15 @@

    Summary

    - - {% set details_content %} +
    + Apply filters {% call form_wrapper(method="get") %} {{ textbox(form.start_date, hint="Enter start date in format YYYY-MM-DD") }} {{ textbox(form.end_date, hint="Enter end date in format YYYY-MM-DD") }}
    {% endcall %} - {% endset %} - - {{ govukDetails({ - "summaryText": "Apply filters", - "html": details_content, - "open": form.errors | convert_to_boolean - }) }} +
    {% for noti_type in global_stats %} diff --git a/app/templates/views/platform-admin/services.html b/app/templates/views/platform-admin/services.html index c42a76af7..c10abb095 100644 --- a/app/templates/views/platform-admin/services.html +++ b/app/templates/views/platform-admin/services.html @@ -6,7 +6,6 @@ {% from "components/message-count-label.html" import message_count_label %} {% from "components/table.html" import mapping_table, field, stats_fields, row_group, row, right_aligned_field_heading, hidden_field_heading, text_field %} {% from "components/form.html" import form_wrapper %} -{% from "components/details/macro.njk" import govukDetails %} {% macro stats_fields(channel, data) -%} @@ -102,21 +101,16 @@ {{ page_title|capitalize }}
  • - - {% set details_content %} - {% call form_wrapper(method="get") %} - {{ textbox(form.start_date, hint="Enter start date in format YYYY-MM-DD") }} - {{ textbox(form.end_date, hint="Enter end date in format YYYY-MM-DD") }} - {{ checkbox(form.include_from_test_key) }} -
    - - {% endcall %} - {% endset %} - - {{ govukDetails({ - "summaryText": "Apply filters", - "html": details_content - }) }} +
    + Apply filters + {% call form_wrapper(method="get") %} + {{ textbox(form.start_date, hint="Enter start date in format YYYY-MM-DD") }} + {{ textbox(form.end_date, hint="Enter end date in format YYYY-MM-DD") }} + {{ checkbox(form.include_from_test_key) }} +
    + + {% endcall %} +
    {% include "views/platform-admin/_global_stats.html" %} diff --git a/gulpfile.js b/gulpfile.js index 257aef277..ff2903295 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -63,8 +63,7 @@ const copy = { 'skip-link', 'header', 'footer', - 'back-link', - 'details' + 'back-link' ]; let done = 0; @@ -144,6 +143,7 @@ const javascripts = () => { paths.src + 'javascripts/govuk/cookie-functions.js', paths.src + 'javascripts/cookieMessage.js', paths.src + 'javascripts/stick-to-window-when-scrolling.js', + paths.src + 'javascripts/detailsPolyfill.js', paths.src + 'javascripts/apiKey.js', paths.src + 'javascripts/autofocus.js', paths.src + 'javascripts/enhancedTextbox.js', diff --git a/tests/app/main/views/test_api_integration.py b/tests/app/main/views/test_api_integration.py index 5ba9a68c1..326f68d1e 100644 --- a/tests/app/main/views/test_api_integration.py +++ b/tests/app/main/views/test_api_integration.py @@ -37,7 +37,7 @@ def test_should_show_api_page( rows = page.find_all('details') assert len(rows) == 5 for row in rows: - assert row.select('h3 .govuk-details__summary-text')[0].string.strip() == '07123456789' + assert row.find('h3').string.strip() == '07123456789' def test_should_show_api_page_with_lots_of_notifications(