From 33b4138e7982f98ce1be849b7a1d3d29d8e8f189 Mon Sep 17 00:00:00 2001 From: Chris Hill-Scott Date: Wed, 27 Apr 2016 09:28:42 +0100 Subject: [PATCH 1/2] Patch update sections of the page on AJAX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, when we update a section of the page with AJAX we replace the entire HTML of the section with the new HTML. This causes problems: - if you’re trying to interact with that section of the page, eg by inpecting it, clicking or hovering an element - (probably) for screenreaders trying to navigate a page which is changing more than is necessary This commit replaces the call to `.html()` with a pretty clever library called diffDOM[1]. DiffDOM works by taking a diff of the old element and the new element, then doing a patch update, ie only modifying the parts that have changed. This is similar in concept to React’s virtual DOM, while still allowing us to render all markup from one set of templates on the server-side. 1. https://github.com/fiduswriter/diffDOM --- app/assets/javascripts/updateContent.js | 9 ++- app/templates/partials/jobs/count.html | 35 ++++++---- .../partials/jobs/notifications.html | 52 +++++++++------ app/templates/partials/jobs/status.html | 28 +++++--- app/templates/views/dashboard/dashboard.html | 9 +-- app/templates/views/dashboard/today.html | 65 ++++++++++--------- app/templates/views/jobs/job.html | 36 +--------- gulpfile.babel.js | 3 +- package.json | 1 + 9 files changed, 124 insertions(+), 114 deletions(-) diff --git a/app/assets/javascripts/updateContent.js b/app/assets/javascripts/updateContent.js index 4c78d4473..0a20bca93 100644 --- a/app/assets/javascripts/updateContent.js +++ b/app/assets/javascripts/updateContent.js @@ -4,6 +4,8 @@ GOVUK.timeCache = {}; GOVUK.resultCache = {}; + var dd = new diffDOM(); + let getter = function(resource, interval, render) { if ( @@ -21,8 +23,11 @@ }; - let poller = (resource, key, component, interval) => () => getter( - resource, interval, response => component.html(response[key]) + let poller = (resource, key, $component, interval) => () => getter( + resource, interval, response => dd.apply( + $component.get(0), + dd.diff($component.get(0), $(response[key]).get(0)) + ) ); Modules.UpdateContent = function() { diff --git a/app/templates/partials/jobs/count.html b/app/templates/partials/jobs/count.html index 6caf5f548..70422f308 100644 --- a/app/templates/partials/jobs/count.html +++ b/app/templates/partials/jobs/count.html @@ -1,13 +1,24 @@ {% from "components/big-number.html" import big_number %} - + +
+ + + +
diff --git a/app/templates/partials/jobs/notifications.html b/app/templates/partials/jobs/notifications.html index 5a257f1b4..68b64bccb 100644 --- a/app/templates/partials/jobs/notifications.html +++ b/app/templates/partials/jobs/notifications.html @@ -1,22 +1,34 @@ {% from "components/table.html" import list_table, field, right_aligned_field_heading %} -{% call(item, row_number) list_table( - notifications, - caption=uploaded_file_name, - caption_visible=False, - empty_message="No messages to show yet", - field_headings=[ - 'Recipient', - right_aligned_field_heading('Status') - ] -) %} - {% call field() %} - {{ item.to }} - {% endcall %} - {% call field( - align='right', - status='error' if item.status == 'Failed' else 'default' - ) %} - {{ item.status|title }} at {{ item.sent_at|format_time }} - {% endcall %} -{% endcall %} +
+ +
+ {% call(item, row_number) list_table( + notifications, + caption=uploaded_file_name, + caption_visible=False, + empty_message="No messages to show yet", + field_headings=[ + 'Recipient', + right_aligned_field_heading('Status') + ] + ) %} + {% call field() %} + {{ item.to }} + {% endcall %} + {% call field( + align='right', + status='error' if item.status == 'Failed' else 'default' + ) %} + {{ item.status|title }} at {{ item.sent_at|format_time }} + {% endcall %} + {% endcall %} +
+ +
diff --git a/app/templates/partials/jobs/status.html b/app/templates/partials/jobs/status.html index 775d0c2d1..18305c4be 100644 --- a/app/templates/partials/jobs/status.html +++ b/app/templates/partials/jobs/status.html @@ -1,9 +1,19 @@ -{% if finished_at %} -

