LP1999158 Form labels for eg-org-select component user/sleary/lp1999158-org-select-labels
authorStephanie Leary <stephanie.leary@equinoxOLI.org>
Tue, 6 Dec 2022 22:27:20 +0000 (16:27 -0600)
committerStephanie Leary <stephanie.leary@equinoxoli.org>
Mon, 8 May 2023 21:28:49 +0000 (21:28 +0000)
Adds several input directives to <eg-org-select> to support <label> tags
with various options. Label tags are included alongside inputs unless
explicitly suppressed. Where a visible label would disrupt the current
layout, the "sr-only" CSS class may be used to hide the label visually
while leaving it available to screen readers.

All current instances of <eg-org-select> have been updated. Where labels
already existed, those with specific layout requirements have been
adjusted only to add missing "for" attributes, and the component's
automatic output is suppressed.

Signed-off-by: Stephanie Leary <stephanie.leary@equinoxOLI.org>
31 files changed:
Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.html
Open-ILS/src/eg2/src/app/share/grid/grid-filter-control.component.html
Open-ILS/src/eg2/src/app/share/org-family-select/org-family-select.component.html
Open-ILS/src/eg2/src/app/share/org-family-select/org-family-select.component.ts
Open-ILS/src/eg2/src/app/share/org-select/org-select.component.html
Open-ILS/src/eg2/src/app/share/org-select/org-select.component.ts
Open-ILS/src/eg2/src/app/staff/acq/lineitem/copy-attrs.component.html
Open-ILS/src/eg2/src/app/staff/acq/picklist/upload.component.html
Open-ILS/src/eg2/src/app/staff/acq/po/create.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/local/copy-loc-order/copy-loc-order.component.html
Open-ILS/src/eg2/src/app/staff/admin/local/negative-balances/list.component.html
Open-ILS/src/eg2/src/app/staff/admin/local/org-unit-settings/edit-org-unit-setting-dialog.component.html
Open-ILS/src/eg2/src/app/staff/admin/local/staff_portal_page/clone-portal-entries-dialog.component.html
Open-ILS/src/eg2/src/app/staff/admin/workstation/workstations/workstations.component.html
Open-ILS/src/eg2/src/app/staff/booking/create-reservation-dialog.component.html
Open-ILS/src/eg2/src/app/staff/booking/pull-list.component.html
Open-ILS/src/eg2/src/app/staff/cat/vandelay/match-set-list.component.html
Open-ILS/src/eg2/src/app/staff/cat/volcopy/config.component.html
Open-ILS/src/eg2/src/app/staff/cat/volcopy/copy-attrs.component.html
Open-ILS/src/eg2/src/app/staff/cat/volcopy/vol-edit.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/search-form.component.html
Open-ILS/src/eg2/src/app/staff/circ/patron/edit.component.html
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html
Open-ILS/src/eg2/src/app/staff/share/holds/grid.component.html
Open-ILS/src/eg2/src/app/staff/share/holds/manage.component.html
Open-ILS/src/eg2/src/app/staff/share/patron/search.component.html

index c0ea3e4..ca4d549 100644 (file)
@@ -90,6 +90,8 @@
               <eg-org-select
                 placeholder="{{field.label}}..."
                 i18n-placeholder
+                labelText = "{{field.label}}"
+                labelClass = "visually-hidden"
                 domId="{{idPrefix}}-{{field.name}}"
                 persistKey="{{field.persistKey}}"
                 [limitPerms]="modePerms[mode]"
index 25d8e0a..03f9556 100644 (file)
                 </div>
               </div>
               <div class="pt-2">
-                <eg-org-select [applyOrgId]="col.filterValue" 
+                <eg-org-select labelClass="visually-hidden" [applyOrgId]="col.filterValue" 
                   (onChange)="col.filterValue = $event; applyFilterCommon(col)"
                   [disabled]="col.filterInputDisabled || context.dataSource.requestingData"
                   i18n-placeholder placeholder="Enter library to filter by" #ousel></eg-org-select>
