This post is part 30 of 31 in the series Programming by Stealth

In this instalment we’re going to continue with our dual-track approach, first, looking at some more JavaScript prototypes, then switching tack to HTML forms again.

We’ll start with my sample solution to the challenge set in the previous instalment. Then, we’ll move on to add an important enhancement to our prototypes – support for object comparisons. Strictly speaking, this won’t actually be revision – we haven’t looked at the intricacies of comparing objects before.

We’ll finish our JavaScript section with another challenge.

When we switch back to HTML we’ll take a big-picture look at an important accessibility standard named WAI-ARIA. We want to build our forms in a screen-reader-friendly way from day one, and to do that, we need to begin learning about ARIA. ARIA is really quite big, so all we’ll be doing this time is taking in an overview so we understand why it exists, and the basic concepts its built around.

We’ll finish by creating a final, fully accessible, button complete with a pretty scalable icon.

In the next instalment we’ll finally be ready to move on to some more different form inputs, specifically, checkboxes and radio buttons.

Solution to PBS 29 Challenge

Comparing Objects

At this stage our prototypes are free of glaring problems, but they are still missing an important chunk of functionality – they lack support for comparisons.

The JavaScript language provides useful comparison operators for values like numbers, strings, and booleans, but not for objects. When dealing with objects, the == and === operators only tell us whether or not two variables contain references to the same object. The following code illustrates this:

t1 and t2 contain references to two different objects that contain the same values, while t1 and t3 are references to the same object.

The core JavaScript language does not provide any mechanism for meaningful object comparisons – if you want instances of your prototypes to be comparable to each other, it’s entirely up to you to provide that functionality.

Not only does JavaScript not provide you with a mechanism for object comparison, there is not even an agreed standard approach to this problem. The closest we can come to any kind of right way of doing this is to follow some community conventions.

Basically, what many people choose to do in JavaScript is to follow Java’s comparison rules (Java does not rely on conventions, there is a formally defined correct way of making Java objects comparable). That is to say, many JavaScript programmers choose to add two comparison functions to each of their prototypes – .equals(), and .compareTo().

The first of these, .equals() should take one argument, return true if that argument is a reference to an object that should be considered to have the same value as the object the function was called on, and return false in all other situations.

Let’s add a .equals() function to the pbs.Time prototype:

We can test our new .equals() function with the following code:

Notice the symmetry – t1.equals(t2) gives the same result as t2.equals(t1). This should always be the case with a properly implemented .equals() function.

The second comparison function, .compareTo(), is a little more complex, but not much. Like .equals(), it expects one argument, but rather than simply testing for equality, it tests for ordering, and returns -1 if the object passed should be considered less than the object the function was called on, 0 if they should be considered equal, 1 if the value passed should be considered greater than the object the function was called on, or NaN if the passed value is invalid in some way.

Let’s add a .compareTo() function to our pbs.Time prototype:

We can test our .compareTo() function with the following code:

Again, there should be symmetry in the outputs, if t1.compareTo(t2) returns 0, then t2.compareTo(t1) should also return 0. Furthermore, if t1.compareTo(t2) returns -1, then t2.compareTo(t1) should return 1, and vica-versa.

Updated JavaScript Prototype Algorithm

Given all we have learned over the past few instalments, we need to update our original six-step process for creating prototypes to the following 8 step process:

  1. Gather your requirements, specifically, what data do your objects need to store, and, what functions need to be provided.
  2. Initialise your namespace and start a self-executing anonymous function within which you’ll define your prototype.
  3. Write your constructor. In general, your constructor should accept initial values for all your object’s pieces of data, and if none are provided, a sane default should be used. You should validate all data from the user and throw an exception if it’s not usable.
  4. Write your accessor methods – one for each piece of data your objects need to store. When called with no arguments, the accessor methods should get the current value, when called with an argument, they should set the value. Again, when setting, validate the data and throw an exception if the passed value is unusable.
  5. Write the functions you need to provide.
  6. Provide a .toString() function.
  7. Provide a .clone() function.
  8. Provide comparison functions (.equals() & .compareTo()).

Challenge

Add .equals() and .compareTo() functions to all three prototypes. You can make use of the .equals() and .compareTo() functions in pbs.Date and pbs.Time to avoid code duplication in pbs.DateTime.

Finally, because our prototypes are all time-related, implement two additional functions in each prototype named .isBefore() and .isAfter(). You can make use of the prototypes’ .compareTo() functions to do most of the work within these new functions.

You can test all of your comparison operators with the following code:

Making Web Forms Accessible

Let’s leave JavaScript Prototypes behind, and switch context back to HTML forms.

It’s been my aim in this series to skip over all the mistakes made in earlier versions of HTML, and to start by doing things the right way. That’s why I want to make the forms we create accessible from the start, and to that end, we should look at the relevant web standard – WAI-ARIA.

