Accessibility Bug Fix

Recently one of our customers discovered an accessibility bug that caused read order and tab order to diverge. When we investigated it, we discovered that the bug existed in the reader runtime, but that we could work-around the bug by changing the syntax that Designer generates. Fixing the problem in Designer is much preferable, since that doesn’t require upgrading Reader. Of course, waiting for a fix in Designer is not easy either. Fortunately, the macro capability offers us an alternative way to disseminate a fix.  First the usual caveat: macros are an experimental, unsupported product feature.  

The Bug

The bug scenario is when a custom tab order exits a subform; the read order follows the next-in-geographic order, while the tab order follows the explicit custom order.  Described differently, imagine a form with fields named "One", "Two" and "Three" and a subform named "S’.  The geographic order is: S.One, Three, Two, but the custom tab order is S.One, Two, Three. In the Reader runtime, the tab order correctly follows the custom order, but the Reader order gets confused on exiting the subform.

If you’re only interested in correct tab order you will not notice the problem.  However if you are using a screen reader and following read order, you will follow an incorrect order.  (If you examine the resulting form with tools like inspect32 or AccExplorer32 you’ll be able to see the result without actually running a screen reader)

I have included a sample form that illustrates the problem, and a version of the form with the fix applied.

The Fix

Down below, I’ll discuss the technical details of the fix.  But first the macro (rename to FixReadOrder.js) When you install and run the macro, it will scan the entire form searching for all the places where a custom tab order exits a subform. Each of these places will be modified. 

You will need to re-run the macro every time you make edits to the form that modify tab order.

The macro includes some logic so that it will stop functioning in the next version of Designer – given that we expect the bug to be fixed.

The Deep End

Custom tab order is controlled by the <traversal> and <traverse> elements.  The (stripped down) syntax of the original form looks like this:

 1 <subform>
 2  <subform name="S">
 3    <field name="One">
 4      <traversal>
 5        <traverse ref="Two[0]"/>
 6      </traversal>
 7    </field>
 8    <traversal>
 9      <traverse operation="first" ref="One[0]"/>
10    </traversal>
11  </subform>
12  <field name="Three"/>
13  <field name="Two">
14    <traversal>
15      <traverse ref="Three[0]"/>
16    </traversal>
17  </field>
18  <traversal>
19    <traverse operation="first" ref="Subform1[0]"/>
20  </traversal>
21 </subform>

There are two variations of the traverse element used here:

  1. operation="first": specifies the first child of a container (subform)
  2. operation attribute is unspecified (the default) — which means operation="next". Specifies the next element.

The runtime problem occurs when the traverse from field "one" at line 5 does not correctly navigate to field "Two".

Here is the fixed version:

 1 <subform>
 2   <subform name="S">
 3    <field name="One">
 4       <traversal>
 5         <traverse ref="Two[0]"/>
 6       </traversal>
 7     </field>
 8     <traversal>
 9       <traverse operation="first" ref="One[0]"/>
10       <traverse ref="Two[0]"/>
11     </traversal>
12   </subform>
13   <field name="Three"/>
14   <field name="Two">
15     <traversal>
16       <traverse ref="Three[0]"/>
17     </traversal>
18   </field>
19   <traversal>
20     <traverse operation="first" ref="Subform1[0]"/>
21   </traversal>
22 </subform>

The macro added a traverse element at line 10. Now we’ve explicitly told the subform which child to navigate to first and also where to navigate to when the children are finished.  In fact, we end up with two traverse elements pointing to field "Two".  Not surprisingly, the runtime correctly moves to "Two" in both tab order and read order.