From f13f932f6a2e7de4ccfa11df1e8e4293da9daf5c Mon Sep 17 00:00:00 2001
From: Owen Leonard <oleonard@myacpl.org>
Date: Wed, 10 Feb 2021 19:43:25 +0000
Subject: [PATCH] Bug 27668: Improve validation of patron entry form in the
 OPAC

This patch improves the way we handle required fields in the patron
entry/update form in the OPAC. Instead of doing multiple checks for each
field using mandatory.defined(), the template now loops over a list of
fields and sets a "required" variable for any which are required.

Then, for each form field, the "required" variable is used to set
classes on labels, input fields, and the "required" text hints. The
class on form fields acts as a hook for the jQuery validator plugin. The
class on the text hints allows us to hide the text hint using CSS,
eliminating the necessity of using a template conditional.

The patch also adds the missing validator-strings include which enables
translation of the jQuery validator plugin's validation error messages.

To test, apply the patch and rebuild the OPAC CSS
(https://wiki.koha-community.org/wiki/Working_with_SCSS_in_the_OPAC_and_staff_client).

 - Go to Administration -> System preferences and enable
   PatronSelfRegistration.
 - Select multiple fields to be required using the
   PatronSelfRegistrationBorrowerMandatoryField preference.
 - In the OPAC, start the process of registering for an account.
 - The fields you designated as mandatory should each have a "Required"
   label under them.
 - Try to submit the form without entering any data. The required fields
   should now be highlighted in red and have another label, "This field
   is  required."
 - Fill in the required fields and submit the form. It should submit
   correctly.
 - Modify the PatronSelfRegistrationBorrowerMandatoryField preference
   and select all fields as mandatory. Confirm that all fields in the
   patron entry form work correctly.
 - Test that form validation works correctly when modifying a logged-in
   patron's existing account.

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>

https://bugs.koha-community.org/show_bug.cgi?id=27688
---
 koha-tmpl/opac-tmpl/bootstrap/css/src/opac.scss    |  40 +-
 .../bootstrap/en/includes/validator-strings.inc    |  24 +
 .../bootstrap/en/modules/opac-memberentry.tt       | 481 +++++++--------------
 3 files changed, 211 insertions(+), 334 deletions(-)
 create mode 100644 koha-tmpl/opac-tmpl/bootstrap/en/includes/validator-strings.inc

diff --git a/koha-tmpl/opac-tmpl/bootstrap/css/src/opac.scss b/koha-tmpl/opac-tmpl/bootstrap/css/src/opac.scss
index 8f411ae789..37c843a918 100644
--- a/koha-tmpl/opac-tmpl/bootstrap/css/src/opac.scss
+++ b/koha-tmpl/opac-tmpl/bootstrap/css/src/opac.scss
@@ -624,8 +624,24 @@ th {
     }
 }
 
+div {
+    &.required_label {
+        display: none;
+
+        &.required {
+            color: #C00;
+            display: block;
+            font-size: 95%;
+            margin-left: 10rem;
+            margin-top: 3px;
+        }
+    }
+}
+
 .required {
-    color: #C00;
+    &.valid {
+        color: #000;
+    }
 }
 
 
