LP1615714 Accessible names for Material Icons
authorStephanie Leary <stephanie.leary@equinoxoli.org>
Thu, 25 May 2023 18:24:09 +0000 (18:24 +0000)
committerStephanie Leary <stephanie.leary@equinoxoli.org>
Wed, 31 May 2023 18:44:48 +0000 (18:44 +0000)
Adds ARIA labels or hidden text, as appropriate, to ensure that Material
Icons are announced to screen reader users in a sensible way rather than
having the icon keyword read as if it were normal text.

In buttons containing an icon with no text, both ARIA labels and title
attributes are used so that the tooltip matches the button's accessible
name. This helps sighted users of dictation software identify the
button's name. The icon keyword is hidden from screen readers with the
aria-hidden attribute.

In buttons with both an icon and text, the icon keyword is hidden from
screen readers.

Where icons appeared in inline text rather than a button or link, a
visually-hidden span has been added to mirror the existing title
attribute (tooltip), unless the icon was purely decorative.

As part of this cleanup, several <a click()> elements were identified
that had not already been addressed in other bug reports related to
keyboard navigation support. These have been changed to <button>, and
button types have been specified throughout. Other small role and alt
text errors identified by the Axe linter have also been corrected.

Note that this branch does not include labels for  the grid flair icons
(bug 1818086) or the grid actions toolbar (bug 1833726), which are
being addressed separately.

Signed-off-by: Stephanie Leary <stephanie.leary@equinoxoli.org>
60 files changed:
Open-ILS/src/eg2/src/app/share/combobox/combobox.component.html
Open-ILS/src/eg2/src/app/share/date-select/date-select.component.html
Open-ILS/src/eg2/src/app/share/datetime-select/datetime-select.component.html
Open-ILS/src/eg2/src/app/share/eg-help-popover/eg-help-popover.component.html
Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.html
Open-ILS/src/eg2/src/app/share/tree/tree.component.css
Open-ILS/src/eg2/src/app/share/tree/tree.component.html
Open-ILS/src/eg2/src/app/staff/acq/lineitem/copies.component.html
Open-ILS/src/eg2/src/app/staff/acq/lineitem/copy-attrs.component.html
Open-ILS/src/eg2/src/app/staff/acq/lineitem/lineitem-list.component.html
Open-ILS/src/eg2/src/app/staff/acq/lineitem/notes.component.html
Open-ILS/src/eg2/src/app/staff/acq/po/notes.component.html
Open-ILS/src/eg2/src/app/staff/acq/po/summary.component.html
Open-ILS/src/eg2/src/app/staff/acq/provider/acq-provider-search-form.component.html
Open-ILS/src/eg2/src/app/staff/acq/provider/summary-pane.component.html
Open-ILS/src/eg2/src/app/staff/acq/related/related.component.html
Open-ILS/src/eg2/src/app/staff/acq/search/acq-search-form.component.html
Open-ILS/src/eg2/src/app/staff/admin/acq/distribution_formula/distribution-formula-edit-dialog.component.html
Open-ILS/src/eg2/src/app/staff/admin/acq/funds/fund-tags.component.html
Open-ILS/src/eg2/src/app/staff/admin/local/copy-loc-order/copy-loc-order.component.html
Open-ILS/src/eg2/src/app/staff/admin/local/course-reserves/course-associate-users.component.html
Open-ILS/src/eg2/src/app/staff/admin/local/course-reserves/course-page.component.html
Open-ILS/src/eg2/src/app/staff/admin/local/course-reserves/course-term-map.component.ts
Open-ILS/src/eg2/src/app/staff/admin/server/floating-group/edit-floating-group.component.html
Open-ILS/src/eg2/src/app/staff/admin/server/perm-group-tree.component.html
Open-ILS/src/eg2/src/app/staff/booking/create-reservation-dialog.component.html
Open-ILS/src/eg2/src/app/staff/booking/create-reservation.component.html
Open-ILS/src/eg2/src/app/staff/booking/manage-reservations.component.html
Open-ILS/src/eg2/src/app/staff/cat/authority/manage.component.html
Open-ILS/src/eg2/src/app/staff/cat/marcbatch/marcbatch.component.html
Open-ILS/src/eg2/src/app/staff/cat/vandelay/import.component.html
Open-ILS/src/eg2/src/app/staff/cat/vandelay/queue-items.component.html
Open-ILS/src/eg2/src/app/staff/cat/vandelay/queued-record-matches.component.html
Open-ILS/src/eg2/src/app/staff/cat/vandelay/queued-record.component.html
Open-ILS/src/eg2/src/app/staff/cat/vandelay/recent-imports.component.html
Open-ILS/src/eg2/src/app/staff/cat/volcopy/vol-edit.component.html
Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.component.html
Open-ILS/src/eg2/src/app/staff/catalog/basket-actions.component.html
Open-ILS/src/eg2/src/app/staff/catalog/hold/hold.component.html
Open-ILS/src/eg2/src/app/staff/catalog/prefs.component.html
Open-ILS/src/eg2/src/app/staff/catalog/record/holdings.component.html
Open-ILS/src/eg2/src/app/staff/catalog/record/pagination.component.html
Open-ILS/src/eg2/src/app/staff/catalog/result/record.component.html
Open-ILS/src/eg2/src/app/staff/catalog/search-form.component.html
Open-ILS/src/eg2/src/app/staff/circ/checkin/checkin.component.html
Open-ILS/src/eg2/src/app/staff/circ/patron/checkout.component.html
Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.html
Open-ILS/src/eg2/src/app/staff/circ/patron/patron.component.html
Open-ILS/src/eg2/src/app/staff/login.component.html
Open-ILS/src/eg2/src/app/staff/nav.component.html
Open-ILS/src/eg2/src/app/staff/reporter/simple/sr-field.component.html
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html
Open-ILS/src/eg2/src/app/staff/share/admin-page/admin-page.component.html
Open-ILS/src/eg2/src/app/staff/share/bib-summary/bib-summary.component.html
Open-ILS/src/eg2/src/app/staff/share/holdings/batch-item-attr.component.html
Open-ILS/src/eg2/src/app/staff/share/holdings/copy-notes-edit/copy-notes-edit.component.html
Open-ILS/src/eg2/src/app/staff/share/marc-edit/rich-editor.component.html
Open-ILS/src/eg2/src/app/staff/share/patron/search.component.html
Open-ILS/src/eg2/src/app/staff/share/staff-banner.component.ts
Open-ILS/src/eg2/src/styles.css

index 08cf04f..cfc576e 100644 (file)
@@ -18,7 +18,7 @@
 </ng-container>
 
 <ng-container *ngIf="!readOnly">
-  <div class="d-flex">
+  <div class="input-group">
     <input type="text" 
       class="form-control"
       [id]="domId"
@@ -39,9 +39,9 @@
       container="body"
       (selectItem)="selectorChanged($event)"
       #instance="ngbTypeahead"/>
-    <div class="d-flex flex-column icons" (click)="openMe($event)">
-      <span class="material-icons">keyboard_arrow_up</span>
-      <span class="material-icons">keyboard_arrow_down</span>
-    </div>
+    <button type="button" class="input-group-text" (click)="openMe($event)"
+      aria-label="Open" i18n-aria-label title="Open" i18n-title>
+      <span class="material-icons" aria-hidden="true">unfold_more</span>
+    </button>
   </div>
 </ng-container>
index 78e2179..153d352 100644 (file)
       (ngModelChange)="inputChanged($event)"
       (keyup.enter)="onDateEnter()"
       (dateSelect)="onDateSelect($event)"/>
-    <div class="input-group-text p-0">
-      <button class="btn px-2" [disabled]="disabled"
+      
+      <button class="input-group-text" [disabled]="disabled"
+        title="Select Date" i18n-title aria-label="Select Date" i18n-aria-label
         (click)="datePicker.toggle()" type="button">
-        <span title="Select Date" i18n-title class="material-icons">event</span>
+        <span class="material-icons mat-icon-in-button" aria-hidden="true">event</span>
       </button>
-    </div>
   </div>
 </ng-container>
index 48f10cb..a6d1ed3 100644 (file)
     [attr.disabled]="readOnly ? true : null"
     [required]="required"
     (touch)="onTouched()">
-  <div class="input-group-btn">
-    <button class="btn btn-primary" ngbDropdownToggle
+  
+    <button class="input-group-text" ngbDropdownToggle
+      title="Select date and time" i18n-title
       aria-label="Select date and time" i18n-aria-label>
-      <span class="material-icons mat-icon-in-button">event</span>
+      <span class="material-icons mat-icon-in-button" aria-hidden="true">event</span>
     </button>
-  </div>
   <div ngbDropdownMenu>
     <div i18n *ngIf="readOnly">
       Cannot edit this date or time.
index 6b5e8ee..0998810 100644 (file)
@@ -3,8 +3,8 @@
   <span *ngIf="helpLink.length < 1">{{helpText}}</span>
 </ng-template>
 <button class="btn {{buttonClass}}" placement="{{placement}}" 
-  [ngbPopover]="popContent" triggers="click"
-  i18n-aria-label aria-label="Show help" aria-haspopup="true">
+  [ngbPopover]="popContent" triggers="click" aria-haspopup="true"
+  i18n-title title="Show help" i18n-aria-label aria-label="Show help">
   <span class="material-icons mat-icon-shrunk-in-button" 
-    i18n-aria-label aria-label="Show help">live_help</span>
+    aria-hidden="true">live_help</span>
 </button>
index 9de182c..d1daea3 100644 (file)
     <h4 class="modal-title" i18n>Record Editor: {{recordLabel}}</h4>
     <ng-container *ngIf="isDialog()">
       <button type="button" class="btn-close btn-close-white" 
+        i18n-title title="Close"
         i18n-aria-label aria-label="Close" (click)="closeEditor()"></button>
     </ng-container>
   </div>
   <div class="modal-body">
-    <form #fmEditForm="ngForm" role="form"
-          class="form-validated common-form striped-odd"
+    <form #fmEditForm="ngForm" class="form-validated common-form striped-odd"
           [egDateFieldOrderList]="dateFieldOrderList">
       <ng-container *ngIf="!record">
         <!-- display a progress dialog while the editor
@@ -29,6 +29,7 @@
       <ng-container *ngIf="record">
       <div role="alert" class="alert alert-danger" *ngIf="fmEditForm.errors?.['datesOutOfOrder'] && (fmEditForm.touched || fmEditForm.dirty)">
         <span class="material-icons" aria-hidden="true">error</span>
+        <span i18n class="visually-hidden">Error: </span>
         <span i18n>Dates must be in the correct order</span>
       </div>
 
           </ng-container> <!-- switch -->
         </div>
         <div class="col-lg-1" *ngIf="field.i18n && !field.readOnly">
-          <a (click)="openTranslator(field.name)"
-            i18n-title title="Translate">
-            <button class="btn btn-outline-info mat-icon-in-button">
-              <span class="material-icons">translate</span>
-            </button>
-          </a>
+          <button (click)="openTranslator(field.name)"
+            i18n-title title="Translate" i18n-aria-label aria-label="Translate"
+            class="btn btn-outline-info mat-icon-in-button">
+            <span class="material-icons" aria-hidden="true">translate</span>
+          </button>
         </div>
       </div>
       </ng-container>
index 0d29dd7..ed0167c 100644 (file)
@@ -17,3 +17,6 @@
   border-left: 2px dashed rgba(0,0,0,.125);
 }
 
+.btn-link {
+  line-height: 1;
+}
\ No newline at end of file
index 525fece..e59e6ca 100644 (file)
@@ -4,17 +4,21 @@
   <div class="eg-tree-node-wrapper d-flex"
     [ngStyle]="{'padding-left': (node.depth * 20) + 'px'}">
     <div class="eg-tree-node-expandy">
-      <div *ngIf="node.children.length" (click)="node.toggleExpand()"
-        i18n-title title="Toggle Expand Node">
-        <span *ngIf="!node.expanded" class="material-icons">expand_more</span>
-        <span *ngIf="node.expanded" class="material-icons">expand_less</span>
-      </div>
+      <ng-container *ngIf="node.children.length">
+        <button (click)="node.toggleExpand()" 
+          type="button" class="input-group-text" 
+          [attr.title]="node.expanded? 'Close nodes under ' + node.label : 'Open nodes under ' + node.label" 
+          [attr.aria-label]="node.expanded? 'Close nodes under ' + node.label : 'Open nodes under ' + node.label" 
+          i18n-aria-label i18n-title>
+          <span class="material-icons" aria-hidden="true">{{node.expanded? 'expand_less' : 'expand_more'}}</span>
+        </button>
+      </ng-container>
       <div *ngIf="!node.children.length" class="eg-tree-node-nochild">
        &nbsp; 
       </div>
     </div>
     <div class="eg-tree-node" [ngClass]="{active : node.selected}">