- Finished {{ finished_at|format_datetime }} -

-{% else %} -

- Started {{ uploaded_at|format_datetime }} -

-{% endif %} +
+ + {% if finished_at %} +

+ Finished {{ finished_at|format_datetime }} +

+ {% else %} +

+ Started {{ uploaded_at|format_datetime }} +

+ {% endif %} + +
diff --git a/app/templates/views/dashboard/dashboard.html b/app/templates/views/dashboard/dashboard.html index aab538aeb..4e4278bbc 100644 --- a/app/templates/views/dashboard/dashboard.html +++ b/app/templates/views/dashboard/dashboard.html @@ -18,13 +18,6 @@ {% include 'views/dashboard/no-permissions-banner.html' %} {% endif %} -
- {% include 'views/dashboard/today.html' %} -
+ {% include 'views/dashboard/today.html' %} {% endblock %} diff --git a/app/templates/views/dashboard/today.html b/app/templates/views/dashboard/today.html index 3c2377642..240e661bb 100644 --- a/app/templates/views/dashboard/today.html +++ b/app/templates/views/dashboard/today.html @@ -1,33 +1,40 @@ {% from "components/big-number.html" import big_number_with_status %} -

- In the last 7 days -

-
-
- {{ big_number_with_status( - statistics.get('emails_delivered', 0), - 'email' if statistics.get('emails_delivered') == 1 else 'emails', - statistics.get('emails_failed'), - statistics.get('emails_failure_rate', 0.0), - statistics.get('emails_failure_rate', 0)|float > 3, - failure_link=url_for(".view_notifications", service_id=current_service.id, template_type='email', status='failed') - ) }} -
-
- {{ big_number_with_status( - statistics.get('sms_requested', 0), - 'text message' if statistics.get('sms_requested') == 1 else 'text messages', - statistics.get('sms_failed'), - statistics.get('sms_failure_rate', 0.0), - statistics.get('sms_failure_rate', 0)|float > 3, - failure_link=url_for(".view_notifications", service_id=current_service.id, template_type='sms', status='failed') - ) }} +
+

+ In the last 7 days +