@@ -686,12 +702,21 @@ fieldset {
         .label {
             float: left;
             font-weight: bold;
-            margin-right: 1em;
+            margin-right: 1rem;
             text-align: right;
-            width: 9em;
+            width: 9rem;
         }
 
         label {
+            &.error {
+                color: #C00;
+                float: none;
+                font-style: italic;
+                font-weight: normal;
+                margin-left: 1rem;
+                text-align: left;
+                width: auto;
+            }
             &.lradio {
                 float: none;
                 margin: inherit;
@@ -744,7 +769,7 @@ fieldset {
 
         .hint {
             display: block;
-            margin-left: 11em;
+            margin-left: 10rem;
         }
     }
 
@@ -784,7 +809,7 @@ div {
                 font-weight: bold;
                 margin-right: 1em;
                 text-align: left;
-                width: 9em;
+                width: 9rem;
             }
         }
 
@@ -2246,14 +2271,11 @@ nav {
 #memberentry-form {
     input.error {
         border-color: #C00;
-        box-shadow: 0 1px 1px #C00 inset, 0 0 8px #C00;
-        color: #F00;
         outline: 0 none;
 
         &:focus {
             border-color: #C00;
-            box-shadow: 0 1px 1px #C00 inset, 0 0 8px #C00;
-            color: #F00;
+            box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(204, 0, 0, .6);
             outline: 0 none;
         }
 
diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/validator-strings.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/validator-strings.inc
new file mode 100644
index 0000000000..0600f0a672
--- /dev/null
+++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/validator-strings.inc
@@ -0,0 +1,24 @@
+<!-- validator-strings.inc -->
+<script>
+    $(document).ready(function(){
+        jQuery.extend(jQuery.validator.messages, {
+            required: _("This field is required."),
+            remote: _("Please fix this field."),
+            email: _("Please enter a valid email address."),
+            url: _("Please enter a valid URL."),
+            date: _("Please enter a valid date."),
+            dateISO: _("Please enter a valid date (ISO)."),
+            number: _("Please enter a valid number."),
+            digits: _("Please enter only digits."),
+            equalTo: _("Please enter the same value again."),
+            maxlength: $.validator.format(_("Please enter no more than {0} characters.")),
+            minlength: $.validator.format(_("Please enter at least {0} characters.")),
+            rangelength: $.validator.format(_("Please enter a value between {0} and {1} characters long.")),
+            range: $.validator.format(_("Please enter a value between {0} and {1}.")),
+            max: $.validator.format(_("Please enter a value less than or equal to {0}.")),
+            min: $.validator.format(_("Please enter a value greater than or equal to {0}.")),
+            phone: $.validator.format(_("Please enter a valid phone number."))
+        });
+    });
+</script>
+<!-- / validator-strings.inc -->
diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt
index fc46fedda5..580a780767 100644
--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt
+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-memberentry.tt
@@ -10,14 +10,10 @@
 [% BLOCK streetnumber %]
     [% UNLESS hidden.defined('streetnumber') %]
         <li>
-            [% IF mandatory.defined('streetnumber') %]
-                <label for="borrower_streetnumber" class="required">Street number:</label>
-            [% ELSE %]
-                <label for="borrower_streetnumber">Street number:</label>
-            [% END %]
+            <label for="borrower_streetnumber" class="[% required.streetnumber | html %]">Street number:</label>
 
-            <input type="text" id="borrower_streetnumber" name="borrower_streetnumber" value="[% borrower.streetnumber | html %]" />
-            [% IF mandatory.defined('streetnumber') %]<span class="required">Required</span>[% END %]
+            <input type="text" id="borrower_streetnumber" name="borrower_streetnumber" value="[% borrower.streetnumber | html %]" class="[% required.streetnumber | html %]" />
+            <div class="required_label [% required.streetnumber | html %]">Required</div>
         </li>
     [% END %]
 [% END %]
@@ -191,6 +187,12 @@
 
                 <form method="post" action="/cgi-bin/koha/opac-memberentry.pl" id="memberentry-form" autocomplete="off">
 
+                [% FOREACH field = ['streetnumber' 'cardnumber' 'branchcode' 'categorycode' 'title' 'surname' 'firstname' 'dateofbirth' 'initials' 'othernames' 'address' 'address2' 'city' 'state' 'zipcode' 'country' 'phone' 'phonepro' 'mobile' 'email' 'emailpro' 'fax' 'B_address' 'B_address2' 'B_city' 'B_state' 'B_zipcode' 'B_country' 'B_phone' 'B_email' 'contactnote' 'altcontactsurname' 'altcontactfirstname' 'altcontactaddress1' 'altcontactaddress2' 'altcontactaddress3' 'altcontactstate' 'altcontactzipcode' 'altcontactcountry' 'altcontactphone' 'password' ] %]
+                    [% IF mandatory.defined( field ) %]
+                        [% SET required.$field = 'required' %]
+                    [% END %]
+                [% END %]
+
                     [%# Following on one line for translatability %]
                     [% UNLESS ( hidden.defined('cardnumber') || ( !borrower && Koha.Preference('autoMemberNum') ) ) && hidden.defined('dateexpiry') && hidden.defined('branchcode') && hidden.defined('categorycode') %]
                         <div class="row">
@@ -201,29 +203,27 @@
                                         <ol>
                                             [% UNLESS hidden.defined('cardnumber') || ( !borrower && Koha.Preference('autoMemberNum') ) %]
                                             <li>
-                                                [% IF mandatory.defined('cardnumber') %]
-                                                    <label for="borrower_cardnumber" class="required">Library card number:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_cardnumber">Library card number:</label>
-                                                [% END %]
+
+                                                <label for="borrower_cardnumber" class="[% required.cardnumber | html %]">Library card number:</label>
+
                                                 [% IF borrower && !(cardnumber_wrong_length || cardnumber_already_exists) %]
                                                     [% borrower.cardnumber | html %]
                                                 [% ELSE %]
                                                     [% IF minlength_cardnumber == maxlength_cardnumber %]
-                                                        <input type="text" id="borrower_cardnumber" name="borrower_cardnumber" size="20" value="[% borrower.cardnumber | html %]" minlength="[% minlength_cardnumber | html %]" maxlength="[% maxlength_cardnumber | html %]" />
-                                                        [% IF ( mandatory.defined('cardnumber') ) %]<span class="required">Required</span>[% END %]
+                                                        <input type="text" id="borrower_cardnumber" name="borrower_cardnumber" size="20" value="[% borrower.cardnumber | html %]" minlength="[% minlength_cardnumber | html %]" maxlength="[% maxlength_cardnumber | html %]" class="[% required.cardnumber | html %]" />
+                                                        <div class="required_label [% required.cardnumber | html %]">Required</div>
                                                         <div class="hint">Card number must be exactly [% minlength_cardnumber | html %] characters.</div>
                                                     [% ELSIF minlength_cardnumber && maxlength_cardnumber %]
-                                                        <input type="text" id="borrower_cardnumber" name="borrower_cardnumber" size="20" value="[% borrower.cardnumber | html %]" minlength="[% minlength_cardnumber | html %]" maxlength="[% maxlength_cardnumber | html %]" />
-                                                        [% IF ( mandatory.defined('cardnumber') ) %]<span class="required">Required</span>[% END %]
+                                                        <input type="text" id="borrower_cardnumber" name="borrower_cardnumber" size="20" value="[% borrower.cardnumber | html %]" minlength="[% minlength_cardnumber | html %]" maxlength="[% maxlength_cardnumber | html %]" class="[% required.cardnumber | html %]" />
+                                                        <div class="required_label [% required.cardnumber | html %]">Required</div>
                                                         <div class="hint">Card number must be between [% minlength_cardnumber | html %] and [% maxlength_cardnumber | html %] characters.</div>
                                                     [% ELSIF maxlength_cardnumber %]
-                                                        <input type="text" id="borrower_cardnumber" name="borrower_cardnumber" size="20" value="[% borrower.cardnumber | html %]" maxlength="[% maxlength_cardnumber | html %]" />
-                                                        [% IF ( mandatory.defined('cardnumber') ) %]<span class="required">Required</span>[% END %]
+                                                        <input type="text" id="borrower_cardnumber" name="borrower_cardnumber" size="20" value="[% borrower.cardnumber | html %]" maxlength="[% maxlength_cardnumber | html %]" class="[% required.cardnumber | html %]" />
+                                                        <div class="required_label [% required.cardnumber | html %]">Required</div>
                                                         <div class="hint">Card number can be up to [% maxlength_cardnumber | html %] characters.</div>
                                                     [% ELSE %]
-                                                        <input type="text" id="borrower_cardnumber" name="borrower_cardnumber" size="20" value="[% borrower.cardnumber | html %]" />
-                                                        [% IF ( mandatory.defined('cardnumber') ) %]<span class="required">Required</span>[% END %]
+                                                        <input type="text" id="borrower_cardnumber" name="borrower_cardnumber" size="20" value="[% borrower.cardnumber | html %]" class="[% required.cardnumber | html %]" />
+                                                        <div class="required_label [% required.cardnumber | html %]">Required</div>
                                                         <div class="hint">There is no minimum or maximum character length.</div>
                                                     [% END %]
                                                 [% END %]
@@ -240,13 +240,9 @@
                                             [% UNLESS hidden.defined('branchcode') %]
                                                 <li>
                                                     [% IF ( libraries.size > 1 ) %]
-                                                        [% IF mandatory.defined('branchcode') %]
-                                                            <label for="borrower_branchcode" class="required">Home library:</label>
-                                                        [% ELSE %]
-                                                            <label for="borrower_branchcode">Home library:</label>
-                                                        [% END %]
+                                                        <label for="borrower_branchcode" class="[% required.branchcode | html %]">Home library:</label>
 
-                                                        <select id="borrower_branchcode" name="borrower_branchcode">
+                                                        <select id="borrower_branchcode" name="borrower_branchcode" class="[% required.branchcode | html %]">
                                                             [% FOREACH l IN libraries %]
                                                                 [% IF l.branchcode == borrower.branchcode %]
                                                                     <option value="[% l.branchcode | html %]" selected="selected">[% l.branchname | html %]</option>
@@ -255,6 +251,7 @@
                                                                 [% END %]
                                                             [% END %]
                                                         </select>
+                                                        <div class="required_label [% required.branchcode | html %]">Required</div>
                                                     [% ELSE %]
                                                         <span class="label">Home library:</span>
                                                         [% FOREACH l IN libraries %]
@@ -267,14 +264,14 @@
 
                                             [% UNLESS hidden.defined('categorycode') %]
                                                 <li>
-                                                    <label for="borrower_categorycode">
+                                                    <label for="borrower_categorycode" class="[% required.categorycode | html %]">
                                                     Category:</label>
 
                                                     [% IF borrower %]
                                                         [% Categories.GetName( borrower.categorycode ) | html %]
                                                         <input type="hidden" name="borrower_categorycode" value="[% borrower.categorycode | html %]" />
                                                     [% ELSE %]
-                                                        <select id="borrower_categorycode" name="borrower_categorycode">
+                                                        <select id="borrower_categorycode" name="borrower_categorycode" class="[% required.categorycode | html %]">
                                                             [% FOREACH c IN Categories.all() %]
                                                                 [% IF c.categorycode == Koha.Preference('PatronSelfRegistrationDefaultCategory') %]
                                                                     <option value="[% c.categorycode | html %]" data-pwd-length="[% c.effective_min_password_length | html %]" data-pwd-strong="[% c.effective_require_strong_password | html %]" selected="selected">[% c.description | html %]</option>
@@ -283,6 +280,7 @@
                                                                 [% END %]
                                                             [% END %]
                                                         </select>
+                                                        <div class="required_label [% required.categorycode | html %]">Required</div>
                                                     [% END %]
                                                 </li>
                                             [% END %]
@@ -302,13 +300,9 @@
                                     <ol>
                                         [% UNLESS hidden.defined('title') || !Koha.Preference('BorrowersTitles') %]
                                             <li>
-                                                [% IF mandatory.defined('title') %]
-                                                    <label for="borrower_title" class="required">Salutation:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_title">Salutation:</label>
-                                                [% END %]
+                                                <label for="borrower_title" class="[% required.title | html %]">Salutation:</label>
 
-                                                <select id="borrower_title" name="borrower_title">
+                                                <select id="borrower_title" name="borrower_title" class="[% required.title | html %]">
                                                     <option value=""></option>
                                                     [% FOREACH mt IN Koha.Preference('BorrowersTitles').split('\|') %]
                                                         [% IF mt == borrower.title %]
@@ -318,44 +312,33 @@
                                                         [% END %]
                                                     [% END %]
                                                 </select>
+                                                <div class="required_label [% required.title | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('surname') %]
                                             <li>
-                                                [% IF mandatory.defined('surname') %]
-                                                    <label for="borrower_surname" class="required">Surname:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_surname">Surname:</label>
-                                                [% END %]
+                                                <label for="borrower_surname" class="[% required.surname | html %]">Surname:</label>
 
-                                                <input type="text" id="borrower_surname" name="borrower_surname" value="[% borrower.surname | html %]" />
-                                                [% IF mandatory.defined('surname') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_surname" name="borrower_surname" value="[% borrower.surname | html %]" class="[% required.surname | html %]" />
+                                                <div class="required_label [% required.surname | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('firstname') %]
                                             <li>
-                                                [% IF mandatory.defined('firstname') %]
-                                                    <label for="borrower_firstname" class="required">First name:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_firstname">First name:</label>
-                                                [% END %]
+                                                <label for="borrower_firstname" class="[% required.firstname | html %]">First name:</label>
 
-                                                <input type="text" id="borrower_firstname" name="borrower_firstname" value="[% borrower.firstname | html %]" />
-                                                [% IF mandatory.defined('firstname') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_firstname" name="borrower_firstname" value="[% borrower.firstname | html %]" class="[% required.firstname | html %]" />
+                                                <div class="required_label [% required.firstname | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('dateofbirth') %]
                                             <li>
-                                                [% IF mandatory.defined('dateofbirth') %]
-                                                    <label for="borrower_dateofbirth" class="required">Date of birth:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_dateofbirth">Date of birth:</label>
-                                                [% END %]
+                                                <label for="borrower_dateofbirth" class="[% required.dateofbirth | html %]">Date of birth:</label>
 
-                                                <input type="text" id="borrower_dateofbirth" name="borrower_dateofbirth" value="[% borrower.dateofbirth | $KohaDates %]" size="10" />
+                                                <input type="text" id="borrower_dateofbirth" name="borrower_dateofbirth" value="[% borrower.dateofbirth | $KohaDates %]" size="10" class="[% required.dateofbirth | html %]" />
 
                                                 [% UNLESS action == 'edit' && !OPACPatronDetails %]
                                                     [% UNLESS ( mandatory.defined('dateofbirth') ) %]
@@ -363,33 +346,25 @@
                                                     [% END %]
                                                 [% END %]
 
-                                                [% IF mandatory.defined('dateofbirth') %]<span class="required">Required</span>[% END %]
+                                                <div class="required_label [% required.dateofbirth | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('initials') %]
                                             <li>
-                                                [% IF mandatory.defined('initials') %]
-                                                    <label for="borrower_initials" class="required">Initials:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_initials">Initials:</label>
-                                                [% END %]
+                                                <label for="borrower_initials" class="[% required.initials | html %]">Initials:</label>
 
-                                                <input type="text" id="borrower_initials" name="borrower_initials" value="[% borrower.initials | html %]" />
-                                                [% IF mandatory.defined('initials') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_initials" name="borrower_initials" value="[% borrower.initials | html %]" class="[% required.initials | html %]" />
+                                                <div class="required_label [% required.initials | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('othernames') %]
                                             <li>
-                                                [% IF mandatory.defined('othernames') %]
-                                                    <label for="borrower_othernames" class="required">Other names:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_othernames">Other names:</label>
-                                                [% END %]
+                                                <label for="borrower_othernames" class="[% required.othernames | html %]">Other names:</label>
 
-                                                <input type="text" id="borrower_othernames" name="borrower_othernames" value="[% borrower.othernames | html %]" />
-                                                [% IF mandatory.defined('othernames') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_othernames" name="borrower_othernames" value="[% borrower.othernames | html %]" class="[% required.othernames | html %]" />
+                                                <div class="required_label [% required.initials | html %]">Required</div>
                                             </li>
                                         [% END %]
 
@@ -449,14 +424,10 @@
 
                                         [% UNLESS hidden.defined('address') %]
                                             <li>
-                                                [% IF mandatory.defined('address') %]
-                                                    <label for="borrower_address" class="required">Address:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_address">Address:</label>
-                                                [% END %]
+                                                <label for="borrower_address" class="[% required.address | html %]">Address:</label>
 
-                                                <input type="text" id="borrower_address" name="borrower_address" value="[% borrower.address | html %]" />
-                                                [% IF mandatory.defined('address') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_address" name="borrower_address" value="[% borrower.address | html %]" class="[% required.address | html %]" />
+                                                <div class="required_label [% required.address | html %]">Required</div>
                                             </li>
                                         [% END %]
 
@@ -464,66 +435,46 @@
 
                                         [% UNLESS hidden.defined('address2') %]
                                             <li>
-                                                [% IF mandatory.defined('address2') %]
-                                                    <label for="borrower_address2" class="required">Address 2:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_address2">Address 2:</label>
-                                                [% END %]
+                                                <label for="borrower_address2" class="[% required.address2 | html %]">Address 2:</label>
 
-                                                <input type="text" id="borrower_address2" name="borrower_address2" value="[% borrower.address2 | html %]" />
-                                                [% IF mandatory.defined('address2') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_address2" name="borrower_address2" value="[% borrower.address2 | html %]" class="[% required.address2 | html %]" />
+                                                <div class="required_label [% required.address2 | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('city') %]
                                             <li>
-                                                [% IF mandatory.defined('city') %]
-                                                    <label for="borrower_city" class="required">City:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_city">City:</label>
-                                                [% END %]
+                                                <label for="borrower_city" class="[% required.city | html %]">City:</label>
 
-                                                <input type="text" id="borrower_city" name="borrower_city" value="[% borrower.city | html %]" />
-                                                [% IF mandatory.defined('city') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_city" name="borrower_city" value="[% borrower.city | html %]" class="[% required.city | html %]" />
+                                                <div class="required_label [% required.city | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('state') %]
                                             <li>
-                                                [% IF mandatory.defined('state') %]
-                                                    <label for="borrower_state" class="required">State:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_state">State:</label>
-                                                [% END %]
+                                                <label for="borrower_state" class="[% required.state | html %]">State:</label>
 
-                                                <input type="text" id="borrower_state" name="borrower_state" value="[% borrower.state | html %]" />
-                                                [% IF mandatory.defined('state') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_state" name="borrower_state" value="[% borrower.state | html %]" class="[% required.state | html %]" />
+                                                <div class="required_label [% required.state | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('zipcode') %]
                                             <li>
-                                                [% IF mandatory.defined('zipcode') %]
-                                                    <label for="borrower_zipcode" class="required">ZIP/Postal code:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_zipcode">ZIP/Postal code:</label>
-                                                [% END %]
+                                                <label for="borrower_zipcode" class="[% required.zipcode | html %]">ZIP/Postal code:</label>
 
-                                                <input type="text" id="borrower_zipcode" name="borrower_zipcode" value="[% borrower.zipcode | html %]" />
-                                                [% IF mandatory.defined('zipcode') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_zipcode" name="borrower_zipcode" value="[% borrower.zipcode | html %]" class="[% required.zipcode | html %]" />
+                                                <div class="required_label [% required.zipcode | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('country') %]
                                             <li>
-                                                [% IF mandatory.defined('country') %]
-                                                    <label for="borrower_country" class="required">Country:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_country">Country:</label>
-                                                [% END %]
+                                                <label for="borrower_country" class="[% required.country | html %]">Country:</label>
 
-                                                <input type="text" id="borrower_country" name="borrower_country" value="[% borrower.country | html %]" />
-                                                [% IF mandatory.defined('country') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_country" name="borrower_country" value="[% borrower.country | html %]" class="[% required.country | html %]" />
+                                                <div class="required_label [% required.country | html %]">Required</div>
                                             </li>
                                         [% END %]
 
@@ -543,92 +494,64 @@
                                     <ol>
                                         [% UNLESS hidden.defined('phone') %]
                                             <li>
-                                                [% IF mandatory.defined('phone') %]
-                                                    <label for="borrower_phone" class="required">Primary phone:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_phone">Primary phone:</label>
-                                                [% END %]
+                                                <label for="borrower_phone" class="[% required.phone | html %]">Primary phone:</label>
 
-                                                <input type="text" id="borrower_phone" name="borrower_phone" value="[% borrower.phone | html %]" />
-                                                [% IF mandatory.defined('phone') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_phone" name="borrower_phone" value="[% borrower.phone | html %]" class="[% required.phone | html %]" />
+                                                <div class="required_label [% required.phone | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('phonepro') %]
                                             <li>
-                                                [% IF mandatory.defined('phonepro') %]
-                                                    <label for="borrower_phonepro" class="required">Secondary phone:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_phonepro">Secondary phone:</label>
-                                                [% END %]
+                                                <label for="borrower_phonepro" class="[% required.phonepro | html %]">Secondary phone:</label>
 
-                                                <input type="text" id="borrower_phonepro" name="borrower_phonepro" value="[% borrower.phonepro | html %]" />
-                                                [% IF mandatory.defined('phonepro') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_phonepro" name="borrower_phonepro" value="[% borrower.phonepro | html %]" class="[% required.phonepro | html %]" />
+                                                <div class="required_label [% required.phonepro | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('mobile') %]
                                             <li>
-                                                [% IF mandatory.defined('mobile') %]
-                                                    <label for="borrower_mobile" class="required">Other phone:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_mobile">Other phone:</label>
-                                                [% END %]
+                                                <label for="borrower_mobile" class="[% required.mobile | html %]">Other phone:</label>
 
-                                                <input type="text" id="borrower_mobile" name="borrower_mobile" value="[% borrower.mobile | html %]" />
-                                                [% IF mandatory.defined('mobile') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_mobile" name="borrower_mobile" value="[% borrower.mobile | html %]" class="[% required.mobile | html %]" />
+                                                <div class="required_label [% required.mobile | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('email') %]
                                             <li>
-                                                [% IF mandatory.defined('email') %]
-                                                    <label for="borrower_email" class="required">Primary email:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_email">Primary email:</label>
-                                                [% END %]
+                                                <label for="borrower_email" class="[% required.email | html %]">Primary email:</label>
 
-                                                <input type="text" id="borrower_email" name="borrower_email" value="[% borrower.email | html %]" />
-                                                [% IF mandatory.defined('email') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_email" name="borrower_email" value="[% borrower.email | html %]" class="[% required.email | html %]" />
+                                                <div class="required_label [% required.email | html %]">Required</div>
                                             </li>
 
                                             [% IF action != 'edit' and Koha.Preference('PatronSelfRegistrationConfirmEmail') %]
                                                 <li>
-                                                    [% IF mandatory.defined('email') %]
-                                                        <label for="borrower_repeat_email" class="required">Confirm primary email:</label>
-                                                    [% ELSE %]
-                                                        <label for="borrower_repeat_email">Confirm primary email:</label>
-                                                    [% END %]
+                                                    <label for="borrower_repeat_email" class="[% required.email | html %]">Confirm primary email:</label>
 
-                                                    <input type="text" id="borrower_repeat_email" name="borrower_repeat_email" autocomplete=off>
-                                                    [% IF mandatory.defined('email') %]<span class="required">Required</span>[% END %]
+                                                    <input type="text" id="borrower_repeat_email" name="borrower_repeat_email" autocomplete="off" class="[% required.email | html %]">
+                                                    <div class="required_label [% required.email | html %]">Required</div>
                                                 </li>
                                             [% END %]
                                         [% END %]
 
                                         [% UNLESS hidden.defined('emailpro') %]
                                             <li>
-                                                [% IF mandatory.defined('emailpro') %]
-                                                    <label for="borrower_emailpro" class="required">Secondary email:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_emailpro">Secondary email:</label>
-                                                [% END %]
+                                                <label for="borrower_emailpro" class="[% required.emailpro | html %]">Secondary email:</label>
 
-                                                <input type="text" id="borrower_emailpro" name="borrower_emailpro" value="[% borrower.emailpro | html %]" />
-                                                [% IF mandatory.defined('emailpro') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_emailpro" name="borrower_emailpro" value="[% borrower.emailpro | html %]" class="[% required.emailpro | html %]" />
+                                                <div class="required_label [% required.emailpro | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('fax') %]
                                             <li>
-                                                [% IF mandatory.defined('fax') %]
-                                                    <label for="borrower_fax" class="required">Fax:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_fax">Fax:</label>
-                                                [% END %]
+                                                <label for="borrower_fax" class="[% required.fax | html %]">Fax:</label>
 
-                                                <input type="text" id="borrower_fax" name="borrower_fax" value="[% borrower.fax | html %]" />
-                                                [% IF mandatory.defined('fax') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_fax" name="borrower_fax" value="[% borrower.fax | html %]" class="[% required.fax | html %]" />
+                                                <div class="required_label [% required.fax | html %]">Required</div>
                                             </li>
                                         [% END %]
                                     </ol>
@@ -647,118 +570,82 @@
                                     <ol>
                                         [% UNLESS hidden.defined('B_address') %]
                                             <li>
-                                                [% IF mandatory.defined('B_address') %]
-                                                    <label for="borrower_B_address" class="required">Address:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_B_address">Address:</label>
-                                                [% END %]
+                                                <label for="borrower_B_address" class="[% required.B_address | html %]">Address:</label>
 
-                                                <input type="text" id="borrower_B_address" name="borrower_B_address" value="[% borrower.B_address | html %]" />
-                                                [% IF mandatory.defined('B_address') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_B_address" name="borrower_B_address" value="[% borrower.B_address | html %]" class="[% required.B_address | html %]" />
+                                                <div class="required_label [% required.B_address | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('B_address2') %]
                                             <li>
-                                                [% IF mandatory.defined('B_address2') %]
-                                                    <label for="borrower_B_address2" class="required">Address 2:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_B_address2">Address 2:</label>
-                                                [% END %]
+                                                <label for="borrower_B_address2" class="[% required.B_address | html %]">Address 2:</label>
 
-                                                <input type="text" id="borrower_B_address2" name="borrower_B_address2" value="[% borrower.B_address2 | html %]" />
-                                                [% IF mandatory.defined('B_address2') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_B_address2" name="borrower_B_address2" value="[% borrower.B_address2 | html %]" class="[% required.B_address | html %]" />
+                                                <div class="required_label [% required.B_address2 | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('B_city') %]
                                             <li>
-                                                [% IF mandatory.defined('B_city') %]
-                                                    <label for="borrower_B_city" class="required">City:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_B_city">City:</label>
-                                                [% END %]
+                                                <label for="borrower_B_city" class="[% required.B_city | html %]">City:</label>
 
-                                                <input type="text" id="borrower_B_city" name="borrower_B_city" value="[% borrower.B_city | html %]" />
-                                                [% IF mandatory.defined('B_city') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_B_city" name="borrower_B_city" value="[% borrower.B_city | html %]" class="[% required.B_city | html %]" />
+                                                <div class="required_label [% required.B_city | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('B_state') %]
                                             <li>
-                                                [% IF mandatory.defined('B_state') %]
-                                                    <label for="borrower_B_state" class="required">State:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_B_state">State:</label>
-                                                [% END %]
+                                                <label for="borrower_B_state" class="[% required.B_state | html %]">State:</label>
 
-                                                <input type="text" id="borrower_B_state" name="borrower_B_state" value="[% borrower.B_state | html %]" />
-                                                [% IF mandatory.defined('B_state') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_B_state" name="borrower_B_state" value="[% borrower.B_state | html %]" class="[% required.B_state | html %]" />
+                                                <div class="required_label [% required.B_state | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('B_zipcode') %]
                                             <li>
-                                                [% IF mandatory.defined('B_zipcode') %]
-                                                    <label for="borrower_B_zipcode" class="required">ZIP/Postal code:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_B_zipcode">ZIP/Postal code:</label>
-                                                [% END %]
+                                                <label for="borrower_B_zipcode" class="[% required.B_zipcode | html %]">ZIP/Postal code:</label>
 
-                                                <input type="text" id="borrower_B_zipcode" name="borrower_B_zipcode" value="[% borrower.B_zipcode | html %]" />
-                                                [% IF mandatory.defined('B_zipcode') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_B_zipcode" name="borrower_B_zipcode" value="[% borrower.B_zipcode | html %]" class="[% required.B_zipcode | html %]" />
+                                                <div class="required_label [% required.B_zipcode | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('B_country') %]
                                             <li>
-                                                [% IF mandatory.defined('B_country') %]
-                                                    <label for="borrower_B_country" class="required">Country:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_B_country">Country:</label>
-                                                [% END %]
+                                                <label for="borrower_B_country" class="[% required.B_country | html %]">Country:</label>
 
-                                                <input type="text" id="borrower_B_country" name="borrower_B_country" value="[% borrower.B_country | html %]" />
-                                                [% IF mandatory.defined('B_country') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_B_country" name="borrower_B_country" value="[% borrower.B_country | html %]" class="[% required.B_country | html %]" />
+                                                <div class="required_label [% required.B_country | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('B_phone') %]
                                             <li>
-                                                [% IF mandatory.defined('B_phone') %]
-                                                    <label for="borrower_B_phone" class="required">Phone:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_B_phone">Phone:</label>
-                                                [% END %]
+                                                <label for="borrower_B_phone" class="[% required.B_phone | html %]">Phone:</label>
 
-                                                <input type="text" id="borrower_B_phone" name="borrower_B_phone" value="[% borrower.B_phone | html %]" />
-                                                [% IF mandatory.defined('B_phone') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_B_phone" name="borrower_B_phone" value="[% borrower.B_phone | html %]" class="[% required.B_phone | html %]" />
+                                                <div class="required_label [% required.B_phone | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('B_email') %]
                                             <li>
-                                                [% IF mandatory.defined('B_email') %]
-                                                    <label for="borrower_B_email" class="required">Email:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_B_email">Email:</label>
-                                                [% END %]
+                                                <label for="borrower_B_email" class="[% required.B_email | html %]">Email:</label>
 
-                                                <input type="text" id="borrower_B_email" name="borrower_B_email" value="[% borrower.B_email | html %]" />
-                                                [% IF mandatory.defined('B_email') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_B_email" name="borrower_B_email" value="[% borrower.B_email | html %]" class="[% required.B_email | html %]" />
+                                                <div class="required_label [% required.B_email | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('contactnote') %]
                                             <li>
-                                                [% IF mandatory.defined('contactnote') %]
-                                                    <label for="borrower_contactnote" class="required">Contact note:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_contactnote">Contact note:</label>
-                                                [% END %]
+                                                <label for="borrower_contactnote" class="[% required.contactnote | html %]">Contact note:</label>
 
-                                                <textarea id="borrower_contactnote" name="borrower_contactnote" cols="30" rows="2">[% borrower.contactnote | html %]</textarea>
-                                                [% IF mandatory.defined('contactnote') %]<span class="required">Required</span>[% END %]
+                                                <textarea id="borrower_contactnote" name="borrower_contactnote" cols="30" rows="2" class="[% required.contactnote | html %]">[% borrower.contactnote | html %]</textarea>
+                                                <div class="required_label [% required.contactnote | html %]">Required</div>
                                             </li>
                                         [% END %]
 
@@ -778,118 +665,82 @@
                                     <ol>
                                         [% UNLESS hidden.defined('altcontactsurname') %]
                                             <li>
-                                                [% IF mandatory.defined('altcontactsurname') %]
-                                                    <label for="borrower_altcontactsurname" class="required">Surname:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_altcontactsurname">Surname:</label>
-                                                [% END %]
+                                                <label for="borrower_altcontactsurname" class="[% required.altcontactsurname | html %]">Surname:</label>
 
-                                                <input type="text" id="borrower_altcontactsurname" name="borrower_altcontactsurname" value="[% borrower.altcontactsurname | html %]" />
-                                                [% IF mandatory.defined('altcontactsurname') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_altcontactsurname" name="borrower_altcontactsurname" value="[% borrower.altcontactsurname | html %]" class="[% required.altcontactsurname | html %]" />
+                                                <div class="required_label [% required.altcontactsurname | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('altcontactfirstname') %]
                                             <li>
-                                                [% IF mandatory.defined('altcontactfirstname') %]
-                                                    <label for="borrower_altcontactfirstname" class="required">First name:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_altcontactfirstname">First name:</label>
-                                                [% END %]
+                                                <label for="borrower_altcontactfirstname" class="[% required.altcontactfirstname | html %]">First name:</label>
 
-                                                <input type="text" id="borrower_altcontactfirstname" name="borrower_altcontactfirstname" value="[% borrower.altcontactfirstname | html %]" />
-                                                [% IF mandatory.defined('altcontactfirstname') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_altcontactfirstname" name="borrower_altcontactfirstname" value="[% borrower.altcontactfirstname | html %]" class="[% required.altcontactfirstname | html %]" />
+                                                <div class="required_label [% required.altcontactfirstname | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('altcontactaddress1') %]
                                             <li>
-                                                [% IF mandatory.defined('altcontactaddress1') %]
-                                                    <label for="borrower_altcontactaddress1" class="required">Address:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_altcontactaddress1">Address:</label>
-                                                [% END %]
+                                                <label for="borrower_altcontactaddress1" class="[% required.altcontactaddress1 | html %]">Address:</label>
 
-                                                <input type="text" id="borrower_altcontactaddress1" name="borrower_altcontactaddress1" value="[% borrower.altcontactaddress1 | html %]" />
-                                                [% IF mandatory.defined('altcontactaddress1') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_altcontactaddress1" name="borrower_altcontactaddress1" value="[% borrower.altcontactaddress1 | html %]" class="[% required.altcontactaddress1 | html %]" />
+                                                <div class="required_label [% required.altcontactaddress1 | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('altcontactaddress2') %]
                                             <li>
-                                                [% IF mandatory.defined('altcontactaddress2') %]
-                                                    <label for="borrower_altcontactaddress2" class="required">Address 2:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_altcontactaddress2">Address 2:</label>
-                                                [% END %]
+                                                <label for="borrower_altcontactaddress2" class="[% required.altcontactaddress2 | html %]">Address 2:</label>
 
-                                                <input type="text" id="borrower_altcontactaddress2" name="borrower_altcontactaddress2" value="[% borrower.altcontactaddress2 | html %]" />
-                                                [% IF mandatory.defined('altcontactaddress2') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_altcontactaddress2" name="borrower_altcontactaddress2" value="[% borrower.altcontactaddress2 | html %]" class="[% required.altcontactaddress2 | html %]" />
+                                                <div class="required_label [% required.altcontactaddress2 | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('altcontactaddress3') %]
                                             <li>
-                                                [% IF mandatory.defined('altcontactaddress3') %]
-                                                    <label for="borrower_altcontactaddress3" class="required">City:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_altcontactaddress3">City:</label>
-                                                [% END %]
+                                                <label for="borrower_altcontactaddress3" class="[% required.altcontactaddress3 | html %]">City:</label>
 
-                                                <input type="text" id="borrower_altcontactaddress3" name="borrower_altcontactaddress3" value="[% borrower.altcontactaddress3 | html %]" />
-                                                [% IF mandatory.defined('altcontactaddress3') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_altcontactaddress3" name="borrower_altcontactaddress3" value="[% borrower.altcontactaddress3 | html %]" class="[% required.altcontactaddress3 | html %]" />
+                                                <div class="required_label [% required.altcontactaddress3 | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('altcontactstate') %]
                                             <li>
-                                                [% IF mandatory.defined('altcontactstate') %]
-                                                    <label for="borrower_altcontactstate" class="required">State:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_altcontactstate">State:</label>
-                                                [% END %]
+                                                <label for="borrower_altcontactstate" class="[% required.altcontactstate | html %]">State:</label>
 
-                                                <input type="text" id="borrower_altcontactstate" name="borrower_altcontactstate" value="[% borrower.altcontactstate | html %]" />
-                                                [% IF mandatory.defined('altcontactstate') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_altcontactstate" name="borrower_altcontactstate" value="[% borrower.altcontactstate | html %]" class="[% required.altcontactstate | html %]" />
+                                                <div class="required_label [% required.altcontactstate | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('altcontactzipcode') %]
                                             <li>
-                                                [% IF mandatory.defined('altcontactzipcode') %]
-                                                    <label for="borrower_altcontactzipcode" class="required">ZIP/Postal code:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_altcontactzipcode">ZIP/Postal code:</label>
-                                                [% END %]
+                                                <label for="borrower_altcontactzipcode" class="[% required.altcontactzipcode | html %]">ZIP/Postal code:</label>
 
-                                                <input type="text" id="borrower_altcontactzipcode" name="borrower_altcontactzipcode" value="[% borrower.altcontactzipcode | html %]" />
-                                                [% IF mandatory.defined('altcontactzipcode') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_altcontactzipcode" name="borrower_altcontactzipcode" value="[% borrower.altcontactzipcode | html %]" class="[% required.altcontactzipcode | html %]" />
+                                                <div class="required_label [% required.altcontactzipcode | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('altcontactcountry') %]
                                             <li>
-                                                [% IF mandatory.defined('altcontactcountry') %]
-                                                    <label for="borrower_altcontactcountry" class="required">Country:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_altcontactcountry">Country:</label>
-                                                [% END %]
+                                                <label for="borrower_altcontactcountry" class="[% required.altcontactcountry | html %]">Country:</label>
 
-                                                <input type="text" id="borrower_altcontactcountry" name="borrower_altcontactcountry" value="[% borrower.altcontactcountry | html %]" />
-                                                [% IF mandatory.defined('altcontactcountry') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_altcontactcountry" name="borrower_altcontactcountry" value="[% borrower.altcontactcountry | html %]" class="[% required.altcontactcountry | html %]" />
+                                                <div class="required_label [% required.altcontactcountry | html %]">Required</div>
                                             </li>
                                         [% END %]
 
                                         [% UNLESS hidden.defined('altcontactphone') %]
                                             <li>
-                                                [% IF mandatory.defined('altcontactphone') %]
-                                                    <label for="borrower_altcontactphone" class="required">Phone:</label>
-                                                [% ELSE %]
-                                                    <label for="borrower_altcontactphone">Phone:</label>
-                                                [% END %]
+                                                <label for="borrower_altcontactphone" class="[% required.altcontactphone | html %]">Phone:</label>
 
-                                                <input type="text" id="borrower_altcontactphone" name="borrower_altcontactphone" value="[% borrower.altcontactphone | html %]" />
-                                                [% IF mandatory.defined('altcontactphone') %]<span class="required">Required</span>[% END %]
+                                                <input type="text" id="borrower_altcontactphone" name="borrower_altcontactphone" value="[% borrower.altcontactphone | html %]" class="[% required.altcontactphone | html %]" />
+                                                <div class="required_label [% required.altcontactphone | html %]">Required</div>
                                             </li>
                                         [% END %]
                                     </ol>
@@ -918,27 +769,16 @@
                                         [% END %]
                                     </div>
 
-                                    [% IF mandatory.defined('password') %]
-                                        <ol>
-                                            <li><label for="borrower_password" class="required">Password</label>
-                                                <input type="password" name="borrower_password" id="password" />
-                                                <span class="required">Required</span>
-                                            </li>
-                                            <li><label for="borrower_password2" class="required">Confirm password</label>
-                                                <input type="password" name="borrower_password2" id="password2" />
-                                                <span class="required">Required</span>
-                                            </li>
-                                        </ol>
-                                    [% ELSE %]
-                                        <ol>
-                                            <li><label for="borrower_password">Password</label>
-                                                <input type="password" name="borrower_password" id="password" />
-                                            </li>
-                                            <li><label for="borrower_password2">Confirm password</label>
-                                                <input type="password" name="borrower_password2" id="password2" />
-                                            </li>
-                                        </ol>
-                                    [% END %]
+                                    <ol>
+                                        <li><label for="borrower_password" class="[% required.password | html %]">Password</label>
+                                            <input type="password" name="borrower_password" id="password" class="[% required.password | html %]" />
+                                            <div class="required_label [% required.password | html %]">Required</div>
+                                        </li>
+                                        <li><label for="borrower_password2" class="[% required.password | html %]">Confirm password</label>
+                                            <input type="password" name="borrower_password2" id="password2" />
+                                            <div class="required_label [% required.password | html %]">Required</div>
+                                        </li>
+                                    </ol>
                                 </fieldset>
                             </div> <!-- /.col -->
                         </div> <!-- /.row -->
@@ -987,7 +827,7 @@
                                                                 <textarea rows="2" cols="30" id="[% form_id | html %]" name="patron_attribute_value">[% pa_value | html %]</textarea>
                                                             [% END %]
                                                             [% IF pa.type.mandatory %]
-                                                                <span class="required">Required</span>
+                                                                <div class="required">Required</div>
                                                             [% END %]
                                                             <a href="#" class="clear-attribute">Clear</a>
                                                             [% IF ( pa.type.repeatable ) %]
@@ -1017,7 +857,7 @@
                                     <legend>GDPR consent</legend>
                                     <ol>
                                     <li>
-                                        <label></label><span><input type="checkbox" name="borrower_gdpr_proc_consent" value="agreed"> I agree with your processing of my personal data as outlined in the <a target="_blank" href="[% Koha.Preference('PrivacyPolicyURL') | url %]">privacy policy</a>. <span class="required">Required</span></span>
+                                        <label></label><span><input type="checkbox" name="borrower_gdpr_proc_consent" value="agreed"> I agree with your processing of my personal data as outlined in the <a target="_blank" href="[% Koha.Preference('PrivacyPolicyURL') | url %]">privacy policy</a>. <div class="required">Required</div></span>
                                     </li>
                                     </ol>
                                 </fieldset>
@@ -1036,6 +876,7 @@
                                             <label for="captcha" class="required">Verification:</label>
 
                                             <input type="text" name="captcha" id="captcha" />
+                                            <div class="required_label required">Required</div>
                                             <input type="hidden" name="captcha_digest" value="[% captcha_digest | html %]" />
 
                                             <span class="hint">Please type the following characters into the preceding box: <strong>[% captcha | html %]</strong></span>
@@ -1075,6 +916,7 @@
 
 [% INCLUDE 'opac-bottom.inc' %]
 [% BLOCK jsinclude %]
+    [% INCLUDE 'validator-strings.inc' %]
     [% Asset.js("lib/jquery/plugins/jquery.validate.min.js") | $raw %]
     [% INCLUDE 'calendar.inc' %]
 
@@ -1105,16 +947,10 @@
                         email: true
                     },
                     borrower_password: {
-                        [% IF mandatory.defined('password') %]
-                        required: true,
-                        [% END %]
                         password_strong: true,
                         password_no_spaces: true
                     },
                     borrower_password2: {
-                        [% IF mandatory.defined('password') %]
-                        required: true,
-                        [% END %]
                         password_match: true
                     },
                     captcha: {
@@ -1129,18 +965,13 @@
                         form.beenSubmitted = true;
                         form.submit();
                     }
-                },
-                errorPlacement: function(error, element) {
-                    offset = element.offset();
-                    error.insertAfter(element)
-                    error.addClass('error');  // add a class to the wrapper
-                    error.css('position', 'absolute');
-                    error.css('left', offset.left + element.outerWidth() + 10);
-                    error.css('top', offset.top);
-                    error.css('width', 'auto');
                 }
             });
 
+            $("input.required,select.required,textarea.required").rules("add", {
+                required: true
+            });
+
             [% IF patron.guarantor_relationships && !Koha.Preference('OPACPrivacy') %]
 
                 [% IF Koha.Preference('AllowPatronToSetCheckoutsVisibilityForGuarantor') %]
@@ -1254,7 +1085,7 @@
             $('select#borrower_categorycode').change(setPwdMessage);
         });
     [% END %]
-    //]]>
+
     </script>
     [% PROCESS 'password_check.inc' new_password => 'borrower_password', category_selector => '#borrower_categorycode', RequireStrongPassword => patron ? patron.category.effective_require_strong_password : defaultCategory.effective_require_strong_password, minPasswordLength => patron ? patron.category.effective_min_password_length : defaultCategory.effective_min_password_length %]
 
-- 
2.11.0