From aeeb64b0d3ba3c92f3d854a0e5b88a493257b373 Mon Sep 17 00:00:00 2001 From: Kyle M Hall <kyle@bywatersolutions.com> Date: Mon, 24 Feb 2020 12:06:17 -0500 Subject: [PATCH] Bug 24857: Add volume management to detail.pl Signed-off-by: Andrew Fuerste-Henry <andrew@bywatersolutions.com> Signed-off-by: Rebecca Coert <rcoert@arlingtonva.us> --- .../prog/en/modules/catalogue/detail.tt | 287 +++++++++++++++++++++ 1 file changed, 287 insertions(+) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt index efbf34fb5d..51d7102cbf 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt @@ -184,6 +184,7 @@ <a href="#holdings">Holdings ([% itemloop.size() || 0 | html %])</a> </li> [% END %] +[% IF Koha.Preference('EnableVolumes') %]<li><a href="#volumes">Volumes</a></li>[% END %] [% IF ( MARCNOTES || notes ) %]<li><a href="#description">Descriptions ([% ( MARCNOTES.size || 1 ) | html %])</a></li>[% END %] [% IF ( subscriptionsnumber ) %]<li><a href="#subscriptions">Subscriptions</a></li>[% END %] [% IF Koha.Preference('AcquisitionDetails') %]<li><a href="#acq_details">Acquisition details</a></li>[% END %] @@ -483,6 +484,23 @@ Note that permanent location is a code, and location may be an authval. </table> [% END %][%# end of block items_table %] +[% IF Koha.Preference('EnableVolumes') %] + <div id="volumes"> + <div class="volumes_table_table_controls"> + <a href="#" class="volume-create btn btn-default btn-xs"><i class="fa fa-plus"></i> Create new</a> + </div> + <table class="volumes-table" id="volumes-table"> + <thead> + <tr> + <td>Display Order</td> + <td>Description</td> + <td> </td> + </tr> + </thead> + </table> + </div> +[% END %] + <div id="holdings"> [% IF ( Koha.Preference('NovelistSelectStaffEnabled') && Koha.Preference('NovelistSelectStaffProfile') && Koha.Preference('NovelistSelectStaffView') == 'above' ) %] @@ -899,6 +917,88 @@ Note that permanent location is a code, and location may be an authval. [% END %] +<div class="modal fade" id="modal-volume-create" tabindex="-1" role="dialog" aria-labelledby="modal-volume-create-label"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button> + <h3 id="modal-volume-create-label"><i class="fa fa-plus"></i> Create a new volume</h3> + </div> + <form id="modal-volume-create-form" class="validated"> + <div class="modal-body"> + <fieldset> + <p> + <label for="volume_description" class="required">Name: </label> + <input name="description" id="modal-volume-create-form-description" type="text" size="30" required="required" class="required" /> + <span class="required">Required</span> + </p> + <p> + <label for="volume_display_order" class="required">Display order: </label> + <input name="display_order" id="modal-volume-create-form-display_order" value="0" type="number" size="5" required="required" class="required" /> + <span class="required">Required</span> + <br/> + <span class="hint">Numbers only, volumes will be displayed in counting order</span> + </p> + </fieldset> + </div> + <div class="modal-footer"> + <button id="modal-volume-create-submit" class="btn btn-default"><i class="fa fa-plus"></i> Submit</button> + <button class="btn btn-link" data-dismiss="modal" aria-hidden="true">Cancel</button> + </div> + </form> + </div> + </div> +</div> + +<div class="modal fade" id="modal-volume-edit" tabindex="-1" role="dialog" aria-labelledby="modal-volume-edit-label"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button> + <h3 id="modal-volume-edit-label"><i class='fa fa-edit'></i> Edit volume</h3> + </div> + <form id="modal-volume-edit-form" class="validated"> + <div class="modal-body"> + <fieldset> + <p> + <label for="volume_description" class="required">Name: </label> + <input name="description" id="modal-volume-edit-form-description" type="text" size="30" required="required" class="required" /> + <span class="required">Required</span> + </p> + <p> + <label for="volume_display_order" class="required">Sort order: </label> + <input name="display_order" id="modal-volume-edit-form-display_order" type="number" size="5" /> + <span class="hint">Numbers only, volumes will be displayed in counting order</span> + </p> + </fieldset> + </div> + <div class="modal-footer"> + <button id="modal-volume-edit-submit" class="btn btn-default"><i class='fa fa-edit'></i> Submit</button> + <button class="btn btn-link" data-dismiss="modal" aria-hidden="true">Cancel</button> + </div> + </form> + </div> + </div> +</div> + +<div class="modal fade" id="modal-volume-delete" tabindex="-1" role="dialog" aria-labelledby="modal-volume-create-label"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="closebtn" data-dismiss="modal" aria-hidden="true">×</button> + <h3 id="modal-volume-delete-label"><i class='fa fa-trash'></i> Delete volume</h3> + </div> + <div class="modal-body"> + Are you sure you want to delete this volume? + </div> + <div class="modal-footer"> + <button id="modal-volume-delete-submit" class="btn btn-danger"><i class='fa fa-trash'></i> Delete</button> + <button class="btn btn-link" data-dismiss="modal" aria-hidden="true">Cancel</button> + </div> + </div> + </div> +</div> + [% MACRO jsinclude BLOCK %] [% INCLUDE 'catalog-strings.inc' %] [% Asset.js("js/catalog.js") | $raw %] @@ -1162,6 +1262,193 @@ Note that permanent location is a code, and location may be an authval. })); [% END %] }); + + [% IF Koha.Preference('EnableVolumes') %] + // Load volumes table + var volumesTable = KohaTable("volumes-table", { + "bAutoWidth": false, + 'sDom': '<"top pager"ilp>t<"bottom pager"ip>r', + "aoColumns": [ + { + "mDataProp": function( oObj ) { + return oObj.display_order; + }, + }, + { + "mDataProp": function( oObj ) { + return oObj.description; + }, + }, + { + "mDataProp": function( oObj ) { + return `<button class='volume-edit btn btn-default btn-xs' data-volume-id='${oObj.volume_id}'> + <i class='fa fa-edit'></i> ${_('Edit')} + </button>` + + ' ' + + `<button class='volume-delete btn btn-default btn-xs' data-volume-id='${oObj.volume_id}'> + <i class='fa fa-trash'></i> ${('Delete')} + </button>`; + }, + }, + ], + "bPaginate": false, + "bProcessing": true, + "bServerSide": false, + "sAjaxSource": `/api/v1/biblios/${biblionumber}/volumes`, + "sAjaxDataProp": "", + "fnServerData": function ( sSource, aoData, fnCallback ) { + $.getJSON( sSource, aoData, function (json) { + fnCallback(json) + } ); + }, + }); + + // Create new volumes + $('.volume-create').on('click', function(){ + $('#modal-volume-create-form-description').val(""); + $('#modal-volume-create-submit').removeAttr('disabled'); + $('#modal-volume-create').modal('show'); + }); + + $("#modal-volume-create-form").validate({ + submitHandler: function(form) { + $.ajax({ + url: `/api/v1/biblios/${biblionumber}/volumes`, + headers: { "x-koha-embed": "items" }, + success: function(volumes){ + $('#modal-volume-create-submit').attr('disabled', 'disabled'); + + var settings = { + "url": `/api/v1/biblios/${biblionumber}/volumes`, + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "data": JSON.stringify( + { + "description": $("#modal-volume-create-form-description").val(), + "display_order": $("#modal-volume-create-form-display_order").val(), + } + ), + }; + + $.ajax(settings) + .done(function (response) { + $('#volume-add-form-select').append($('<option>', { + value: response.volume_id, + text: response.description + })); + + $('#modal-volume-create').modal('hide'); + if ( volumes.length == 0 ) { + // This bib has no previous volumes, reload the page + window.location.replace(`/cgi-bin/koha/catalogue/detail.pl?biblionumber=${biblionumber}`); + } else { + // Has other volumes, just reload the table + volumesTable.api().ajax.reload(); + } + }) + .fail(function(err) { + var message = err.responseJSON.error; + alert(message); + }); + } + }); + } + }); + + $('#modal-volume-create').on('shown.bs.modal', function () { + $('#modal-volume-create-form-description').focus(); + }) + + // Edit existing volumes + $('body').on( 'click', '.volume-edit', function(){ + const volume_id = $(this).data('volume-id'); + const url = `/api/v1/biblios/${biblionumber}/volumes/${volume_id}`; + $.get( url, function( data ) { + $('#modal-volume-edit-form-description').val( data.description ); + $('#modal-volume-edit-form-display_order').val( data.display_order ); + $('#modal-volume-edit-submit').data('volume-id', volume_id ); + $('#modal-volume-edit-submit').removeAttr('disabled'); + $('#modal-volume-edit').modal('show'); + }); + }); + + $("#modal-volume-edit-form").validate({ + submitHandler: function(form) { + $('#modal-volume-edit-submit').attr('disabled', 'disabled'); + + const volume_id = $('#modal-volume-edit-submit').data('volume-id'); + const url = `/api/v1/biblios/${biblionumber}/volumes/${volume_id}`; + + var settings = { + "url": url, + "method": "PUT", + "headers": { + "Content-Type": "application/json" + }, + "data": JSON.stringify( + { + "description": $("#modal-volume-edit-form-description").val(), + "display_order": $("#modal-volume-edit-form-display_order").val(), + } + ), + }; + + $.ajax(settings) + .done(function (response) { + $('#modal-volume-edit').modal('hide'); + volumesTable.api().ajax.reload(); + }) + .fail(function(err) { + var message = err.responseJSON.error; + alert(message); + }); + } + }); + + $('#modal-volume-edit').on('shown.bs.modal', function () { + $('#modal-volume-edit-form-description').focus(); + }) + + // Delete existing volumes + $('body').on( 'click', '.volume-delete', function(){ + const volume_id = $(this).data('volume-id'); + $('#modal-volume-delete-submit').data('volume-id', volume_id ); + $('#modal-volume-delete-submit').removeAttr('disabled'); + $('#modal-volume-delete').modal('show'); + }); + $("#modal-volume-delete-submit").on('click', function(){ + $('#modal-volume-delete-submit').attr('disabled', 'disabled'); + const volume_id = $("#modal-volume-delete-submit").data('volume-id'); + + $.ajax({ + url: `/api/v1/biblios/${biblionumber}/volumes/${volume_id}`, + headers: { "x-koha-embed": "items" }, + success: function(volume_data){ + $.ajax({ + "url": `/api/v1/biblios/${biblionumber}/volumes/${volume_id}`, + "method": "DELETE", + }) + .done(function (response) { + $('#modal-volume-delete').modal('hide'); + $(`#volume-add-form-select option[value='${volume_id}']`).remove(); + if ( volume_data.items === null ) { + // No items for this volume, we can just refresh the table + volumesTable.api().ajax.reload(); + } else { + // This volume had items attached to it, we need to reload the page + window.location.replace(`/cgi-bin/koha/catalogue/detail.pl?biblionumber=${biblionumber}`); + } + }) + .fail(function(err) { + var message = err.responseJSON.error; + alert(message); + }); + } + }); + }); + [% END %] </script> [% END %] [% INCLUDE 'intranet-bottom.inc' %] -- 2.11.0