-      <a [routerLink]="" (click)="handleNodeClick(node)">{{node.label}}</a>
+      <button class="btn btn-link" (click)="handleNodeClick(node)">{{node.label}}</button>
     </div>
   </div>
 </div>
index 4978c66..923796e 100644 (file)
         <li class="list-group-item p-0 m-0 border-0" 
           *ngFor="let formula of lineitem.distribution_formulas()">
           <div class="d-flex">
-            <button class="btn btn-outline-danger material-icon-button p-0 m-0"
-              (click)="deleteFormula(formula)" title="Delete Formula" i18n-title>
-              <span class="material-icons">delete</span>
+            <button type="button" class="btn btn-outline-danger material-icon-button p-0 m-0"
+              (click)="deleteFormula(formula)" title="Delete {{formula.formula().name()}}" i18n-title
+              aria-label="Delete {{formula.formula().name()}}" i18n-aria-label>
+              <span class="material-icons" aria-hidden="true">delete</span>
             </button>
             <div class="ms-2">{{formula.create_time() | date:'short'}}</div>
             <div class="ms-2">{{formula.creator().usrname()}}</div>
index f45c6f1..99a1193 100644 (file)
         <ng-container *ngIf="disposition() === 'pre-order'">
           <button
             class="btn btn-outline-danger material-icon-button"
-            (click)="deleteRequested.emit(copy)" title="Delete Item" i18n-title>
-            <span class="material-icons">delete</span>
+            (click)="deleteRequested.emit(copy)" title="Delete Item" i18n-title
+            aria-label="Delete Item" i18n-aria-label>
+            <span class="material-icons" aria-hidden="true">delete</span>
           </button>
         </ng-container>
         <ng-container *ngIf="disposition() === 'on-order' || disposition() === 'delayed'">
-          <a href="javascript:;" (click)="receiveRequested.emit(copy)" i18n>Mark Received</a>
+          <button type="button" class="btn btn-link" (click)="receiveRequested.emit(copy)" i18n>Mark Received</button>
         </ng-container>
         <ng-container *ngIf="disposition() === 'received'">
-          <a href="javascript:;" (click)="unReceiveRequested.emit(copy)" i18n>Un-Receive</a>
+          <button type="button" class="btn btn-link" (click)="unReceiveRequested.emit(copy)" i18n>Un-Receive</button>
         </ng-container>
         <ng-container *ngIf="disposition() === 'on-order'">
-          <a href="javascript:;" class="ms-2" (click)="cancelRequested.emit(copy)" i18n>Cancel</a>
+          <button type="button" class="btn btn-link" class="ms-2" (click)="cancelRequested.emit(copy)" i18n>Cancel</button>
         </ng-container>
         <ng-container *ngIf="disposition() === 'delayed'">
-          &nbsp;<a href="javascript:;" (click)="cancelRequested.emit(copy)" i18n>Cancel</a>
+          &nbsp;<button type="button" class="btn btn-link" (click)="cancelRequested.emit(copy)" i18n>Cancel</button>
         </ng-container>
         <ng-container *ngIf="disposition() === 'delayed'">
           <span class="fst-italic ms-2" title="{{copy.cancel_reason().description()}}">
index ca92e3d..d997235 100644 (file)
 </div>
 
 <div *ngIf="batchFailure" class="row mt-2 p-2">
-  <div class="col-lg-12 p-2 border border-danger label-with-material-icon" i18n>
-    <span class="material-icons text-danger pe-2">report</span>
-    Batch operation failed: 
+  <div class="col-lg-12 p-2 border border-danger label-with-material-icon">
+    <span class="material-icons text-danger pe-2" aria-hidden="true">report</span>
+    <span class="visually-hidden" i18n>Alert</span>
+    <span i18n>Batch operation failed: 
     {{batchFailure.textcode}} {{batchFailure.desc}}
-
-    <a class="ms-auto" href="javascript:;
-      (click)="batchFailure = null" title="Close" i18n-title>
-      <span class="material-icons text-danger">close</span>
-    </a>
+    </span>
+    <button class="btn btn-link ms-auto" (click)="batchFailure = null
+      title="Close" i18n-title aria-label="Close" i18n-aria-label>
+      <span class="material-icons text-danger" aria-hidden="true">close</span>
+    </button>
   </div>
 </div>
 
 
     <div class="btn-toolbar">
       <button type="button" (click)="toggleExpandAll()"
-        class="btn btn-sm btn-outline-dark me-1">
-        <span title="Expand All" i18n-title *ngIf="!expandAll"
-          class="material-icons mat-icon-in-button">unfold_more</span>
-        <span title="Collapse All" i18n-title *ngIf="expandAll"
-          class="material-icons mat-icon-in-button">unfold_less</span>
+        class="btn btn-sm btn-outline-dark me-1"
+        [title]="expandAll ? 'Collapse All' : 'Expand All'" i18n-title 
+        [attr.aria-label]="expandAll ? 'Collapse All' : 'Expand All'" i18n-aria-label>
+        <span class="material-icons mat-icon-in-button" aria-hidden="true">{{expandAll ? 'unfold_less' : unfold_more}}</span>
       </button>
       <button [disabled]="pager.isFirstPage()" type="button"
+        title="First Page" i18n-title aria-label="First Page" i18n-aria-label
         class="btn btn-sm btn-outline-dark me-1" (click)="pager.toFirst(); goToPage()">
-        <span title="First Page" i18n-title
-          class="material-icons mat-icon-in-button">first_page</span>
+        <span class="material-icons mat-icon-in-button" aria-hidden="true">first_page</span>
       </button>
       <button [disabled]="pager.isFirstPage()" type="button"
+        title="Previous Page" i18n-title aria-label="Previous Page" i18n-aria-label
         class="btn btn-sm btn-outline-dark me-1" (click)="pager.decrement(); goToPage()">
-        <span title="Previous Page" i18n-title
-            class="material-icons mat-icon-in-button">keyboard_arrow_left</span>
+        <span class="material-icons mat-icon-in-button" aria-hidden="true">keyboard_arrow_left</span>
       </button>
       <button [disabled]="pager.isLastPage()" type="button"
+        title="Next Page" i18n-title aria-label="Next Page" i18n-aria-label
         class="btn btn-sm btn-outline-dark me-1" (click)="pager.increment(); goToPage()">
-        <span title="Next Page" i18n-title
-          class="material-icons mat-icon-in-button">keyboard_arrow_right</span>
+        <span class="material-icons mat-icon-in-button" aria-hidden="true">keyboard_arrow_right</span>
       </button>
       <div ngbDropdown class="me-1" placement="bottom-right">
         <button ngbDropdownToggle class="btn btn-outline-dark text-button">
       <div class="jacket-wrapper">
         <ng-container *ngIf="jacketIdent(li)">
           <a href="/opac/extras/ac/jacket/large/{{jacketIdent(li)}}">
-            <img class="jacket"
+            <img class="jacket" alt=""
               src='/opac/extras/ac/jacket/small/{{jacketIdent(li)}}'/>
           </a>
         </ng-container>
-        <ng-container *ngIf="!jacketIdent(li)"><img class="jacket"/></ng-container>
+        <ng-container *ngIf="!jacketIdent(li)"><img class="jacket" alt=""/></ng-container>
       </div>
 
       <div class="ms-2 flex-1"> <!-- lineitem summary info -->
             <span class="ms-1 me-1" i18n> | </span>
             <a class="label-with-material-icon" title="Items" i18n-title
               routerLink="./lineitem/{{li.id()}}/items" queryParamsHandling="merge">
-              <span class="material-icons small me-1">shopping_basket</span>
+              <span class="material-icons small me-1" aria-hidden="true">shopping_basket</span>
               <span i18n>Items ({{li.lineitem_details().length}})</span>
             </a>
             <span class="ms-1 me-1" i18n> | </span>
-            <a class="label-with-material-icon" title="Expand" i18n-title
-              href="javascript:;" (click)="toggleShowExpand(li.id())">
-              <ng-container *ngIf="!expandLineitem[li.id()]">
-                <span class="material-icons small me-1">unfold_more</span>
-                <span i18n>Expand</span>
-              </ng-container>
-              <ng-container *ngIf="expandLineitem[li.id()]">
-                <span class="material-icons small me-1">unfold_less</span>
-                <span i18n>Collapse</span>
-              </ng-container>
-            </a>
+            <button class="btn btn-link label-with-material-icon"
+              [title]="expandLineitem[li.id()] ? Collapse : Expand" i18n-title 
+              [attr.aria-label]="expandLineitem[li.id()] ? Collapse : Expand" i18n-aria-label 
+              (click)="toggleShowExpand(li.id())" type="button">
+              <span class="material-icons small me-1" aria-hidden="true">{{expandLineitem[li.id()] ? 'unfold_less' : 'unfold_more'}}</span>
+            </button>
             <span class="ms-1 me-1" i18n> | </span>
-            <a class="label-with-material-icon" title="Notes and Alerts" i18n-title
-              href="javascript:;" (click)="toggleShowNotes(li.id())">
-              <span class="material-icons small me-1">event_note</span>
+            <button class="btn btn-link label-with-material-icon" 
+              title="Notes and Alerts" i18n-title
+              (click)="toggleShowNotes(li.id())" type="button">
+              <span class="material-icons small me-1" aria-hidden="true">event_note</span>
               <span i18n>Notes and Alerts ({{li.lineitem_notes().length}})</span>
-              <span *ngIf="liHasAlerts(li)" class="text-danger material-icons"
-                title="Has Alerts" i18n-title>flag</span>
-            </a>
+              <span *ngIf="liHasAlerts(li)" class="text-danger material-icons" aria-hidden="true">flag</span>
+            </button>
             <ng-container *ngIf="li.eg_bib_id()">
               <span class="ms-1 me-1" i18n> | </span>
               <a class="label-with-material-icon me-2"
                 routerLink="/staff/catalog/record/{{li.eg_bib_id()}}"
                 target="_blank">
-                <span class="material-icons small me-1">library_books</span>
+                <span class="material-icons small me-1" aria-hidden="true">library_books</span>
                 <span i18n>Catalog</span>
               </a>
             </ng-container>
 
             <ng-container *ngIf="!li.eg_bib_id()">
               <span class="ms-1 me-1" i18n> | </span>
-              <a class="label-with-material-icon me-2"
-                href="javascript:;" (click)="openBibFinder(li.id())"
-                title="Link to Catalog" i18n-title>
-                <span class="material-icons small me-1">library_books</span>
+              <button class="btn btn-link label-with-material-icon me-2"
+                (click)="openBibFinder(li.id())" type="button">
+                <span class="material-icons small me-1" aria-hidden="true">library_books</span>
                 <span i18n>Link to Catalog</span>
-              </a>
+              </button>
             </ng-container>
 
             <span class="ms-1 me-1" i18n> | </span>
             <a class="label-with-material-icon"
               routerLink="lineitem/{{li.id()}}/worksheet/">
-              <span class="material-icons small me-1">create</span>
+              <span class="material-icons small me-1" aria-hidden="true">create</span>
               <span i18n>Worksheet</span>
             </a>
             <ng-container *ngIf="!picklistId && li.picklist() && li.picklist().name()">
               <a class="label-with-material-icon"
                 title="Selection List" i18n-title 
                 routerLink="/staff/acq/picklist/{{li.picklist().id()}}">
-                <span class="material-icons small me-1">widgets</span>
+                <span class="material-icons small me-1" aria-hidden="true">widgets</span>
                 <span i18n>{{li.picklist().name()}}</span>
               </a>
             </ng-container>
               <a class="label-with-material-icon"
                 title="Purchase Order" i18n-title
                 routerLink="/staff/acq/po/{{li.purchase_order().id()}}">
-                <span class="material-icons small me-1">center_focus_weak</span>
+                <span class="material-icons small me-1" aria-hidden="true">center_focus_weak</span>
                 <span i18n>{{li.purchase_order().name()}}</span>
               </a>
             </ng-container>
 
             <span class="ms-1 me-1" i18n> | </span>
             <a class="label-with-material-icon"
