Bug 30000: Replace the use of jQueryUI tabs on the search engine configuration page

This patch replaces jQueryUI tabs on the search engine configuration
page, replacing them with Bootstrap tabs.

To test, apply the patch and go to Administration -> Search engine
configuration.

- The "Search fields" tab should be selected by default, and the table
  should be initialized as a DataTable with sorting and filtering.
- When you switch to the "Bibliographic records" and "Authorities" tabs
  the tables on those tabs should also be initialized, each with
  filtering and drag-and-drop row re-ordering.
- All tables should continue to work correctly after switching back and
  forth between tabs.

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Fridolin Somers <fridolin.somers@biblibre.com>
This commit is contained in:
Owen Leonard 2022-03-18 14:37:54 +00:00 committed by Fridolin Somers
parent 772ffc726d
commit ab495c64bd
2 changed files with 340 additions and 331 deletions

View File

@ -115,353 +115,363 @@ a.add, a.delete {
</div>
<form id="es_mappings" method="post">
<div id="tabs" class="toptabs ui-tabs" style="clear:both">
<ul>
<li><a href="#search_fields">Search fields</a></li>
<div id="tabs" class="toptabs">
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
<a href="#search_fields" data-tab="search_fields" aria-controls="search_fields" role="tab" data-toggle="tab" >Search fields</a>
</li>
[% FOREACH index IN indexes %]
[% SWITCH index.index_name %]
[% CASE 'biblios' %]<li><a href="#mapping_biblios">Bibliographic records</a></li>
[% CASE 'authorities' %]<li><a href="#mapping_authorities">Authorities</a></li>
[% CASE 'biblios' %]
<li role="presentation">
<a href="#mapping_biblios" data-tab="mapping_biblios" aria-controls="mapping_biblios" role="tab" data-toggle="tab">Bibliographic records</a>
</li>
[% CASE 'authorities' %]
<li role="presentation">
<a href="#mapping_authorities" data-tab="mapping_authorities" aria-controls="mapping_authorities" role="tab" data-toggle="tab">Authorities</a>
</li>
[% END %]
[% END %]
</ul>
<div id="search_fields" class="ui-tabs-panel">
<table class="search_fields" id="search_fields_table">
<thead>
<tr>
<th>Name</th>
<th>Aliases</th>
<th>Label</th>
<th>Type</th>
<th>Weight</th>
<th colspan="2">Searchable</th>
</tr>
<tr>
<th colspan="5" class="NoSort">&nbsp;</th>
<th class="NoSort">Staff interface</th>
<th class="NoSort">OPAC</th>
</tr>
</thead>
<tbody>
[% FOREACH search_field IN all_search_fields %]
<tr>
<td data-order="[% search_field.name | html %]">
[% IF search_field.mandatory %]
<input type="text" name="search_field_name" value="[% search_field.name | html %]" readonly />
[% ELSE %]
<input type="text" name="search_field_name" value="[% search_field.name | html %]" />
[% END %]
</td>
<td>
[% search_field.aliases.join(', ') | html %]
</td>
<td data-order="[% search_field.label | html %]">
[% IF search_field.mandatory %]
<input type="text" name="search_field_label" value="[% search_field.label | html %]" readonly />
[% ELSE %]
<input type="text" name="search_field_label" value="[% search_field.label | html %]" />
[% END %]
</td>
<td data-order="[% search_field.type | html %]">
[% IF search_field.mandatory %]
<input type="hidden" name="search_field_type" value="[% search_field.type | html %]" />
<select name="search_field_type" disabled>
[% ELSE %]
<select name="search_field_type">
[% END %]
<option value=""></option>
[% IF search_field.type == "string" %]
<option value="string" selected="selected">String</option>
[% ELSE %]
<option value="string">String</option>
[% END %]
[% IF search_field.type == "date" %]
<option value="date" selected="selected">Date</option>
[% ELSE %]
<option value="date">Date</option>
[% END %]
[% IF search_field.type == "year" %]
<option value="year" selected="selected">Year</option>
[% ELSE %]
<option value="year">Year</option>
[% END %]
[% IF search_field.type == "number" %]
<option value="number" selected="selected">Number</option>
[% ELSE %]
<option value="number">Number</option>
[% END %]
[% IF search_field.type == "boolean" %]
<option value="boolean" selected="selected">Boolean</option>
[% ELSE %]
<option value="boolean">Boolean</option>
[% END %]
[% IF search_field.type == "sum" %]
<option value="sum" selected="selected">Sum</option>
[% ELSE %]
<option value="sum">Sum</option>
[% END %]
[% IF search_field.type == "isbn" %]
<option value="isbn" selected="selected">ISBN</option>
[% ELSE %]
<option value="isbn">ISBN</option>
[% END %]
[% IF search_field.type == "stdno" %]
<option value="stdno" selected="selected">Std. Number</option>
[% ELSE %]
<option value="stdno">Std. Number</option>
[% END %]
</select>
</td>
<td data-order="[% search_field.weight | html %]">
[% IF search_field.mapped_biblios %]
<input type="text" inputmode="decimal" pattern="[0-9\.]*" name="search_field_weight" value="[% search_field.weight | html %]" />
[% ELSE %]
<input type="text" name="search_field_weight" value="">
[% END %]
</td>
<td>
<select name="search_field_staff_client">
[% IF search_field.staff_client %]
<option value="1" selected="selected">Yes</option>
<option value="0">No</option>
[% ELSE %]
<option value="1">Yes</option>
<option value="0" selected="selected">No</option>
[% END %]
</select>
</td>
<td>
<select name="search_field_opac">
[% IF search_field.opac %]
<option value="1" selected="selected">Yes</option>
<option value="0">No</option>
[% ELSE %]
<option value="1">Yes</option>
<option value="0" selected="selected">No</option>
[% END %]
</select>
</td>
</tr>
[% END %]
</tbody>
</table>
</div>
[% FOREACH index IN indexes %]
<div id="mapping_[% index.index_name | html %]" class="ui-tabs-panel">
<table class="mappings" data-index_name="[% index.index_name | html %]" data-ordering="false" id="mapping_[% index.index_name | html %]_table">
<thead>
<tr class="nodrag nodrop">
<th>Search field</th>
<th>Sortable</th>
<th>Facetable</th>
<th>Suggestible</th>
<th>Searchable</th>
<th>Mapping</th>
<th>&nbsp;</th>
<div class="tab-content">
<div id="search_fields" role="tabpanel" class="tab-pane active">
<table class="search_fields" id="search_fields_table">
<thead>
<tr>
<th>Name</th>
<th>Aliases</th>
<th>Label</th>
<th>Type</th>
<th>Weight</th>
<th colspan="2">Searchable</th>
</tr>
</thead>
<tbody>
[% FOREACH mapping IN index.mappings %]
[% IF mapping.search_field_mandatory && mapping.search_field_label != loop.next.search_field_label && mapping.search_field_label != loop.prev.search_field_label %]
<tr>
<td>
<input type="hidden" name="mapping_index_name" value="[% index.index_name | html %]" />
<input type="hidden" name="mapping_search_field_name" value="[% mapping.search_field_name | html %]">
[% mapping.search_field_label | html %]
</td>
<td>
[% IF mapping.sort == 0 %]
<input type="hidden" name="mapping_sort" value="0" readonly />No
[% ELSE %]
<input type="hidden" name="mapping_sort" value="1" readonly />Yes
[% END %]
</td>
<td>
<input type="hidden" name="mapping_facet" value="[% mapping.facet | html %]" readonly />[% IF mapping.facet == 1 %]Yes[% ELSE %]No[% END %]
</td>
<td>
<input type="hidden" name="mapping_suggestible" value="[% mapping.suggestible | html %]" readonly />[% IF mapping.suggestible == 1 %]Yes[% ELSE %]No[% END %]
</td>
<td>
<input type="hidden" name="mapping_search" value="[% mapping.search | html %]" readonly />[% IF mapping.search == 1 %]Yes[% ELSE %]No[% END %]
</td>
<td>
<input name="mapping_marc_field" type="text" value="[% mapping.marc_field | html %]" />
</td>
<td>&nbsp;</td>
</tr>
[% ELSE %]
<tr>
<td>
<input type="hidden" name="mapping_index_name" value="[% index.index_name | html %]" />
<input type="hidden" name="mapping_search_field_name" value="[% mapping.search_field_name | html %]">
[% mapping.search_field_label | html %]
</td>
<td>
<select name="mapping_sort">
[% IF mapping.sort == 0 %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
<tr>
<th colspan="5" class="NoSort">&nbsp;</th>
<th class="NoSort">Staff interface</th>
<th class="NoSort">OPAC</th>
</tr>
</thead>
<tbody>
[% FOREACH search_field IN all_search_fields %]
<tr>
<td data-order="[% search_field.name | html %]">
[% IF search_field.mandatory %]
<input type="text" name="search_field_name" value="[% search_field.name | html %]" readonly />
[% ELSE %]
<input type="text" name="search_field_name" value="[% search_field.name | html %]" />
[% END %]
</td>
<td>
[% search_field.aliases.join(', ') | html %]
</td>
<td data-order="[% search_field.label | html %]">
[% IF search_field.mandatory %]
<input type="text" name="search_field_label" value="[% search_field.label | html %]" readonly />
[% ELSE %]
<input type="text" name="search_field_label" value="[% search_field.label | html %]" />
[% END %]
</td>
<td data-order="[% search_field.type | html %]">
[% IF search_field.mandatory %]
<input type="hidden" name="search_field_type" value="[% search_field.type | html %]" />
<select name="search_field_type" disabled>
[% ELSE %]
<select name="search_field_type">
[% END %]
<option value=""></option>
[% IF search_field.type == "string" %]
<option value="string" selected="selected">String</option>
[% ELSE %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
<option value="string">String</option>
[% END %]
[% IF search_field.type == "date" %]
<option value="date" selected="selected">Date</option>
[% ELSE %]
<option value="date">Date</option>
[% END %]
[% IF search_field.type == "year" %]
<option value="year" selected="selected">Year</option>
[% ELSE %]
<option value="year">Year</option>
[% END %]
[% IF search_field.type == "number" %]
<option value="number" selected="selected">Number</option>
[% ELSE %]
<option value="number">Number</option>
[% END %]
[% IF search_field.type == "boolean" %]
<option value="boolean" selected="selected">Boolean</option>
[% ELSE %]
<option value="boolean">Boolean</option>
[% END %]
[% IF search_field.type == "sum" %]
<option value="sum" selected="selected">Sum</option>
[% ELSE %]
<option value="sum">Sum</option>
[% END %]
[% IF search_field.type == "isbn" %]
<option value="isbn" selected="selected">ISBN</option>
[% ELSE %]
<option value="isbn">ISBN</option>
[% END %]
[% IF search_field.type == "stdno" %]
<option value="stdno" selected="selected">Std. Number</option>
[% ELSE %]
<option value="stdno">Std. Number</option>
[% END %]
</select>
</td>
<td data-order="[% search_field.weight | html %]">
[% IF search_field.mapped_biblios %]
<input type="text" inputmode="decimal" pattern="[0-9\.]*" name="search_field_weight" value="[% search_field.weight | html %]" />
[% ELSE %]
<input type="text" name="search_field_weight" value="">
[% END %]
</select>
</td>
<td>
[% IF mapping.is_facetable %]
<select name="mapping_facet">
[% IF mapping.facet %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% ELSE %]
<td>
<select name="search_field_staff_client">
[% IF search_field.staff_client %]
<option value="1" selected="selected">Yes</option>
<option value="0">No</option>
[% ELSE %]
<option value="1">Yes</option>
<option value="0" selected="selected">No</option>
[% END %]
</select>
</td>
<td>
<select name="search_field_opac">
[% IF search_field.opac %]
<option value="1" selected="selected">Yes</option>
<option value="0">No</option>
[% ELSE %]
<option value="1">Yes</option>
<option value="0" selected="selected">No</option>
[% END %]
</select>
</td>
</tr>
[% END %]
</tbody>
</table>
</div>
[% FOREACH index IN indexes %]
<div id="mapping_[% index.index_name | html %]" role="tabpanel" class="tab-pane">
<table class="mappings" data-index_name="[% index.index_name | html %]" data-ordering="false" id="mapping_[% index.index_name | html %]_table">
<thead>
<tr class="nodrag nodrop">
<th>Search field</th>
<th>Sortable</th>
<th>Facetable</th>
<th>Suggestible</th>
<th>Searchable</th>
<th>Mapping</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
[% FOREACH mapping IN index.mappings %]
[% IF mapping.search_field_mandatory && mapping.search_field_label != loop.next.search_field_label && mapping.search_field_label != loop.prev.search_field_label %]
<tr>
<td>
<input type="hidden" name="mapping_index_name" value="[% index.index_name | html %]" />
<input type="hidden" name="mapping_search_field_name" value="[% mapping.search_field_name | html %]">
[% mapping.search_field_label | html %]
</td>
<td>
[% IF mapping.sort == 0 %]
<input type="hidden" name="mapping_sort" value="0" readonly />No
[% ELSE %]
<input type="hidden" name="mapping_sort" value="1" readonly />Yes
[% END %]
</td>
<td>
<input type="hidden" name="mapping_facet" value="[% mapping.facet | html %]" readonly />[% IF mapping.facet == 1 %]Yes[% ELSE %]No[% END %]
</td>
<td>
<input type="hidden" name="mapping_suggestible" value="[% mapping.suggestible | html %]" readonly />[% IF mapping.suggestible == 1 %]Yes[% ELSE %]No[% END %]
</td>
<td>
<input type="hidden" name="mapping_search" value="[% mapping.search | html %]" readonly />[% IF mapping.search == 1 %]Yes[% ELSE %]No[% END %]
</td>
<td>
<input name="mapping_marc_field" type="text" value="[% mapping.marc_field | html %]" />
</td>
<td>&nbsp;</td>
</tr>
[% ELSE %]
<tr>
<td>
<input type="hidden" name="mapping_index_name" value="[% index.index_name | html %]" />
<input type="hidden" name="mapping_search_field_name" value="[% mapping.search_field_name | html %]">
[% mapping.search_field_label | html %]
</td>
<td>
<select name="mapping_sort">
[% IF mapping.sort == 0 %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
[% END %]
[% ELSE %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% END %]
</select>
[% ELSE %]
<input type="hidden" name="mapping_facet" value="0" />
No
[% END %]
</td>
<td>
<select name="mapping_suggestible">
[% IF mapping.suggestible %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
</td>
<td>
[% IF mapping.is_facetable %]
<select name="mapping_facet">
[% IF mapping.facet %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
[% END %]
</select>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
<input type="hidden" name="mapping_facet" value="0" />
No
[% END %]
</select>
</td>
<td>
<select name="mapping_search">
[% IF mapping.search %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
</td>
<td>
<select name="mapping_suggestible">
[% IF mapping.suggestible %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
[% END %]
</select>
</td>
<td>
<select name="mapping_search">
[% IF mapping.search %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
[% END %]
</select>
</td>
<td>
<input name="mapping_marc_field" type="text" value="[% mapping.marc_field | html %]" />
</td>
[% IF mapping.search_field_mandatory %]
<td><a class="btn btn-default btn-xs delete mandatory" data-field_name="[% mapping.search_field_name | html %]" style="cursor: pointer;"><i class="fa fa-trash"></i> Delete</a></td>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
<td><a class="btn btn-default btn-xs delete" style="cursor: pointer;"><i class="fa fa-trash"></i> Delete</a></td>
[% END %]
</select>
</td>
<td>
<input name="mapping_marc_field" type="text" value="[% mapping.marc_field | html %]" />
</td>
[% IF mapping.search_field_mandatory %]
<td><a class="btn btn-default btn-xs delete mandatory" data-field_name="[% mapping.search_field_name | html %]" style="cursor: pointer;"><i class="fa fa-trash"></i> Delete</a></td>
[% ELSE %]
<td><a class="btn btn-default btn-xs delete" style="cursor: pointer;"><i class="fa fa-trash"></i> Delete</a></td>
</tr>
[% END %]
</tr>
[% END %]
[% END %]
</tbody>
<tfoot>
<tr class="nodrag nodrop">
<td>
<input data-id="mapping_index_name" type="hidden" value="[% index.index_name | html %]" />
<select data-id="mapping_search_field_name">
[% FOREACH f IN all_search_fields %]
<option value="[% f.name | html %]">[% f.name | html %]</option>
[% END %]
</select>
</td>
<td>
<select data-id="mapping_sort">
<option value="undef">Undef</option>
<option value="0">0</option>
<option value="1">1</option>
</select>
</td>
<td>
<select data-id="mapping_facet">
[% IF mapping.facet %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
[% END %]
</select>
</td>
<td>
<select data-id="mapping_suggestible">
[% IF mapping.suggestible %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
[% END %]
</select>
</td>
<td>
<select data-id="mapping_search">
[% IF mapping.search %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
[% END %]
</select>
</td>
<td><input data-id="mapping_marc_field" type="text" /></td>
<td><a class="btn btn-default btn-xs add"><i class="fa fa-plus"></i> Add</a></td>
</tr>
</tfoot>
</table>
</tbody>
<tfoot>
<tr class="nodrag nodrop">
<td>
<input data-id="mapping_index_name" type="hidden" value="[% index.index_name | html %]" />
<select data-id="mapping_search_field_name">
[% FOREACH f IN all_search_fields %]
<option value="[% f.name | html %]">[% f.name | html %]</option>
[% END %]
</select>
</td>
<td>
<select data-id="mapping_sort">
<option value="undef">Undef</option>
<option value="0">0</option>
<option value="1">1</option>
</select>
</td>
<td>
<select data-id="mapping_facet">
[% IF mapping.facet %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
[% END %]
</select>
</td>
<td>
<select data-id="mapping_suggestible">
[% IF mapping.suggestible %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
[% END %]
</select>
</td>
<td>
<select data-id="mapping_search">
[% IF mapping.search %]
<option value="0">No</option>
<option value="1" selected="selected">Yes</option>
[% ELSE %]
<option value="0" selected="selected">No</option>
<option value="1">Yes</option>
[% END %]
</select>
</td>
<td><input data-id="mapping_marc_field" type="text" /></td>
<td><a class="btn btn-default btn-xs add"><i class="fa fa-plus"></i> Add</a></td>
</tr>
</tfoot>
</table>
[% IF index.index_name == 'biblios' %]
<h3>Facet order</h3>
<div id="facet_[% index.index_name | html %]" class="ui-tabs-panel">
<table>
<thead>
<tr>
<th>Search field</th>
<th>Label</th>
<th>Display</th>
</tr>
</thead>
<tbody>
[% FOREACH f IN facetable_fields %]
[% IF index.index_name == 'biblios' %]
<h3>Facet order</h3>
<div id="facet_[% index.index_name | html %]" class="ui-tabs-panel">
<table>
<thead>
<tr>
<td>
[% f.name | html %]
</td>
<td>
[% SWITCH f.name %]
[% CASE 'author' %]Authors
[% CASE 'itype' %]Item types
[% CASE 'location' %]Locations
[% CASE 'su-geo' %]Places
[% CASE 'title-series' %]Series
[% CASE 'subject' %]Topics
[% CASE 'ccode' %]Collections
[% CASE 'holdingbranch' %]Holding libraries
[% CASE 'homebranch' %]Home libraries
[% CASE 'ln' %]Language
[% CASE %][% f | html %]
[% END %]
</td>
<td>
[% IF f.facet_order %]
<input type="checkbox" name="display_facet" value="[% f.name | html %]" checked="checked" />
[% ELSE %]
<input type="checkbox" name="display_facet" value="[% f.name | html %]" />
[% END %]
</td>
<th>Search field</th>
<th>Label</th>
<th>Display</th>
</tr>
[% END %]
</tbody>
</table>
</div>
[% END %]
</div>
[% END %]
</div>
</thead>
<tbody>
[% FOREACH f IN facetable_fields %]
<tr>
<td>
[% f.name | html %]
</td>
<td>
[% SWITCH f.name %]
[% CASE 'author' %]Authors
[% CASE 'itype' %]Item types
[% CASE 'location' %]Locations
[% CASE 'su-geo' %]Places
[% CASE 'title-series' %]Series
[% CASE 'subject' %]Topics
[% CASE 'ccode' %]Collections
[% CASE 'holdingbranch' %]Holding libraries
[% CASE 'homebranch' %]Home libraries
[% CASE 'ln' %]Language
[% CASE %][% f | html %]
[% END %]
</td>
<td>
[% IF f.facet_order %]
<input type="checkbox" name="display_facet" value="[% f.name | html %]" checked="checked" />
[% ELSE %]
<input type="checkbox" name="display_facet" value="[% f.name | html %]" />
[% END %]
</td>
</tr>
[% END %]
</tbody>
</table>
</div>
[% END %]
</div>
[% END %]
</div> <!-- /.tab-content -->
</div> <!-- /#tabs -->
<fieldset class="action">
<button class="btn btn-default" type="submit" name="op" value="edit"><i class="fa fa-hdd-o" aria-hidden="true"></i> Save</button>
<button class="btn btn-default" type="submit" name="op" value="reset_confirm"><i class="fa fa-refresh" aria-hidden="true"></i> Reset mappings</button>

View File

@ -21,7 +21,6 @@ function clone_line(line) {
}
function tableInit( oldtabid, newtabid ) {
if ( oldtabid ){
var oldTableId = $("#" + oldtabid + "_table");
oldTableId.DataTable().destroy();
@ -42,10 +41,10 @@ $(document).ready(function () {
tableInit( "", "search_fields");
$("#tabs").tabs({
activate: function( event, ui ){
tableInit( ui.oldPanel.attr('id'), ui.newPanel.attr('id') );
},
$("a[data-toggle='tab']").on("shown.bs.tab", function (e) {
var oldtabid = $(e.relatedTarget).data("tab");
var newtabid = $(e.target).data("tab");
tableInit( oldtabid, newtabid );
});
$('.delete').click(function () {