TPAC: Address severe accessibility issues
authorDan Scott <dscott@laurentian.ca>
Thu, 14 Mar 2013 21:52:09 +0000 (17:52 -0400)
committerMike Rylander <mrylander@gmail.com>
Fri, 15 Mar 2013 16:10:34 +0000 (12:10 -0400)
Using the Chrome Accessibility Dev Tools extension to run accessibility
audits against the TPAC turned up some "severe" issues, such as input
widgets lacking labels. In most cases the text for the labels was
present, but it needed to be associated with a <label> element. In some
other cases, it was easier to use the aria-label attribute to give the
widget an accessible label. Finally, we can use the placeholder
attribute where warranted as an accessible label.

These changes address the first set of accessibility issues I came
across via the audits and could address quickly.

Signed-off-by: Dan Scott <dscott@laurentian.ca>
Signed-off-by: Mike Rylander <mrylander@gmail.com>
Open-ILS/src/templates/opac/myopac/holds.tt2
Open-ILS/src/templates/opac/myopac/prefs_notify.tt2
Open-ILS/src/templates/opac/myopac/prefs_settings.tt2
Open-ILS/src/templates/opac/parts/advanced/expert.tt2
Open-ILS/src/templates/opac/parts/advanced/numeric.tt2
Open-ILS/src/templates/opac/parts/coded_value_selector.tt2
Open-ILS/src/templates/opac/parts/org_selector.tt2
Open-ILS/src/templates/opac/parts/place_hold.tt2
Open-ILS/src/templates/opac/parts/qtype_selector.tt2
Open-ILS/src/templates/opac/parts/searchbar.tt2

index fb89c50..e6ddb5a 100644 (file)
@@ -56,7 +56,9 @@
         <table cellpadding='0' cellspacing='0' class="opac-auto-097">
             <tr>
                 <td width="1">
-                    <select name="action" id="acct_holds_actions">
+                    <select name="action" id="acct_holds_actions" aria-label="[%
+                        l('Select your action for the selected holds')
+                    %]">
                         <option id='myopac_holds_actions_none' value=''>
                         -- [% l("Actions for selected holds") %] --
                         </option>
                     %]
                 </td>
                 <td align="right">
-                    [% IF CGI.param("available") %]
-                    <a href="[% mkurl('holds', {}, ['limit','offset','available']) %]">[% l('Show all') %]</a> |
-                    <strong>[% l("Show only available") %]</strong>
-                    [% ELSE %]
-                    <strong>[% l("Show all") %]</strong> |
-                    <a href="[% mkurl('holds',{available => 1},['limit','offset']) %]">[% l("Show only available") %]</a>
-                    [% END %] &nbsp; &nbsp;
-                    [% l("holds") %]
+                    [% IF CGI.param("available") -%]
+                    <a href="[% mkurl('holds', {}, ['limit','offset','available']) %]">[% l('Show all holds') %]</a> |
+                    <strong>[% l("Show only available holds") %]</strong>
+                    [% ELSE -%]
+                    <strong>[% l("Show all holds") %]</strong> |
+                    <a href="[% mkurl('holds',{available => 1},['limit','offset']) %]">[% l("Show only available holds") %]</a>
+                    [% END -%]
                     <select class="hide_me" id="holds_sort">
                         <option value="">[% l('-- Sort By --') %]</option>
                         <option value="title">[% l('Title') %]</option>
index cf7309a..43eed64 100644 (file)
             </td></tr>
             [% END %]
 
+            [% setting = 'opac.hold_notify' %]
             <tr>
-                <td>[% l('Notify by Email by default when a hold is ready for pickup?') %]</td>
+                <td><label for='[% setting %].email'>[%
+                    l('Notify by Email by default when a hold is ready for pickup?')
+                %]</label></td>
                 <td>
-                    [% setting = 'opac.hold_notify' %]
-                    <input name='[% setting %].email' type="checkbox"
+                    <input id='[% setting %].email' name='[% setting %].email' type="checkbox"
                         [% IF (matches = ctx.user_setting_map.$setting.match('email')); %] checked='checked' [% END %]/>
                 </td>
             </tr>
-            [%- IF allow_phone_notifications == 'true' %]
+            [%- IF allow_phone_notifications == 'true';
+                setting = 'opac.hold_notify'; 
+            -%]
             <tr>
-                <td>[% l('Notify by Phone by default when a hold is ready for pickup?') %]</td>
+                <td><label for='[% setting %].phone'>[%
+                    l('Notify by Phone by default when a hold is ready for pickup?')
+                %]</label></td>
                 <td>