index 31385d8..e6fa537 100644 (file)
@@ -1,6 +1,6 @@
 <form class="d-flex align-items-start" [formGroup]="familySelectors">
-  <span class="input-group-text">{{labelText}}</span>
-  <eg-org-select [domId]="domId"
+  <label for="{{domId}}" class="input-group-text org-unit-select-label" i18n-labelText>{{labelText}}</label>
+  <eg-org-select [domId]="domId" labelSuppressed="true"
     (onChange)="orgOnChange($event)"
     [limitPerms]="limitPerms"
     [applyOrgId]="selectedOrgId">
index 64188da..aaf7d16 100644 (file)
@@ -27,7 +27,7 @@ export interface OrgFamily {
 export class OrgFamilySelectComponent implements ControlValueAccessor, OnInit {
 
     // The label for this input
-    @Input() labelText = 'Library';
+    @Input() labelText = $localize `Library`;
 
     // Should the Ancestors checkbox be hidden?
     @Input() hideAncestorSelector = false;
index 5a38457..77eaf54 100644 (file)
@@ -9,7 +9,7 @@
 </ng-container>
 
 <ng-container *ngIf="!readOnly">
-
+  <label *ngIf="!labelSuppressed" for="{{domId}}" class="org-unit-select-label {{labelClass}}" i18n-labelText>{{labelText}}</label>
   <input type="text" 
     class="form-control"
     id="{{domId}}"
index d0a1b79..00b2cb0 100644 (file)
@@ -73,6 +73,15 @@ export class OrgSelectComponent implements OnInit {
     // Placeholder text for selector input
     @Input() placeholder = '';
 
+    // <label> contents for selector. Must not be empty.
+    @Input() labelText = $localize `Library`;
+
+    // Class attributes for <label>. Use 'sr-only' to hide the label from display.
+    @Input() labelClass = '';
+
+    // Suppress <label> output (if <label> is defined explicitly elsewhere)
+    @Input() labelSuppressed = false;
+
     // ID to display in the DOM for this selector
     @Input() domId = 'eg-org-select-' + OrgSelectComponent.domId++;
 
index f45c6f1..b7d3fb6 100644 (file)
@@ -10,6 +10,7 @@
   <div class="flex-1 p-1">
     <eg-org-select #owningLibSelect placeholder="Owning Branch..." 
       i18n-placeholder [readOnly]="fieldIsDisabled('owning_lib')"
+      labelText="Owning Branch" i18n-labelText labelClass="visually-hidden"
       [applyOrgId]="copy.owning_lib()"
       [limitPerms]="['CREATE_PICKLIST','CREATE_PURCHASE_ORDER']"
       (onChange)="valueChange('owning_lib', $event)">
index 515bd92..0f22400 100644 (file)
@@ -77,6 +77,7 @@
     </div>
       <div class="col-lg-3">
         <eg-org-select
+          labelSuppressed="true"
           [applyOrgId]="orderingAgency"
           (onChange)="orgOnChange($event)"
           [limitPerms]="['CREATE_PICKLIST','CREATE_PURCHASE_ORDER']">
index 130ef76..30b44b9 100644 (file)
@@ -11,9 +11,8 @@
     <hr class="p-1" />
   </div>
   <div class="form-group">
-    <label class="form-label" for="order-agency-input" i18n>Ordering Agency</label>
     <eg-org-select (onChange)="orgChange($event)" domId="order-agency-input"
-      [limitPerms]="['CREATE_PURCHASE_ORDER']">
+    labelText="Ordering Agency" i18n-labelText [limitPerms]="['CREATE_PURCHASE_ORDER']">
     </eg-org-select>
   </div>
   <div class="form-group">
index 2885660..d285773 100644 (file)
@@ -84,6 +84,7 @@
           <option i18n value="f">No</option>
         </select>
         <eg-org-select *ngIf="searchTermDatatypes[t.field] === 'org_unit'"
+          labelClass = "visually-hidden"
           [initialOrgId]="t.value1"
           (onChange)="setOrgUnitSearchValue($event, t)">
         </eg-org-select>
index 6e8a6e5..0b08d54 100644 (file)
@@ -24,6 +24,8 @@
             placeholder="Owner..."
             i18n-placeholder
             domId="formula-owner"
+            labelText="Formula Owner" i18n-labelText
+            labelClass="col-sm-1 col-form-owner"
             [applyOrgId]="formula.owner()"
             [limitPerms]="['ADMIN_ACQ_DISTRIB_FORMULA']"
             (onChange)="formula.owner($event); myForm.form.markAsDirty()">
index 04ee702..4fba963 100644 (file)
@@ -5,11 +5,11 @@
 
 <div class="row">
   <div class="col-lg-12 d-flex">
-    <div class="me-2" i18n>Context Org Unit</div>
-    <div>
-      <eg-org-select (onChange)="orgChanged($event)" [initialOrgId]="contextOrg">
+    
+      <eg-org-select labelText="Context Org Unit" i18n-labelText labelClass="mr-2"
+        (onChange)="orgChanged($event)" [initialOrgId]="contextOrg">
       </eg-org-select>
-    </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">
index 69995ce..f5329ba 100644 (file)
@@ -3,8 +3,7 @@
 
 <div class="row mt-2 mb-2">
   <div class="col-lg-6 form-inline">
-    <span class="pe-2" i18n>Patron Home Library:</span>
-    <eg-org-select
+    <eg-org-select labelText="Patron Home Library:" i18n-labelText labelClass="pr-2"
       persistKey="admin.local.negative_balances"
       (componentLoaded)="contextOrgLoaded = true"
       [initialOrg]="contextOrg"
index b929ac8..f40dd85 100644 (file)
     <div class="row mt-3">
         <div class="col-md-6">
             <div class="input-group">
-              <div class="input-group-text" i18n>Context</div>
-              <eg-org-select [initialOrg]="entryContext"
-                  (onChange)="entryContext = $event"></eg-org-select>
+                <div class="input-group-prepend">
+                    <eg-org-select labelText="Context" i18n-labelText labelClass="input-group-text"
+                    [initialOrg]="entryContext" (onChange)="entryContext = $event"></eg-org-select>
+                </div>
             </div>
         </div>
     </div>
index 124190d..664cfc4 100644 (file)
@@ -10,6 +10,7 @@
         <label for="source_library" class="form-label col-sm-6 col-form-label" i18n>Source Library</label>
         <div class="col-sm-6">
           <eg-org-select
+            labelSuppressed="true"
             placeholder="Source Library..."
             domId="source_library"
             i18n-placeholder
@@ -22,6 +23,7 @@
         <label for="target_library" class="form-label col-sm-6 col-form-label" i18n>Target Library</label>
         <div class="col-sm-6">
           <eg-org-select
+            labelSuppressed="true"
             placeholder="Target Library..."
             domId="target_library"
             i18n-placeholder
index 8a06216..2f76b5d 100644 (file)
     </div>
 
     <div class="row">
-      <div class="col" i18n>Register a New Workstation For This Browser</div>
+      <div class="col">
+        <label for="workstationSelect" i18n>Register a New Workstation For This Browser</label>
+      </div>
     </div>
     <div class="row mt-2">
       <div class="col-lg-2">
         <eg-org-select 
+          domId="workstationSelect"
+          labelSuppressed="true"
           [applyDefault]="true"
           (onChange)="orgOnChange($event)"
           [hideOrgs]="hideOrgs"
index 5dd9efb..39ce68e 100644 (file)
@@ -47,9 +47,8 @@
       </div>
     </div>
     <div class="form-group row">
-      <label class="form-label col-lg-4 text-end fw-bold"
-        i18n for="create-pickup-library">Reservation location</label>
       <eg-org-select domId="create-pickup-library" [applyDefault]="true"
+        labelText="Reservation location" i18n-labelText labelClass="form-label col-lg-4 text-right font-weight-bold"
         [disableOrgs]="disableOrgs()" [hideOrgs]="disableOrgs()"
         (onChange)="handlePickupLibChange($event)">
       </eg-org-select>
index 0471210..6383e1d 100644 (file)
@@ -6,7 +6,7 @@
   <div class="col-md-4">
     <div class="input-group">
         <label for="ou" class="form-label input-group-text" i18n>Library:</label>
-      <eg-org-select domId="ou" [applyDefault]="true"
+      <eg-org-select domId="ou" [applyDefault]="true" labelSuppressed="true"
         (onChange)="handleOrgChange($event)"
         [disableOrgs]="disableOrgs()" [hideOrgs]="disableOrgs()">
       </eg-org-select>
index a446b2f..60caf5b 100644 (file)
@@ -2,8 +2,12 @@
 <div class="d-flex mb-3">
   <div>
     <div class="input-group">
-      <span class="input-group-text">Owner</span>
+      <div class="input-group-prepend">
+        <label for="contextOrgSelect" i18n class="input-group-text">Owner</label>
+      </div>
       <eg-org-select
+        domId="contextOrgSelect"
+        labelSuppressed="true"
         [initialOrg]="contextOrg"
         (onChange)="orgOnChange($event)">
       </eg-org-select>
index 548a1b1..a01c6e5 100644 (file)
             <eg-org-select
               domId="statcat_filter"
               placeholder="Stat Cat Filter..." i18n-placeholder
+              labelSuppressed="true"
               [initialOrgId]="volcopy.defaults.values.statcat_filter"
               (onChange)="volcopy.defaults.values.statcat_filter = $event ? $event.id() : null">
             </eg-org-select>
index b0d1c29..3b6f849 100644 (file)
       <ng-template #circLibTemplate>
         <eg-org-select 
           domId="circ_lib-input"
+          labelClass="visually-hidden"
           (onChange)="values['circ_lib'] = $event ? $event.id() : null"
           [hideOrgs]="volcopy.hideVolOrgs"
           [limitPerms]="['UPDATE_COPY']">
       <ng-template #owningLibTemplate>
         <eg-org-select 
           domId="owning_lib-input"
+          labelClass="visually-hidden"
           (onChange)="values['owning_lib'] = $event ? $event.id() : null"
           [hideOrgs]="volcopy.hideVolOrgs"
           [limitPerms]="['UPDATE_COPY']">
     </div>
 
     <div class="border rounded m-1" *ngIf="displayAttr('statcat_filter')">
-      <div class="batch-header fw-bold p-2" i18n>Stat Cat Filter</div>
+      <div class="batch-header font-weight-bold p-2">
+        <label for="statcat_filter-select" i18n>Stat Cat Filter</label>
+      </div>
       <div class="p-1">
         <eg-org-select
+          labelSuppressed="true"
           domId="statcat_filter-select"
           placeholder="Stat Cat Filter..." i18n-placeholder
           [initialOrgId]="statCatFilter"
index 471fa9f..c83d7fa 100644 (file)
                 <ng-template #addOrgTmpl>
                   <eg-org-select [limitPerms]="['CREATE_VOLUME']" 
                     placeholder="Select Location..." i18n-placeholder
+                    labelText="Select Location" i18n-labelText labelClass="visually-hidden"
                     [hideOrgs]="volcopy.hideVolOrgs"
                     (onChange)="addVol($event); addOrgPopover.close()">
                   </eg-org-select>
                 <ng-template #editOrgTmpl>
                   <eg-org-select [limitPerms]="['CREATE_VOLUME']" 
                     placeholder="Select Location..." i18n-placeholder
+                    labelText="Select Location" labelClass="visually-hidden"
                     [hideOrgs]="volcopy.hideVolOrgs"
                     (onChange)="editVolOwner(volNode, $event); editOrgPopover.close()">
                   </eg-org-select>
index ce18269..b81695d 100644 (file)
       </div>
       <div class="row mt-2">
         <div class="col-lg-6">
-          <label class="form-label" i18n>Pickup Location: </label>
+          <label class="form-label" for="pickupLibSelect" i18n>Pickup Location: </label>
         </div>
         <div class="col-lg-6">
-          <eg-org-select (onChange)="pickupLib = $event ? $event.id() : null"
-            [disableOrgs]="disableOrgs" [applyOrgId]="pickupLib"></eg-org-select>
+          <eg-org-select domId="pickupLibSelect" (onChange)="pickupLib = $event ? $event.id() : null"
+            [disableOrgs]="disableOrgs" [applyOrgId]="pickupLib" labelSuppressed="true"></eg-org-select>
         </div>
       </div>
       <div class="row mt-2">
index d608871..8266fab 100644 (file)
@@ -12,7 +12,7 @@
     </label>
   </div>
   <div class="col-lg-2">
-    <eg-org-select domId="default-lib-selector" 
+    <eg-org-select domId="default-lib-selector" labelSuppressed="true"
       (onChange)="orgChanged($event, 'eg.search.search_lib')"
       [applyOrgId]="settings['eg.search.search_lib']">
     </eg-org-select>
@@ -33,7 +33,7 @@
     </label>
   </div>
   <div class="col-lg-2">
-    <eg-org-select domId="pref-lib-selector" 
+    <eg-org-select domId="pref-lib-selector" labelSuppressed="true"
       (onChange)="orgChanged($event, 'eg.search.pref_lib')"
       [applyOrgId]="settings['eg.search.pref_lib']">
     </eg-org-select>
index 1f87ce9..6aac948 100644 (file)
@@ -4,8 +4,14 @@
 <div class="row mt-3">
   <div class="col-lg-4">
     <div class="input-group">
-      <div class="input-group-text" i18n>Holdings Maintenance</div>
+      <div class="input-group-prepend">
+        <div class="input-group-text">
+          <label for="contextOrgSelect" class="form-label" i18n>Holdings Maintenance</label>
+        </div>
+      </div>
       <eg-org-select [initialOrg]="contextOrg"
+        domId="contextOrgSelect"
+        labelSuppressed = "true"
         persistKey="catalog.holdings"
         (onChange)="contextOrgChanged($event)"
         [orgClassCallback]="orgClassCallback">
index f2111de..590c90f 100644 (file)
               <eg-org-select 
                 (onChange)="orgOnChange($event)"
                 [initialOrg]="context.searchOrg"
-                [placeholder]="'Library'" >
+                [placeholder]="'Library'" i18n-placeholder
+                labelText="Library" i18n-labelText labelClass="visually-hidden" >
               </eg-org-select>
               <button class="btn btn-success me-1 ms-1" type="button"
                 [disabled]="searchIsActive()"
index f53c638..7c22f1f 100644 (file)
   </div>
 
   <div class="row pt-1 pb-1 mt-1" *ngIf="showField('au.home_ou')">
+    <label for="au-home_ou-input" class="org-unit-select-label visually-hidden">
     <ng-container 
       *ngTemplateOutlet="fieldLabel; context: {args: {field: 'home_ou'}}">
     </ng-container>
+    </label>
     <div class="col-lg-3">
       <eg-org-select
+        labelSuppressed="true"
         domId="au-home_ou-input"
         fieldName="au-home_ou-input"
         [initialOrgId]="patron.home_ou()"
     </ng-container>
     <div class="col-lg-3">
       <eg-org-select
+        labelSuppressed="true"
         domId="cust-opac.default_pickup_location-input"
         fieldName="cust-opac.default_pickup_location-input"
         [initialOrgId]="userSettings['opac.default_pickup_location']"
index e9737bc..98c1eeb 100644 (file)
    <button class="btn btn-info" (click)="testToast()">Test Toast Message</button>
   </div>
   <div class="col-lg-2">
-    Org select with limit perms
+    <label for="limitPermsSelect" class="org-unit-select-label" i18n>Org select with limit perms</label>
   </div>
   <div class="col-lg-2">
-    <eg-org-select [limitPerms]="['REGISTER_WORKSTATION']">
+    <eg-org-select 
+      domId="limitPermsSelect"
+      labelSuppressed="true"
+      [limitPerms]="['REGISTER_WORKSTATION']">
     </eg-org-select>
   </div>
 </div>
 
 <div class="m-4">
   <div class="col-lg-4">
-    <h4>Org Unit Selector With Styled Orgs</h4>
-    <eg-org-select [orgClassCallback]="orgClassCallback">
+    <h4>
+      <label for="styledOrgSelect" class="org-unit-select-label" i18n>Org Unit Selector With Styled Orgs</label>
+    </h4>
+    <eg-org-select [orgClassCallback]="orgClassCallback" labelSuppressed="true">
     </eg-org-select>
   </div>
 </div>
index 487fae8..7f06212 100644 (file)
     <div class="row" *ngIf="!hidePickupLibFilter">
       <div class="col-lg-5">
         <div class="input-group">
-          <div class="input-group-text" i18n>Pickup Library</div>
-          <eg-org-select [persistKey]="persistKey" [fallbackOrg]="pickupLib"
-            (componentLoaded)="plCompLoaded = true" (onChange)="pickupLibChanged($event)">
+          <div class="input-group-text">
+            <label for="pickupLibSelect" class="form-label" i18n>Pickup Library</label>
+          </div>
+          <eg-org-select 
+            domId="pickupLibSelect"
+            labelSuppressed="true"
+            [persistKey]="persistKey" 
+            [fallbackOrg]="pickupLib"
+            (componentLoaded)="plCompLoaded = true" 
+            (onChange)="pickupLibChanged($event)">
           </eg-org-select>
         </div>
       </div>
     <div class="row" *ngIf="pullListOrg">
       <div class="col-lg-4 mb-2">
         <div class="input-group">
-          <div class="input-group-text" i18n>View Pull List For:</div>
-          <eg-org-select [initialOrgId]="pullListOrg" [limitPerms]="['VIEW_HOLD_PULL_LIST']"
+          <div class="input-group-text">
+            <label for="pullListOrg" class="form-label" i18n>View Pull List For:</label>
+          </div>
+          <eg-org-select 
+            domId="pullListOrgSelect"
+            labelSuppressed="true"
+            [initialOrgId]="pullListOrg"
             (onChange)="pullListOrgChanged($event)">
           </eg-org-select>
         </div>
index 01eab0f..20b9d56 100644 (file)
             name="active_pickup_lib" [(ngModel)]="activeFields.pickup_lib"/>
         </div>
       </div>
-      <div class="flex-1"><label class="form-label" i18n>Pickup Library:</label></div>
+      <div class="flex-1"><label for="pickupLibSelect" class="form-label" i18n>Pickup Library:</label></div>
     </div>
     <div class="col-lg-4">
       <!-- TODO: filter orgs as needed -->
-      <eg-org-select [initialOrgId]="hold.pickup_lib()"
+      <eg-org-select 
+        domId="pickupLibSelect"
+        labelSuppressed="true"
+        [initialOrgId]="hold.pickup_lib()"
         [disabled]="isBatch() && !activeFields.pickup_lib"
         (onChange)="pickupLibChanged($event)">
       </eg-org-select>
index f35caa1..331f0a4 100644 (file)
         <eg-org-select (onChange)="searchOrg = $event"
           persistKey="patron.search"
           [fallbackOrg]="org.root()"
-          i18n-placeholder placeholder="Home Library">
+          i18n-placeholder placeholder="Home Library"
+          labelText="Home Library" i18n-labelText labelClass="visually-hidden">
         </eg-org-select>
         <!-- home org -->
       </div>