1
0
mirror of https://github.com/janeczku/calibre-web synced 2025-06-03 23:14:11 +00:00

Add bulk read/unread buttons; Fix buttons not working when moved into table

This commit is contained in:
James Armstrong 2024-08-02 14:57:20 -07:00
parent 34fec0ed97
commit 4ed0633edf
3 changed files with 184 additions and 17 deletions

View File

@ -525,6 +525,27 @@ def delete_selected_books():
return json.dumps({'success': True})
return ""
@editbook.route("/ajax/readselectedbooks", methods=['POST'])
@user_login_required
@edit_required
def read_selected_books():
vals = request.get_json().get('selections')
markAsRead = request.get_json().get('markAsRead')
if vals:
try:
for book_id in vals:
ret = helper.edit_book_read_status(book_id, markAsRead)
except (OperationalError, IntegrityError, StaleDataError) as e:
calibre_db.session.rollback()
log.error_or_exception("Database error: {}".format(e))
ret = Response(json.dumps({'success': False,
'msg': 'Database error: {}'.format(e.orig if hasattr(e, "orig") else e)}),
mimetype='application/json')
return json.dumps({'success': True})
return ""
@editbook.route("/ajax/mergebooks", methods=['POST'])
@user_login_required
@edit_required

View File

@ -90,6 +90,12 @@ $(function() {
$("#unarchive_selected_books").removeClass("disabled");
$("#unarchive_selected_books").attr("aria-disabled", false);
$("#read_selected_books").removeClass("disabled");
$("#read_selected_books").attr("aria-disabled", false);
$("#unread_selected_books").removeClass("disabled");
$("#unread_selected_books").attr("aria-disabled", false);
} else {
$("#delete_selected_books").addClass("disabled");
$("#delete_selected_books").attr("aria-disabled", true);
@ -99,6 +105,12 @@ $(function() {
$("#unarchive_selected_books").addClass("disabled");
$("#unarchive_selected_books").attr("aria-disabled", true);
$("#read_selected_books").addClass("disabled");
$("#read_selected_books").attr("aria-disabled", true);
$("#unread_selected_books").addClass("disabled");
$("#unread_selected_books").attr("aria-disabled", true);
}
if (selections.length < 1) {
$("#delete_selection").addClass("disabled");
@ -154,7 +166,7 @@ $(function() {
});
});
$("#archive_selected_books").click(function(event) {
$(document).on('click', '#archive_selected_books', function(event) {
if ($(this).hasClass("disabled")) {
event.stopPropagation()
} else {
@ -176,7 +188,7 @@ $(function() {
});
});
$("#archive_selected_confirm").click(function(event) {
$(document).on('click', '#archive_selected_confirm', function(event) {
$.ajax({
method:"post",
contentType: "application/json; charset=utf-8",
@ -190,7 +202,7 @@ $(function() {
});
});
$("#unarchive_selected_books").click(function(event) {
$(document).on('click', '#unarchive_selected_books', function(event) {
if ($(this).hasClass("disabled")) {
event.stopPropagation()
} else {
@ -212,7 +224,7 @@ $(function() {
});
});
$("#unarchive_selected_confirm").click(function(event) {
$(document).on('click', '#unarchive_selected_confirm', function(event) {
$.ajax({
method:"post",
contentType: "application/json; charset=utf-8",
@ -226,7 +238,7 @@ $(function() {
});
});
$("#delete_selected_books").click(function(event) {
$(document).on('click', '#delete_selected_books', function(event) {
if ($(this).hasClass("disabled")) {
event.stopPropagation()
} else {
@ -248,7 +260,7 @@ $(function() {
});
});
$("#delete_selected_confirm").click(function(event) {
$(document).on('click', '#delete_selected_confirm', function(event) {
$.ajax({
method:"post",
contentType: "application/json; charset=utf-8",
@ -262,6 +274,78 @@ $(function() {
});
});
$(document).on('click', '#read_selected_books', function(event) {
if ($(this).hasClass("disabled")) {
event.stopPropagation()
} else {
$('#read_selected_modal').modal("show");
}
$.ajax({
method:"post",
contentType: "application/json; charset=utf-8",
dataType: "json",
url: window.location.pathname + "/../ajax/displayselectedbooks",
data: JSON.stringify({"selections":selections}),
success: function success(booTitles) {
$('#display-read-selected-books').empty();
$.each(booTitles.books, function(i, item) {
$("<span>- " + item + "</span><p></p>").appendTo("#display-read-selected-books");
});
}
});
});
$(document).on('click', '#read_selected_confirm', function(event) {
$.ajax({
method:"post",
contentType: "application/json; charset=utf-8",
dataType: "json",
url: window.location.pathname + "/../ajax/readselectedbooks",
data: JSON.stringify({"selections":selections, "markAsRead": true}),
success: function success(booTitles) {
$("#books-table").bootstrapTable("refresh");
$("#books-table").bootstrapTable("uncheckAll");
}
});
});
$(document).on('click', '#unread_selected_books', function(event) {
if ($(this).hasClass("disabled")) {
event.stopPropagation()
} else {
$('#unread_selected_modal').modal("show");
}
$.ajax({
method:"post",
contentType: "application/json; charset=utf-8",
dataType: "json",
url: window.location.pathname + "/../ajax/displayselectedbooks",
data: JSON.stringify({"selections":selections}),
success: function success(booTitles) {
$('#display-unread-selected-books').empty();
$.each(booTitles.books, function(i, item) {
$("<span>- " + item + "</span><p></p>").appendTo("#display-unread-selected-books");
});
}
});
});
$(document).on('click', '#unread_selected_confirm', function(event) {
$.ajax({
method:"post",
contentType: "application/json; charset=utf-8",
dataType: "json",
url: window.location.pathname + "/../ajax/readselectedbooks",
data: JSON.stringify({"selections":selections, "markAsRead": false}),
success: function success(booTitles) {
$("#books-table").bootstrapTable("refresh");
$("#books-table").bootstrapTable("uncheckAll");
}
});
});
$("#table_xchange").click(function() {
$.ajax({
method:"post",

View File

@ -15,14 +15,26 @@
{%- endmacro %}
{% macro book_checkbox_row(parameter, show_text, sort) -%}
<th data-name="{{parameter}}" data-field="{{parameter}}"
<th data-name="{{parameter}}" data-field="{{parameter}}" data-switchable="false"
{% if sort %}data-sortable="true" {% endif %}
data-visible="{{visiblility.get(parameter)}}"
data-formatter="bookCheckboxFormatter">
{% if parameter == "is_archived"%}
<div class="btn btn-default disabled" id="archive_selected_books" aria-disabled="true">{{_('Archive selected books')}}</div>
{% if parameter == "is_archived" %}
<div class="btn btn-default disabled" id="archive_selected_books" aria-disabled="true">
{{_('Archive selected books')}}
</div>
<br>
<div class="btn btn-default disabled" id="unarchive_selected_books" aria-disabled="true">{{_('Unarchive selected books')}}</div>
<div class="btn btn-default disabled" id="unarchive_selected_books" aria-disabled="true">
{{_('Unarchive selected books')}}
</div>
<br>
{% elif parameter == "read_status" %}
<div class="btn btn-default disabled" id="read_selected_books" aria-disabled="true">
{{_('Mark selected books as read')}}
</div>
<br>
<div class="btn btn-default disabled" id="unread_selected_books" aria-disabled="true">
{{_('Mark selected books as unread')}}</div>
<br>
{% endif %}
{{show_text}}
@ -40,8 +52,12 @@
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<div class="col-xs-12 col-sm-6">
<div class="row form-group">
<div class="btn btn-default disabled" id="merge_books" aria-disabled="true">{{_('Merge selected books')}}</div>
<div class="btn btn-default disabled" id="delete_selection" aria-disabled="true">{{_('Clear selections')}}</div>
<div class="btn btn-default disabled" id="merge_books" aria-disabled="true">
{{_('Merge selected books')}}
</div>
<div class="btn btn-default disabled" id="delete_selection" aria-disabled="true">
{{_('Clear selections')}}
</div>
</div>
<div class="row form-group">
<div class="btn btn-default disabled" id="table_xchange" ><span class="glyphicon glyphicon-arrow-up"></span><span class="glyphicon glyphicon-arrow-down"></span>{{_('Exchange author and title')}}</div>
@ -103,7 +119,13 @@
{% endif %}
{% endfor %}
{% if current_user.role_delete_books() and current_user.role_edit()%}
<th data-align="right" data-formatter="EbookActions" data-switchable="false"><div class="btn btn-default disabled" id="delete_selected_books" aria-disabled="true">{{_('Delete selected books')}}</div><br>{{_('Delete')}}</th>
<th data-align="right" data-formatter="EbookActions" data-switchable="false">
<div class="btn btn-default disabled" id="delete_selected_books" aria-disabled="true">
{{_('Delete selected books')}}
</div>
<br>
{{_('Delete')}}
</th>
{% endif %}
</tr>
</thead>
@ -130,7 +152,7 @@
<div class="text-left" id="merge_to"></div>
</div>
<div class="modal-footer">
<input id="merge_confirm" type="button" class="btn btn-danger" value="{{_('Merge')}}" name="merge_confirm" id="merge_confirm" data-dismiss="modal">
<input id="merge_confirm" type="button" class="btn btn-danger" value="{{_('Merge')}}" name="merge_confirm" data-dismiss="modal">
<button id="merge_abort" type="button" class="btn btn-default" data-dismiss="modal">{{_('Cancel')}}</button>
</div>
</div>
@ -149,7 +171,7 @@
<p></p>
<div class="text-left" id="display-delete-selected-books"></div>
<div class="modal-footer">
<input id="delete_selected_confirm" type="button" class="btn btn-danger" value="{{_('Delete')}}" name="delete_selected_confirm" id="delete_selected_confirm" data-dismiss="modal">
<input id="delete_selected_confirm" type="button" class="btn btn-danger" value="{{_('Delete')}}" name="delete_selected_confirm" data-dismiss="modal">
<button id="delete_selected_abort" type="button" class="btn btn-default" data-dismiss="modal">{{_('Cancel')}}</button>
</div>
</div>
@ -169,7 +191,7 @@
<p></p>
<div class="text-left" id="display-archive-selected-books"></div>
<div class="modal-footer">
<input id="archive_selected_confirm" type="button" class="btn btn-danger" value="{{_('Archive')}}" name="archive_selected_confirm" id="archive_selected_confirm" data-dismiss="modal">
<input id="archive_selected_confirm" type="button" class="btn btn-danger" value="{{_('Archive')}}" name="archive_selected_confirm" data-dismiss="modal">
<button id="archive_selected_abort" type="button" class="btn btn-default" data-dismiss="modal">{{_('Cancel')}}</button>
</div>
</div>
@ -189,13 +211,53 @@
<p></p>
<div class="text-left" id="display-unarchive-selected-books"></div>
<div class="modal-footer">
<input id="unarchive_selected_confirm" type="button" class="btn btn-danger" value="{{_('Unarchive')}}" name="unarchive_selected_confirm" id="unarchive_selected_confirm" data-dismiss="modal">
<input id="unarchive_selected_confirm" type="button" class="btn btn-danger" value="{{_('Unarchive')}}" name="unarchive_selected_confirm" data-dismiss="modal">
<button id="unarchive_selected_abort" type="button" class="btn btn-default" data-dismiss="modal">{{_('Cancel')}}</button>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="read_selected_modal" role="dialog" aria-labelledby="metaReadSelectedLabel">
<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">
<p></p>
<div class="text-left">{{_('The following books will be marked read:')}}</div>
<p></p>
<div class="text-left" id="display-read-selected-books"></div>
<div class="modal-footer">
<input id="read_selected_confirm" type="button" class="btn btn-danger" value="{{_('Mark as read')}}" name="read_selected_confirm" data-dismiss="modal">
<button id="read_selected_abort" type="button" class="btn btn-default" data-dismiss="modal">{{_('Cancel')}}</button>
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="unread_selected_modal" role="dialog" aria-labelledby="metaReadSelectedLabel">
<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">
<p></p>
<div class="text-left">{{_('The following books will be marked unread:')}}</div>
<p></p>
<div class="text-left" id="display-unread-selected-books"></div>
<div class="modal-footer">
<input id="unread_selected_confirm" type="button" class="btn btn-danger" value="{{_('Mark as unread')}}" name="unread_selected_confirm" data-dismiss="modal">
<button id="read_selected_abort" type="button" class="btn btn-default" data-dismiss="modal">{{_('Cancel')}}</button>
</div>
</div>
</div>
</div>
</div>
{% endif %}
{% endblock %}