The polyfill we use for details/summary only renders the arrow if the
browser doesn’t natively support the feature.
The latest versions of Firefox _do_ now support the feature (after 5
years), but for some reason they don’t draw the arrow. So this commit
forces the arrow to be polyfilled in all browsers, and hides the browser
default one, for those browsers that do render it.
It’s weird to be on a page that says ‘2 seconds ago’ and stays stuck
there.
We don’t want to AJAX the whole page because it would get in the way of
interacting with the list of notifications.
This commit adds the venerable jQuery Timeago[1] plugin to keep the
relative times accurate and fresh.
1. http://timeago.yarp.com/
Services who are in alpha or building prototypes need a way of sending
to any email address or phone number without having to sign the MOU.
This commit adds a page where they can whitelist up to 5 email addresses
and 5 phone numbers.
It uses the ‘list entry’ UI pattern from the Digital Marketplace
frontend toolkit [1] [2] [3].
I had to do some modification:
- of the Javascript, to make it work with the GOV.UK Module pattern
- of the template to make it work with WTForms
- of the content security policy, because the list entry pattern uses
Hogan[1], which needs to use `eval()` (this should be fine if we’re
only allowing it for scripts that we serve)
- of our SASS lint config, to allow browser-targeting mixins to come
after normal rules (so that they can override them)
This commit also adds a new form class to validate and populate the two
whitelists. The validation is fairly rudimentary at the moment, and
doesn’t highlight which item in the list has the error, but it’s
probably good enough.
The list can only be updated all-at-once, this is how it’s possible to
remove items from the list without having to make multiple `POST`
requests.
1. 434ad30791/toolkit/templates/forms/list-entry.html
2. 434ad30791/toolkit/scss/forms/_list-entry.scss
3. 434ad30791/toolkit/javascripts/list-entry.js
4. http://twitter.github.io/hogan.js/
Users need to pick a time in the next 24hrs, or send a file immediately.
Rationale for this is a bit lost in time-before-holiday, but generally:
‘Now’ and ‘later’ as the inital choices makes it really clear what
this feature is about conceptually.
The choice of times is absolute, eg ‘1pm’ not ‘in 3 hours’
The pages with AJAX on were feeling quite sluggish, and it felt like
they were making the whole browser slow down.
Looking at the performance stuff in Chrome, the number of DOM nodes was
going up and up, which is weird because the number of things on the page
wasn’t changing. This was causing the page to consume more and more
memory in order to store all these nodes.
This is kinda beyond my understanding, but I tried a few things and it
looks like the browser was having a hard time garbage collecting the
temporary bits of DOM used to update the page.
By assinging these bits of DOM to variables before using them it seems
that the browser has an easier time cleaning them up.
Implements: https://github.com/alphagov/notifications-utils/pull/51
Copies the same regex.
Adds some CSS to display conditional placeholders differently to
normal placeholders (vertical rather that curved right-hand edge).
Text messages have a maximum length, which we tell the users. We
shouldn’t expect people to count the characters in the message
themselves.
This commit borrows [the word counter from the Digital Marketplace
frontend toolkit](9d17690de5/toolkit/javascripts/word-counter.js)
and adapts it to count characters instead.
Things I’m still not sure about with this:
- what should it say when the message goes over the length of one text
message
- what’s the interaction with placeholders, which will change the length
of the message
This commit also adds a line to the pricing page which explains that
service name counts towards the length of the message.
A long email message needs to be collapsed to only show the first few
lines. The problem is that we were doing this by adding a class with
Javascript, meaning that the email wasn’t being collapsed until the
script in the footer ran.
This caused a jump in the page because the browser was painting the
whole email message, then repainting it once it was collapsed.
This commit takes advantage of the `.js-enabled` class added to the
`<body>` by a script in the `<head>` of GOV.UK template.
This means that the email message is collapsed with CSS before the first
paint of the page, so no jump.
This introduces some complexity in how we determine which emails get the
expander toggle. Because they’re already collapsed we can’t get their
height and work out if they’re long enough to need collapsing.
So we need to take a copy of the message, put it off-screen, expand it,
get its height, then remove it from the DOM. Bit of a faff.
Because of this there’s still a quick flash of the toggle if you see an
email message that’s too short to need collapsing. I think this is the
lesser of two evils—very short email messages will be few and far
between in the real world.
With the change in implementation in the previous commit, any error
(eg server responds with `500`) would cause the page to not be updated
again.
This is better than the previous implementation, whereby the browser
would re-request as fast as it could until it got a successful response.
This commit handles errors by clearing the render queue if the server
returns an error. So:
- Any updates that would have been performed based on this request are
dropped
- Subsequent updates will be attempted as if it was the first load of
the page, ie after a delay of `x` seconds
The `updateContent` module updates a section of the page based on an
AJAX request.
The current implementation will poll every `x` seconds. If the server
takes a long time to respond, this results in a the browser queuing up
requests. If a particular endpoint is slow, this can result in one
client making enough requests to slow down the whole server, to the
point where it gets removed from the loadbalancer, eventually bringing
the whole site down.
This commit rewrites the module so that it queues up the render
operations, not the requests.
There is one queue per endpoint, so for
`http://example.com/endpoint.json`:
1. Queue is empty
```javascript
{
'http://example.com/endpoint.json': []
}
```
2. Inital re-render is put on the queue…
```javascript
{
'http://example.com/endpoint.json': [
function render(){…}
]
}
```
…AJAX request fires
```
GET http://example.com/endpoint.json
```
3. Every `x` seconds, another render operation is put on the queue
```javascript
{
'http://example.com/endpoint.json': [
function render(){…},
function render(){…},
function render(){…}
]
}
```
4. AJAX request returns queue is flushed by executing each queued
render function in sequence
```javascript
render(response); render(response); render(response);
```
```javascript
{
'http://example.com/endpoint.json': []
}
```
5. Repeat
This means that, at most, the AJAX requests will never fire more than
once every `x` seconds, where `x` defaults to `1.5`.
Depends on:
- [ ] https://github.com/alphagov/notifications-utils/pull/40
In research we’ve noticed two problems with the appearance of
placeholders:
1. We are inconsistent about when we display the ((double brackets)).
Sometimes we show them, sometimes we don’t. This doesn’t help user’s
understanding about where the column names in their CSV file come
from, or how they can edit the template to fix any errors.
2. Because they look so different from normal `<textarea>` text, it’s
not immediately obvious that they can be edited just like normal
text. They look more like something that can be dragged/inserted.
So this commit:
1. Makes the brackets always-visible.
2. Makes the text colour of the placeholder `$text-colour`, and only
highlights the name of the ‘variable’, not the brackets themselves.
The details element is fairly new. It doesn’t work in all browsers,
and isn’t keyboard/screenreader accessible even in some new browsers.
This commit adds the Polyfill script from GOV.UK elements[1] which
polyfills these features for browsers that don’t support them.
1. http://govuk-elements.herokuapp.com/typography/#typography-hidden-text
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
For users who:
- want to send messages from a template
- want to edit templates
For developers:
- who need to get the ID of a template
This commit mainly cleans up the choose template page so there are less
options, and the options that are there are less wordy.
This means:
- moving ‘send yourself a test’ onto the send messages page, and making
it button
- stripping a lot of stuff out of the ‘send from API’ page, so it’s more
obvious what the template ID is
This commit makes the placeholder hint not be dependent on their only
being one textbox with placeholders on a page.
To do this it needs to be its own module, because the two textboxes are
each self-contained instances of the same module.
The way I’ve gone about this is to make the placeholder hint accept a
list of textboxes it should look in when deciding what message to
display to the user.
Most of the code is extracted from the existing placeholder highlighting
module.
It’s a bit silly to have email templates expandable if you’re only going
to reveal a couple more lines.
This commit adds a data attribute which specifies how high (in pixels)
the email template can be before it gets truncated. It then changes the
script to only truncate emails which are naturally taller than this
height.
Currently the cut off is at 200px, which is approximately 8 lines of
text: `200px / (font-size: 19px * line-height: 1.31) = 8.03`
Emails can get very long.
When you’re trying to do other things on the page this results in a lot
of scrolling.
This commit truncates email messages to about 3 lines, and adds a JS
toggle which reveal the full contents of the email.
We’ve seen users try to click the upload again when their file doesn’t
upload in time. This is because we’re giving them no feedback that
something is happening.
I reckon that changing the button to a cancel button is the easiest way
to show that something is happening, and also means that (unlike
disabling the send button) the user can’t get stuck if the connection
drops completely.
We put a border on text boxes that have errors. This means that they
take up more space than the layers above them which don’t have borders.
This makes the layers that highlight the fields in a template misalign.
This commit adds a line to make the borders match, which fixes this.
This commit makes the ‘how to do placeholders’ box part of the tour,
with the same blue background.
It also adds some Javascript enhancement so that:
- it responds to the contents of the message template
- has a ‘show me’ link which inserts ‘Dear ((name))’ into the template
contents textbox
We’ve found that this has helped people understnad what placeholders
are, and how to do them.
Some pages with AJAX should update quickly, because the data is likely
to be changing quickly, and be finished changing sooner. Other pages we
want to have tick over a bit slower.
This commit adds an optional ‘interval’ parameter to the updateContent
modules, which sets how often the page should ping the server for an
update.
It then sets the interval for the dashboard page to be 10 seconds,
rather than the default 1.5 seconds.
This applies to any textbox which has placeholders.
There are two reasons to do this:
1. Scrolling in textboxes is fiddly, especially on touch devices
2. Keeping the placeholders aligned with the textbox is fiddly too
These can both be avoided by always having the textbox be larger than its
contents so it never needs to scroll.
By default—and unlike other block-level elements—textboxes dont expand to fit
their contents. The layer with the placeholders in _does_ however, because it’s
a normal block-level element.
Since the layer with the placeholders always has an exact copy of what in the
textbox, we can set the textbox’s height to match the height of the layer with
the placeholders, and do this every time the content changes.
This is a bug with the code that highlights placeholders.
It was taking the value of the textbox and copying it straight into the HTML
of the layer that contains the blue lozenges. This meant that any HTML that the
user typed into the textbox was rendered by the browser.
This commit fixes the bug by:
1. taking the contents of the textbox
2. copying it to the _text_ (not inner HTML) of a temporary `<div>`
3. taking the inner HTML of that `<div>` (whose text has been encoded with HTML
entities in step 2., eg `>` becomes `>`)
4. using that for the HTML content of the layer with the blue lozenges
This is a first go at having the job page update without refreshing.
The approach I’ve taken is to do all the rendering of HTML on the server side,
rather than use a Javascipt templating engine like mustache. This ensures that
we don’t have to maintain two sets of templates.
So the approach is to split the job page into partials. These partials can then:
- be included in the job page to render the whole page
- be rendered indivudually and then returned as a blob of HTML inside a JSON
response
Then I’ve added a Javascript module which looks for areas of the page that should
be reloaded. For each area of the page it will poll a URL and re-render that
section of the page when it gets new HTML. It implements some throttling so that
API calls will never happen more frequently than 0.67 times/second.
**Problem**
The file upload form submit automatically whenever the name of the selected file
changes.
If the user picks a file, and then navigates back the field is pre-filled
because the page is loaded from the browser’s back/forward cache.
This means that if they pick the same file again, the value of the upload field
hasn’t changed, and the form won’t be submitted.
**Solution**
The solution is to clear the form field[1] if the page is being loaded from the
back/forward cache. Then any time the user picks a file it represents and
actual change.
1. http://stackoverflow.com/questions/8861181/clear-all-fields-in-a-form-upon-going-back-with-browser-back-button
Because we’re not showing a summary of error messages screen reader users might
take a while to discover that there’s an error on the page. Since the only
real action on a page with errors is to correct them this commit adds some
Javascript to send focus straight to the first error message on a page.
As part of https://github.com/alphagov/notifications-admin/pull/187 the file
upload pattern was changed to auto-submit once a file had been picked. The
form that was submitted was, however, missing a CSRF token, as well as a submit
button for non-JS users.
This commit makes the file upload pattern self-contained, so that it will always
include a form with a CSRF token in a hidden input and a submit button, which is
then hidden when Javascript loads.
The ‘manage templates’ page was almost identical to the ‘send text messages’
page.
This commit consolidates them into one and makes them all hang together.
Part of this means tweaks to the javascript so that files upload as soon as
you’ve chosen them.
This involves:
- removing the hard coded width on any textbox that does placeholder
highlighting
- adding JS to make sure that the extra layers on top of the textbox inherit
the width of the textbox that the user types in (so the layers don’t get
misaligned)
Keeping the textboxes at 2/3 width for consistency with how wide the messages
are on the ‘manage templates’ page.
This commit adds a very small Javascript module to autofocus a textbox on page
load. It should only be used once per page.
It also adds a parameter to the textbox macro which adds the attribute to
trigger autofocus.
This commit moves user-related navigation into the proposition header (the black
bar) at the top of the site. It adds some custom SASS to override GOV.UK
template and align these navigation items to the right (because it looks
better).
It then removes the service chooser dropdown (and its associated SASS and JS) in
favour of a link alongside the user-related navigation items. ‘Switch service’
is the best language for this that we’ve come up with so far.
This means that the only way of adding a new service is from the `/services`
page. So this commit removes the redirect if you land on this page with only one
service (else it would prevent you from ever being able to add more).
Copying what they’ve done on GOV.UK Pay, we should let users:
- generate as many keys as they want
- only see the key at time of creation
- give keys a name
- revoke any key at any time (this should be a one way operation)
And based on discussions with @minglis and @servingUpAces, the keys should be
used in conjunction with some kind of service ID, which gets encrypted with the
key. In other words the secret itself never gets sent over the wire.
This commit adds the UI (but not the underlying API integration) for doing the
above.
A previous commit removed these to differentiate between this page and the
manage templates page. It turns out that we do want previews on this page
because:
- the users for the two pages might be different—they might only be allowed to
do one or the other depending what permissions they have
- it’s useful to see what the placeholders in the message are before uploading
a CSV, to make sure the CSV has the correct column headings
This commit re-adds the message preview with a simpler UI. Discussed with
@antimega and we both agreed that the speech bubble tails on the messages should
go.
The previous service switcher was built purely in Javascript, which meant that,
for the purposes of progressive enhancement, it had to load in the open state.
Setting it to the closed state with Javascript happened a fraction of a second
after page load. This caused an unpleasant flicker as the whole page shifted up
and down as it loaded.
This commit changes the switcher to use the native HTML5 `details` and
`summary` elements[1].
This commit adds a polyfill from GOV.UK Elements for browsers which don’t
support `details`/`summary`.
1. http://html5doctor.com/the-details-and-summary-elements/
This commit adds a component for showing an API key. Usage:
```jinja
{{ from 'components/api-key.html' import api_key }}
{{ api_key('e1b0751388f3cd0fc9982c701acdb3c2') }}
```
Depending on the user’s browser, it works in three different ways.
No Javascript
---
The API key is shown on the page.
Older browsers with Javascript
---
The API key is hidden, and users can click a button to reveal it.
Newer browsers that support copying to clipboard without Flash
---
As above, but when the key is shown there is a button which copies it to the
clipboard. This is acheived by using
[this polyfill](https://www.npmjs.com/package/query-command-supported)
to reliably detect browser support for the ‘copy’ command.
The styling of the component is a bit different to the initial sketch. I think
a grey button works better than green. Green feels like it’s going to take you
somewhere else.
- by default, the menu is open
- if Javascript is enabled/loaded, the links are hidden, and visual cues (▶) to
show that it can be opened are added
- clicking it opens and closes it
This commit adds a feature detection for the `oninput` event, which isn’t
supported in older browsers[1].
This means that the code that highlights placeholders will only be run in
browsers that support the `oninput` event.
1. http://caniuse.com/#feat=input-event
ES6 has some nice new features. Specifically relevant to this piece of
work are:
Arrow functions[1], whose `this` context is bound the value of `this` in the
current scope and can’t be overidden. The code is cleaner as a result, and
doesn’t need the addition of a bind polyfill for older browsers.
Template strings[2], which are similar to triple-quoted multi line strings in
Python. This means less fiddly and error-prone string concatenation.
This commit adds Babel[3] to the Gulp pipeline. This transpiles Javascript
written to the ES6 specification into code which is compatible with older
browsers that don’t understand ES6 syntax.
It also rewrites the gulpfile itself using some ES6 syntax, for the same reasons.
1. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions
2. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/template_strings
3. https://babeljs.io
Users can add placeholders to their messages, eg
> …your vehicle ((registration number))
when the message is sent, this gets replaced with the data the user uploads, eg
> …your vehicle LC12 BFL
We reckon that it will be useful to see that the placeholder has been
recognised, ie that its syntax is correct, before uploading any data.
We reckon that the best way to do this is by styling it differently to the rest
of the text that the user types.
This is not a trivial problem. There are two possible ways to do it:
1 Write a Google Docs-style text rendering engine, which completely replaces
the native HTML `<textarea>` with a custom control, and programme what should
happen when the user types something that looks like a placeholder, or
presses an arrow key, or makes a selection, or…
2 Leave the `<textarea>` in place, unmodified, and duplicate layers in front
of/behind it to visually replace a placeholder with the blue lozenge
Unsurprisingly, this commit implements 2.
There are four layers. Each layer contains live-updated copy of the text in the
textbox, and each is styled differently:
- one layer behind the textbox to make the blue background
- the textbox itself
- a layer with the white text, which overlays the black text of the textbox
- a layer with an inner shadow to knock back the brackets
This is because of some interesting limitations:
- The text in the foreground and background must occupy the same physical space,
so no deleting characters from the duplicated layers
- Words can’t be split up into multiple elements,
eg `<span>((</span>regist…`:—this results in slightly different kerning to
`((regis…`, which messes up the alignment of the layers
- The textbox can’t be completely overlapped with a block of colour, because
the cursor disappears behind it. Trying to edit text when you can’t see the
cursor is hard.
Implementation
Technically this makes use of Paul Hayes work on Javascript modules in the
GOV.UK frontend toolkit[1].
It also makes use of the `oninput` event to detect changes to the textbox’s
contents. This is much more performant than `onkeydown`, `onpaste`, etc. Without
it the delay between user input and the layers all updating is too slow and you
see misalignment of the layers.
1. https://github.com/alphagov/govuk_frontend_toolkit/pull/227
…or how to move a bunch of things from a bunch of different places into
`app/static`.
There are three main reasons not to use Flask Assets:
- It had some strange behaviour like only
- It was based on Ruby SASS, which is slower to get new features than libsass,
and meant depending on Ruby, and having the SASS Gem globally installed—so
you’re already out of being a ‘pure’ Python app
- Martyn and I have experience of doing it this way on Marketplace, and we’ve
ironed out the initial rough patches
The specific technologies this introduces, all of which are Node-based:
- Gulp – like a Makefile written in Javascript
- NPM – package management, used for managing Gulp and its related dependencies
- Bower – also package management, and the only way I can think to have
GOV.UK template as a proper dependency
…speaking of which, GOV.UK template is now a dependency. This means it can’t be
modified at all (eg to add a global `#content` wrapper), so every page now
inherits from a template that has this wrapper. But it also means that we have a
clean upgrade path when the template is modified.
Everything else (toolkit, elements) I’ve kept as submodules but moved them to a
more logical place (`app/assets` not `app/assets/stylesheets`, because they
contain more than just SASS/CSS).