Skip to content

0.3.1 to 1.0.0 Migration Guide

mnewcomb314 edited this page Mar 24, 2021 · 17 revisions

Introduction

The 1.0.0 release of CAM finished adding support for all ARIA roles. It also brought in some bug fixes and improvements, some of which are breaking changes that lead to multiple 1.0 pre-release versions of CAM before the 1.0.0 version was released. The purpose of this page is to document the breaking changes and how to address them in consuming projects. This page organizes the breaking changes by category, but all need to be addressed as part of the upgrade to the 1.0.0 version of CAM.

Role Splitting

  • ROLES.OPTION has been split into ROLES.SINGLESELECTOPTION and ROLES.MULTISELECTOPTION. This was needed in order to support getting ROLES.SINGLESELECTLISTBOX working visually consistent across browsers combined with CAM's one-to-one role to HTML tag mapping.
    • If an option is being added to a ROLES.SINGLESELECTLISTBOX, then replace ROLES.OPTION with ROLES.SINGLESELECTOPTION.
    • For options added to ROLES.MULTISELECTLISTBOX, then replace ROLES.OPTION with ROLES.MULTISELECTOPTION.

Binding Event Listeners When Registering

  • If event listeners are bound after the register function is called, such as by addEventListener or on, then no changes are needed.
  • In the 0.x versions of CAM, the object passed to register could contain onFocus and onKeyboardClick callbacks for handling those particular events. In order to handle any event, those fields have been replaced by an events array of objects that allows for binding an event handler for any event. The objects that make up this array have a field of eventName for the string name of the particular event to bind for, and a listener field for specifying the event handler function. A sample of this way of binding event listeners can be seen in the test app at https://github.com/CurriculumAssociates/createjs-accessibility-tester/blob/290d6ab51c49381345b3b831c37c4f5c7ef48c89/src/widgets/ScrollBar.js#L29-L38.
    • For prior onFocus and onKeyboardClick fields, for example:
        onFocus: _focusHandler,
        onKeyboardClick: _keyboardClickHandler,
      
    • Becomes:
        events: [
          {
            eventName: 'focus',
            listener: _focusHandler
          },
          {
            eventName: 'keyboardClick',
            listener: _keyboardClickHandler
          }
        ],
      

Events Emitted

  • ROLES.ROW used to emit a keyboardClick event when used inside a ROLES.TREEGRID to indicate that a row should expand or collapse. That has been replaced by ROLES.TREEGRID emitting collapseRow or expandRow events. To handle this, the keyboardClick event listener on the row DisplayObject should be removed, and event listeners added to the tree grid DisplayObject for the collapse and expand row events.

Preventing CAM's Default Keyboard Behavior

Due to trying using semantic markup as much as possible, most keyboard behavior is actually the browser's default behavior for that element. But there are cases where CAM needs to add a keydown listener in order to follow WAI-ARIA Practices (https://www.w3.org/TR/wai-aria-practices-1.1/). Since CAM can emit keydown events once .accessible.enableKeyEvents on a registered DisplayObject is set to true, the intent is to allow for calling preventDefault on the event object passed to those listeners to prevent both default browser behavior and CAM's internal keydown listeners from providing their default behavior, in order to allow consuming projects to customize the behavior completely as needed. In 0.x not all keyboard listeners followed this pattern (some would, others would turn off the CAM keydown listener just by setting .accessible.enableKeyEvents to true). So, consuming projects should ensure that they are calling preventDefault in their keydown listeners when they want to disable default keyboard behavior as provided either by the browser or CAM.

Helping Achieve a Valid DOM

