1
0
mirror of https://github.com/janeczku/calibre-web synced 2024-11-24 18:47:23 +00:00

Improvements for books table editor

This commit is contained in:
Ozzieisaacs 2020-06-11 21:19:09 +02:00
parent 94b5ec91cc
commit 1c681ee378
6 changed files with 219 additions and 61 deletions

View File

@ -240,6 +240,9 @@ class Languages(Base):
self.lang_code = lang_code
def get(self):
if self.language_name:
return self.language_name
else:
return self.lang_code
def __repr__(self):

View File

@ -27,6 +27,7 @@ import json
from shutil import copyfile
from uuid import uuid4
from babel import Locale as LC
from flask import Blueprint, request, flash, redirect, url_for, abort, Markup, Response
from flask_babel import gettext as _
from flask_login import current_user, login_required
@ -902,16 +903,17 @@ def edit_list_book(param):
elif param =='series':
edit_book_series(vals['value'], book)
elif param =='publishers':
edit_book_publisher(vals['value'], book)
# ToDo: edit books
vals['publisher'] = vals['value']
edit_book_publisher(vals, book)
elif param =='languages':
edit_book_languages(vals['value'], book)
elif param =='title':
edit_book_languages(vals['value'], book)
elif param =='sort':
edit_book_languages(vals['value'], book)
elif param =='author_sort':
edit_book_languages(vals['value'], book)
book.author_sort = vals['value']
elif param =='title':
book.title = vals['value']
elif param =='sort':
book.sort = vals['value']
# ToDo: edit books
elif param =='authors':
edit_book_languages(vals['value'], book)
@ -919,7 +921,18 @@ def edit_list_book(param):
calibre_db.session.commit()
return ""
@editbook.route("/ajax/sort_value")
@login_required
def get_sorted_entry():
pass
@editbook.route("/ajax/deletebooks")
@login_required_if_no_ano
@login_required
def delete_list_book():
pass
@editbook.route("/ajax/mergebooks", methods=['POST'])
@login_required
def merge_list_book():
vals = request.get_json()
return ""

View File

