Bug 22844: Simplify the process of selecting database columns for system preferences
authorOwen Leonard <oleonard@myacpl.org>
Fri, 3 May 2019 13:56:02 +0000 (13:56 +0000)
committerJonathan Druart <jonathan.druart@bugs.koha-community.org>
Mon, 20 Jul 2020 14:08:22 +0000 (16:08 +0200)
This patch introduces a new way for users to select database columns for
system preferences like BorrowerMandatoryField, which currently
require hand-typing of database names.

This new system uses a JSON file containing label:column pairs for
database columns which are relevant to preferences which reference
borrower table columns. My intention was to have user-friendly values as
the labels, but embedding English strings in JSON would make them
untranslatable.

The following preferences are affected:

 - BorrowerMandatoryField
 - BorrowerUnwantedField
 - PatronSelfModificationBorrowerUnwantedField
 - PatronSelfRegistrationBorrowerMandatoryField
 - PatronSelfRegistrationBorrowerUnwantedField

== Test plan ==
 - apply the patches
 - regenerate the staff client CSS (yarn build)
 - updatedatabase
 - dbic
 - flush_memcached
 - restart_all to make sure the updated .pref file is used

 - Go to Administration -> System preferences, and search for
   "PatronSelf"
 - The input fields for PatronSelfModificationBorrowerUnwantedField,
   PatronSelfRegistrationBorrowerMandatoryField, and
   PatronSelfRegistrationBorrowerUnwantedField should appear as "locked"
   (read-only) inputs.
 - Clicking the input field should trigger a modal window with
   checkboxes for each available column from the borrowers table.
 - Test that the "select all" and "clear all" links work correctly.
 - Test that the "cancel" link closes the modal without saving your
   selections.
 - Test that the "Save" button closes the modal, copies your selections
   to the form field, and triggers the preference-saving function (this
   eliminates the need to click a save button again after closing the
   modal).
   - Test this process by making modifications to all three different
     preferences, confirming that the right data is preselected each
     time the modal is shown and the right data is saved to the right
     field each time.

Signed-off-by: Hayley Mapley <hayleymapley@catalyst.net.nz>

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>

Signed-off-by: David Nind <david@davidnind.com>

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>

Signed-off-by: Victor Grousset/tuxayo <victor@tuxayo.net>

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

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>

admin/preferences.pl
koha-tmpl/intranet-tmpl/prog/css/preferences.css
koha-tmpl/intranet-tmpl/prog/css/src/staff-global.scss
koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences.tt
koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/borrowers.json [new file with mode: 0644]
koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref
koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref
koha-tmpl/intranet-tmpl/prog/js/pages/preferences.js