-              title="Request(s)" i18n-title
               href="/eg/staff/acq/requests/lineitem/{{li.id()}}"
               target="_blank">
-              <span class="material-icons small me-1">help</span>
+              <span class="material-icons small me-1" aria-hidden="true">help</span>
               <span i18n>Request(s)</span>
             </a>
 
             <a class="label-with-material-icon"
               [queryParams]="{f: 'jub:id', val1: li.id()}"
               routerLink="/staff/acq/search/invoices" target="_blank">
-              <span class="material-icons small me-1">list</span>
+              <span class="material-icons small me-1" aria-hidden="true">list</span>
               <span i18n>Invoice(s)</span>
             </a>
 
               <a class="label-with-material-icon"
                 title="Provider" i18n-title target="_blank" 
                 routerLink="/staff/acq/provider/{{li.provider().id()}}/details">
-                <span class="material-icons small me-1">store</span>
+                <span class="material-icons small me-1" aria-hidden="true">store</span>
                 <span i18n>{{li.provider().name()}}</span>
               </a>
             </ng-container>
             <ng-container *ngIf="li.queued_record()">
               <span class="ms-1 me-1" i18n> | </span>
               <a class="label-with-material-icon"
-                title="Import Queue" i18n-title
                 routerLink="/staff/cat/vandelay/queue/bib/{{li.queued_record().queue()}}"
                 target="_blank">
-                <span class="material-icons small me-1">queue</span>
+                <span class="material-icons small me-1" aria-hidden="true">queue</span>
                 <span i18n>Import Queue</span>
               </a>
             </ng-container>
index f942894..04366b1 100644 (file)
     </span>
     <button class="btn btn-sm btn-success ms-2" [disabled]="!alertEntry" 
       (click)="newNote(true)" i18n>Create Alert</button>
-    <a class="ms-auto" href="javascript:;" (click)="close()" title="Close" i18n-title>
+    <button type="button" class="btn btn-link ms-auto" (click)="close()" 
+      title="Close" i18n-title aria-label="Close" i18n-aria-label>
       <span class="material-icons text-danger">close</span>
-    </a>
+    </button>
   </div>
 
   <div *ngFor="let note of lineitem.lineitem_notes()">
index 5a8944b..4b8774d 100644 (file)
     </div>
     <button class="btn btn-sm btn-success ms-2" [disabled]="!noteText" 
       (click)="newNote()" i18n>New Note</button>
-    <a class="ms-auto" href="javascript:;" (click)="close()" title="Close" i18n-title>
+    <button type="button" class="btn btn-link ms-auto" (click)="close()" 
+      title="Close" i18n-title aria-label="Close" i18n-aria-label>
       <span class="material-icons text-danger">close</span>
-    </a>
+    </button>
   </div>
 
   <div *ngFor="let note of po.notes()">
index 44c9000..4add6a5 100644 (file)
   <hr class="p-0 m-0 mt-1"/>
   <div class="row mt-1">
     <div class="col-lg-12">
-      <a class="" href="javascript:;" class="label-with-material-icon"
+      <button type="button" class="btn btn-link label-with-material-icon"
         (click)="showNotes=!showNotes">
-        <span class="material-icons small me-1">event_note</span>
+        <span class="material-icons small me-1" aria-hidden="true">event_note</span>
         <span>Notes ({{po().notes().length}})</span>
-      </a>
+      </button>
       <ng-container *ngIf="po().order_date()"> <!-- show invoice actions only if order was activated -->
       <span class="ps-2 pe-2" i18n> | </span>
       <a [queryParams]="{f: 'acqpo:id', val1: poId}" class="label-with-material-icon"
         routerLink="/staff/acq/search/invoices">
-          <span class="material-icons small me-1">list</span>
+          <span class="material-icons small me-1" aria-hidden="true">list</span>
           <span i18n>Invoices ({{invoiceCount}})</span>
       </a>
       <span class="ps-2 pe-2" i18n> | </span>
       <a href="/eg/staff/acq/legacy/invoice/view?create=1&attach_po={{poId}}"
         class="label-with-material-icon">
-        <span class="material-icons small me-1">receipt</span>
+        <span class="material-icons small me-1" aria-hidden="true">receipt</span>
         <span i18n>Create Invoice</span>
       </a>
       <span class="ps-2 pe-2" i18n> | </span>
-      <a (click)="linkInvoiceFromPo()" href="javascript:;"
-        class="label-with-material-icon">
-        <span class="material-icons small me-1">receipt</span>
+      <button (click)="linkInvoiceFromPo()"
+        class="btn btn-link label-with-material-icon">
+        <span class="material-icons small me-1" aria-hidden="true">receipt</span>
         <span i18n>Link Invoice</span>
-      </a>
+      </button>
       </ng-container> <!-- show invoice actions -->
       <span class="ps-2 pe-2" i18n> | </span>
       <a routerLink="./edi" i18n>EDI Messages ({{ediMessageCount}})</a>
       <a routerLink="./history" i18n>History</a>
       <span class="ps-2 pe-2" i18n> | </span>
       <a routerLink="./printer" class="label-with-material-icon">
-        <span class="material-icons small me-1">print</span>
+        <span class="material-icons small me-1" aria-hidden="true">print</span>
         <span i18n>Print</span>
       </a>
       <ng-container *ngIf="po().state() === 'on-order'">
       </ng-container>
       <ng-container *ngIf="canFinalize">
         <span class="ps-2 pe-2" i18n> | </span>
-        <a (click)="finalizePo()" href="javascript:;" class="label-with-material-icon">
-          <span class="material-icons small me-1">check_circle</span>
+        <button (click)="finalizePo()" class="btn btn-link label-with-material-icon">
+          <span class="material-icons small me-1" aria-hidden="true">check_circle</span>
           <span i18n>Finalize Blanket Order</span>
-        </a>
+        </button>
       </ng-container>
       <ng-container *ngIf="showLegacyLinks">
         <span class="ps-2 pe-2" i18n> | </span>
index e0d33c3..d440ea7 100644 (file)
     <div class="col-auto align-items-end text-end">
       <button class="btn btn-primary me-1" (click)="submitSearch()" type="submit" [hidden]="!collapsed" i18n>Search</button>
       <button class="btn btn-secondary" (click)="clearSearch()" type="button" [hidden]="!collapsed" i18n>Reset Form</button>
-      <button class="btn" [hidden]="collapsed" (click)="toggleCollapse()" type="submit" i18n><span class="material-icons">expand_less</span></button>
-      <button class="btn" [hidden]="!collapsed" (click)="toggleCollapse()" type="submit" i18n><span class="material-icons">expand_more</span></button>
-    </div>
+      <button class="btn" (click)="toggleCollapse()" type="button" 
+        i18n-title [attr.title]="collapsed? 'Show Provider Details' : 'Hide Provider Details'"
+        i18n-aria-label [attr.aria-label]="collapsed? 'Show Provider Details' : 'Hide Provider Details'">
+        <span class="material-icons">{{collapsed? 'expand_less' : 'expand_more'}}</span>
+      </button>
+      </div>
   </div>
 
   <div class="row mb-1" [hidden]="collapsed">
index 5ce3c98..dbc43a9 100644 (file)
@@ -1,5 +1,8 @@
-<button class="btn" *ngIf="provider_id" [hidden]="!collapsed" (click)="toggleCollapse()" type="submit" i18n><span class="material-icons">expand_more</span></button>
-<button class="btn" *ngIf="provider_id" [hidden]="collapsed" (click)="toggleCollapse()" type="submit" i18n><span class="material-icons">expand_less</span></button>
+<button class="btn" (click)="toggleCollapse()" type="button" i18n-title
+  [attr.title]="collapsed? 'Show Provider Details' : 'Hide Provider Details'" i18n-aria-label
+  [attr.aria-label]="collapsed? 'Show Provider Details' : 'Hide Provider Details'">
+  <span class="material-icons">{{collapsed? 'expand_less' : 'expand_more'}}</span>
+</button>
 
 <div id="acq-provider-summary-pane" [hidden]="!provider_id || collapsed" class="ps-3 pe-3 pt-3 pb-3 mb-3">
 
index 17ab1cc..9c6c1a0 100644 (file)
 <div class="row mt-2 mb-2 border border-info">
   <div class="col-lg-2 p-1">
     <button class="btn btn-outline-dark label-with-material-icon"
-      (click)="createPicklist()" i18n>
-      <span class="material-icons me-1">create_new_folder</span>
-      Create Selection List
+      (click)="createPicklist()" type="button">
+      <span class="material-icons me-1" aria-hidden="true">create_new_folder</span>
+      <span i18n>Create Selection List</span>
     </button>
   </div>
   <div class="col-lg-2 p-1">
     <button class="btn btn-outline-dark label-with-material-icon" 
-      (click)="addingToPl=!addingToPl" i18n>
-      <span class="material-icons me-1">add_circle</span>
-      Add To Selection List
+      (click)="addingToPl=!addingToPl" type="button">
+      <span class="material-icons me-1" aria-hidden="true">add_circle</span>
+      <span i18n>Add To Selection List</span>
     </button>
   </div>
   <div class="col-lg-2 p-1">
     <div *ngIf="addingToPl" class="d-flex">
       <eg-combobox [(ngModel)]="selectedPl" idlClass="acqpl"
         placeholder="Select List..." i18n-placeHolder></eg-combobox>
-      <button class="btn btn-outline-primary btn-sm" 
+      <button class="btn btn-outline-primary btn-sm" type="button"
         (click)="addToPicklist(selectedPl ? selectedPl.id : null)" i18n>
         Apply
       </button>
   </div>
   <div class="col-lg-2 p-1">
     <button class="btn btn-outline-dark label-with-material-icon"
-      (click)="createPo()" i18n>
-      <span class="material-icons me-1">create_new_folder</span>
-      Create Purchase Order
+      (click)="createPo()" type="button">
+      <span class="material-icons me-1" aria-hidden="true">create_new_folder</span>
+      <span i18n>Create Purchase Order</span>
     </button>
   </div>
   <div class="col-lg-2 p-1">
     <button class="btn btn-outline-dark label-with-material-icon" 
-      (click)="addingToPo=!addingToPo" i18n>
-      <span class="material-icons me-1">add_circle_outline</span>
-      Add To Purchase Order
+      (click)="addingToPo=!addingToPo" type="button">
+      <span class="material-icons me-1" aria-hidden="true">add_circle_outline</span>
+      <span i18n>Add To Purchase Order</span>
     </button>
   </div>
   <div class="col-lg-2 p-1">
     <div *ngIf="addingToPo" class="d-flex">
       <eg-combobox [(ngModel)]="selectedPo" idlClass="acqpo"
         placeholder="Select Order..." i18n-placeHolder></eg-combobox>
-      <button class="btn btn-outline-primary btn-sm" 
+      <button class="btn btn-outline-primary btn-sm" type="button"
         (click)="addToPo(selectedPo ? selectedPo.id : null)" i18n>
         Apply
       </button>
index 2885660..5cfed95 100644 (file)
       of the following terms:</label>
     </div>
     <div class="col">
-      <a class="with-material-icon no-href text-primary"
+      <button class="with-material-icon btn btn-link text-primary"
         title="Show Form" i18n-title
-        tabindex="0"
-        *ngIf="!showForm" (click)="showForm=true"><span class="visually-hidden" i18n>Show Form</span>
+        aria-label="Show Form" i18n-aria-label
+        *ngIf="!showForm" (click)="showForm=true">
         <span class="material-icons" aria-hidden="true">expand_more</span>
-      </a>
-      <a class="with-material-icon no-href text-primary"
+      </button>
+      <button class="with-material-icon btn btn-link text-primary"
         title="Hide Form" i18n-title
-        tabindex="0"
-        *ngIf="showForm" (click)="showForm=false"><span class="visually-hidden" i18n>Hide Form</span>
+        aria-label="Hide Form" i18n-aria-label
+        *ngIf="showForm" (click)="showForm=false">
         <span class="material-icons" aria-hidden="true">expand_less</span>
-      </a>
+      </button>
     </div>
   </div>
   <div class="row row-cols-auto mb-1" *ngFor="let t of searchTerms; let idx=index" [hidden]="!showForm">
