Internal paged Search prepared

Search for table list is working
This commit is contained in:
Ozzieisaacs 2020-06-08 17:34:03 +02:00
parent 628658972c
commit 4038cb5b85
9 changed files with 82 additions and 48 deletions

View file

@ -631,21 +631,26 @@ class CalibreDB(threading.Thread):
.filter(and_(Books.authors.any(and_(*q)), func.lower(Books.title).ilike("%" + title + "%"))).first() .filter(and_(Books.authors.any(and_(*q)), func.lower(Books.title).ilike("%" + title + "%"))).first()
# read search results from calibre-database and return it (function is used for feed and simple search # read search results from calibre-database and return it (function is used for feed and simple search
def get_search_results(self, term, order=None, limit=-1): def get_search_results(self, term, offset=None, order=None, limit=None):
order = order or [Books.sort] order = order or [Books.sort]
if offset != None and limit != None:
offset = int(offset)
limit = offset + int(limit)
term.strip().lower() term.strip().lower()
self.session.connection().connection.connection.create_function("lower", 1, lcase) self.session.connection().connection.connection.create_function("lower", 1, lcase)
q = list() q = list()
authorterms = re.split("[, ]+", term) authorterms = re.split("[, ]+", term)
for authorterm in authorterms: for authorterm in authorterms:
q.append(Books.authors.any(func.lower(Authors.name).ilike("%" + authorterm + "%"))) q.append(Books.authors.any(func.lower(Authors.name).ilike("%" + authorterm + "%")))
return self.session.query(Books).filter(self.common_filters(True)).filter( result = self.session.query(Books).filter(self.common_filters(True)).filter(
or_(Books.tags.any(func.lower(Tags.name).ilike("%" + term + "%")), or_(Books.tags.any(func.lower(Tags.name).ilike("%" + term + "%")),
Books.series.any(func.lower(Series.name).ilike("%" + term + "%")), Books.series.any(func.lower(Series.name).ilike("%" + term + "%")),
Books.authors.any(and_(*q)), Books.authors.any(and_(*q)),
Books.publishers.any(func.lower(Publishers.name).ilike("%" + term + "%")), Books.publishers.any(func.lower(Publishers.name).ilike("%" + term + "%")),
func.lower(Books.title).ilike("%" + term + "%") func.lower(Books.title).ilike("%" + term + "%")
)).order_by(*order).limit(limit).all() )).order_by(*order).all()
result_count = len(result)
return result[offset:limit], result_count
# Creates for all stored languages a translated speaking name in the array for the UI # Creates for all stored languages a translated speaking name in the array for the UI
def speaking_language(self, languages=None): def speaking_language(self, languages=None):

View file

@ -408,7 +408,7 @@ def get_metadata_calibre_companion(uuid, library):
def feed_search(term): def feed_search(term):
if term: if term:
entries = calibre_db.get_search_results(term) entries, __ = calibre_db.get_search_results(term)
entriescount = len(entries) if len(entries) > 0 else 1 entriescount = len(entries) if len(entries) > 0 else 1
pagination = Pagination(1, entriescount, entriescount) pagination = Pagination(1, entriescount, entriescount)
return render_xml_template('feed.xml', searchterm=term, entries=entries, pagination=pagination) return render_xml_template('feed.xml', searchterm=term, entries=entries, pagination=pagination)

View file