index 3b1676e..c5fd6eb 100755 (executable)
@@ -64,6 +64,12 @@ sub _get_chunk {
     if( $options{'syntax'} ){
         $chunk->{'syntax'} = $options{'syntax'};
     }
+
+    if( $options{'type'} && $options{'type'} eq 'modalselect' ){
+        $chunk->{'source'} = $options{'source'};
+        $chunk->{'type'} = 'modalselect';
+    }
+
     if ( $options{'class'} && $options{'class'} eq 'password' ) {
         $chunk->{'input_type'} = 'password';
     } elsif ( $options{'class'} && $options{'class'} eq 'date' ) {
index 1855af1..2745ded 100644 (file)
@@ -1,4 +1,8 @@
-.preference-url, .preference-multi, .preference-long, .preference-file {
+.preference-url,
+.preference-multi,
+.preference-long,
+.preference-file,
+.preference-modalselect {
     width: 20em;
 }
 
     width: 5em;
 }
 
+input[type="text"].modalselect {
+    cursor: pointer;
+}
+
+input[type="text"].modalselect:hover {
+    background-color: #FFC;
+}
+
 textarea.preference {
     width: 35em;
        height: 20em;
@@ -152,6 +164,17 @@ span.overridden {
     resize:  vertical;
 }
 
+#prefModal label {
+    display: block;
+    font-weight: bold;
+    line-height: 1.5em;
+}
+
+.dbcolumn {
+    font-weight: normal;
+    font-family: monospace;
+    color: #666;
+}
 #menu ul li.active a.pref_sublink {
     background: #FFF none;
     border: 0;
index b55b97e..2f65e0f 100644 (file)
@@ -4051,6 +4051,11 @@ input.renew {
     margin:  .5em 0;
 }
 
+.columns-2 {
+    columns: 2 auto;
+    column-gap: 2.5em;
+}
+
 .columns-3 {
     columns: 3 auto;
     column-gap: 2.5em;
index ccdb621..4ec818f 100644 (file)
                         </option>
                         [% END %]
                     </select>
+                    [% ELSIF ( CHUNK.type_modalselect ) %]
+                        <input type="text" name="pref_[% CHUNK.name | html %]" id="pref_[% CHUNK.name | html %]" class="modalselect preference preference-[% CHUNK.type | html %]" data-source="[% CHUNK.source | html %]" readonly="readonly" value="[% CHUNK.value | html %]"/>
                     [% ELSIF ( CHUNK.type_multiple ) %]
                     <select name="pref_[% CHUNK.name | html %]" id="pref_[% CHUNK.name | html %]" class="preference preference-[% CHUNK.class or "choice" | html %]" multiple="multiple">
                         [% FOREACH CHOICE IN CHUNK.CHOICES %][% IF ( CHOICE.selected ) %]<option value="[% CHOICE.value | html %]" selected="selected">[% ELSE %]<option value="[% CHOICE.value | html %]">[% END %][% CHOICE.text | html %]</option>[% END %]
         </div> <!-- /.col-sm-2.col-sm-pull-10 -->
      </div> <!-- /.row -->
 
+<!-- Modal -->
+<div class="modal" id="prefModal" tabindex="-1" role="dialog" aria-labelledby="prefModalLabel">
+    <div class="modal-dialog modal-wide" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <button type="button" class="closebtn" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                <h4 class="modal-title" id="prefModalLabel">Modal title</h4>
+            </div>
+            <div class="modal-body">
+                <p>
+                    <a href="#" id="select_all"><i class="fa fa-check"></i> Select all</a>
+                    |
+                    <a href="#" id="clear_all"><i class="fa fa-remove"></i> Clear all</a>
+                </p>
+                <form action="#" id="prefModalForm">
+                </form>
+            </div>
+            <div class="modal-footer">
+                <button id="saveModalPrefs" data-target="" type="button" class="btn btn-default">Save</button>
+                <button type="button" class="btn btn-link cancel" data-dismiss="modal">Cancel</button>
+            </div>
+        </div>
+    </div>
+</div>
+
 [% MACRO jsinclude BLOCK %]
     [% INCLUDE 'datatables.inc' %]
     [% Asset.js("lib/hc-sticky.js") | $raw %]
 
     <script>
         var Sticky;
+        var themelang = "[% themelang | html %]";
         $(document).ready(function(){
             [% UNLESS ( searchfield ) %]
                 Sticky = $("#toolbar");
                 e.preventDefault();
                 window.location.reload(true);
             });
-
         });
         // This is here because of its dependence on template variables, everything else should go in js/pages/preferences.js - jpw
         var to_highlight = "[% To.json( searchfield ) | $raw %]";
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/borrowers.json b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/borrowers.json
new file mode 100644 (file)
index 0000000..fc1482f
--- /dev/null
@@ -0,0 +1,53 @@
+{
+    "cardnumber": "cardnumber",
+    "surname": "surname",
+    "firstname": "firstname",
+    "title": "title",
+    "othernames": "othernames",
+    "initials": "initials",
+    "streetnumber": "streetnumber",
+    "streettype": "streettype",
+    "address": "address",
+    "address2": "address2",
+    "city": "city",
+    "state": "state",
+    "zipcode": "zipcode",
+    "country": "country",
+    "email": "email",
+    "phone": "phone",
+    "mobile": "mobile",
+    "fax": "fax",
+    "emailpro": "emailpro",
+    "phonepro": "phonepro",
+    "B_streetnumber": "B_streetnumber",
+    "B_streettype": "B_streettype",
+    "B_address": "B_address",
+    "B_address2": "B_address2",
+    "B_city": "B_city",
+    "B_state": "B_state",
+    "B_zipcode": "B_zipcode",
+    "B_country": "B_country",
+    "B_email": "B_email",
+    "B_phone": "B_phone",
+    "dateofbirth": "dateofbirth",
+    "branchcode": "branchcode",
+    "categorycode": "categorycode",
+    "contactname": "contactname",
+    "contactfirstname": "contactfirstname",
+    "borrowernotes": "borrowernotes",
+    "sex": "sex",
+    "password": "password",
+    "userid": "userid",
+    "opacnote": "opacnote",
+    "contactnote": "contactnote",
+    "altcontactfirstname": "altcontactfirstname",
+    "altcontactsurname": "altcontactsurname",
+    "altcontactaddress1": "altcontactaddress1",
+    "altcontactaddress2": "altcontactaddress2",
+    "altcontactaddress3": "altcontactaddress3",
+    "altcontactstate": "altcontactstate",
+    "altcontactzipcode": "altcontactzipcode",
+    "altcontactcountry": "altcontactcountry",
+    "altcontactphone": "altcontactphone",
+    "smsalertnumber": "smsalertnumber"
+}
\ No newline at end of file
index a0c0672..4b9ab45 100644 (file)
@@ -834,18 +834,18 @@ OPAC:
         -
             - "The following <a href='http://schema.koha-community.org/__VERSION__/tables/borrowers.html' target='blank'>database columns</a> must be filled in on the patron entry screen:"
             - pref: PatronSelfRegistrationBorrowerMandatoryField
-              class: multi
-            - (separate columns with |)
+              type: modalselect
+              source: borrowers
         -
             - "The following <a href='http://schema.koha-community.org/__VERSION__/tables/borrowers.html' target='blank'>database columns</a> will not appear on the patron self-registration screen:"
             - pref: PatronSelfRegistrationBorrowerUnwantedField
-              class: multi
-            - (separate columns with |)
+              type: modalselect
+              source: borrowers
         -
             - "The following <a href='http://schema.koha-community.org/__VERSION__/tables/borrowers.html' target='blank'>database columns</a> will not appear on the patron self-modification screen:"
             - pref: PatronSelfModificationBorrowerUnwantedField
-              class: multi
-            - (separate columns with |)
+              type: modalselect
+              source: borrowers
         -
             - "Display the following additional instructions for patrons who self register via the OPAC ( HTML is allowed ):"
             - pref: PatronSelfRegistrationAdditionalInstructions
index 0aba117..fadf251 100644 (file)
@@ -172,13 +172,14 @@ Patrons:
      -
          - "The following <a href='http://schema.koha-community.org/__VERSION__/tables/borrowers.html' target='blank'>database columns</a> must be filled in on the patron entry screen:"
          - pref: BorrowerMandatoryField
-           class: multi
-         - (separate columns with |)
+           type: modalselect
+           source: borrowers
          - "<strong>NOTE:</strong> If autoMemberNum is enabled, the system preference BorrowerMandatoryField must not contain the field cardnumber."
      -
          - "The following <a href='http://schema.koha-community.org/__VERSION__/tables/borrowers.html' target='blank'>database columns</a> will not appear on the patron entry screen:"
          - pref: BorrowerUnwantedField
-           class: multi
+           type: modalselect
+           source: borrowers
          - (separate columns with |)
      -
          - "Borrowers can have the following titles:"
index 2e83327..8bb977a 100644 (file)
@@ -1,4 +1,4 @@
-/* global KOHA MSG_MADE_CHANGES CodeMirror MSG_CLICK_TO_EXPAND MSG_CLICK_TO_COLLAPSE to_highlight search_jumped humanMsg MSG_NOTHING_TO_SAVE MSG_MODIFIED MSG_SAVING MSG_SAVED_PREFERENCE dataTablesDefaults */
+/* global KOHA MSG_MADE_CHANGES CodeMirror MSG_CLICK_TO_EXPAND MSG_CLICK_TO_COLLAPSE to_highlight search_jumped humanMsg MSG_NOTHING_TO_SAVE MSG_MODIFIED MSG_SAVING MSG_SAVED_PREFERENCE dataTablesDefaults themelang */
 // We can assume 'KOHA' exists, as we depend on KOHA.AJAX
 
 KOHA.Preferences = {
@@ -221,4 +221,63 @@ $( document ).ready( function () {
             email: true
         });
     });