A Big-Picture Introduction to WAI-ARIA

ARIA is big, very big. It would take us months to go through it all in any kind of detail. So, what we’ll do is start with a very high-level overview, and then learn the specifics in small bite-sizes pieces as and when we need them.

The Problem to be Solved

Let’s start with the problem to be solved. Historically, web pages were very simple things, so if developers remembered to do a few little things like add alt attributes to <img> tags, screen readers and other assistive devices would have no problem helping the visually impaired surf the web. However, things have changed – modern web sites are often interactive, and in fact, many modern sites would be much more accurately described as web-based apps. JavaScript and CSS have turned what was once mostly just text into a collection of complex interactive user interfaces, and assistive technologies need some help to deal with this new reality.

WAI-ARIA 1.0 to the Rescue

This is where the Web Accessibility Initiative, or WAI, comes in. The WAI are an industry group under the World Wide Web Consortium (AKA the WC3) with high-profile members like Adobe, HP & IBM. They work on standards for making the web accessible.

In 2014 WAI finalised the first version of the W3C recommendation on Accessible Rich Internet Applications, or WAI-ARIA. This is still the most recent finalised versions of ARIA. To save our sanity, from now on in this series, we’ll refer to version 1.0 of WAI-ARIA as simply ARIA.

Three Main Components of ARIA

Like I said, ARIA is big, very big, but if you zoom out far enough, you can break it into three broad topic areas:

  1. ARIA Roles
  2. ARIA States & Properties
  3. Keyboard Navigation

These concepts are quite abstract, but in practice, the actual code tends to be very human-friendly, and thankfully, most things in ARIA are well named, so I think most people will find them quite intuitive.

The most important concept is that of ARIA roles. The basic idea is that no matter what HTML tags you use, a page or web app consists of widgets that do certain things, and you should use the role attribute to tell assistive technologies what role different HTML elements play on your web page/web app.

For example, you might have a div that contains an h1, an h2, and an image that together form your site’s banner. To make that fact clear to assistive devices, you should add a role attribute to the <div> tag with the value banner:

The specification defines a lot of different possible roles, and they get quite granular. A very common example of a more granular role is that of button. For aesthetic reasons, some websites like to use images with JavaScript click handlers as buttons. Before ARIA this would totally flummox assistive technologies. Now, with ARIA roles, you simply add a role attribute with the value button to the <img> tag, and assistive technologies know they should treat the image as if it were a button.

ARIA roles don’t only exist on elements with explicit role attributes, they also exist implicitly for HTML tags for which they make sense.

For example, the top-level <header> tag on any page gets the implicit ARIA role banner. Unsurprisingly, <button> tags get the implicit ARIA role button.

Elements on a page that have an ARIA role, be that an explicit role defined with a role attribute or an implicit role based on the tag name, can define ARIA states and properties. From a practical point of view, there’s basically no difference between a state and a property, and they’re both defined by adding attributes to html elements who’s names start with aria-. The difference is so subtle that the official spec says:

Because the distinction between states and properties is of little consequence to most web content authors, this specification refers to both “states” and “properties” simply as “attributes” whenever possible.

Different roles support different states and properties, but some states and properties are globally applicable to all elements on a page.

An example of a global property is aria-hidden, which can be used to tell assistive technologies to completely ignore an element.

An example of a role-dependent state is aria-disabled, which only makes sense on things with roles like button, which can be disabled.

Finally, the ARIA spec says that everything clickable must be focusable with the keyboard. In practical terms that basically means you sometimes have to use the tabindex attribute when you assign an explicit ARIA role to things. For example, if you use an image as a button you should add two additional attributes to the <img> tag, role="button", and something like tabindex="0".

Properly Accessible Buttons with Glyph Icons

Let’s finish this instalment by getting back to some specifics. In the previous instalment we learned how to use glyph icon sets like Font Awesome to add icons to buttons. Our code looked something like:

Visually, buttons of this form work fine, but for assistive technologies they contain some potentially confusing additional information – that empty <span> tag. This serves no purpose other than visual ornamentation. As such, we should hide it from assistive technologies by applying the aria-hiden property to it like so:

Final Thoughts

At this stage we’ve nearly finished our second look at JavaScript prototypes. There is just one more object-related concept we need to look at next time – static functions. This is a technical term you may have encountered in the documentation for the various JavaScript APIs we have used, but it’s one we’ve neither defined nor explained in this series to date. It’s about time we rectified that oversight.

Now that we’ve been introduced to WAI-ARIA, we’re ready to start learning about more types of form elements. In the next instalment we’ll look at two new types – checkboxes and radio buttons, and we’ll learn how to use them so they are compatible with accessibility tools like screen readers.