Internal paged Search prepared
Search for table list is working
This commit is contained in:
parent
628658972c
commit
4038cb5b85
9 changed files with 82 additions and 48 deletions
11
cps/db.py
11
cps/db.py
|
@ -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):
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 %}
|
|
@ -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">
|
||||||
|
|
14
cps/web.py
14
cps/web.py
|
@ -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)\
|
||||||
|
|
Loading…
Reference in a new issue