+
+
+    $(".modalselect").on("click", function(){
+        var datasource = $(this).data("source");
+        var pref_name = this.id.replace(/pref_/, '');
+        var pref_value = this.value;
+        var prefs = pref_value.split("|");
+
+        $.getJSON( themelang + "/modules/admin/preferences/" + datasource + ".json", function( data ){
+            var items = [];
+            var checked = "";
+            $.each( data, function( key, val ){
+                if( prefs.indexOf( val ) >= 0 ){
+                    checked = ' checked="checked" ';
+                } else {
+                    checked = "";
+                }
+                items.push('<label><input class="dbcolumn_selection" type="checkbox" id="' + key + '"' + checked + ' name="pref" value="' + val + '" /> ' + key + '</label>');
+            });
+            $("<div/>", {
+                "class": "columns-2",
+                html: items.join("")
+            }).appendTo("#prefModalForm");
+        });
+        $("#saveModalPrefs").data("target", this.id );
+        $("#prefModalLabel").text( pref_name );
+        $("#prefModal").modal("show");
+    });
+
+    $("#saveModalPrefs").on("click", function(){
+        var formfieldid = $("#" + $(this).data("target") );
+        var prefs = [];
+        $("#prefModal input[type='checkbox']").each(function(){
+            if( $(this).prop("checked") ){
+                prefs.push( this.value );
+            }
+        });
+
+        formfieldid.val( prefs.join("|") )
+            .addClass("modified");
+        mark_modified.call( formfieldid );
+        KOHA.Preferences.Save( formfieldid.closest("form") );
+        $("#prefModal").modal("hide");
+    });
+
+    $("#prefModal").on("hide.bs.modal", function(){
+        $("#prefModalLabel,#prefModalForm").html("");
+        $("#saveModalPrefs").data("target", "" );
+    });
+
+    $("#select_all").on("click",function(e){
+        e.preventDefault();
+        $(".dbcolumn_selection").prop("checked", true);
+    });
+    $("#clear_all").on("click",function(e){
+        e.preventDefault();
+        $(".dbcolumn_selection").prop("checked", false);
+    });
+
 } );