-                    [% setting = 'opac.hold_notify' %]
-                    <input name='[% setting %].phone' type="checkbox"
+                    <input id='[% setting %].phone' name='[% setting %].phone' type="checkbox"
                         [% IF (matches = ctx.user_setting_map.$setting.match('phone')); %] checked='checked' [% END %]/>
                 </td>
             </tr>
+            [% setting = 'opac.default_phone' %]
             <tr>
-                <td>[% l('Default Phone Number') %]</td>
+                <td><label for='[% setting %]'>[% l('Default Phone Number') %]</label></td>
                 <td>
-                    [% setting = 'opac.default_phone' %]
-                    <input name='[% setting %]' type="text"
+                    <input id='[% setting %]' name='[% setting %]' type="text"
                         [% IF ctx.user_setting_map.$setting; %] value='[% ctx.user_setting_map.$setting | html %]' [% END %]/>
                 </td>
             </tr>
             [%- END %]
-            [% IF ctx.get_org_setting(ctx.search_ou, 'sms.enable') == 1 %]
+            [%- IF ctx.get_org_setting(ctx.search_ou, 'sms.enable') == 1;
+               setting = 'opac.hold_notify';
+            -%]
             <tr>
-                <td>[% l('Notify by Text by default when a hold is ready for pickup?') %]</td>
+                <td><label for='[% setting %].sms'>[%
+                    l('Notify by Text by default when a hold is ready for pickup?')
+                %]</label></td>
                 <td>
-                    [% setting = 'opac.hold_notify' %]
-                    <input name='[% setting %].sms' type="checkbox"
+                    <input id='[% setting %].sms' name='[% setting %].sms' type="checkbox"
                         [% IF (matches = ctx.user_setting_map.$setting.match('sms')); %] checked='checked' [% END %]/>
                 </td>
             </tr>
                 <td>[% l('Default Mobile Carrier') %]</td>
                 <td>[% INCLUDE "opac/parts/sms_carrier_selector.tt2" sms_carrier_hide_label="true" %]</td>
             </tr>
+            [% setting = 'opac.default_sms_notify' %]
             <tr>
-                <td>[% l('Default Mobile Number') %]</td>
+                <td><label for='[% setting %]'>[% l('Default Mobile Number') %]</label></td>
                 <td>
-                    [% setting = 'opac.default_sms_notify' %]
-                    <input name='[% setting %]' type="text"
+                    <input id='[% setting %]' name='[% setting %]' type="text"
                         [% IF ctx.user_setting_map.$setting; %] value='[% ctx.user_setting_map.$setting | html %]' [% END %]/>
                     [% l('Hint: use the full 10 digits of your phone #, no spaces, no dashes'); %]
                 </td>
index cd3ba17..7f682a2 100644 (file)
                 </td></tr>
                 [% END %]
 
+                [%- setting = 'opac.hits_per_page' -%]
                 <tr >
-                    <td width='20%'>[% l("Search hits per page") %]</td>
+                    <td width='20%'><label for='[% setting %]'>l("Search hits per page") %]</label></td>
                     <td>