index e11271c..60593b9 100644 (file)
@@ -7,7 +7,7 @@
       i18n-aria-label aria-label="Close" (click)="close()"></button>
   </div>
   <div class="modal-body">
-    <form #myForm="ngForm" role="form" class="form-validated">
+    <form #myForm="ngForm" class="form-validated">
       <div class="form-group row mt-2" *ngIf="formula">
         <label for="formula-name" class="form-label col-sm-1 col-form-label" i18n>Formula Name
         </label>
@@ -43,8 +43,8 @@
       <div class="form-group row mt-2" *ngFor="let entry of formula?.entries(); index as idx; last as isLast; first as isFirst; count as count">
         <div class="col-sm-1">
           <button *ngIf="!isLast" class="btn btn-sm material-icon-button" type="button"
-            (click)="removeRow(idx)"
-            i18n-title title="Remove Entry"><span class="visually-hidden">Remove Entry</span>
+            (click)="removeRow(idx)" i18n-aria-label aria-label="Remove Entry"
+            i18n-title title="Remove Entry">
             <span class="material-icons" aria-hidden="true">delete</span>
           </button>
         </div>
           <button *ngIf="!isLast" class="btn btn-sm material-icon-button" type="button"
             [disabled]="isFirst"
             (click)="moveUp(idx)"
-            i18n-title title="Move Up"><span class="visually-hidden">Move Up</span>
+            i18n-aria-label aria-label="Move Up"
+            i18n-title title="Move Up">
             <span class="material-icons" aria-hidden="true">keyboard_arrow_up</span>
           </button>
           <button *ngIf="!isLast" class="btn btn-sm material-icon-button" type="button"
             (click)="moveDown(idx)"
             [disabled]="count < 3 || idx === count - 2"
-            i18n-title title="Move Down"><span class="visually-hidden">Move Down</span>
+            i18n-aria-label aria-label="Move Down"
+            i18n-title title="Move Down">
             <span class="material-icons" aria-hidden="true">keyboard_arrow_down</span>
           </button>
           <button *ngIf="isLast" type="button" class="btn btn-info" (click)="addRow()" i18n>Add</button>
index c29b6f1..726f481 100644 (file)
@@ -11,7 +11,8 @@
   <div class="col-sm-2" *ngFor="let ftm of tagMaps">
     <button class="btn btn-sm material-icon-button" type="button"
       (click)="removeTagMap(ftm)"
-      i18n-title title="Remove Tag"><span class="visually-hidden">Remove Tag</span>
+      i18n-aria-label aria-label="Remove Tag"
+      i18n-title title="Remove Tag">
       <span class="material-icons" aria-hidden="true">delete</span>
     </button>
     {{ftm.tag().name()}} ({{ftm.tag().owner().shortname()}})
index 04ee702..a4b7546 100644 (file)
     </div>
     <div class="ms-3">
       <button (click)="up()" i18n-title title="Move Selected Location Up"
-        class="me-2 btn btn-sm btn-outline-dark .mat-icon-shrunk-in-button">
-        <span class="material-icons">arrow_upward</span>
+        i18n-aria-label aria-label="Move Selected Location Up"
+        class="me-2 btn btn-sm btn-outline-dark mat-icon-shrunk-in-button">
+        <span class="material-icons" aria-hidden="true">arrow_upward</span>
       </button>
       <button (click)="down()" i18n-title title="Move Selected Location Down"
-        class="me-2 btn btn-sm btn-outline-dark .mat-icon-shrunk-in-button">
-        <span class="material-icons">arrow_downward</span>
+        i18n-aria-label aria-label="Move Selected Location Down"
+        class="me-2 btn btn-sm btn-outline-dark mat-icon-shrunk-in-button">
+        <span class="material-icons" aria-hidden="true">arrow_downward</span>
       </button>
       <button (click)="up(true)" i18n-title title="Move Selected Location To Top"
-        class="me-2 btn btn-sm btn-outline-dark .mat-icon-shrunk-in-button">
-        <span class="material-icons">vertical_align_top</span>
+        i18n-aria-label aria-label="Move Selected Location To Top"
+        class="me-2 btn btn-sm btn-outline-dark mat-icon-shrunk-in-button">
+        <span class="material-icons" aria-hidden="true">vertical_align_top</span>
       </button>
       <button (click)="down(true)" i18n-title title="Move Selected Location To Bottom"
-        class="me-2 btn btn-sm btn-outline-dark .mat-icon-shrunk-in-button">
-        <span class="material-icons">vertical_align_bottom</span>
+        i18n-aria-label aria-label="Move Selected Location To Bottom"
+        class="me-2 btn btn-sm btn-outline-dark mat-icon-shrunk-in-button">
+        <span class="material-icons" aria-hidden="true">vertical_align_bottom</span>
       </button>
       <span class="ms-2 fst-italic" *ngIf="selected()">
         Selected: {{selected().location().name()}} 
@@ -33,7 +37,7 @@
       </span>
     </div>
     <div class="flex-1"></div>
-    <button class="btn btn-outline-dark" (click)="save()" 
+    <button class="btn btn-outline-dark" (click)="save()" type="submit"
       [disabled]="!changesPending()" i18n>Save Changes</button>
   </div>
 </div>
index 1678407..372a0c6 100644 (file)
@@ -30,7 +30,7 @@
               />
             <button class="btn btn-outline-dark btn-sm" (click)="searchPatrons()">
               <span class="material-icons mat-icon-in-button align-middle"
-              i18n-title title="Search for Patron">search</span>
+              aria-hidden="true">search</span>
               <span class="align-middle" i18n>Search for Patron</span>
             </button>
           </div>
index b305110..7428da8 100644 (file)
@@ -16,7 +16,7 @@
       <span class="align-middle">Unarchive Course</span>
     </button>
     <a class="btn btn-warning ms-3" routerLink="/staff/admin/local/asset/course_list" i18n>
-      <i class="material-icons align-middle">keyboard_return</i>
+      <i class="material-icons align-middle" aria-hidden="true">keyboard_return</i>
       <span class="align-middle">Return to Course List</span>
     </a>
   </div>
index ecbd3c1..d5c4686 100644 (file)
@@ -14,7 +14,7 @@ import {ActivatedRoute} from '@angular/router';
         <div class="row">
             <div class="col text-right">
                 <a class="btn btn-warning ml-3" routerLink="/staff/admin/local/asset/course_list" i18n>
-                    <i class="material-icons align-middle">keyboard_return</i>
+                    <i class="material-icons align-middle" aria-hidden="true">keyboard_return</i>
                     <span class="align-middle">Return to Course List</span>
                 </a>
             </div>
index 0f930a5..096aa67 100644 (file)
@@ -5,7 +5,7 @@
 <div class="row">
     <div class="col text-end">
         <a class="btn btn-warning ms-3" routerLink="/staff/admin/server/config/floating_group">
-            <span class="material-icons align-middle">keyboard_return</span>
+            <span class="material-icons align-middle" aria-hidden="true">keyboard_return</span>
             <span class="align-middle" i18n>Return to Floating Groups List</span>
         </a>
     </div>
index a4dbafc..a7defbb 100644 (file)
             </div>
 
             <div class="row fst-italic">
-              <span class="label-with-material-icon" i18n>
-                Permissions marked with a 
-                <span class="ps-1 pe-1 fw-bold text-danger 
-                  material-icons mat-icon-shrunk-in-button">new_releases</span>
+              <span class="label-with-material-icon">
+              <span class="ps-1 pe-1 fw-bold text-danger 
+                material-icons mat-icon-shrunk-in-button">new_releases</span>
+              <span i18n>
+                Permissions marked with an enclosed checkmark
                 override parent group permissions.
               </span>
+              </span>
             </div>
             
             <div class="row fw-bold">
                   <span i18n-title title="{{map.perm().description() || map.perm().code()}}">
                     {{map.perm().code()}}
                   </span>
-                  <span *ngIf="permOverrides(map)" 
-                    i18n-title title="Permission Overrides a Parent Group Permission"
-                    class="ps-1 fw-bold text-danger material-icons mat-icon-shrunk-in-button"
-                    i18n>new_releases</span>
+                  <ng-container *ngIf="permOverrides(map)">
+                    <span i18n-title title="Permission Overrides a Parent Group Permission"
+                      class="ps-1 fw-bold text-danger material-icons mat-icon-shrunk-in-button">new_releases</span>
+                    <span class="visually-hidden" i18n>Parent group override</span>
+                  </ng-container>
                 </span>
               </div>
               <ng-container *ngIf="permIsInherited(map); else nativeMap">
index 0f5af7b..091212e 100644 (file)
@@ -16,7 +16,7 @@
         class="form-control " formControlName="patronBarcode" [disabled]="patronId">
         <button class="btn btn-outline-dark btn-sm" (click)="searchPatrons()">
           <span class="material-icons mat-icon-in-button align-middle"
-            i18n-title title="Search for Patron">search</span>
+            aria-hidden="true">search</span>
           <span class="align-middle" i18n>Search for Patron</span>
         </button>
       </div>
index f6d896d..5c43cbb 100644 (file)
@@ -26,7 +26,7 @@
     <ul ngbNav #details="ngbNav" [(activeId)]="detailsTab" [keyboard]="true" [roles]="false" role="tablist" class="nav-tabs">
       <li role="presentation" [ngbNavItem]="'select-resource-type'">
         <a ngbNavLink role="tab">
-          <span class="material-icons">dns</span>
+          <span class="material-icons" aria-hidden="true">dns</span>
           <ng-container i18n>Choose resource by type</ng-container>
         </a>
         <ng-template ngbNavContent>
@@ -52,7 +52,7 @@
 
       <li role="presentation" [ngbNavItem]="'select-resource'">
         <a ngbNavLink role="tab">
-          <span class="material-icons">assignment</span>
+          <span class="material-icons" aria-hidden="true">assignment</span>
           <ng-container i18n>Choose resource by barcode</ng-container>
         </a>
         <ng-template ngbNavContent>
@@ -69,7 +69,7 @@
 
       <li role="presentation" [ngbNavItem]="'attributes'" [disabled]="0 === attributes.length">
         <a ngbNavLink role="tab">
-          <span class="material-icons">filter_list</span>
+          <span class="material-icons" aria-hidden="true">filter_list</span>
           <ng-container i18n>Limit by attributes</ng-container>
         </a>
         <ng-template ngbNavContent>
@@ -90,7 +90,7 @@
 
       <li role="presentation" [ngbNavItem]="'display-settings'">
         <a ngbNavLink role="tab">
-          <span class="material-icons">settings</span>
+          <span class="material-icons" aria-hidden="true">settings</span>
           <ng-container i18n>Schedule settings</ng-container>
         </a>
         <ng-template ngbNavContent>
   <hr>
   <div class="row" *ngIf="idealDate && !multiday">
     <button class="btn btn-info col-sm-2 offset-sm-3" (click)="addDays(-1)">
-        <span class="material-icons mat-icon-in-button">keyboard_arrow_left</span>
+        <span class="material-icons mat-icon-in-button" aria-hidden="true">keyboard_arrow_left</span>
         <span i18n>Previous day</span>
     </button>
     <h2 class="col-sm-2 text-center" i18n>{{idealDate | formatValue:'timestamp'}}</h2>
     <button class="btn btn-info col-sm-2" (click)="addDays(1)">
       <span i18n>Next day</span>
-      <span class="material-icons mat-icon-in-button">keyboard_arrow_right</span>
+      <span class="material-icons mat-icon-in-button" aria-hidden="true">keyboard_arrow_right</span>
     </button>
   </div>
   <eg-grid #scheduleGrid
index a947066..65aeaf9 100644 (file)
       <ul ngbNav #filterTabs="ngbNav" [(activeId)]="startingTab" [keyboard]="true" [roles]="false" role="tablist" class="nav-tabs">
         <li role="presentation" [ngbNavItem]="'patron'">
           <a ngbNavLink role="tab">
-            <span class="material-icons" *ngIf="patronId">filter_list</span> <span i18n>Filter by patron</span>
+            <span class="material-icons" aria-hidden="true" *ngIf="patronId">filter_list</span> <span i18n>Filter by patron</span>
           </a>
           <ng-template ngbNavContent>
             <div class="m-2">
               <div class="input-group m-2">
                 <input type="text" id="patron-barcode-value" class="form-control" formControlName="patronBarcode">
                 <div class="input-group-button">