@ -100,6 +100,33 @@ $(function() {
$(e.currentTarget).find("#btndeletedomain").data("domainId", domainId); $(e.currentTarget).find("#btndeletedomain").data("domainId", domainId);
}); });
$("#delete_confirm").click(function() {
//get data-id attribute of the clicked element
var deleteId = $(this).data("deleteid");
$.ajax({
method:"get",
url: window.location.pathname + "/../../delete"/+deleteId,
});
});
//triggered when modal is about to be shown
$("#deleteModal").on("show.bs.modal", function(e) {
//get data-id attribute of the clicked element and store in button
var bookId = $(e.relatedTarget).data("delete-id");
$(e.currentTarget).find("#delete_confirm").data("deleteid", bookId);
});
// receive result from request, dismiss modal dialog, show flash message
// insert after navbar
/*$("#deleteModal").on("hidden.bs.modal", function () {
<div class="row-fluid text-center" style="margin-top: -20px;">
<div id="flash_success" class="alert alert-success">{{ message[1] }}</div>
</div>*/
// to save current setting
// coresponding event: onColumnSwitch
//$table.bootstrapTable('getVisibleColumns')
//$table.bootstrapTable('getHiddenColumns').
$("#restrictModal").on("hidden.bs.modal", function () { $("#restrictModal").on("hidden.bs.modal", function () {
// Destroy table and remove hooks for buttons // Destroy table and remove hooks for buttons
$("#restrict-elements-table").unbind(); $("#restrict-elements-table").unbind();
@ -223,9 +250,8 @@ function RestrictionActions (value, row) {
/* Function for deleting books */ /* Function for deleting books */
function EbookActions (value, row) { function EbookActions (value, row) {
return [ return [
"<div class=\"danger remove\" listbook-id=\"" + row.id + "\" title=\"Remove\">", "<div class='danger remove' data-toggle='modal' data-target=\"#deleteModal\" data-delete-id=\"" + row.id + "\" title=\"Remove\">",
"<i class=\"glyphicon glyphicon-trash\"></i>", "<i class=\"glyphicon glyphicon-trash\"></i>",
"</div>" "</div>"
].join(""); ].join("");
} }

View file

@ -192,34 +192,7 @@
{% endblock %} {% endblock %}
{% block modal %} {% block modal %}
{% if g.user.role_delete_books() %} {{ delete_book(book.id) }}
<div class="modal fade" id="deleteModal" role="dialog" aria-labelledby="metaDeleteLabel">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-danger text-center">
<span>{{_('Are you really sure?')}}</span>
</div>
<div class="modal-body text-center">
<p>
<span>{{_('This book will be permanently erased from database')}}</span>
<span>{{_('and hard disk')}}</span>
</p>
{% if config.config_kobo_sync %}
<p>
<span>{{_('Important Kobo Note: deleted books will remain on any paired Kobo device.')}}</span>
<span>{{_('Books must first be archived and the device synced before a book can safely be deleted.')}}</span>
</p>
{% endif %}
</div>
<div class="modal-footer">
<a href="{{ url_for('editbook.delete_book', book_id=book.id) }}" id="delete_confirm" class="btn btn-danger">{{_('Delete')}}</a>
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Cancel')}}</button>
</div>
</div>
</div>
</div>
{% endif %}
<div class="modal fade" id="metaModal" tabindex="-1" role="dialog" aria-labelledby="metaModalLabel"> <div class="modal fade" id="metaModal" tabindex="-1" role="dialog" aria-labelledby="metaModalLabel">
<div class="modal-dialog modal-lg" role="document"> <div class="modal-dialog modal-lg" role="document">

View file

@ -5,12 +5,7 @@
{% endblock %} {% endblock %}
{% block body %} {% block body %}
<h2 class="{{page}}">{{_(title)}}</h2> <h2 class="{{page}}">{{_(title)}}</h2>
<!--
-->
<table class="table table-no-bordered table-striped" <table class="table table-no-bordered table-striped"
data-toggle="table"
data-side-pagination="server" data-side-pagination="server"
data-pagination="true" data-pagination="true"
data-pagination-detail-h-align=" hidden" data-pagination-detail-h-align=" hidden"
@ -23,6 +18,7 @@
data-search="true" data-search="true"
data-search-align="left" data-search-align="left"
data-show-search-button="false" data-show-search-button="false"
data-search-on-enter-key="true"
data-checkbox-header="false" data-checkbox-header="false"
data-maintain-meta-data="true"> data-maintain-meta-data="true">
<thead> <thead>
@ -47,6 +43,9 @@
</thead> </thead>
</table> </table>
{% endblock %} {% endblock %}
{% block modal %}
{{ delete_book(0) }}
{% endblock %}
{% block js %} {% block js %}
<script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-table.min.js') }}"></script> <script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-table.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-table-editable.min.js') }}"></script> <script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-table-editable.min.js') }}"></script>

View file

@ -1,4 +1,4 @@
{% from 'modal_restriction.html' import restrict_modal %} {% from 'modal_dialogs.html' import restrict_modal, delete_book %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="{{ g.user.locale }}"> <html lang="{{ g.user.locale }}">
<head> <head>

View file

@ -37,3 +37,34 @@
</div> </div>
</div> </div>
{% endmacro %} {% endmacro %}
{% macro delete_book(bookid) %}
{% if g.user.role_delete_books() %}
<div class="modal fade" id="deleteModal" role="dialog" aria-labelledby="metaDeleteLabel">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header bg-danger text-center">
<span>{{_('Are you really sure?')}}</span>
</div>
<div class="modal-body text-center">
<p>
<span>{{_('This book will be permanently erased from database')}}</span>
<span>{{_('and hard disk')}}</span>
</p>
{% if config.config_kobo_sync %}
<p>
<span>{{_('Important Kobo Note: deleted books will remain on any paired Kobo device.')}}</span>
<span>{{_('Books must first be archived and the device synced before a book can safely be deleted.')}}</span>
</p>
{% endif %}
</div>
<div class="modal-footer">
<input type="button" class="btn btn-danger" value="{{_('Delete')}}" name="delete_confirm" id="delete_confirm" data-dismiss="modal">
<!--a href="{{ url_for('editbook.delete_book', book_id=bookid) }}" id="delete_confirm" class="btn btn-danger">{{_('Delete')}}</a-->
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Cancel')}}</button>
</div>
</div>
</div>
</div>
{% endif %}
{% endmacro %}

View file

@ -5,7 +5,7 @@
<h2>{{_('No Results Found')}} {{adv_searchterm}}</h2> <h2>{{_('No Results Found')}} {{adv_searchterm}}</h2>
<p>{{_('Search Term:')}} {{adv_searchterm}}</p> <p>{{_('Search Term:')}} {{adv_searchterm}}</p>
{% else %} {% else %}
<h2>{{entries|length}} {{_('Results for:')}} {{adv_searchterm}}</h2> <h2>{{result_count}} {{_('Results for:')}} {{adv_searchterm}}</h2>
{% if g.user.is_authenticated %} {% if g.user.is_authenticated %}
{% if g.user.shelf.all() or g.shelves_access %} {% if g.user.shelf.all() or g.shelves_access %}
<div id="shelf-actions" class="btn-toolbar" role="toolbar"> <div id="shelf-actions" class="btn-toolbar" role="toolbar">

View file

@ -832,13 +832,13 @@ def render_language_books(page, name, order):
@web.route("/table") @web.route("/table")
@login_required_if_no_ano @login_required
def books_table(): def books_table():
# __, __, pagination = calibre_db.fill_indexpage(1, 0, db.Books, True, [db.Books.timestamp.asc()]) # __, __, pagination = calibre_db.fill_indexpage(1, 0, db.Books, True, [db.Books.timestamp.asc()])
return render_title_template('book_table.html', title=_(u"Books list"), page="book_table") #, pagination=pagination) return render_title_template('book_table.html', title=_(u"Books list"), page="book_table") #, pagination=pagination)
@web.route("/ajax/listbooks") @web.route("/ajax/listbooks")
@login_required_if_no_ano @login_required
def list_books(): def list_books():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
limit = request.args.get("limit") or config.config_books_per_page limit = request.args.get("limit") or config.config_books_per_page
@ -850,9 +850,7 @@ def list_books():
search = request.args.get("search") search = request.args.get("search")
total_count = calibre_db.session.query(db.Books).count() total_count = calibre_db.session.query(db.Books).count()
if search: if search:
entries = calibre_db.get_search_results(search, order, limit) entries, filtered_count = calibre_db.get_search_results(search, off, order, limit)
#ToDo not right web.py 1259
filtered_count = len(entries)
else: else:
entries, __, __ = calibre_db.fill_indexpage((int(off) / (int(limit)) + 1), limit, db.Books, True, order) entries, __, __ = calibre_db.fill_indexpage((int(off) / (int(limit)) + 1), limit, db.Books, True, order)
filtered_count = total_count filtered_count = total_count
@ -1035,7 +1033,7 @@ def reconnect():
def search(): def search():
term = request.args.get("query") term = request.args.get("query")
if term: if term:
entries = calibre_db.get_search_results(term) entries, result_count = calibre_db.get_search_results(term)
ids = list() ids = list()
for element in entries: for element in entries:
ids.append(element.id) ids.append(element.id)
@ -1044,11 +1042,13 @@ def search():
searchterm=term, searchterm=term,
adv_searchterm=term, adv_searchterm=term,
entries=entries, entries=entries,
result_count=result_count,
title=_(u"Search"), title=_(u"Search"),
page="search") page="search")
else: else:
return render_title_template('search.html', return render_title_template('search.html',
searchterm="", searchterm="",
result_count=0,
title=_(u"Search"), title=_(u"Search"),
page="search") page="search")
@ -1192,7 +1192,7 @@ def advanced_search():
ids.append(element.id) ids.append(element.id)
searched_ids[current_user.id] = ids searched_ids[current_user.id] = ids
return render_title_template('search.html', adv_searchterm=searchterm, return render_title_template('search.html', adv_searchterm=searchterm,
entries=q, title=_(u"search"), page="search") entries=q, result_count=len(q), title=_(u"search"), page="search")
# prepare data for search-form # prepare data for search-form
tags = calibre_db.session.query(db.Tags)\ tags = calibre_db.session.query(db.Tags)\
.join(db.books_tags_link)\ .join(db.books_tags_link)\