@ -51,9 +51,9 @@ body h2 {
color:#444;
}
a, .danger, .editable-empty, .editable-empty:hover { color: #45b29d; }
a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d; }
.danger:hover { color: #23527c; }
.book-remove:hover { color: #23527c; }
.btn-default a { color: #444; }

View File

@ -15,16 +15,150 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* exported TableActions, RestrictionActions, EbookActions*/
/* exported TableActions, RestrictionActions, EbookActions, responseHandler */
var selections = [];
$(function() {
$("#books-table").bootstrapTable({
formatNoMatches: function () {
return "";
$("#books-table").on("check.bs.table check-all.bs.table uncheck.bs.table uncheck-all.bs.table",
function (e, rowsAfter, rowsBefore) {
var rows = rowsAfter;
if (e.type === "uncheck-all") {
rows = rowsBefore;
}
var ids = $.map(!$.isArray(rows) ? [rows] : rows, function (row) {
return row.id;
});
var func = $.inArray(e.type, ["check", "check-all"]) > -1 ? "union" : "difference";
selections = window._[func](selections, ids);
if (selections.length >= 2) {
$("#merge_books").removeClass("disabled");
$("#merge_books").attr("aria-disabled", false);
} else {
$("#merge_books").addClass("disabled");
$("#merge_books").attr("aria-disabled", true);
}
});
$("#merge_books").click(function() {
$.ajax({
method:"post",
contentType: "application/json; charset=utf-8",
dataType: "json",
url: window.location.pathname + "/../../ajax/mergebooks",
data: JSON.stringify({"Merge_books":selections}),
success: function success() {
// ToDo:
}
});
});
/*$("#books-table").bootstrapTable({
});
test = $("#books-table").bootstrapTable('getOptions');
var column = test.columns[0]
column.forEach(function(item){
if ('editableValidate' in item) {
item.editable = {
mode: 'inline',
validate: function (value) { if($.trim(value) == '') return 'This field is required'; },
}
}
});
$("#books-table").bootstrapTable('refreshOptions', {columns: [column]});*/
var column = [];
$('#table1 > thead > tr > th').each(function(){
if ($(this).attr('data-edit')) {
if ($(this).attr('data-edit-validate')) {
column.push({
editable: {
mode: 'inline',
emptytext: "<span class='glyphicon glyphicon-plus'></span>",
validate: function (value) { if($.trim(value) == '') return 'This field is required'; },
}
});
} else {
column.push({
editable: {
mode: 'inline',
emptytext: "<span class='glyphicon glyphicon-plus'></span>",
}
});
}
} else {
column.push({});
}
});
$("#table1").bootstrapTable({
sidePagination: "server",
pagination: true,
paginationDetailHAlign: " hidden",
paginationHAlign: "left",
/*url: window.location.pathname + "/../../ajax/listbooks",*/
idField: "id",
search: true,
showColumns: true,
searchAlign: "left",
showSearchButton : false,
searchOnEnterKey: true,
checkboxHeader: false,
maintainMetaData: true,
responseHandler: responseHandler,
columns: column,
/*editable-mode="inline"
editable-emptytext="<span class='glyphicon glyphicon-plus'></span>">*/
/*columns: [
{},
{}, {
editable: {
mode: 'inline',
emptytext: "<span class='glyphicon glyphicon-plus'></span>",
validate: function (value) { if($.trim(value) == '') return 'This field is required'; },
},
}, {
editable: {
mode: 'inline',
validate: function (value) { if($.trim(value) == '') return 'This field is required'; },
},
}, {
editable: {
mode: 'inline',
validate: function (value) { if($.trim(value) == '') return 'This field is required'; },
}
}, {
editable: {
mode: 'inline',
emptytext: "<span class='glyphicon glyphicon-plus'></span>",
validate: function (value) { if($.trim(value) == '') return 'This field is required'; },
},
}, {
editable: {
mode: 'inline',
emptytext: "<span class='glyphicon glyphicon-plus'></span>",
validate: function (value) { if($.trim(value) == '') return 'This field is required'; },
},
}, {
editable: {
mode: 'inline',
emptytext: "<span class='glyphicon glyphicon-plus'></span>",
validate: function (value) { if($.trim(value) == '') return 'This field is required'; },
},
}],*/
formatNoMatches: function () {
return "";
},
});
/*var $table = $('#books-table');
$('#books-table').bootstrapTable('getOptions')*/
/*$('#books-table').bootstrapTable('editable')*/
/*{ field: 'aimValue', title: 'Aim<br>Value', class: 'danger',editable: { mode: 'inline', validate: function (v) { return validateData(this, v); }, }, },*/
$("#domain_allow_submit").click(function(event) {
event.preventDefault();
$("#domain_add_allow").ajaxForm();
@ -105,7 +239,7 @@ $(function() {
var deleteId = $(this).data("deleteid");
$.ajax({
method:"get",
url: window.location.pathname + "/../../delete"/+deleteId,
url: window.location.pathname + "/../../delete/" + deleteId,
});
});
@ -238,6 +372,7 @@ function TableActions (value, row) {
].join("");
}
/* Function for deleting domain restrictions */
function RestrictionActions (value, row) {
return [
@ -250,8 +385,22 @@ function RestrictionActions (value, row) {
/* Function for deleting books */
function EbookActions (value, row) {
return [
"<div class=\"danger remove\" data-toggle=\"modal\" data-target=\"#deleteModal\" data-delete-id=\"" + row.id + "\" title=\"Remove\">",
"<div class=\"book-remove\" data-toggle=\"modal\" data-target=\"#deleteModal\" data-delete-id=\"" + row.id + "\" title=\"Remove\">",
"<i class=\"glyphicon glyphicon-trash\"></i>",
"</div>"
].join("");
}
/* Function for keeping checked rows */
function responseHandler(res) {
$.each(res.rows, function (i, row) {
row.state = $.inArray(row.id, selections) !== -1;
});
return res;
}
function validato(value) {
if($.trim(value) == '') return 'This field is required';
}
/*function validateVal(value) { if($.trim(value) == '') return 'This field is required'; }*/

View File

@ -1,6 +1,14 @@
{% extends "layout.html" %}
{% macro text_table_row(parameter, edit_text, show_text) -%}
<th data-field="{{ parameter }}" id="{{ parameter }}" data-sortable="true" {% if g.user.role_edit() %}data-editable-type="text" data-editable-url="{{ url_for('editbook.edit_list_book', param=parameter)}}" data-editable="true" data-editable-title="{{ edit_text}}"{% endif %}>{{ show_text }}</th>
{% macro text_table_row(parameter, edit_text, show_text, validate) -%}
<th data-field="{{ parameter }}" id="{{ parameter }}" data-sortable="true"
{% if g.user.role_edit() %}
data-editable-type="text"
data-editable-url="{{ url_for('editbook.edit_list_book', param=parameter)}}"
data-editable-title="{{ edit_text}}"
data-edit="true"
{% if validate %}data-edit-validate="true" {% endif %}
{% endif %}
>{{ show_text }}</th>
{%- endmacro %}
{% block header %}
@ -9,13 +17,14 @@
{% endblock %}
{% block body %}
<h2 class="{{page}}">{{_(title)}}</h2>
<table class="table table-no-bordered table-striped"
<!--table id="table1"></table-->
<!--a href="{{url_for('editbook.merge_list_book')}}" class="btn btn-default disabled" id="merge_book" role="button" aria-disabled="true">{{_('Merge selected books')}}
data-side-pagination="server"
data-pagination="true"
data-pagination-detail-h-align=" hidden"
data-pagination-h-align="left"
id="books-table"
data-url="{{url_for('web.list_books')}}"
data-id-field="id"
data-editable-mode="inline"
data-show-columns="true"
@ -26,24 +35,27 @@
data-checkbox-header="false"
data-maintain-meta-data="true"
data-response-handler="responseHandler"
data-editable-emptytext="<span class='glyphicon glyphicon-plus'></span>">
data-editable-emptytext="<span class='glyphicon glyphicon-plus'></span>"
</a-->
<div class="btn btn-default disabled" id="merge_books" aria-disabled="true">{{_('Merge selected books')}}</div>
<table id="table1" class="table table-no-bordered table-striped"
data-url="{{url_for('web.list_books')}}">
<thead>
<tr>
{% if g.user.role_edit() %}
<th data-field="state" data-checkbox="true" data-sortable="true"></th>
{% endif %}
<th data-field="id" id="id" data-visible="false" data-switchable="false"></th>
{{ text_table_row('title', _('Enter Title'),_('Title')) }}
{{ text_table_row('sort', _('Enter Titlesort'),_('Sort')) }}
{{ text_table_row('author_sort', _('Enter Authorsort'),_('Authors Sort')) }}
{{ text_table_row('authors', _('Enter Authors'),_('Authors')) }}
{{ text_table_row('tags', _('Enter Tags'),_('Tags')) }}
{{ text_table_row('series', _('Enter Series'),_('Series')) }}
{{ text_table_row('title', _('Enter Title'),_('Title'), true) }}
{{ text_table_row('sort', _('Enter Titlesort'),_('Sort'), false) }}
{{ text_table_row('author_sort', _('Enter Authorsort'),_('Authors Sort'), false) }}
{{ text_table_row('authors', _('Enter Authors'),_('Authors'), false) }}
{{ text_table_row('tags', _('Enter Tags'),_('Tags'), false) }}
{{ text_table_row('series', _('Enter Series'),_('Series'), false) }}
<th data-field="series_index" id="series_index" data-sortable="true" {% if g.user.role_edit() %} data-editable-type="number" data-editable-placeholder="1" data-editable-step="0.01" data-editable-min="0" data-editable-url="{{ url_for('editbook.edit_list_book', param='series_index')}}" data-editable="true" data-editable-title="{{_('Enter title')}}"{% endif %}>{{_('Series Index')}}</th>
{{ text_table_row('languages', _('Enter Languages'),_('Languages')) }}
<th data-field="pubdate" id="pubdate" data-sortable="true">Publishing Date</th>
{{ text_table_row('publishers', _('Enter Publishers'),_('Publishers')) }}
{{ text_table_row('languages', _('Enter Languages'),_('Languages'), false) }}
<th data-field="pubdate" data-type="date" data-viewformat="dd.mm.yyyy" id="pubdate" data-sortable="true">Publishing Date</th>
{{ text_table_row('publishers', _('Enter Publishers'),_('Publishers'), false) }}
{% if g.user.role_edit() %}
<th data-align="right" data-formatter="EbookActions" data-switchable="false"></th>
{% endif %}
@ -60,32 +72,5 @@
<script src="{{ url_for('static', filename='js/libs/bootstrap-table/bootstrap-editable.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/table.js') }}"></script>
<script>
var $table = $('#books-table')
var selections = []
function responseHandler(res) {
$.each(res.rows, function (i, row) {
row.state = $.inArray(row.id, selections) !== -1
})
return res
}
$(function() {
$table.on('check.bs.table check-all.bs.table uncheck.bs.table uncheck-all.bs.table',
function (e, rowsAfter, rowsBefore) {
var rows = rowsAfter
if (e.type === 'uncheck-all') {
rows = rowsBefore
}
var ids = $.map(!$.isArray(rows) ? [rows] : rows, function (row) {
return row.id
})
var func = $.inArray(e.type, ['check', 'check-all']) > -1 ? 'union' : 'difference'
selections = window._[func](selections, ids)
})
})
</script>
{% endblock %}

View File

@ -30,8 +30,8 @@ import traceback
import binascii
import re
from babel import Locale as LC
from babel.dates import format_date
from babel import Locale as LC
from babel.core import UnknownLocaleError
from flask import Blueprint
from flask import render_template, request, redirect, send_from_directory, make_response, g, flash, abort, url_for
@ -849,6 +849,14 @@ def list_books():
else:
entries, __, __ = calibre_db.fill_indexpage((int(off) / (int(limit)) + 1), limit, db.Books, True, order)
filtered_count = total_count
for entry in entries:
for index in range(0, len(entry.languages)):
try:
entry.languages[index].language_name = LC.parse(entry.languages[index].lang_code)\
.get_language_name(get_locale())
except UnknownLocaleError:
entry.languages[index].language_name = _(
isoLanguages.get(part3=entry.languages[index].lang_code).name)
table_entries = {'totalNotFiltered': total_count, 'total': filtered_count, "rows": entries}
js_list = json.dumps(table_entries, cls=db.AlchemyEncoder)
#js_list = json.dumps(entries, cls=db.AlchemyEncoder)