-                  <button *ngIf="patronBarcode.value" class="btn btn-warning" (click)="removeFilters()" i18n><span class="material-icons">delete</span> Remove filter</button>
+                  <button *ngIf="patronBarcode.value" class="btn btn-warning" (click)="removeFilters()" i18n><span class="material-icons" aria-hidden="true">delete</span> Remove filter</button>
                 </div>
               </div>
             </div>
@@ -28,7 +28,8 @@
         </li>
         <li role="presentation" [ngbNavItem]="'resource'">
           <a ngbNavLink role="tab">
-            <span class="material-icons" *ngIf="resourceBarcode.value">filter_list</span> <span i18n>Filter by resource</span>
+            <span class="material-icons" *ngIf="resourceBarcode.value" aria-hidden="true">filter_list</span> 
+            <span i18n>Filter by resource</span>
           </a>
           <ng-template ngbNavContent>
             <div class="m-2">
                   <label class="form-label input-group-text" for="resource-barcode-value" i18n>Resource barcode</label>
                 <input type="text" id="resource-barcode-value" class="form-control" formControlName="resourceBarcode">
                 <div class="input-group-button">
-                  <button *ngIf="resourceBarcode.value" class="btn btn-warning" (click)="removeFilters()" i18n><span class="material-icons">delete</span> Remove filter</button>
+                  <button *ngIf="resourceBarcode.value" class="btn btn-warning" (click)="removeFilters()">
+                    <span class="material-icons" aria-hidden="true">delete</span> 
+                    <span i18n>Remove filter</span>
+                  </button>
                 </div>
               </div>
             </div>
           </ng-template>
         </li>
-        <li role="presentation" [ngbNavItem]="'type'">
+        <li role="presentation" [ngbNavItem]="'type'" *ngIf="resourceTypeForGrid">
           <a ngbNavLink role="tab">
-            <span class="material-icons" *ngIf="resourceTypeForGrid">filter_list</span> <span i18n>Filter by resource type</span>
+            <span class="material-icons" aria-hidden="true">filter_list</span> 
+            <span i18n>Filter by resource type</span>
           </a>
           <ng-template ngbNavContent>
             <div class="m-2">
                   <label class="form-label input-group-text" for="resource-type-value" i18n>Resource type</label>
                 <eg-combobox domId="resource-type-value" formControlName="resourceType" idlClass="brt" [asyncSupportsEmptyTermClick]="true"></eg-combobox>
                 <div class="input-group-button">
-                  <button class="btn btn-warning" (click)="removeFilters()" i18n><span class="material-icons">delete</span> Remove filter</button>
+                  <button class="btn btn-warning" (click)="removeFilters()">
+                    <span class="material-icons" aria-hidden="true">delete</span> 
+                    <span i18n>Remove filter</span>
+                  </button>
                 </div>
               </div>
             </div>
index df3eb9a..58fc4fd 100644 (file)
@@ -5,7 +5,7 @@
   <div class="col-lg-3">
     <a routerLink="/staff/cat/authority/browse">
       <button class="btn btn-outline-dark">
-        <span class="material-icons material-mat-icon-shrunk-in-button">arrow_back</span>
+        <span class="material-icons material-mat-icon-shrunk-in-button" aria-hidden="true">arrow_back</span>
         <span class="ps-1" i18n>Return to Browse</span>
       </button>
     </a>
index 2fbb4c7..b12333a 100644 (file)
@@ -84,9 +84,9 @@
       <div class="row mb-2">
         <div class="col-lg-12 d-flex justify-content-end">
           <button class="btn btn-outline-danger label-with-material-icon"
-            (click)="removeRule(idx)" i18n>
-            <span>Remove this Merge Rule</span>
-            <span class="material-icons ms-2">delete</span>
+            (click)="removeRule(idx)" type="button">
+            <span i18n>Remove this Merge Rule</span>
+            <span class="material-icons ms-2" aria-hidden="true">delete</span>
           </button>
         </div>
       </div>
@@ -94,9 +94,9 @@
     <div class="row mb-2">
       <div class="col-lg-6">
         <button class="btn btn-outline-dark label-with-material-icon" 
-          (click)="addRule()">
+          (click)="addRule()" type="button">
           <span i18n>Add a New Merge Rule</span>
-          <span class="material-icons ms-2">arrow_downward</span>
+          <span class="material-icons ms-2" aria-hidden="true">arrow_downward</span>
         </button>
       </div>
     </div>
index 6e10419..15f0ec4 100644 (file)
@@ -1,8 +1,8 @@
 <div class="row mb-3" *ngIf="importSelection()">
   <div class="col-lg-2" *ngIf="selectedQueue">
-    <button class="btn btn-info label-with-material-icon"
+    <button class="btn btn-info label-with-material-icon" type="button"
       routerLink="/staff/cat/vandelay/queue/{{recordType}}/{{selectedQueue.id}}">
-      <span class="material-icons">arrow_back</span>
+      <span class="material-icons" aria-hidden="true">arrow_back</span>
       <span i18n>Return to Queue</span>
     </button>
   </div>
index 3185a38..479c21b 100644 (file)
@@ -1,8 +1,8 @@
 <div class="row mb-3">
   <div class="col-lg-2">
-    <button class="btn btn-info label-with-material-icon"
+    <button class="btn btn-info label-with-material-icon" type="button"
       routerLink="/staff/cat/vandelay/queue/{{queueType}}/{{queueId}}">
-      <span class="material-icons">arrow_back</span>
+      <span class="material-icons" aria-hidden="true">arrow_back</span>
       <span i18n>Return to Queue</span>
     </button>
   </div>
index 7dd6d1b..fccc9b9 100644 (file)
@@ -8,7 +8,8 @@
 <ng-template #targetTemplate let-row="row">
   <ng-container *ngIf="isOverlayTarget(row.id)">
     <span i18n-title title="Selected Merge Target" 
-      class="material-icons">check_circle</span>
+      class="material-icons" aria-hidden="true">check_circle</span>
+    <span class="visually-hidden" i18n>Selected Merge Target</span>
   </ng-container>
 </ng-template>
 
index 21fb720..eeb7ed9 100644 (file)
@@ -1,9 +1,9 @@
 
 <div class="row mb-3">
   <div class="col-lg-2">
-    <button class="btn btn-info label-with-material-icon"
+    <button class="btn btn-info label-with-material-icon" type="button"
       routerLink="/staff/cat/vandelay/queue/{{queueType}}/{{queueId}}">
-      <span class="material-icons">arrow_back</span>
+      <span class="material-icons" aria-hidden="true">arrow_back</span>
       <span i18n>Return to Queue</span>
     </button>
   </div>
index 3e5c710..f46dc7e 100644 (file)
@@ -54,7 +54,8 @@
               <span *ngIf="tracker.state() === 'complete'" i18n>Complete</span>
               <span *ngIf="tracker.state() === 'error'" i18n>Error</span>
               <span class='ps-3' *ngIf="tracker.state() === 'complete'">
-                <span class="material-icons text-success">thumb_up</span>
+                <span class="material-icons text-success" aria-hidden="true">thumb_up</span>
+                <span class="visually-hidden" i18n>Success</span>
               </span>
             </div>
           </div>
index 471fa9f..82dacf6 100644 (file)
@@ -15,7 +15,7 @@
   <button class="btn btn-sm btn-outline-dark label-with-material-icon" 
     (click)="toggleBatchVisibility()">
     <span i18n>Batch Actions</span>
-    <span class="material-icons">unfold_more</span>
+    <span class="material-icons" aria-hidden="true">unfold_more</span>
   </button>
 </div>
 
@@ -26,7 +26,7 @@
     <button class="btn btn-sm btn-outline-dark label-with-material-icon" 
       (click)="toggleBatchVisibility()">
       <span i18n>Batch Actions</span>
-      <span class="material-icons">unfold_less</span>
+      <span class="material-icons" aria-hidden="true">unfold_less</span>
     </button>
   </div>
   <div class="p-1" [ngStyle]="{flex: flexAt(3)}">
@@ -84,9 +84,9 @@
     <div><label class="form-label fw-bold" i18n>Batch</label></div>
     <div>
       <button class="btn btn-sm btn-outline-dark label-with-material-icon"
-        (click)="batchVolApply()">
+        type="button" (click)="batchVolApply()">
         <span i18n>Apply</span>
-        <span class="material-icons">arrow_downward</span>
+        <span class="material-icons" aria-hidden="true">arrow_downward</span>
       </button>
     </div>
   </div>
   <div class="p-1" [ngStyle]="{flex: flexAt(1)}">
     <span class="fw-bold" i18n>Owning Library
       <ng-container *ngIf="expand !== 1">
-        <button title="Expand Column" i18n-title 
+        <button type="button" title="Expand Column" i18n-title
+          aria-label="Expand Column" i18n-aria-label 
           class="material-icon-button" (click)="expand = 1">
-          &#x2197;
+          <span aria-hidden="true">&#x2197;</span>
         </button>
       </ng-container>
       <ng-container *ngIf="expand === 1">
-        <button title="Shrink Column" i18n-title 
+        <button type="button" title="Shrink Column" i18n-title 
+          aria-label="Shrink Column" i18n-aria-label 
           class="material-icon-button" (click)="expand = null">
-          &#x2199;
+          <span aria-hidden="true">&#x2199;</span>
         </button>
       </ng-container>
     </span>
     <ng-container *ngIf="displayColumn('classification')">
       <span class="fw-bold" i18n>Classification
         <ng-container *ngIf="expand !== 3">
-          <button title="Expand Column" i18n-title 
+          <button type="button" title="Expand Column" i18n-title
+            aria-label="Expand Column" i18n-aria-label 
             class="material-icon-button" (click)="expand = 3">
-            &#x2197;
+            <span aria-hidden="true">&#x2197;</span>
           </button>
         </ng-container>
         <ng-container *ngIf="expand === 3">
-          <button title="Shrink Column" i18n-title 
+          <button type="button" title="Shrink Column" i18n-title
+            aria-label="Shrink Column" i18n-aria-label 
             class="material-icon-button" (click)="expand = null">
-            &#x2199;
+            <span aria-hidden="true">&#x2199;</span>
           </button>
         </ng-container>
       </span>
     <ng-container *ngIf="displayColumn('prefix')">
       <span class="fw-bold" i18n>Prefix
         <ng-container *ngIf="expand !== 4">
-          <button title="Expand Column" i18n-title 
+          <button type="button" title="Expand Column" i18n-title 
+            aria-label="Expand Column" i18n-aria-label 
             class="material-icon-button" (click)="expand = 4">
-            &#x2197;
+            <span aria-hidden="true">&#x2197;</span>
           </button>
         </ng-container>
         <ng-container *ngIf="expand === 4">
-          <button title="Shrink Column" i18n-title 
+          <button type="button" title="Shrink Column" i18n-title
+            aria-label="Shrink Column" i18n-aria-label 
             class="material-icon-button" (click)="expand = null">
-            &#x2199;
+            <span aria-hidden="true">&#x2199;</span>
           </button>
         </ng-container>
       </span>
   <div class="p-1" [ngStyle]="{flex: flexAt(5)}">
     <span class="fw-bold" i18n>Call Number Label
       <ng-container *ngIf="expand !== 5">
-        <button title="Expand Column" i18n-title 
+        <button type="button" title="Expand Column" i18n-title 
+          aria-label="Expand Column" i18n-aria-label 
           class="material-icon-button" (click)="expand = 5">
-          &#x2197;
+          <span aria-hidden="true">&#x2197;</span>
         </button>
       </ng-container>
       <ng-container *ngIf="expand === 5">
-        <button title="Shrink Column" i18n-title
+        <button type="button" title="Shrink Column" i18n-title
+          aria-label="Shrink Column" i18n-aria-label
           class="material-icon-button" (click)="expand = null">
-          &#x2199;
+          <span aria-hidden="true">&#x2199;</span>
         </button>
       </ng-container>
     </span>
     <ng-container *ngIf="displayColumn('suffix')">
       <span class="fw-bold" i18n>Suffix
         <ng-container *ngIf="expand !== 6">
-          <button title="Expand Column" i18n-title 
+          <button type="button" title="Expand Column" i18n-title 
+          aria-label="Expand Column" i18n-aria-label
             class="material-icon-button" (click)="expand = 6">
-            &#x2197;
+            <span aria-hidden="true">&#x2197;</span>
           </button>
         </ng-container>
         <ng-container *ngIf="expand === 6">