+
+
+ {{ big_number_with_status( + statistics.get('emails_delivered', 0), + 'email' if statistics.get('emails_delivered') == 1 else 'emails', + statistics.get('emails_failed'), + statistics.get('emails_failure_rate', 0.0), + statistics.get('emails_failure_rate', 0)|float > 3, + failure_link=url_for(".view_notifications", service_id=current_service.id, template_type='email', status='failed') + ) }} +
+
+ {{ big_number_with_status( + statistics.get('sms_requested', 0), + 'text message' if statistics.get('sms_requested') == 1 else 'text messages', + statistics.get('sms_failed'), + statistics.get('sms_failure_rate', 0.0), + statistics.get('sms_failure_rate', 0)|float > 3, + failure_link=url_for(".view_notifications", service_id=current_service.id, template_type='sms', status='failed') + ) }} +
+ {% with period = "in the last 7 days" %} + {% include 'views/dashboard/template-statistics.html' %} + {% endwith %} +
-{% with period = "in the last 7 days" %} - {% include 'views/dashboard/template-statistics.html' %} -{% endwith %} - diff --git a/app/templates/views/jobs/job.html b/app/templates/views/jobs/job.html index 1781ed70d..befbd0aa4 100644 --- a/app/templates/views/jobs/job.html +++ b/app/templates/views/jobs/job.html @@ -30,40 +30,10 @@ )}} {% endif %} - {% if not finished_at %} -
- {% endif %} - {% include 'partials/jobs/status.html' %} - {% if not finished_at %} -
- {% endif %} + {% include 'partials/jobs/status.html' %} - {% if not finished_at %} -
- {% endif %} - {% include 'partials/jobs/count.html' %} - {% if not finished_at %} -
- {% endif %} + {% include 'partials/jobs/count.html' %} - {% if not finished_at %} -
- {% endif %} - {% include 'partials/jobs/notifications.html' %} - {% if not finished_at %} -
- {% endif %} + {% include 'partials/jobs/notifications.html' %} {% endblock %} diff --git a/gulpfile.babel.js b/gulpfile.babel.js index bb1b4b2c6..1794e9961 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -68,7 +68,8 @@ gulp.task('javascripts', () => gulp .pipe(plugins.uglify()) .pipe(plugins.addSrc.prepend([ paths.npm + 'jquery/dist/jquery.min.js', - paths.npm + 'query-command-supported/dist/queryCommandSupported.min.js' + paths.npm + 'query-command-supported/dist/queryCommandSupported.min.js', + paths.npm + 'diff-dom/diffDOM.js' ])) .pipe(plugins.concat('all.js')) .pipe(gulp.dest(paths.dist + 'javascripts/')) diff --git a/package.json b/package.json index 09bef0a4e..e51d2b135 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "dependencies": { "babel-core": "6.3.26", "babel-preset-es2015": "6.3.13", + "diff-dom": "2.0.3", "govuk-elements-sass": "1.1.1", "govuk_frontend_toolkit": "4.6.0", "govuk_template_jinja": "https://github.com/alphagov/govuk_template/releases/download/v0.17.1/jinja_govuk_template-0.17.1.tgz", From 2f49e919e73191d721844bfd99933706a6cfb242 Mon Sep 17 00:00:00 2001 From: Chris Hill-Scott Date: Wed, 27 Apr 2016 09:43:27 +0100 Subject: [PATCH 2/2] Add ARIA live attribute to all AJAX updated areas So that screenreaders will report on updates to the page. --- app/templates/partials/jobs/count.html | 1 + app/templates/partials/jobs/notifications.html | 1 + app/templates/partials/jobs/status.html | 1 + app/templates/views/dashboard/today.html | 1 + 4 files changed, 4 insertions(+) diff --git a/app/templates/partials/jobs/count.html b/app/templates/partials/jobs/count.html index 70422f308..78583a7f6 100644 --- a/app/templates/partials/jobs/count.html +++ b/app/templates/partials/jobs/count.html @@ -5,6 +5,7 @@ data-module="update-content" data-resource="{{url_for(".view_job_updates", service_id=current_service.id, job_id=job_id)}}" data-key="counts" + aria-live="polite" {% endif %} > diff --git a/app/templates/partials/jobs/notifications.html b/app/templates/partials/jobs/notifications.html index 68b64bccb..687f18889 100644 --- a/app/templates/partials/jobs/notifications.html +++ b/app/templates/partials/jobs/notifications.html @@ -5,6 +5,7 @@ data-module="update-content" data-resource="{{url_for(".view_job_updates", service_id=current_service.id, job_id=job_id)}}" data-key="notifications" + aria-live="polite" {% endif %} > diff --git a/app/templates/partials/jobs/status.html b/app/templates/partials/jobs/status.html index 18305c4be..fcb11c38e 100644 --- a/app/templates/partials/jobs/status.html +++ b/app/templates/partials/jobs/status.html @@ -3,6 +3,7 @@ data-module="update-content" data-resource="{{url_for(".view_job_updates", service_id=current_service.id, job_id=job_id)}}" data-key="status" + aria-live="polite" {% endif %} > diff --git a/app/templates/views/dashboard/today.html b/app/templates/views/dashboard/today.html index 240e661bb..0a37580c5 100644 --- a/app/templates/views/dashboard/today.html +++ b/app/templates/views/dashboard/today.html @@ -5,6 +5,7 @@ data-resource="{{url_for(".service_dashboard_updates", service_id=current_service.id)}}" data-key="today" data-interval-seconds="2" + aria-live="polite" >

In the last 7 days