CAM tries to help ensure its translation of DisplayObjects to HTML produces valid a HTML structure by performing checks when adding a DisplayObject to the accessibility tree. It does this in the addChild and addChildAt functions of the AccessibilityObject and its subclasses by checking if the role and any other relevant properties of the DisplayObject trying to be added are valid given the this instance's role. However, in 0.x not all roles performed this check leading to it being overly lenient and allowing for invalid DOM structures. An audit and update of all roles was done for 1.0 and the added missing restrictions are:

  • ROLES.BUTTON only allows for interactive elements (either semantically or with a tabIndex set) to be added as children. This still allows for non-interactive children, such as a button wrapping an image.
  • ROLES.CHECKBOX, ROLES.IMG, ROLES.RADIO, ROLES.SINGLELINETEXTBOX, ROLES.SEPARATOR, ROLES.SLIDER, and ROLES.SPINBUTTON cannot have children.
  • ROLES.ORDEREDLIST and ROLES.UNORDEREDLIST can only have ROLES.LISTITEM as children.
  • ROLES.ROW can only have ROLES.CELL, ROLES.GRIDCELL, ROLES.COLUMNHEADER, and ROLES.ROWHEADER as children.
  • ROLES.TABLEBODY, ROLES.TABLEFOOT, and ROLES.TABLEHEAD can only have ROLES.ROW as children.
  • ROLES.TREE can only have ROLES.TREEITEM as children.

Parameter type fixes

  • The hasPopUp getter/setter of AccessibilityObject (the base class used to populate a registered DisplayObject's .accessible field) has been updated from a boolean to a string in order to allow for all the valid values that https://www.w3.org/TR/wai-aria-1.1/#aria-haspopup specifies
    • For existing true or false parameter values, add quotes around the value or use another mechanism to convert it to a string
    • For existing undefined parameter values, no change needs to be made

Getter/Setter Name Updates

This module uses camelCase for the various getters/setters available off of a registered DisplayObject's .accessible field. However, in 0.x, not all getters/setters followed this convention which has been corrected as part of the 1.0 release. The table below shows the change in name between 0.x and 1.0, where consuming projects should be updated to the 1.0 names. Since these getters/setters are defined by AccessibilityObject or its subclasses, some roles may already be using the camelCase in 0.x, but for simplicity the table below doesn't break out the 0.x to 1.0 changes by role; the 1.0 name should now work with all roles that support that getter/setter.

0.x Name 1.0 Name
autocomplete autoComplete
autofocus autoFocus
colcount colCount
colindex colIndex
colspan colSpan
crossorigin crossOrigin
hreflang hrefLang
ismap isMap
longdesc longDesc
rowcount rowCount
rowindex rowIndex
rowspan rowSpan
srcset srcSet
usemap useMap
valuetext valueText

Getter/Setter Removals

On AccessibilityObject there used to be a getter named reactProps. While the comment did list its access level as package, due to the lack of a _ some consuming projects thought it was a public property and would directly modify its contents. Since that object and its fields are an internal implementation detail of this module, it should not be accessed or modified by consuming projects. To help make this clear when not looking at the documentation comment, the getter has been removed. Consuming projects should use the public getters/setters of a registered DisplayObject's .accessible field. If there is not one available for the corresponding HTML attribute, then a PR or issue should be opened so adding support for that can be discussed and potentially added.

Single selection listboxes needing a default selected option

Due to the display of the select tag being controlled by the browser and not stylable through CSS, in some browsers an open listbox would appear over the canvas even if the DOM translation produced by CAM is otherwise hidden. To address this, CAM 1.0 changed from using the semantic select tag to the non-semantic ul tag. This is what caused the earlier discussed ROLES.OPTION splitting into single and multiselect variants, so that the single select option would use the li tag in order to ensure a valid DOM. A consequence of this is now single select listboxes require an option to be designated as the default selection. The test-app already does this (starting at https://github.com/CurriculumAssociates/createjs-accessibility-tester/blob/main/src/widgets/ListBox.js#L25-L26 which gets to https://github.com/CurriculumAssociates/createjs-accessibility-tester/blob/main/src/widgets/ListBox.js#L110). A sample of how to do this is:

listboxDisplayObject.accessible.selected = optionDisplayObjects[0];