-          <button title="Shrink Column" i18n-title
+          <button type="button" title="Shrink Column" i18n-title
+            aria-label="Shrink Column" i18n-aria-label
             class="material-icon-button" (click)="expand = null">
-            &#x2199;
+            <span aria-hidden="true">&#x2199;</span>
           </button>
         </ng-container>
       </span>
   <div class="p-1" [ngStyle]="{flex: flexAt(8)}">
     <span class="fw-bold" i18n>Barcode
       <ng-container *ngIf="expand !== 8">
-        <button title="Expand Column" i18n-title 
+        <button type="button" title="Expand Column" i18n-title 
+          aria-label="Expand Column" i18n-aria-label 
           class="material-icon-button" (click)="expand = 8">
-          &#x2197;
+          <span aria-hidden="true">&#x2197;</span>
         </button>
       </ng-container>
       <ng-container *ngIf="expand === 8">
-        <button title="Shrink Column" i18n-title
+        <button type="button" title="Shrink Column" i18n-title
+          aria-label="Shrink Column" i18n-aria-label
           class="material-icon-button" (click)="expand = null">
-          &#x2199;
+          <span aria-hidden="true">&#x2199;</span>
         </button>
       </ng-container>
     </span>
     <ng-container *ngIf="displayColumn('copy_part')">
       <span class="fw-bold" i18n>Part
         <ng-container *ngIf="expand !== 10">
-          <button title="Expand Column" i18n-title 
+          <button type="button" title="Expand Column" i18n-title 
+            aria-label="Expand Column" i18n-aria-label 
             class="material-icon-button" (click)="expand = 10">
-            &#x2197;
+            <span aria-hidden="true">&#x2197;</span>
           </button>
         </ng-container>
         <ng-container *ngIf="expand === 10">
-          <button title="Shrink Column" i18n-title 
+          <button type="button" title="Shrink Column" i18n-title
+            aria-label="Shrink Column" i18n-aria-label 
             class="material-icon-button" (click)="expand = null">
-            &#x2199;
+            <span aria-hidden="true">&#x2199;</span>
           </button>
         </ng-container>
       </span>
                   placement="bottom" [ngbPopover]="addOrgTmpl"
                   autoClose="outside" #addOrgPopover="ngbPopover"
                   i18n-popoverTitle="Add Call Number For Location"
-                  i18n-title title="Add Call Number For Location">
-                  <span class="material-icons">add_circle_outline</span>
+                  i18n-title title="Add Call Number For Location"
+                  i18n-aria-label aria-label="Add Call Number For Location">
+                  <span class="material-icons" aria-hidden="true">add_circle_outline</span>
                 </button>
               </div>
             </ng-container>
                   placement="bottom" [ngbPopover]="editOrgTmpl"
                   autoClose="outside" #editOrgPopover="ngbPopover"
                   i18n-popoverTitle="Edit Call Number Owning Location"
-                  i18n-title title="Edit Call Number Owning Location">
-                  <span class="material-icons">edit</span>
+                  i18n-title title="Edit Call Number Owning Location"
+                  i18n-aria-label aria-label="Edit Call Number Owning Location">
+                  <span class="material-icons" aria-hidden="true">edit</span>
                 </button>
               </div>
             </ng-container>
             <ng-container 
               *ngIf="context.sessionType === 'record' || context.sessionType === 'mixed'">
               <button class="btn btn-sm material-icon-button p-1"
-                (click)="createVols(orgNode, 1)"
-                i18n-title title="Add Call Number">
-                <span class="material-icons">add_circle_outline</span>
+                (click)="createVols(orgNode, 1)" type="button"
+                i18n-title title="Add Call Number"
+                i18n-aria-label aria-label="Add Call Number">
+                <span class="material-icons" aria-hidden="true">add_circle_outline</span>
               </button>
 
               <ng-template #addVolCountTmpl>
                     id='add-vol-popover' 
                     (keyup.enter)="createVolsFromPopover(orgNode, addVolsPopover)"
                     [(ngModel)]="addVolCount" [required]="true" min="1"/>
-                  <button class="btn btn-sm btn-success ms-1" 
+                  <button class="btn btn-sm btn-success ms-1" type="button"
                     (click)="createVolsFromPopover(orgNode, addVolsPopover)"
                     i18n>Add</button>
                 </div>
                 placement="bottom" [ngbPopover]="addVolCountTmpl"
                 autoClose="outside" #addVolsPopover="ngbPopover"
                 i18n-popoverTitle="Add Call Numbers"
-                i18n-title title="Add Call Numbers">
-                <span class="material-icons">playlist_add</span>
+                i18n-title title="Add Call Numbers"
+                i18n-aria-label aria-label="Add Call Numbers">
+                <span class="material-icons" aria-hidden="true">playlist_add</span>
               </button>
 
-              <button class="btn btn-sm material-icon-button p-1"
+              <button type="button" class="btn btn-sm material-icon-button p-1"
                 (click)="deleteVol(volNode)"
+                i18n-aria-label aria-label="Remove Call Number"
                 i18n-title title="Remove Call Number">
-                <span class="material-icons">remove_circle_outline</span>
+                <span class="material-icons" aria-hidden="true">remove_circle_outline</span>
               </button>
 
             </ng-container>
         <div class="p-1" [ngStyle]="{flex: flexAt(11)}">
           <ng-container *ngIf="context.sessionType !== 'copy'">
 
-            <button class="btn btn-sm material-icon-button p-1"
-              (click)="createCopies(volNode, 1)" i18n-title title="Add Item">
-              <span class="material-icons">add_circle_outline</span>
+            <button class="btn btn-sm material-icon-button p-1" type="button"
+              (click)="createCopies(volNode, 1)" i18n-title title="Add Item"
+              i18n-aria-label aria-label="Add Item">
+              <span class="material-icons" aria-hidden="true">add_circle_outline</span>
             </button>
 
             <ng-template #addCopyCountTmpl>
                   id="add-copy-popover"
                   (keyup.enter)="createCopiesFromPopover(volNode, addCopiesPopover)"
                   [(ngModel)]="addCopyCount" [required]="true" min="1"/>
-                <button class="btn btn-sm btn-success ms-1" 
+                <button class="btn btn-sm btn-success ms-1"  type="button"
                   (click)="createCopiesFromPopover(volNode, addCopiesPopover)"
                   i18n>Add</button>
               </div>
             </ng-template>
 
-            <button class="btn btn-sm material-icon-button p-1"
+            <button type="button" class="btn btn-sm material-icon-button p-1"
               placement="left" [ngbPopover]="addCopyCountTmpl"
               autoClose="outside" #addCopiesPopover="ngbPopover"
               i18n-popoverTitle="Add Items" i18n-title title="Add Items"
+              i18n-aria-label aria-label="Add Items"
               (shown)="focusElement('add-copy-popover')">
-              <span class="material-icons">playlist_add</span>
+              <span class="material-icons" aria-hidden="true">playlist_add</span>
             </button>
 
-            <button class="btn btn-sm material-icon-button p-1"
-              (click)="deleteCopy(copyNode)" i18n-title title="Remove Item">
-              <span class="material-icons">remove_circle_outline</span>
+            <button type="button" class="btn btn-sm material-icon-button p-1"
+              (click)="deleteCopy(copyNode)" i18n-title title="Remove Item"
+              i18n-aria-label aria-label="Remove Item">
+              <span class="material-icons" aria-hidden="true">remove_circle_outline</span>
             </button>
 
           </ng-container>
index c418063..2b56fb1 100644 (file)
@@ -88,7 +88,7 @@
             <button class="btn btn-sm btn-outline-dark label-with-material-icon"
               (click)="volcopy.genBarcodesRequested.emit()">
               <span i18n>Generate Barcodes</span>
-              <span class="material-icons">refresh</span>
+              <span class="material-icons" aria-hidden="true">refresh</span>
             </button>
           </ng-container>
         </ng-container>
index 8b4794d..432cc06 100644 (file)
@@ -9,7 +9,7 @@
       <!-- note basket view link does not propagate search params -->
       <a routerLink="/staff/catalog/search" [queryParams]="{showBasket: true}" 
         class="label-with-material-icon">
-        <span class="material-icons">shopping_basket</span>
+        <span class="material-icons" aria-hidden="true">shopping_basket</span>
         <span i18n>({{basketCount()}})</span>
       </a>
     </div>
       <button class="btn btn-light" id="basketActions"
         ngbDropdownToggle i18n>Basket Actions</button>
       <div ngbDropdownMenu aria-labelledby="basketActions">
-        <button class="dropdown-item" [disabled]="isMetarecordSearch()"
+        <button type="button" class="dropdown-item" ngbDropdownItem [disabled]="isMetarecordSearch()"
           (click)="applyAction('add_all')" i18n>Add All Search Results</button>
-        <button class="dropdown-item" [disabled]="!basketCount()"
+        <button type="button" class="dropdown-item" ngbDropdownItem [disabled]="!basketCount()"
           (click)="applyAction('view')" i18n>View Basket</button>
-        <button class="dropdown-item" [disabled]="!basketCount()"
+        <button type="button" class="dropdown-item" ngbDropdownItem [disabled]="!basketCount()"
           (click)="applyAction('hold')" i18n>Place Hold</button>
-        <button class="dropdown-item" [disabled]="!basketCount()"
+        <button type="button" class="dropdown-item" ngbDropdownItem [disabled]="!basketCount()"
           (click)="applyAction('print')" i18n>Print Title Details</button>
-        <button class="dropdown-item" [disabled]="!basketCount()"
+        <button type="button" class="dropdown-item" ngbDropdownItem [disabled]="!basketCount()"
           (click)="applyAction('email')" i18n>Email Title Details</button>
-        <button class="dropdown-item" [disabled]="!basketCount()"
+        <button type="button" class="dropdown-item" ngbDropdownItem [disabled]="!basketCount()"
           (click)="applyAction('bucket')" i18n>Add Basket to Bucket</button>
-        <button class="dropdown-item" [disabled]="!basketCount()"
+        <button type="button" class="dropdown-item" ngbDropdownItem [disabled]="!basketCount()"
           (click)="applyAction('export_marc')" i18n>Export Records</button>
-        <button class="dropdown-item" [disabled]="!basketCount()"
+        <button type="button" class="dropdown-item" ngbDropdownItem [disabled]="!basketCount()"
           (click)="applyAction('clear')" i18n>Clear Basket</button>
       </div>
     </div>
index ce18269..e4b3969 100644 (file)
@@ -12,9 +12,9 @@
 
 <div class="row">
   <div class="col-lg-1">
-    <button class="btn btn-info label-with-material-icon"
+    <button type="button" class="btn btn-info label-with-material-icon"
       (click)="goBack()" [disabled]="hasNoHistory()">
-      <span class="material-icons">keyboard_backspace</span>
+      <span class="material-icons" aria-hidden="true">keyboard_backspace</span>
       <span i18n>Return</span>
     </button>
   </div>
@@ -34,9 +34,8 @@
     </ng-container>
   </div>
   <div class="col-lg-2">
-    <button class="btn btn-outline-dark btn-sm" (click)="searchPatrons()">
-      <span class="material-icons mat-icon-in-button align-middle"
-        i18n-title title="Search for Patron">search</span>
+    <button type="button" class="btn btn-outline-dark btn-sm" (click)="searchPatrons()">
+      <span class="material-icons mat-icon-in-button align-middle" aria-hidden="true">search</span>
       <span class="align-middle" i18n>Search for Patron</span>
     </button>
   </div>
index d608871..2f7c9cb 100644 (file)
 </div>
 <div class="row">
   <div class="col-lg-1">
-  <button class="btn btn-info label-with-material-icon" (click)="goBack()" [disabled]="hasNoHistory()">
-      <span class="material-icons">keyboard_backspace</span>
+  <button type="button" class="btn btn-info label-with-material-icon" (click)="goBack()" [disabled]="hasNoHistory()">
+      <span class="material-icons" aria-hidden="true">keyboard_backspace</span>
       <span i18n>Return</span>
   </button>
   </div>
index 1f87ce9..f66d32d 100644 (file)
   <!-- ps-* is doubled for added impact -->
   <div class="ps-{{row.locationDepth}}">
     <span class="ps-{{row.locationDepth}}">