-                        [% setting = 'opac.hits_per_page' %]
-                        <select name='[% setting %]'>
+                        <select id='[% setting %]' name='[% setting %]'>
                             [%  UNLESS ctx.user_setting_map.$setting;
                                     ctx.user_setting_map.$setting = 10;
                                 END;
                         /></a>
                     </td>
                 </tr>
+                [%- setting = 'opac.default_search_location'; -%]
                 <tr >
-                    <td width='20%'>[% l("Preferred search location") %]</td>
+                    <td width='20%'><label for='[% setting %]'>[% l("Preferred search location") %]</label></td>
                     <td>
-                        [%- setting = 'opac.default_search_location';
-                            thang = ctx.user.home_ou.id;
+                        [%- thang = ctx.user.home_ou.id;
                             IF ctx.user_setting_map.$setting;
                                 thang = ctx.user_setting_map.$setting;
                             END;
+                            id = setting;
                             INCLUDE build_org_selector name=setting value=thang;
                         %]
                     </td>
                 </tr>
+                [%- setting = 'opac.default_pickup_location'; -%]
                 <tr>
-                    <td width='20%'>[% l("Preferred pickup location") %]</td>
+                    <td width='20%'><label for='[% setting %]'>[% l("Preferred pickup location") %]</label></td>
                     <td>
-                        [%- setting = 'opac.default_pickup_location';
-                            thang = ctx.user.home_ou.id;
+                        [%- thang = ctx.user.home_ou.id;
                             IF ctx.user_setting_map.$setting;
                                 thang = ctx.user_setting_map.$setting;
                             END;
+                            id = setting;
                             INCLUDE build_org_selector name=setting value=thang can_have_vols_only=1;
                         %]
                     </td>
                 </tr>
+                [%- setting = 'history.circ.retention_start' -%]
                 <tr>
-                    <td>[% l('Keep history of checked out items?') %]</td>
+                    <td><label for='[% setting %]'>[% l('Keep history of checked out items?') %]</label></td>
                     <td>
-                        [% setting = 'history.circ.retention_start' %]
-                        <input name='[% setting %]' type="checkbox"
+                        <input id='[% setting %]' name='[% setting %]' type="checkbox"
                             [% IF ctx.user_setting_map.$setting; %] checked='checked' [% END %]/>
                     </td>
                 </tr>
+                [%- setting = 'history.hold.retention_start' -%]
                 <tr>
-                    <td>[% l('Keep history of holds?') %]</td>
+                    <td><label for='[% setting %]'>[% l('Keep history of holds?') %]</label></td>
                     <td>
-                        [% setting = 'history.hold.retention_start' %]
-                        <input name='[% setting %]' type="checkbox"
+                        <input id='[% setting %]' name='[% setting %]' type="checkbox"
                             [% IF ctx.user_setting_map.$setting; %] checked='checked' [% END %]/>
                     </td>
                 </tr>
+                [%- setting = 'opac.temporary_list_no_warn' -%]
                 <tr>
-                    <td>[% l('Skip warning when adding to temporary book list?') %]</td>
+                    <td><label for='[% setting %]'>[% l('Skip warning when adding to temporary book list?') %]</label></td>
                     <td>
-                        [% setting = 'opac.temporary_list_no_warn' %]
-                        <input name='[% setting %]' type="checkbox"
+                        <input id='[% setting %]' name='[% setting %]' type="checkbox"
                             [% IF ctx.user_setting_map.$setting %] checked='checked' [% END %]/>
                     </td>
                 </tr>
                 <!--
                 <tr>
-                    <td>[% l("Default Font Size") %]</td>
+                    <td><label for='prefs_def_font'>[% l("Default Font Size") %]</label></td>
                     <td>
                         <select id='prefs_def_font'>
                             <option value='regular'>[% l("Regular Font") %]</option>
index 9d80fe4..dc24767 100644 (file)
@@ -4,12 +4,12 @@
     <table class="expert-search">
         <tbody id="adv_expert_rows_here">
             <tr id="adv_expert_row">
-                <th>[% l("Tag:") %]</th>
-                <td><input type="text" name="tag" size="3" autofocus /></td>
-                <th>[% l("Subfield:") %]</th>
-                <td><input type="text" name="subfield" size="1" /></td>
-                <th>[% l("Value:") %]</th>
-                <td><input type="text" name="term" size="16" /></td>
+                <th><label for="expert_tag">[% l("Tag:") %]</label></th>
+                <td><input id="expert_tag" type="text" name="tag" size="3" autofocus /></td>
+                <th><label for="expert_subfield">[% l("Subfield:") %]</label></th>
+                <td><input id="expert_subfield" type="text" name="subfield" size="1" /></td>
+                <th><label for="expert_term">[% l("Value:") %]</label></th>
+                <td><input id="expert_term" type="text" name="term" size="16" /></td>
                 <td>
                     <a href="javascript:;" class="row-remover"
                         title="[% l('Remove row') %]" alt="[% l('Remove row') %]"
                <td colspan="7"><a href="javascript:addExpertRow();">[ [% l("Add row") %] ]</a></td>
             </tr>
             <tr>
+               [%- lib_select_id = "expert_search_library"; -%]
                <td colspan="5" class="expert-search-row">
-                   <label><strong>[% l("Search Library:") %]</strong>
+                   <label for="[% lib_select_id %]"><strong>[% l("Search Library:") %]</strong>
                        [%- PROCESS "opac/parts/org_selector.tt2";
-                           INCLUDE build_org_selector show_loc_groups=1 
+                           INCLUDE build_org_selector id=lib_select_id show_loc_groups=1 
                        %]
                    </label>
                </td>
index 8c1ad4a..d5df951 100644 (file)
@@ -4,8 +4,8 @@
     <input type="hidden" name="_special" value="1" />
     <table>
         <tr>
-            <td><label><strong>[% l("Field:") %]</strong>
-                <select name="qtype">
+            <td><label for="numeric_qtype"><strong>[% l("Field:") %]</strong></label>
+                <select id="numeric_qtype" name="qtype">
                     <!-- TODO: Pull labels from config.metabib_field.label -->
                     <option value="identifier|isbn">[% l('ISBN') %]</option>
                     <option value="identifier|issn">[% l('ISSN') %]</option>
                 </label>
             </td>
             <td>
-                <input type="text" name="query" size="16" autofocus />
+                <input type="text" name="query" size="16" autofocus placeholder='[% l("Identifier") %]' />
             </td>
         </tr>
         <tr>
-            <td colspan="2"><label><strong>[% l("Search Library:") %]</strong>
+            [%- lib_select_id="numeric_search_library" -%]
+            <td colspan="2"><label for="[% lib_select_id %]"><strong>[% l("Search Library:") %]</strong>
                   [% PROCESS "opac/parts/org_selector.tt2";
-                     INCLUDE build_org_selector show_loc_groups=1
+                     INCLUDE build_org_selector id=lib_select_id show_loc_groups=1
                   %]
                 </label>
             </td>
index 18bb4a4..7d7a03a 100644 (file)
@@ -17,7 +17,8 @@
 
 <select id='[% id %]' name='[% name %]'[%
     multiple ? ' multiple="multiple"' : '';
-    size ? (' size="' _ size _ '"') : ''; %]>
+    size ? (' size="' _ size _ '"') : '';
+%] aria-label="[% l('Select item type:') %]">
 [% IF none_ok %]
     <option value=''>[% none_label ? none_label : l('-- Any --') %]</option>
 [% END;
index 62b1898..d82933d 100644 (file)
@@ -24,10 +24,12 @@ BLOCK build_org_selector;
     # disable the ou-hide scoping altogether.
     hiding_disabled = ctx.org_hiding_disabled(value);
 
-    %]
+    -%]
 
-    <select [% IF id %] id='[% id %]' [% END %] name='[% name %]'>
-    [% 
+    <select [% IF id %] id='[% id %]' [% END -%]
+            [% IF arialabel %] aria-label='[% arialabel %]' [% END -%]
+            name='[% name %]'>
+    [%- 
         WHILE node_stack.size > 0; 
             node = node_stack.pop();
             org_unit = node.org;
@@ -107,6 +109,6 @@ BLOCK build_org_selector;
                 [% '&nbsp;' FOR [0..pad_depth]; display_name | html %]
             </option> 
 
-        [% END %]
+        [%- END %]
     </select>
-[% END %]
+[%- END %]
index 31892fd..33c45a6 100644 (file)
                     [% IF hdata.parts %]
                         [% IF hdata.parts.size > 0 %]
                         <div style='padding-left: 10px'>
-                            <span>[% hdata.part_required ? l('Select a Part:') : l('Select a Part (optional):') %]</span>
-                            <select name='part'>
+                            <span><label for='select_hold_part'>[%
+                                hdata.part_required ? l('Select a Part:') : l('Select a Part (optional):')
+                            %]</label></span>
+                            <select id='select_hold_part' name='part'>
                                 [% IF !hdata.part_required %]
                                 <option selected='selected' value=''>[% l('- All Parts -') %]</option>
                                 [% END %]
         </table>
 
         <p>
-            [% l('Pickup location:') %]
+            [%- org_select_id = 'pickup_lib'; -%]
+            <label for="[% org_select_id %]'>[%l('Pickup location:') %]</label>
             [% PROCESS "opac/parts/org_selector.tt2";
-                INCLUDE build_org_selector name='pickup_lib' value=ctx.default_pickup_lib id='pickup_lib' can_have_vols_only=1 %]
+                INCLUDE build_org_selector name='pickup_lib' value=ctx.default_pickup_lib id=org_select_id can_have_vols_only=1 %]
         </p>
         <p>
             [% l('Notify when hold is ready for pickup?') %]
             <blockquote>
-                <input type="checkbox" name="email_notify" value="t"
+                <input type="checkbox" id="email_notify" name="email_notify" value="t"
                     [% IF !ctx.user.email %]disabled="true"[% ELSIF ctx.default_email_notify %]checked="checked"[% END %]/>
-                    [% l('Yes, by Email') %]<br/>
+                    <label for="email_notify">[% l('Yes, by Email') %]</label><br/>
                 <blockquote>
                     [% l('Email Address:') %] <span name="email_address">[% ctx.user.email %]</span>
                 </blockquote>
                 [%- IF allow_phone_notifications == 'true' %]
-                <input type="checkbox" name="phone_notify_checkbox"
+                <input type="checkbox" id="phone_notify_checkbox" name="phone_notify_checkbox"
                     [% IF ctx.default_phone_notify %]checked="checked"[% END %]/>
-                    [% l('Yes, by Phone') %]<br/>
+                    <label for="phone_notify_checkbox">[% l('Yes, by Phone') %]</label><br/>
                 <blockquote>
-                    [% l('Phone Number:') %]<input type="text" name="phone_notify" [% setting = 'opac.default_phone';
+                    <label>[% l('Phone Number:') %]<input type="text" name="phone_notify" [% setting = 'opac.default_phone';
                     IF ctx.user_setting_map.$setting; %] value='[% ctx.user_setting_map.$setting | html %]'
-                    [%- ELSIF ctx.user.day_phone; %] value='[% ctx.user.day_phone | html %]' [% END %]/>
+                    [%- ELSIF ctx.user.day_phone; %] value='[% ctx.user.day_phone | html %]' [% END %]/></label>
                 </blockquote>
                 [%- END -%]
                 [% IF ctx.get_org_setting(ctx.search_ou, 'sms.enable') == 1 %]
-                <input type="checkbox" name="sms_notify_checkbox"
+                <input type="checkbox" id="sms_notify_checkbox" name="sms_notify_checkbox"
                     [% IF ctx.default_sms_notify %]checked="checked"[% END %]/>
-                    [% l('Yes, by Text Messaging') %]<br/>
+                    <label for="sms_notify_checkbox">[% l('Yes, by Text Messaging') %]</label><br/>
                 <blockquote>
                     [% INCLUDE "opac/parts/sms_carrier_selector.tt2" %]<br/>
                     [% INCLUDE "opac/parts/sms_number_textbox.tt2" %]<br/>
         </p>
         <input id="place_hold_submit" type="submit" name="submit" value="[% l('Submit') %]" title="[% l('Submit') %]"
             alt="[% l('Submit') %]" class="opac-button" />
-        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
         <input type="reset" name="cancel" onclick="javascript:history.go(-1);"
             value="[% l('Cancel') %]" id="holds_cancel" class="opac-button" />
     </form>
index a56bfe3..eda10a3 100644 (file)
@@ -7,7 +7,8 @@
     {value => "series", label => l("Series")},
     {value => "id|bibcn", label => l("Bib Call Number")}
 ] %]
-<select name="qtype"[% IF id; ' id="'; id ; '"' ; END %]>
+<select name="qtype"[% IF id; ' id="'; id ; '"' ; END -%]
+    aria-label="[% l('Select query type:') %]">
     [%  query_type = query_type || CGI.param('qtype') || search.default_qtypes.0;
         FOR qt IN query_types -%]
     <option value='[% qt.value | html %]'[%
index 8df74bb..0359c83 100644 (file)
             l(' for ');
         %]
         <span class='search_box_wrapper'>
-            <input type="text" id="search_box" name="query"
-                value="[% is_advanced ? ctx.naive_query_scrub(ctx.processed_search_query) : CGI.param('query') | html %]"
+            [%- # autosuggest breaks accessibility, as the aria-label
+                # attribute is removed when the Dijit is created. :(  %]
+            <input type="text" id="search_box" name="query" aria-label="[%
+                    l('Enter search query:');
+                %]" value="[% is_advanced ? ctx.naive_query_scrub(ctx.processed_search_query) : CGI.param('query') | html %]"
                 [%- IF use_autosuggest.enabled == "t" %]
                 dojoType="openils.widget.AutoSuggest" type_selector="'qtype'"
                 submitter="this.textbox.form.submit();"
                     [% IF basic_search != "f" %] autofocus [% END %] x-webkit-speech
                 [%- END # autosuggest enabled %] />
         </span>
-        [%- INCLUDE "opac/parts/qtype_selector.tt2" id="qtype";
-            l(' in '); INCLUDE build_org_selector show_loc_groups=1
-    %]
+        [%- 
+            select_lib_label = l("Select search library");
+            INCLUDE "opac/parts/qtype_selector.tt2" id="qtype";
+            l(' in ');
+            INCLUDE build_org_selector arialabel=select_lib_label show_loc_groups=1
+        -%]
     <span>
         <input id='search-submit-go' type="submit" value="[% l('Search') %]" alt="[% l('Search') %]" class="opac-button"
             onclick='setTimeout(function(){$("search-submit-spinner").className=""; $("search-submit-go").className="hidden"}, 2000)'/>