-      <a class="label-with-material-icon" (click)="userContext.toggleExpandRow(row)">
+      <button type="button" class="label-with-material-icon" (click)="userContext.toggleExpandRow(row)">
         <!--  leave the icons in place for all node types, but make them
               invisible when they are not needed. -->
         <span *ngIf="row.treeNode.expanded"
           [ngClass]="{invisible: row.copy || row.treeNode.children.length === 0}"
-          class="material-icons p-0 m-0">keyboard_arrow_down</span>
+          class="material-icons p-0 m-0" aria-hidden="true">keyboard_arrow_down</span>
         <span *ngIf="!row.treeNode.expanded"
           [ngClass]="{invisible: row.copy || row.treeNode.children.length === 0}"
-          class="material-icons p-0 m-0">keyboard_arrow_right</span>
+          class="material-icons p-0 m-0" aria-hidden="true">keyboard_arrow_right</span>
         <span>{{row.locationLabel}}</span>
-      </a>
+      </button>
     </span>
   </div>
 </ng-template>
index be89e17..41253eb 100644 (file)
@@ -1,36 +1,36 @@
 <ul class="pagination mb-0" *ngIf="index !== null">
   <li class="page-item" [ngClass]="{disabled : index === 0}">
-    <a class="no-href page-link" 
-      i18n-aria-label aria-label="Start" (click)="firstRecord()">
+    <button type="button" class="btn btn-link page-link" 
+      (click)="firstRecord()">
       <span i18n>Start</span>
-    </a>
+    </button>
   </li>
   <li class="page-item" [ngClass]="{disabled : index === 0}">
-    <a class="no-href page-link" 
-      i18n-aria-label aria-label="Previous" (click)="prevRecord()">
+    <button type="button" class="btn btn-link page-link" 
+      (click)="prevRecord()">
       <span i18n>Previous</span>
-    </a>
+    </button>
   </li>
   <li class="page-item"
     [ngClass]="{disabled : index >= searchContext.result.count - 1}">
-    <a class="no-href page-link" 
-      i18n-aria-label aria-label="Next" (click)="nextRecord()">
+    <button type="button" class="btn btn-link page-link" 
+      (click)="nextRecord()">
       <span i18n>Next</span>
-    </a>
+    </button>
   </li>
   <li class="page-item"
       [ngClass]="{disabled : index >= searchContext.result.count - 1}">
-    <a class="no-href page-link" 
-      i18n-aria-label aria-label="End" (click)="lastRecord()">
+    <button type="button" class="btn btn-link page-link" 
+      (click)="lastRecord()">
       <span i18n>End</span>
-    </a>
+    </button>
   </li>
   <li class="page-item">
-    <a class="no-href page-link" 
-      i18n-aria-label aria-label="Back to Results" (click)="returnToSearch()">
+    <button type="button" class="btn btn-link page-link" 
+      (click)="returnToSearch()">
       <span i18n>
         Back to Results ({{index + 1}} / {{searchContext.result.count}})
       </span>
-    </a>
+    </button>
   </li>
 </ul>
index aa2cfae..ae0ad9a 100644 (file)
                 <button (click)="placeHold()" [disabled]="!summary.isHoldable"
                   [ngClass]="summary.isHoldable ? 'btn-success' : 'btn-secondary'"
                   class="btn btn-sm label-with-material-icon small-text-1">
-                  <span class="material-icons">check</span>
+                  <span class="material-icons" aria-hidden="true">check</span>
                   <span i18n>Place Hold</span>
                 </button>
               </span>
index 2948433..b197466 100644 (file)
   <div *ngIf="canBeHidden()" class="row pt-1 pe-2">
     <div class="col-lg-12 d-flex">
       <div class="flex-1"></div><!-- push right -->
-      <a (click)="toggleFormDisplay()" class="label-with-material-icon no-href">
-        <ng-container *ngIf="hideForm()" i18n>
-          Show Search Form <span class="material-icons" aria-hidden="true">unfold_more</span>
+      <button (click)="toggleFormDisplay()" class="btn btn-link label-with-material-icon">
+        <ng-container *ngIf="hideForm()">
+          <span i18n>Show Search Form</span> 
+          <span class="material-icons" aria-hidden="true">unfold_more</span>
         </ng-container>
-        <ng-container *ngIf="!hideForm()" i18n>
-          Hide Search Form <span class="material-icons" aria-hidden="true">unfold_less</span>
+        <ng-container *ngIf="!hideForm()">
+          <span i18n>Hide Search Form</span> 
+          <span class="material-icons" aria-hidden="true">unfold_less</span>
         </ng-container>
-      </a>
+      </button>
     </div>
   </div>
   
               </button>
               <button class="btn btn-sm material-icon-button"
                 [disabled]="context.termSearch.query.length < 2"
-                (click)="delSearchRow(idx)"
+                type="button" (click)="delSearchRow(idx)"
                 i18n-title title="Remove Search Row"
                 i18n-aria-label aria-label="Remove Search Row">
                 <span class="material-icons" aria-hidden="true">remove_circle_outline</span>
index 44dbc11..143d062 100644 (file)
 
       <span *ngIf="backdate" 
         class="me-3 pe-3 border-end border-info label-with-material-icon">
-        <span class="material-icons">history</span>
+        <span class="material-icons" aria-hidden="true">history</span>
         <span class="ps-2" i18n>Backdated Check In {{backdate | date:'shortDate'}}</span>
       </span>
 
       <span *ngIf="backdate && backdateUntilLogout"
         class="me-3 pe-3 border-end border-info label-with-material-icon">
-        <span class="material-icons">timeline</span>
+        <span class="material-icons" aria-hidden="true">timeline</span>
         <span class="ps-2" i18n>Use Effective Date Until Logout</span>
       </span>
 
       <span *ngIf="modifiers.no_precat_alert"
         class="me-3 pe-3 border-end border-info label-with-material-icon">
-        <span class="material-icons">edit</span>
+        <span class="material-icons" aria-hidden="true">edit</span>
         <span class="ps-2" i18n>Ignore Pre-Cataloged Items</span>
       </span>
 
       <span *ngIf="modifiers.noop"
         class="me-3 pe-3 border-end border-info label-with-material-icon"> 
-        <span class="material-icons">block</span>
+        <span class="material-icons" aria-hidden="true">block</span>
         <span class="ps-2" i18n>Suppress Holds and Transits</span>
       </span>
 
       <span *ngIf="modifiers.void_overdues"
         class="me-3 pe-3 border-end border-info label-with-material-icon">
-        <span class="material-icons">monetization_on</span>
+        <span class="material-icons" aria-hidden="true">monetization_on</span>
         <span class="ps-2" i18n>Amnesty Mode</span>
       </span>
 
       <span *ngIf="modifiers.auto_print_holds_transits"
         class="me-3 pe-3 border-end border-info label-with-material-icon">
-        <span class="material-icons">print</span>
+        <span class="material-icons" aria-hidden="true">print</span>
         <span class="ps-2" i18n>Auto-Print Hold and Transit Slips</span>
       </span>
 
@@ -68,7 +68,7 @@
 
       <span *ngIf="modifiers.hold_as_transit"
         class="me-3 pe-3 border-end border-info label-with-material-icon">
-        <span class="material-icons">directions_transit</span>
+        <span class="material-icons" aria-hidden="true">directions_transit</span>
         <span class="ps-2" i18n>Capture Local Holds As Transits</span>
       </span>
 
@@ -91,7 +91,7 @@
           i18n-aria-label aria-label="Barcode Input" (keydown.enter)="checkin()" />
         <div class="input-group-text">
           <button class="btn btn-outline-dark" (keydown.enter)="checkin()" 
-            (click)="checkin()" i18n>Submit</button>
+            (click)="checkin()" i18n type="button">Submit</button>
         </div>
       </div>
     </div>
     <div class="me-2" i18n>Effective Date:</div>
     <eg-date-select [initialIso]="backdate" [(ngModel)]="backdateDate"
       (onChangeAsIso)="backdate = $event"></eg-date-select>
-    <button class="btn btn-sm btn-outline-dark ms-1" 
+    <button class="btn btn-sm btn-outline-dark ms-1" type="button"
       (click)="backdateDate=null; backdate=null" i18n>Clear</button>
   </div>
 </div>
index 32f4334..5da9a2f 100644 (file)
     </div>
     <div class="me-3">
       <div class="input-group">
-        <span class="material-icons pt-2 pe-2">
-          <ng-container *ngIf="!mayEmailReceipt()">print</ng-container>
-          <ng-container *ngIf="mayEmailReceipt()">email</ng-container>
+        <span class="material-icons pt-2 pe-2" aria-hidden="true">
+          {{mayEmailReceipt() ? 'email' : 'print'}}
         </span>
-        <button class="btn btn-outline-dark" (click)="quickReceipt()" i18n>
+        <button class="btn btn-outline-dark" (click)="quickReceipt()" i18n type="button">
           Quick Receipt
         </button>
         <div class="input-group-text">
           <div ngbDropdown>
-            <button ngbDropdownToggle class="btn btn-outline-dark">
+            <button ngbDropdownToggle class="btn btn-outline-dark" type="button"
+              aria-label="Select email or print" i18n-aria-label
+              title="Select email or print" i18n-title>
             </button>
             <div ngbDropdownMenu>
-              <button ngbDropdownItem (click)="emailReceipt()" 
+              <button ngbDropdownItem (click)="emailReceipt()" type="button"
                 [disabled]="!mayEmailReceipt()" i18n>Email Receipt</button>
-              <button ngbDropdownItem (click)="printReceipt()" i18n>Print Receipt</button>
+              <button ngbDropdownItem (click)="printReceipt()" i18n type="button">Print Receipt</button>
             </div>
           </div>
         </div>
     </div>
     <div class="me-3">
       <div class="input-group">
-        <button class="btn btn-outline-dark" (click)="doneAutoReceipt()" i18n>
+        <button class="btn btn-outline-dark" (click)="doneAutoReceipt()" i18n type="button">
           Done
         </button>
         <div class="input-group-text">
           <div ngbDropdown>
-            <button ngbDropdownToggle class="btn btn-outline-dark">
+            <button ngbDropdownToggle class="btn btn-outline-dark" type="button"
+              aria-label="Select email or print" i18n-aria-label
+              title="Select email or print" i18n-title>
             </button>
             <div ngbDropdownMenu>
               <button ngbDropdownItem (click)="doneRedirect()" i18n>No Receipt</button>
index f53c638..c6cab3b 100644 (file)
         <div class="ms-3">
           <button class="btn btn-danger material-icon-button" 
             [ngClass]="{'invisible': waiver.isdeleted()}"
-            (click)="removeWaiver(waiver)"
+            (click)="removeWaiver(waiver)" type="button"
+            i18n-aria-label aria-label="Remove Privacy Waiver"
             i18n-title title="Remove Privacy Waiver">
-            <span class="text-danger material-icons">delete</span>
+            <span class="text-danger material-icons" aria-hidden="true">delete</span>
           </button>
         </div>
         <div class="ms-2" *ngIf="index === patron.waiver_entries().length - 1">
           <button class="btn btn-success material-icon-button" 
-          (click)="addWaiver()" i18n-title title="Add Privacy Waiver">
-            <span class="text-success material-icons">add</span>
+            (click)="addWaiver()" type="button"
+            i18n-aria-label aria-label="Add Privacy Waiver"
+            i18n-title title="Add Privacy Waiver">
+            <span class="text-success material-icons" aria-hidden="true">add</span>
           </button>
         </div>
       </div>
index 77eee16..9d34137 100644 (file)
 
         <ng-container *ngIf="patronTab !== 'search'">
           <li ngbDropdown ngbNavItem="toggle">
-            <a href class="nav-link" (click)="toggleSummaryPane(); false"
-              title="Toggle Summary Pane" i18n-title>
-              <ng-container *ngIf="showSummaryPane()">
-                <span class="material-icons">fullscreen</span>
-              </ng-container>
-              <ng-container *ngIf="!showSummaryPane()">
-                <span class="material-icons">fullscreen_exit</span>
-              </ng-container>
-            </a>
+            <button class="nav-link" (click)="toggleSummaryPane(); false"
+              [title]="showSummaryPane() ? 'Hide Summary Pane' : 'Show Summary Pane'" i18n-title
+              [attr.aria-label]="showSummaryPane() ? 'Hide Summary Pane' : 'Show Summary Pane'" i18n-aria-label>
+              <span class="material-icons" aria-hidden="true">{{showSummaryPane() ? 'fullscreen' : 'fullscreen_exit'}}</span>
+            </button>
           </li>
         </ng-container>
 
index 018adec..63d0300 100644 (file)
                 [attr.aria-description]="ariaDescription"
                 [(ngModel)]="args.password"/>
               <button id="show_password" class="input-group-text pointer"
-                type="button" aria-label="password visibility" aria-checked="false"
-                (click)="togglePasswordVisibility()" >
-                <span class="material-icons">{{ passwordVisible ? 'visibility' : 'visibility_off' }}</span>
+                type="button" 
+                [attr.title]="passwordVisible ? 'Hide Password' : 'Show Password'"
+                [attr.aria-label]="passwordVisible ? 'Hide Password' : 'Show Password'"
+                i18n-aria-label i18n-title (click)="togglePasswordVisibility()" >
+                <span class="material-icons" aria-hidden="true">{{ passwordVisible ? 'visibility' : 'visibility_off' }}</span>
               </button>
             </div>
           </div>
index 7054ed6..2321dbb 100644 (file)
@@ -2,11 +2,12 @@
   <div class="collapse navbar-collapse">
     <div class="navbar-nav">
       <div class="nav-item">
-        <a i18n class="nav-link with-material-icon nav-link-home" 
+        <a class="nav-link with-material-icon nav-link-home" 
           routerLink="/staff/"
           egAccessKey keyCtx="navbar" i18n-keySpec i18n-keyDesc
           keySpec="alt+h" keyDesc="Navigate Home">
-          <span class="material-icons">home</span>
+          <span class="material-icons" aria-hidden="true">home</span>
+          <span class="visually-hidden" i18n>Home</span>
         </a>
       </div>
     </div>
     </div>
     <div class="navbar-nav" *ngIf="user()">
       <div ngbDropdown class="nav-item dropdown" display="dynamic">
-        <button ngbDropdownToggle i18n 
-          i18n-title
-          title="Log out and more..."
+        <button ngbDropdownToggle type="button" 
+          i18n-title title="Log out and more..."
+          i18n-aria-label aria-label="Log out and more..."
           class="nav-link dropdown-toggle no-caret with-material-icon">
-          <i class="material-icons">list</i>
+          <i class="material-icons" aria-hidden="true">list</i>
         </button>
         <div class="dropdown-menu dropdown-menu-right" ngbDropdownMenu>
           <eg-op-change #navOpChange
index ef88778..1e03ef6 100644 (file)
@@ -8,8 +8,9 @@
     </div>
 
     <div *ngIf="withDeselect" class="sr-field-deselect col-md-1">
-      <button class="btn btn-sm material-icon-button p-1 sr-checkbox" title="Un-Select Field" (click)="deselectAction()" title-i18n>
-        <span class="material-icons">remove_circle_outline</span></button>
+      <button class="btn btn-sm material-icon-button p-1 sr-checkbox" (click)="deselectAction()" 
+        title="Un-Select Field" i18n-title aria-label="Un-Select Field" aria-label>
+        <span class="material-icons" aria-hidden="true">remove_circle_outline</span></button>
     </div>
 
     <div *ngIf="withAlias" class="sr-field-name col-md-auto">
     </div>
 
     <div *ngIf="withUpDown" class="sr-field-updown col-md-2">
-      <button (click)="upAction()" class="btn btn-outline-primary btn-sm" [disabled]="disableUp"><span class="material-icons">arrow_upward</span></button>
-      <button (click)="downAction()" class="btn btn-outline-primary btn-sm" [disabled]="disableDown"><span class="material-icons">arrow_downward</span></button>
+      <button (click)="upAction()" class="btn btn-outline-primary btn-sm" 
+        [disabled]="disableUp" type="button"
+        aria-label="Move this field up in display order" i18n-aria-label
+        title="Move this field up in display order" i18n-title>
+        <span class="material-icons" aria-hidden="true">arrow_upward</span>
+      </button>
+      <button (click)="downAction()" class="btn btn-outline-primary btn-sm" 
+        [disabled]="disableDown" type="button"
+        aria-label="Move this field down in display order" i18n-aria-label
+        title="Move this field down in display order" i18n-title>
+        <span class="material-icons" aria-hidden="true">arrow_downward</span>
+      </button>
     </div>
 
   </div>
index e9737bc..fa1dcd0 100644 (file)
           <eg-combobox-entry entryId="wrong" entryLabel="42" i18n-entryLabel></eg-combobox-entry>
         </eg-combobox>
         <div *ngIf="!ranganathan.valid" class="alert alert-danger">
-          <span class="material-icons">error</span>
+          <span class="material-icons" aria-hidden="true">error</span>
+          <span class="visually-hidden" i18n>Error</span>
           <span i18n>That isn't a real law of library science!</span>
         </div>
       </div>
           labelText="Choose the fanciest libraries">
         </eg-org-family-select>
         <div *ngIf="!badOrgForm.valid" class="alert alert-danger">
-          <span class="material-icons">error</span>
+          <span class="material-icons" aria-hidden="true">error</span>
+          <span class="visually-hidden" i18n>Error</span>
           <span i18n>Too many fancy libraries!</span>
         </div>
       </div>
index d12a2a4..375699f 100644 (file)
@@ -52,9 +52,9 @@
         <a *ngIf="!hideClearFilters" class="ps-2 fst-italic"
           [attr.href]="clearGridFiltersUrl()" i18n>Clear Filters</a>
         &nbsp;
-        <button class="btn btn-info label-with-material-icon"
+        <button class="btn btn-info label-with-material-icon" type="button"
           (click)="goBack()" [disabled]="hasNoHistory()">
-          <span class="material-icons">keyboard_backspace</span>
+          <span class="material-icons" aria-hidden="true">keyboard_backspace</span>
           <span i18n>Return</span>
         </button>
       </ng-container>
index 51d8d84..1debcdf 100644 (file)
@@ -9,7 +9,7 @@
       <ng-container *ngIf="summary.attributes.icon_format && summary.attributes.icon_format[0]">
         <ng-container *ngFor="let icon of summary.attributes.icon_format">
           <span class="pe-1 ps-2">
-            <img class="pe-1"
+            <img class="pe-1" alt=""
               src="/images/format_icons/icon_format/{{icon}}.png"/>
             <span class="fw-normal">{{iconFormatLabel(icon)}}</span>
           </span>
     </div>
     <div class="flex-1"></div>
     <div>
-      <a class="with-material-icon no-href text-primary"
+      <button class="with-material-icon btn btn-link" type="button"
         title="Show More" i18n-title
         *ngIf="!expand" (click)="expand=true">
-        <span class="material-icons">expand_more</span>
-      </a>
-      <a class="with-material-icon no-href text-primary"
-        title="Show Less" i18n-title
+        <span class="material-icons" aria-hidden="true">expand_more</span>
+      </button>
+      <button class="with-material-icon btn btn-link" type="button"
+        title="Show Less" i18n-title aria-label="Show Less" i18n-aria-label
         *ngIf="expand" (click)="expand=false">
-        <span class="material-icons">expand_less</span>
-      </a>
+        <span class="material-icons" aria-hidden="true">expand_less</span>
+      </button>
     </div>
   </div>
   <div class="row">
index 718e5f3..9017e5b 100644 (file)
@@ -4,12 +4,14 @@
     {{label}} <span *ngIf="hasChanged" class="text-danger">*</span>
     <ng-container *ngIf="bulky()">
       <div class="flex-1"></div>
-      <a href='javascript:;' (click)="expanded = true" *ngIf="!expanded">
-        <span class="material-icons">unfold_more</span>
-      </a>
-      <a href='javascript:;' (click)="expanded = false" *ngIf="expanded">
-        <span class="material-icons">unfold_less</span>
-      </a>
+      <button (click)="expanded = true" *ngIf="!expanded" type="button"
+        aria-label="Expand" i18n-aria-label title="Expand" i18n-title>
+        <span class="material-icons" aria-hidden="true">unfold_more</span>
+      </button>
+      <button (click)="expanded = false" *ngIf="expanded" type="button"
+        aria-label="Condense" i18n-aria-label title="Condense" i18n-title>
+        <span class="material-icons" aria-hidden="true">unfold_less</span>
+      </button>
     </ng-container>
   </div>
   <div tabindex="0" class="p-2" *ngIf="!editing || multiValue()"
index ebbc5ad..0bb20e4 100644 (file)
@@ -1,4 +1,4 @@
-<button class="btn btn-info label-with-material-icon" (click)="doneWithEdits.emit()">
+<button type="button" class="btn btn-info label-with-material-icon" (click)="doneWithEdits.emit()">
     <span class="material-icons" aria-hidden="true">arrow_back</span>
     <span i18n>Back</span>
 </button>
index e3a3fe9..ff033a3 100644 (file)
 
   <ng-container *ngIf="context.recordType === 'biblio' && isControlledBibTag(field.tag)">
     <button class="btn btn-sm btn-outline-info link-button"
+      i18n-aria-label aria-label="Create authority link"
       i18n-title title="Create authority link"
       (click)="openLinkerDialog(field)">
-      <span class="material-icons">link</span>
+      <span class="material-icons" aria-hidden="true">link</span>
     </button>
   </ng-container>
 
         title="Authority Validation Succeeded" i18n-title
         class="material-icons label-with-material-icon text-success">
         check_circle_outline
+        <span class="visually-hidden" i18n>Authority Validation Succeeded</span>
       </span>
       <span *ngIf="!field.authValid"
         title="Authority Validation Failed" i18n-title
         class="material-icons label-with-material-icon text-danger">
         error_outline
+        <span class="visually-hidden" i18n>Authority Validation Failed</span>
       </span>
     </span>
   </ng-container>
       </eg-marc-editable-content>
 
       <ng-container *ngIf="field.tag === '007'">
-         <button class="btn btn-sm btn-outline-info link-button"
+         <button class="btn btn-sm btn-outline-info link-button" type="button"
+          i18n-aria-label aria-label="Open physical characteristics wizard"
           i18n-title title="Open physical characteristics wizard"
           (click)="openPhysCharDialog(field)">
-          <span class="material-icons">launch</span>
+          <span class="material-icons" aria-hidden="true">launch</span>
         </button>
       </ng-container>
     </div>
index f35caa1..4f6b5f1 100644 (file)
       <button class="btn btn-success w-100" (click)="go()" i18n>Search</button>
     </div>
     <div class="col-lg-2 ps-1 pe-1">
-      <button (click)="toggleExpandForm()"
+      <button (click)="toggleExpandForm()" type="button"
         class="btn btn-outline-dark ms-2 label-with-material-icon"
+        i18n-aria-label aria-label="Toggle Expanded Form Display"
         i18n-title title="Toggle Expanded Form Display">
-        <span *ngIf="!expandForm" class="material-icons">arrow_drop_down</span>
-        <span *ngIf="expandForm"  class="material-icons">arrow_drop_up</span>
+        <span class="material-icons" aria-hidden="true">{{expandForm ? 'arrow_drop_up' : 'arrow_drop_down'}}</span>
       </button>
     </div>
   </div>
index f32afa2..0cb25de 100644 (file)
@@ -8,7 +8,7 @@ import {Component, OnInit, Input} from '@angular/core';
     <div class="lead alert alert-primary text-center pt-1 pb-1"
       [ngClass]="bannerStyle ? bannerStyle : 'alert-primary'">
       <h1>
-        <i class="material-icons align-middle text-left" *ngIf="bannerIcon">{{bannerIcon}}</i>
+        <i class="material-icons align-middle text-left" aria-hidden="true" *ngIf="bannerIcon">{{bannerIcon}}</i>
         <span i18n>{{bannerText}}</span>
       </h1>
     </div>
index 0934d1d..d0ef4e5 100644 (file)
@@ -48,16 +48,27 @@ h5 {font-size: .95rem}
 /** Use a default link color that achieves WCAG AA
  *  color contrast against a white background
  */
- a { 
+a { 
   border-color: #0A58CA;
   color: #0A58CA; 
 }
 
+a:focus,
 a:hover { 
   border-color: #0848A5;
   color: #0848A5; 
 }
 
+.btn-link {
+  color: #0A58CA;
+  padding: inherit;
+}
+
+.btn-link:focus,
+.btn-link:hover {
+  color: #0848A5;
+}
+
 /** Ang5 routes on clicks to href's with no values, so we can't have
  * bare href's to force anchor styling.  Use this for anchors w/ no href.
  * TODO: should we style all of them?  a:not([href]) ....