Merged develop, fixed merged conflicts
This commit is contained in:
commit
35c60eaee5
44
cps/admin.py
44
cps/admin.py
|
@ -39,6 +39,7 @@ from sqlalchemy.exc import IntegrityError, OperationalError, InvalidRequestError
|
||||||
from sqlalchemy.sql.expression import func, or_
|
from sqlalchemy.sql.expression import func, or_
|
||||||
|
|
||||||
from . import constants, logger, helper, services, fs
|
from . import constants, logger, helper, services, fs
|
||||||
|
from .cli import filepicker
|
||||||
from . import db, calibre_db, ub, web_server, get_locale, config, updater_thread, babel, gdriveutils
|
from . import db, calibre_db, ub, web_server, get_locale, config, updater_thread, babel, gdriveutils
|
||||||
from .helper import check_valid_domain, send_test_mail, reset_password, generate_password_hash
|
from .helper import check_valid_domain, send_test_mail, reset_password, generate_password_hash
|
||||||
from .gdriveutils import is_gdrive_ready, gdrive_support
|
from .gdriveutils import is_gdrive_ready, gdrive_support
|
||||||
|
@ -118,7 +119,7 @@ def before_request():
|
||||||
g.shelves_access = ub.session.query(ub.Shelf).filter(
|
g.shelves_access = ub.session.query(ub.Shelf).filter(
|
||||||
or_(ub.Shelf.is_public == 1, ub.Shelf.user_id == current_user.id)).order_by(ub.Shelf.name).all()
|
or_(ub.Shelf.is_public == 1, ub.Shelf.user_id == current_user.id)).order_by(ub.Shelf.name).all()
|
||||||
if not config.db_configured and request.endpoint not in (
|
if not config.db_configured and request.endpoint not in (
|
||||||
'admin.basic_configuration', 'login') and '/static/' not in request.path:
|
'admin.basic_configuration', 'login', 'admin.config_pathchooser') and '/static/' not in request.path:
|
||||||
return redirect(url_for('admin.basic_configuration'))
|
return redirect(url_for('admin.basic_configuration'))
|
||||||
|
|
||||||
|
|
||||||
|
@ -209,7 +210,7 @@ def admin():
|
||||||
@admin_required
|
@admin_required
|
||||||
def configuration():
|
def configuration():
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
return _configuration_update_helper()
|
return _configuration_update_helper(True)
|
||||||
return _configuration_result()
|
return _configuration_result()
|
||||||
|
|
||||||
|
|
||||||
|
@ -604,10 +605,11 @@ def list_restriction(res_type):
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@admi.route("/basicconfig/pathchooser/")
|
@admi.route("/basicconfig/pathchooser/")
|
||||||
# @unconfigured
|
@unconfigured
|
||||||
@login_required
|
|
||||||
def config_pathchooser():
|
def config_pathchooser():
|
||||||
return pathchooser()
|
if filepicker:
|
||||||
|
return pathchooser()
|
||||||
|
abort(403)
|
||||||
|
|
||||||
@admi.route("/ajax/pathchooser/")
|
@admi.route("/ajax/pathchooser/")
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -616,7 +618,7 @@ def ajax_pathchooser():
|
||||||
return pathchooser()
|
return pathchooser()
|
||||||
|
|
||||||
def pathchooser():
|
def pathchooser():
|
||||||
browse_for = "folder" # if request.endpoint == "admin.pathchooser" else "file"
|
browse_for = "folder"
|
||||||
folder_only = request.args.get('folder', False) == "true"
|
folder_only = request.args.get('folder', False) == "true"
|
||||||
file_filter = request.args.get('filter', "")
|
file_filter = request.args.get('filter', "")
|
||||||
path = os.path.normpath(request.args.get('path', ""))
|
path = os.path.normpath(request.args.get('path', ""))
|
||||||
|
@ -702,8 +704,8 @@ def pathchooser():
|
||||||
def basic_configuration():
|
def basic_configuration():
|
||||||
logout_user()
|
logout_user()
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
return _configuration_update_helper()
|
return _configuration_update_helper(configured=filepicker)
|
||||||
return _configuration_result()
|
return _configuration_result(configured=filepicker)
|
||||||
|
|
||||||
|
|
||||||
def _config_int(to_save, x, func=int):
|
def _config_int(to_save, x, func=int):
|
||||||
|
@ -858,7 +860,7 @@ def _configuration_ldap_helper(to_save, gdriveError):
|
||||||
return reboot_required, None
|
return reboot_required, None
|
||||||
|
|
||||||
|
|
||||||
def _configuration_update_helper():
|
def _configuration_update_helper(configured):
|
||||||
reboot_required = False
|
reboot_required = False
|
||||||
db_change = False
|
db_change = False
|
||||||
to_save = request.form.to_dict()
|
to_save = request.form.to_dict()
|
||||||
|
@ -878,11 +880,15 @@ def _configuration_update_helper():
|
||||||
|
|
||||||
reboot_required |= _config_string(to_save, "config_keyfile")
|
reboot_required |= _config_string(to_save, "config_keyfile")
|
||||||
if config.config_keyfile and not os.path.isfile(config.config_keyfile):
|
if config.config_keyfile and not os.path.isfile(config.config_keyfile):
|
||||||
return _configuration_result(_('Keyfile Location is not Valid, Please Enter Correct Path'), gdriveError)
|
return _configuration_result(_('Keyfile Location is not Valid, Please Enter Correct Path'),
|
||||||
|
gdriveError,
|
||||||
|
configured)
|
||||||
|
|
||||||
reboot_required |= _config_string(to_save, "config_certfile")
|
reboot_required |= _config_string(to_save, "config_certfile")
|
||||||
if config.config_certfile and not os.path.isfile(config.config_certfile):
|
if config.config_certfile and not os.path.isfile(config.config_certfile):
|
||||||
return _configuration_result(_('Certfile Location is not Valid, Please Enter Correct Path'), gdriveError)
|
return _configuration_result(_('Certfile Location is not Valid, Please Enter Correct Path'),
|
||||||
|
gdriveError,
|
||||||
|
configured)
|
||||||
|
|
||||||
_config_checkbox_int(to_save, "config_uploading")
|
_config_checkbox_int(to_save, "config_uploading")
|
||||||
# Reboot on config_anonbrowse with enabled ldap, as decoraters are changed in this case
|
# Reboot on config_anonbrowse with enabled ldap, as decoraters are changed in this case
|
||||||
|
@ -947,10 +953,10 @@ def _configuration_update_helper():
|
||||||
if "config_rarfile_location" in to_save:
|
if "config_rarfile_location" in to_save:
|
||||||
unrar_status = helper.check_unrar(config.config_rarfile_location)
|
unrar_status = helper.check_unrar(config.config_rarfile_location)
|
||||||
if unrar_status:
|
if unrar_status:
|
||||||
return _configuration_result(unrar_status, gdriveError)
|
return _configuration_result(unrar_status, gdriveError, configured)
|
||||||
except (OperationalError, InvalidRequestError):
|
except (OperationalError, InvalidRequestError):
|
||||||
ub.session.rollback()
|
ub.session.rollback()
|
||||||
_configuration_result(_(u"Settings DB is not Writeable"), gdriveError)
|
_configuration_result(_(u"Settings DB is not Writeable"), gdriveError, configured)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
metadata_db = os.path.join(config.config_calibre_dir, "metadata.db")
|
metadata_db = os.path.join(config.config_calibre_dir, "metadata.db")
|
||||||
|
@ -958,11 +964,13 @@ def _configuration_update_helper():
|
||||||
gdriveutils.downloadFile(None, "metadata.db", metadata_db)
|
gdriveutils.downloadFile(None, "metadata.db", metadata_db)
|
||||||
db_change = True
|
db_change = True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return _configuration_result('%s' % e, gdriveError)
|
return _configuration_result('%s' % e, gdriveError, configured)
|
||||||
|
|
||||||
if db_change:
|
if db_change:
|
||||||
if not calibre_db.setup_db(config, ub.app_DB_path):
|
if not calibre_db.setup_db(config, ub.app_DB_path):
|
||||||
return _configuration_result(_('DB Location is not Valid, Please Enter Correct Path'), gdriveError)
|
return _configuration_result(_('DB Location is not Valid, Please Enter Correct Path'),
|
||||||
|
gdriveError,
|
||||||
|
configured)
|
||||||
if not os.access(os.path.join(config.config_calibre_dir, "metadata.db"), os.W_OK):
|
if not os.access(os.path.join(config.config_calibre_dir, "metadata.db"), os.W_OK):
|
||||||
flash(_(u"DB is not Writeable"), category="warning")
|
flash(_(u"DB is not Writeable"), category="warning")
|
||||||
|
|
||||||
|
@ -971,10 +979,10 @@ def _configuration_update_helper():
|
||||||
if reboot_required:
|
if reboot_required:
|
||||||
web_server.stop(True)
|
web_server.stop(True)
|
||||||
|
|
||||||
return _configuration_result(None, gdriveError)
|
return _configuration_result(None, gdriveError, configured)
|
||||||
|
|
||||||
|
|
||||||
def _configuration_result(error_flash=None, gdriveError=None):
|
def _configuration_result(error_flash=None, gdriveError=None, configured=True):
|
||||||
gdrive_authenticate = not is_gdrive_ready()
|
gdrive_authenticate = not is_gdrive_ready()
|
||||||
gdrivefolders = []
|
gdrivefolders = []
|
||||||
if gdriveError is None:
|
if gdriveError is None:
|
||||||
|
@ -995,7 +1003,7 @@ def _configuration_result(error_flash=None, gdriveError=None):
|
||||||
|
|
||||||
return render_title_template("config_edit.html", config=config, provider=oauthblueprints,
|
return render_title_template("config_edit.html", config=config, provider=oauthblueprints,
|
||||||
show_back_button=show_back_button, show_login_button=show_login_button,
|
show_back_button=show_back_button, show_login_button=show_login_button,
|
||||||
show_authenticate_google_drive=gdrive_authenticate,
|
show_authenticate_google_drive=gdrive_authenticate, filepicker=configured,
|
||||||
gdriveError=gdriveError, gdrivefolders=gdrivefolders, feature_support=feature_support,
|
gdriveError=gdriveError, gdrivefolders=gdrivefolders, feature_support=feature_support,
|
||||||
title=_(u"Basic Configuration"), page="config")
|
title=_(u"Basic Configuration"), page="config")
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ parser.add_argument('-v', '--version', action='version', help='Shows version num
|
||||||
version=version_info())
|
version=version_info())
|
||||||
parser.add_argument('-i', metavar='ip-address', help='Server IP-Address to listen')
|
parser.add_argument('-i', metavar='ip-address', help='Server IP-Address to listen')
|
||||||
parser.add_argument('-s', metavar='user:pass', help='Sets specific username to new password')
|
parser.add_argument('-s', metavar='user:pass', help='Sets specific username to new password')
|
||||||
|
parser.add_argument('-f', action='store_true', help='Enables filepicker in unconfigured mode')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if sys.version_info < (3, 0):
|
if sys.version_info < (3, 0):
|
||||||
|
@ -110,3 +111,6 @@ if ipadress:
|
||||||
|
|
||||||
# handle and check user password argument
|
# handle and check user password argument
|
||||||
user_password = args.s or None
|
user_password = args.s or None
|
||||||
|
|
||||||
|
# Handles enableing of filepicker
|
||||||
|
filepicker = args.f or None
|
||||||
|
|
|
@ -445,6 +445,8 @@ class CalibreDB():
|
||||||
cls.config = config
|
cls.config = config
|
||||||
cls.dispose()
|
cls.dispose()
|
||||||
|
|
||||||
|
# toDo: if db changed -> delete shelfs, delete download books, delete read boks, kobo sync??
|
||||||
|
|
||||||
if not config.config_calibre_dir:
|
if not config.config_calibre_dir:
|
||||||
config.invalidate()
|
config.invalidate()
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -20,11 +20,14 @@ from flask import render_template
|
||||||
from flask_babel import gettext as _
|
from flask_babel import gettext as _
|
||||||
from flask import g
|
from flask import g
|
||||||
from werkzeug.local import LocalProxy
|
from werkzeug.local import LocalProxy
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
from . import config, constants
|
from . import config, constants, ub, logger, db, calibre_db
|
||||||
from .ub import User
|
from .ub import User
|
||||||
|
|
||||||
|
|
||||||
|
log = logger.create()
|
||||||
|
|
||||||
def get_sidebar_config(kwargs=None):
|
def get_sidebar_config(kwargs=None):
|
||||||
kwargs = kwargs or []
|
kwargs = kwargs or []
|
||||||
if 'content' in kwargs:
|
if 'content' in kwargs:
|
||||||
|
@ -91,9 +94,23 @@ def get_sidebar_config(kwargs=None):
|
||||||
|
|
||||||
return sidebar
|
return sidebar
|
||||||
|
|
||||||
|
def get_readbooks_ids():
|
||||||
|
if not config.config_read_column:
|
||||||
|
readBooks = ub.session.query(ub.ReadBook).filter(ub.ReadBook.user_id == int(current_user.id))\
|
||||||
|
.filter(ub.ReadBook.read_status == ub.ReadBook.STATUS_FINISHED).all()
|
||||||
|
return frozenset([x.book_id for x in readBooks])
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
readBooks = calibre_db.session.query(db.cc_classes[config.config_read_column])\
|
||||||
|
.filter(db.cc_classes[config.config_read_column].value == True).all()
|
||||||
|
return frozenset([x.book for x in readBooks])
|
||||||
|
except KeyError:
|
||||||
|
log.error("Custom Column No.%d is not existing in calibre database", config.config_read_column)
|
||||||
|
return []
|
||||||
|
|
||||||
# Returns the template for rendering and includes the instance name
|
# Returns the template for rendering and includes the instance name
|
||||||
def render_title_template(*args, **kwargs):
|
def render_title_template(*args, **kwargs):
|
||||||
sidebar = get_sidebar_config(kwargs)
|
sidebar = get_sidebar_config(kwargs)
|
||||||
return render_template(instance=config.config_calibre_web_title, sidebar=sidebar,
|
return render_template(instance=config.config_calibre_web_title, sidebar=sidebar,
|
||||||
accept=constants.EXTENSIONS_UPLOAD,
|
accept=constants.EXTENSIONS_UPLOAD, read_book_ids=get_readbooks_ids(),
|
||||||
*args, **kwargs)
|
*args, **kwargs)
|
||||||
|
|
34
cps/shelf.py
34
cps/shelf.py
|
@ -381,27 +381,53 @@ def order_shelf(shelf_id):
|
||||||
title=_(u"Change order of Shelf: '%(name)s'", name=shelf.name),
|
title=_(u"Change order of Shelf: '%(name)s'", name=shelf.name),
|
||||||
shelf=shelf, page="shelforder")
|
shelf=shelf, page="shelforder")
|
||||||
|
|
||||||
|
def change_shelf_order(shelf_id, order):
|
||||||
|
result = calibre_db.session.query(db.Books).join(ub.BookShelf,ub.BookShelf.book_id == db.Books.id)\
|
||||||
|
.filter(ub.BookShelf.shelf == shelf_id).order_by(*order).all()
|
||||||
|
for index, entry in enumerate(result):
|
||||||
|
book = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id) \
|
||||||
|
.filter(ub.BookShelf.book_id == entry.id).first()
|
||||||
|
book.order = index
|
||||||
|
try:
|
||||||
|
ub.session.commit()
|
||||||
|
except OperationalError:
|
||||||
|
ub.session.rollback()
|
||||||
|
|
||||||
def render_show_shelf(shelf_type, shelf_id, page_no, sort_param):
|
def render_show_shelf(shelf_type, shelf_id, page_no, sort_param):
|
||||||
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
|
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
|
||||||
|
|
||||||
# check user is allowed to access shelf
|
# check user is allowed to access shelf
|
||||||
if shelf and check_shelf_view_permissions(shelf):
|
if shelf and check_shelf_view_permissions(shelf):
|
||||||
|
|
||||||
if shelf_type == 1:
|
if shelf_type == 1:
|
||||||
|
# order = [ub.BookShelf.order.asc()]
|
||||||
|
if sort_param == 'pubnew':
|
||||||
|
change_shelf_order(shelf_id, [db.Books.pubdate.desc()])
|
||||||
|
if sort_param == 'pubold':
|
||||||
|
change_shelf_order(shelf_id, [db.Books.pubdate])
|
||||||
|
if sort_param == 'abc':
|
||||||
|
change_shelf_order(shelf_id, [db.Books.sort])
|
||||||
|
if sort_param == 'zyx':
|
||||||
|
change_shelf_order(shelf_id, [db.Books.sort.desc()])
|
||||||
|
if sort_param == 'new':
|
||||||
|
change_shelf_order(shelf_id, [db.Books.timestamp.desc()])
|
||||||
|
if sort_param == 'old':
|
||||||
|
change_shelf_order(shelf_id, [db.Books.timestamp])
|
||||||
|
if sort_param == 'authaz':
|
||||||
|
change_shelf_order(shelf_id, [db.Books.author_sort.asc()])
|
||||||
|
if sort_param == 'authza':
|
||||||
|
change_shelf_order(shelf_id, [db.Books.author_sort.desc()])
|
||||||
page = "shelf.html"
|
page = "shelf.html"
|
||||||
pagesize = 0
|
pagesize = 0
|
||||||
order = [ub.BookShelf.order.asc()]
|
|
||||||
else:
|
else:
|
||||||
pagesize = sys.maxsize
|
pagesize = sys.maxsize
|
||||||
page = 'shelfdown.html'
|
page = 'shelfdown.html'
|
||||||
order = [ub.BookShelf.order.asc()]
|
|
||||||
|
|
||||||
result, __, pagination = calibre_db.fill_indexpage(page_no, pagesize,
|
result, __, pagination = calibre_db.fill_indexpage(page_no, pagesize,
|
||||||
db.Books,
|
db.Books,
|
||||||
ub.BookShelf.shelf == shelf_id,
|
ub.BookShelf.shelf == shelf_id,
|
||||||
order,
|
[ub.BookShelf.order.asc()],
|
||||||
ub.BookShelf,ub.BookShelf.book_id == db.Books.id)
|
ub.BookShelf,ub.BookShelf.book_id == db.Books.id)
|
||||||
|
|
||||||
# delete chelf entries where book is not existent anymore, can happen if book is deleted outside calibre-web
|
# delete chelf entries where book is not existent anymore, can happen if book is deleted outside calibre-web
|
||||||
wrong_entries = calibre_db.session.query(ub.BookShelf)\
|
wrong_entries = calibre_db.session.query(ub.BookShelf)\
|
||||||
.join(db.Books, ub.BookShelf.book_id == db.Books.id, isouter=True)\
|
.join(db.Books, ub.BookShelf.book_id == db.Books.id, isouter=True)\
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
body.serieslist.grid-view div.container-fluid>div>div.col-sm-10:before{
|
body.serieslist.grid-view div.container-fluid>div>div.col-sm-10:before{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cover .badge{
|
.cover .badge{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
color: #fff;
|
||||||
background-color: #cc7b19;
|
background-color: #cc7b19;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
|
@ -15,3 +15,8 @@ body.serieslist.grid-view div.container-fluid>div>div.col-sm-10:before{
|
||||||
.cover{
|
.cover{
|
||||||
box-shadow: 0 0 4px rgba(0,0,0,.6);
|
box-shadow: 0 0 4px rgba(0,0,0,.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cover .read{
|
||||||
|
padding: 0 0px;
|
||||||
|
line-height: 15px;
|
||||||
|
}
|
||||||
|
|
6
cps/static/css/libs/bootstrap-select.min.css
vendored
Normal file
6
cps/static/css/libs/bootstrap-select.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -116,6 +116,7 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d
|
||||||
display: block;
|
display: block;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
max-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container-fluid .discover{ margin-bottom: 50px; }
|
.container-fluid .discover{ margin-bottom: 50px; }
|
||||||
|
@ -132,12 +133,19 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container-fluid .book .cover img {
|
.container-fluid .book .cover span.img {
|
||||||
|
bottom: 0;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-fluid .book .cover span img {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 100%;
|
||||||
border: 1px solid #fff;
|
border: 1px solid #fff;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
height: 100%;
|
|
||||||
bottom: 0;
|
|
||||||
position: absolute;
|
|
||||||
-webkit-box-shadow: 0 5px 8px -6px #777;
|
-webkit-box-shadow: 0 5px 8px -6px #777;
|
||||||
-moz-box-shadow: 0 5px 8px -6px #777;
|
-moz-box-shadow: 0 5px 8px -6px #777;
|
||||||
box-shadow: 0 5px 8px -6px #777;
|
box-shadow: 0 5px 8px -6px #777;
|
||||||
|
@ -206,11 +214,22 @@ span.glyphicon.glyphicon-tags {
|
||||||
.navbar-default .navbar-toggle .icon-bar {background-color: #000; }
|
.navbar-default .navbar-toggle .icon-bar {background-color: #000; }
|
||||||
.navbar-default .navbar-toggle {border-color: #000; }
|
.navbar-default .navbar-toggle {border-color: #000; }
|
||||||
.cover { margin-bottom: 10px; }
|
.cover { margin-bottom: 10px; }
|
||||||
|
|
||||||
.cover .badge{
|
.cover .badge{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 2px;
|
top: 2px;
|
||||||
left: 2px;
|
left: 2px;
|
||||||
background-color: #777;
|
color: #000;
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
.cover .read{
|
||||||
|
left: auto;
|
||||||
|
right: 2px;
|
||||||
|
width: 17px;
|
||||||
|
height: 17px;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px;
|
||||||
}
|
}
|
||||||
.cover-height { max-height: 100px;}
|
.cover-height { max-height: 100px;}
|
||||||
|
|
||||||
|
|
|
@ -249,18 +249,26 @@ promisePublishers.done(function() {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#search").on("change input.typeahead:selected", function() {
|
$("#search").on("change input.typeahead:selected", function(event) {
|
||||||
|
if (event.target.type == "search" && event.target.tagName == "INPUT") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var form = $("form").serialize();
|
var form = $("form").serialize();
|
||||||
$.getJSON( getPath() + "/get_matching_tags", form, function( data ) {
|
$.getJSON( getPath() + "/get_matching_tags", form, function( data ) {
|
||||||
$(".tags_click").each(function() {
|
$(".tags_click").each(function() {
|
||||||
if ($.inArray(parseInt($(this).children("input").first().val(), 10), data.tags) === -1 ) {
|
if ($.inArray(parseInt($(this).val(), 10), data.tags) === -1) {
|
||||||
if (!($(this).hasClass("active"))) {
|
if(!$(this).prop("selected")) {
|
||||||
$(this).addClass("disabled");
|
$(this).prop("disabled", true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$(this).removeClass("disabled");
|
$(this).prop("disabled", false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
$("#include_tag option:selected").each(function () {
|
||||||
|
$("#exclude_tag").find("[value="+$(this).val()+"]").prop("disabled", true);
|
||||||
|
});
|
||||||
|
$('#include_tag').selectpicker("refresh");
|
||||||
|
$('#exclude_tag').selectpicker("refresh");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
9
cps/static/js/libs/bootstrap-select.min.js
vendored
Normal file
9
cps/static/js/libs/bootstrap-select.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
8
cps/static/js/libs/bootstrap-select/defaults-cs.min.js
vendored
Normal file
8
cps/static/js/libs/bootstrap-select/defaults-cs.min.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2020 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e,n){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return n(e)}):"object"==typeof module&&module.exports?module.exports=n(require("jquery")):n(e.jQuery)}(this,function(e){e.fn.selectpicker.defaults={noneSelectedText:"Vyberte ze seznamu",noneResultsText:"Pro hled\xe1n\xed {0} nebyly nalezeny \u017e\xe1dn\xe9 v\xfdsledky",countSelectedText:"Vybran\xe9 {0} z {1}",maxOptionsText:["Limit p\u0159ekro\u010den ({n} {var} max)","Limit skupiny p\u0159ekro\u010den ({n} {var} max)",["polo\u017eek","polo\u017eka"]],multipleSeparator:", ",selectAllText:"Vybrat v\u0161e",deselectAllText:"Zru\u0161it v\xfdb\u011br"}});
|
8
cps/static/js/libs/bootstrap-select/defaults-de.min.js
vendored
Normal file
8
cps/static/js/libs/bootstrap-select/defaults-de.min.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2020 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e,t){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery")):t(e.jQuery)}(this,function(e){e.fn.selectpicker.defaults={noneSelectedText:"Bitte w\xe4hlen...",noneResultsText:"Keine Ergebnisse f\xfcr {0}",countSelectedText:function(e,t){return 1==e?"{0} Element ausgew\xe4hlt":"{0} Elemente ausgew\xe4hlt"},maxOptionsText:function(e,t){return[1==e?"Limit erreicht ({n} Element max.)":"Limit erreicht ({n} Elemente max.)",1==t?"Gruppen-Limit erreicht ({n} Element max.)":"Gruppen-Limit erreicht ({n} Elemente max.)"]},selectAllText:"Alles ausw\xe4hlen",deselectAllText:"Nichts ausw\xe4hlen",multipleSeparator:", "}});
|
8
cps/static/js/libs/bootstrap-select/defaults-es.min.js
vendored
Normal file
8
cps/static/js/libs/bootstrap-select/defaults-es.min.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2020 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e,o){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return o(e)}):"object"==typeof module&&module.exports?module.exports=o(require("jquery")):o(e.jQuery)}(this,function(e){e.fn.selectpicker.defaults={noneSelectedText:"No hay selecci\xf3n",noneResultsText:"No hay resultados {0}",countSelectedText:"Seleccionados {0} de {1}",maxOptionsText:["L\xedmite alcanzado ({n} {var} max)","L\xedmite del grupo alcanzado({n} {var} max)",["elementos","element"]],multipleSeparator:", ",selectAllText:"Seleccionar Todos",deselectAllText:"Desmarcar Todos"}});
|
8
cps/static/js/libs/bootstrap-select/defaults-fi.min.js
vendored
Normal file
8
cps/static/js/libs/bootstrap-select/defaults-fi.min.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2020 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e,t){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery")):t(e.jQuery)}(this,function(e){e.fn.selectpicker.defaults={noneSelectedText:"Ei valintoja",noneResultsText:"Ei hakutuloksia {0}",countSelectedText:function(e,t){return 1==e?"{0} valittu":"{0} valitut"},maxOptionsText:function(e,t){return["Valintojen maksimim\xe4\xe4r\xe4 ({n} saavutettu)","Ryhm\xe4n maksimim\xe4\xe4r\xe4 ({n} saavutettu)"]},selectAllText:"Valitse kaikki",deselectAllText:"Poista kaikki",multipleSeparator:", "}});
|
8
cps/static/js/libs/bootstrap-select/defaults-fr.min.js
vendored
Normal file
8
cps/static/js/libs/bootstrap-select/defaults-fr.min.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2020 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e,t){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery")):t(e.jQuery)}(this,function(e){e.fn.selectpicker.defaults={noneSelectedText:"Aucune s\xe9lection",noneResultsText:"Aucun r\xe9sultat pour {0}",countSelectedText:function(e,t){return 1<e?"{0} \xe9l\xe9ments s\xe9lectionn\xe9s":"{0} \xe9l\xe9ment s\xe9lectionn\xe9"},maxOptionsText:function(e,t){return[1<e?"Limite atteinte ({n} \xe9l\xe9ments max)":"Limite atteinte ({n} \xe9l\xe9ment max)",1<t?"Limite du groupe atteinte ({n} \xe9l\xe9ments max)":"Limite du groupe atteinte ({n} \xe9l\xe9ment max)"]},multipleSeparator:", ",selectAllText:"Tout s\xe9lectionner",deselectAllText:"Tout d\xe9s\xe9lectionner"}});
|
8
cps/static/js/libs/bootstrap-select/defaults-hu.min.js
vendored
Normal file
8
cps/static/js/libs/bootstrap-select/defaults-hu.min.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2020 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e,t){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery")):t(e.jQuery)}(this,function(e){e.fn.selectpicker.defaults={noneSelectedText:"V\xe1lasszon!",noneResultsText:"Nincs tal\xe1lat {0}",countSelectedText:function(e,t){return"{0} elem kiv\xe1lasztva"},maxOptionsText:function(e,t){return["Legfeljebb {n} elem v\xe1laszthat\xf3","A csoportban legfeljebb {n} elem v\xe1laszthat\xf3"]},selectAllText:"Mind",deselectAllText:"Egyik sem",multipleSeparator:", "}});
|
8
cps/static/js/libs/bootstrap-select/defaults-it.min.js
vendored
Normal file
8
cps/static/js/libs/bootstrap-select/defaults-it.min.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2020 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e,t){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery")):t(e.jQuery)}(this,function(e){e.fn.selectpicker.defaults={noneSelectedText:"Nessuna selezione",noneResultsText:"Nessun risultato per {0}",countSelectedText:function(e,t){return 1==e?"Selezionato {0} di {1}":"Selezionati {0} di {1}"},maxOptionsText:["Limite raggiunto ({n} {var} max)","Limite del gruppo raggiunto ({n} {var} max)",["elementi","elemento"]],multipleSeparator:", ",selectAllText:"Seleziona Tutto",deselectAllText:"Deseleziona Tutto"}});
|
8
cps/static/js/libs/bootstrap-select/defaults-ja.min.js
vendored
Normal file
8
cps/static/js/libs/bootstrap-select/defaults-ja.min.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2020 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e,t){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery")):t(e.jQuery)}(this,function(e){e.fn.selectpicker.defaults={noneSelectedText:"\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093",noneResultsText:"'{0}'\u306f\u898b\u3064\u304b\u308a\u307e\u305b\u3093",countSelectedText:"{0}/{1} \u9078\u629e\u4e2d",maxOptionsText:["\u9078\u629e\u4e0a\u9650\u6570\u3092\u8d85\u3048\u3066\u3044\u307e\u3059(\u6700\u5927{n}{var})","\u30b0\u30eb\u30fc\u30d7\u306e\u9078\u629e\u4e0a\u9650\u6570\u3092\u8d85\u3048\u3066\u3044\u307e\u3059(\u6700\u5927{n}{var})",["\u30a2\u30a4\u30c6\u30e0","\u30a2\u30a4\u30c6\u30e0"]],selectAllText:"\u5168\u3066\u9078\u629e",deselectAllText:"\u9078\u629e\u3092\u30af\u30ea\u30a2",multipleSeparator:", "}});
|
8
cps/static/js/libs/bootstrap-select/defaults-km.min.js
vendored
Normal file
8
cps/static/js/libs/bootstrap-select/defaults-km.min.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2020 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e,t){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery")):t(e.jQuery)}(this,function(e){e.fn.selectpicker.defaults={noneSelectedText:"\u1798\u17b7\u1793\u1798\u17b6\u1793\u17a2\u17d2\u179c\u17b8\u1794\u17b6\u1793\u1787\u17d2\u179a\u17be\u179f\u179a\u17be\u179f",noneResultsText:"\u1798\u17b7\u1793\u1798\u17b6\u1793\u179b\u1791\u17d2\u1792\u1795\u179b {0}",countSelectedText:function(e,t){return"{0} \u1792\u17b6\u178f\u17bb\u178a\u17c2\u179b\u1794\u17b6\u1793\u1787\u17d2\u179a\u17be\u179f"},maxOptionsText:function(e,t){return[1==e?"\u1788\u17b6\u1793\u178a\u179b\u17cb\u178a\u17c2\u1793\u1780\u17c6\u178e\u178f\u17cb ( {n} \u1792\u17b6\u178f\u17bb\u17a2\u178f\u17b7\u1794\u179a\u1798\u17b6)":"\u17a2\u178f\u17b7\u1794\u179a\u1798\u17b6\u1788\u17b6\u1793\u178a\u179b\u17cb\u178a\u17c2\u1793\u1780\u17c6\u178e\u178f\u17cb ( {n} \u1792\u17b6\u178f\u17bb)",1==t?"\u178a\u17c2\u1793\u1780\u17c6\u178e\u178f\u17cb\u1780\u17d2\u179a\u17bb\u1798\u1788\u17b6\u1793\u178a\u179b\u17cb ( {n} \u17a2\u178f\u17b7\u1794\u179a\u1798\u17b6\u1792\u17b6\u178f\u17bb)":"\u17a2\u178f\u17b7\u1794\u179a\u1798\u17b6\u1780\u17d2\u179a\u17bb\u1798\u1788\u17b6\u1793\u178a\u179b\u17cb\u178a\u17c2\u1793\u1780\u17c6\u178e\u178f\u17cb ( {n} \u1792\u17b6\u178f\u17bb)"]},selectAllText:"\u1787\u17d2\u179a\u17be\u179f\u200b\u1799\u1780\u200b\u1791\u17b6\u17c6\u1784\u17a2\u179f\u17cb",deselectAllText:"\u1798\u17b7\u1793\u1787\u17d2\u179a\u17be\u179f\u200b\u1799\u1780\u200b\u1791\u17b6\u17c6\u1784\u17a2\u179f",multipleSeparator:", "}});
|
8
cps/static/js/libs/bootstrap-select/defaults-nl.min.js
vendored
Normal file
8
cps/static/js/libs/bootstrap-select/defaults-nl.min.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2020 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e,t){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery")):t(e.jQuery)}(this,function(e){e.fn.selectpicker.defaults={noneSelectedText:"Niets geselecteerd",noneResultsText:"Geen resultaten gevonden voor {0}",countSelectedText:"{0} van {1} geselecteerd",maxOptionsText:["Limiet bereikt ({n} {var} max)","Groep limiet bereikt ({n} {var} max)",["items","item"]],selectAllText:"Alles selecteren",deselectAllText:"Alles deselecteren",multipleSeparator:", "}});
|
8
cps/static/js/libs/bootstrap-select/defaults-pl.min.js
vendored
Normal file
8
cps/static/js/libs/bootstrap-select/defaults-pl.min.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2020 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e,n){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return n(e)}):"object"==typeof module&&module.exports?module.exports=n(require("jquery")):n(e.jQuery)}(this,function(e){e.fn.selectpicker.defaults={noneSelectedText:"Nic nie zaznaczono",noneResultsText:"Brak wynik\xf3w wyszukiwania {0}",countSelectedText:"Zaznaczono {0} z {1}",maxOptionsText:["Osi\u0105gni\u0119to limit ({n} {var} max)","Limit grupy osi\u0105gni\u0119ty ({n} {var} max)",["elementy","element"]],selectAllText:"Zaznacz wszystkie",deselectAllText:"Odznacz wszystkie",multipleSeparator:", "}});
|
8
cps/static/js/libs/bootstrap-select/defaults-ru.min.js
vendored
Normal file
8
cps/static/js/libs/bootstrap-select/defaults-ru.min.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2020 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e,t){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery")):t(e.jQuery)}(this,function(e){e.fn.selectpicker.defaults={noneSelectedText:"\u041d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043e",noneResultsText:"\u0421\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0439 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e {0}",countSelectedText:"\u0412\u044b\u0431\u0440\u0430\u043d\u043e {0} \u0438\u0437 {1}",maxOptionsText:["\u0414\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442 \u043f\u0440\u0435\u0434\u0435\u043b ({n} {var} \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c)","\u0414\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442 \u043f\u0440\u0435\u0434\u0435\u043b \u0432 \u0433\u0440\u0443\u043f\u043f\u0435 ({n} {var} \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c)",["\u0448\u0442.","\u0448\u0442."]],doneButtonText:"\u0417\u0430\u043a\u0440\u044b\u0442\u044c",selectAllText:"\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435",deselectAllText:"\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u0441\u0435",multipleSeparator:", "}});
|
8
cps/static/js/libs/bootstrap-select/defaults-sv.min.js
vendored
Normal file
8
cps/static/js/libs/bootstrap-select/defaults-sv.min.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2020 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e,t){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery")):t(e.jQuery)}(this,function(e){e.fn.selectpicker.defaults={noneSelectedText:"Inget valt",noneResultsText:"Inget s\xf6kresultat matchar {0}",countSelectedText:function(e,t){return 1===e?"{0} alternativ valt":"{0} alternativ valda"},maxOptionsText:function(e,t){return["Gr\xe4ns uppn\xe5d (max {n} alternativ)","Gr\xe4ns uppn\xe5d (max {n} gruppalternativ)"]},selectAllText:"Markera alla",deselectAllText:"Avmarkera alla",multipleSeparator:", "}});
|
8
cps/static/js/libs/bootstrap-select/defaults-tr.min.js
vendored
Normal file
8
cps/static/js/libs/bootstrap-select/defaults-tr.min.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2020 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e,i){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return i(e)}):"object"==typeof module&&module.exports?module.exports=i(require("jquery")):i(e.jQuery)}(this,function(e){e.fn.selectpicker.defaults={noneSelectedText:"Hi\xe7biri se\xe7ilmedi",noneResultsText:"Hi\xe7bir sonu\xe7 bulunamad\u0131 {0}",countSelectedText:function(e,i){return"{0} \xf6\u011fe se\xe7ildi"},maxOptionsText:function(e,i){return[1==e?"Limit a\u015f\u0131ld\u0131 (maksimum {n} say\u0131da \xf6\u011fe )":"Limit a\u015f\u0131ld\u0131 (maksimum {n} say\u0131da \xf6\u011fe)","Grup limiti a\u015f\u0131ld\u0131 (maksimum {n} say\u0131da \xf6\u011fe)"]},selectAllText:"T\xfcm\xfcn\xfc Se\xe7",deselectAllText:"Se\xe7iniz",multipleSeparator:", "}});
|
8
cps/static/js/libs/bootstrap-select/defaults-zh_Hans_CN.min.js
vendored
Normal file
8
cps/static/js/libs/bootstrap-select/defaults-zh_Hans_CN.min.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/*!
|
||||||
|
* Bootstrap-select v1.13.14 (https://developer.snapappointments.com/bootstrap-select)
|
||||||
|
*
|
||||||
|
* Copyright 2012-2020 SnapAppointments, LLC
|
||||||
|
* Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
!function(e,t){void 0===e&&void 0!==window&&(e=window),"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery")):t(e.jQuery)}(this,function(e){e.fn.selectpicker.defaults={noneSelectedText:"\u6ca1\u6709\u9009\u4e2d\u4efb\u4f55\u9879",noneResultsText:"\u6ca1\u6709\u627e\u5230\u5339\u914d\u9879",countSelectedText:"\u9009\u4e2d{1}\u4e2d\u7684{0}\u9879",maxOptionsText:["\u8d85\u51fa\u9650\u5236 (\u6700\u591a\u9009\u62e9{n}\u9879)","\u7ec4\u9009\u62e9\u8d85\u51fa\u9650\u5236(\u6700\u591a\u9009\u62e9{n}\u7ec4)"],multipleSeparator:", ",selectAllText:"\u5168\u9009",deselectAllText:"\u53d6\u6d88\u5168\u9009"}});
|
|
@ -509,6 +509,19 @@ $(function() {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#toggle_order_shelf").click(function() {
|
||||||
|
$("#new").toggleClass("disabled");
|
||||||
|
$("#old").toggleClass("disabled");
|
||||||
|
$("#asc").toggleClass("disabled");
|
||||||
|
$("#desc").toggleClass("disabled");
|
||||||
|
$("#auth_az").toggleClass("disabled");
|
||||||
|
$("#auth_za").toggleClass("disabled");
|
||||||
|
$("#pub_new").toggleClass("disabled");
|
||||||
|
$("#pub_old").toggleClass("disabled");
|
||||||
|
var alternative_text = $("#toggle_order_shelf").data('alt-text');
|
||||||
|
$("#toggle_order_shelf")[0].attributes['data-alt-text'].value = $("#toggle_order_shelf").html();
|
||||||
|
$("#toggle_order_shelf").html(alternative_text);
|
||||||
|
});
|
||||||
|
|
||||||
$("#btndeluser").click(function() {
|
$("#btndeluser").click(function() {
|
||||||
ConfirmDialog(
|
ConfirmDialog(
|
||||||
|
|
|
@ -36,7 +36,10 @@
|
||||||
<div id="books" class="col-sm-3 col-lg-2 col-xs-6 book">
|
<div id="books" class="col-sm-3 col-lg-2 col-xs-6 book">
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a href="{{ url_for('web.show_book', book_id=entry.id) }}">
|
<a href="{{ url_for('web.show_book', book_id=entry.id) }}">
|
||||||
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
<span class="img">
|
||||||
|
{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
||||||
|
{% if entry.id in read_book_ids %}<span class="badge read glyphicon glyphicon-ok"></span>{% endif %}
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
|
|
|
@ -16,12 +16,19 @@
|
||||||
<div id="collapseOne" class="panel-collapse collapse in">
|
<div id="collapseOne" class="panel-collapse collapse in">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<label for="config_calibre_dir">{{_('Location of Calibre Database')}}</label>
|
<label for="config_calibre_dir">{{_('Location of Calibre Database')}}</label>
|
||||||
<div class="form-group required input-group">
|
<div class="form-group required{% if filepicker %} input-group{% endif %}">
|
||||||
<input type="text" class="form-control" id="config_calibre_dir" name="config_calibre_dir" value="{% if config.config_calibre_dir != None %}{{ config.config_calibre_dir }}{% endif %}" autocomplete="off">
|
<input type="text" class="form-control" id="config_calibre_dir" name="config_calibre_dir" value="{% if config.config_calibre_dir != None %}{{ config.config_calibre_dir }}{% endif %}" autocomplete="off">
|
||||||
|
{% if filepicker %}
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button type="button" data-toggle="modal" id="converter_modal_path" data-link="config_calibre_dir" data-filefilter="metadata.db" data-target="#fileModal" id="library_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
<button type="button" data-toggle="modal" id="converter_modal_path" data-link="config_calibre_dir" data-filefilter="metadata.db" data-target="#fileModal" id="library_path" class="btn btn-default"><span class="glyphicon glyphicon-folder-open"></span></button>
|
||||||
</span>
|
</span>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
{% if not filepicker %}
|
||||||
|
<div class="form-group">
|
||||||
|
<label id="filepicker-hint">{{_('To activate serverside filepicker start Calibre-Web with -f optionn')}}</label>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% if feature_support['gdrive'] %}
|
{% if feature_support['gdrive'] %}
|
||||||
<div class="form-group required">
|
<div class="form-group required">
|
||||||
<input type="checkbox" id="config_use_google_drive" name="config_use_google_drive" data-control="gdrive_settings" {% if config.config_use_google_drive %}checked{% endif %} >
|
<input type="checkbox" id="config_use_google_drive" name="config_use_google_drive" data-control="gdrive_settings" {% if config.config_use_google_drive %}checked{% endif %} >
|
||||||
|
|
|
@ -9,7 +9,10 @@
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
{% if entry.has_cover is defined %}
|
{% if entry.has_cover is defined %}
|
||||||
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||||
|
<span class="img">
|
||||||
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
||||||
|
{% if entry.id in read_book_ids %}<span class="badge read glyphicon glyphicon-ok"></span>{% endif %}
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -29,8 +29,10 @@
|
||||||
<div class="col-sm-3 col-lg-2 col-xs-6 book sortable" {% if entry[0].sort %}data-name="{{entry[0].series[0].name}}"{% endif %} data-id="{% if entry[0].series[0].name %}{{entry[0].series[0].name}}{% endif %}">
|
<div class="col-sm-3 col-lg-2 col-xs-6 book sortable" {% if entry[0].sort %}data-name="{{entry[0].series[0].name}}"{% endif %} data-id="{% if entry[0].series[0].name %}{{entry[0].series[0].name}}{% endif %}">
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a href="{{url_for('web.books_list', data=data, sort_param='new', book_id=entry[0].series[0].id )}}">
|
<a href="{{url_for('web.books_list', data=data, sort_param='new', book_id=entry[0].series[0].id )}}">
|
||||||
{{ book_cover_image(entry[0], entry[0].id|get_book_thumbnails(thumbnails)) }}
|
<span class="img">
|
||||||
<span class="badge">{{entry.count}}</span>
|
{{ book_cover_image(entry[0], entry[0].id|get_book_thumbnails(thumbnails)) }}
|
||||||
|
<span class="badge">{{entry.count}}</span>
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
|
|
|
@ -9,7 +9,10 @@
|
||||||
<div class="col-sm-3 col-lg-2 col-xs-6 book" id="books_rand">
|
<div class="col-sm-3 col-lg-2 col-xs-6 book" id="books_rand">
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||||
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
<span class="img">
|
||||||
|
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
||||||
|
{% if entry.id in read_book_ids %}<span class="badge read glyphicon glyphicon-ok"></span>{% endif %}
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
|
@ -83,7 +86,10 @@
|
||||||
<div class="col-sm-3 col-lg-2 col-xs-6 book" id="books">
|
<div class="col-sm-3 col-lg-2 col-xs-6 book" id="books">
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||||
|
<span class="img">
|
||||||
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
||||||
|
{% if entry.id in read_book_ids %}<span class="badge read glyphicon glyphicon-ok"></span>{% endif %}
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
|
|
|
@ -44,7 +44,10 @@
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
{% if entry.has_cover is defined %}
|
{% if entry.has_cover is defined %}
|
||||||
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||||
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
<span class="img">
|
||||||
|
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
||||||
|
{% if entry.id in read_book_ids %}<span class="badge read glyphicon glyphicon-ok"></span>{% endif %}
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -31,87 +31,87 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<label for="include_tag">{{_('Tags')}}</label>
|
<div class="form-group">
|
||||||
<div class="form-group" id="tag">
|
<label for="read_status">{{_('Read Status')}}</label>
|
||||||
<div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
|
<select name="read_status" id="read_status" class="form-control">
|
||||||
{% for tag in tags %}
|
<option value="" selected></option>
|
||||||
<label id="tag_{{tag.id}}" class="btn btn-primary tags_click">
|
<option value="True" >{{_('Yes')}}</option>
|
||||||
<input type="checkbox" autocomplete="off" name="include_tag" id="include_tag" value="{{tag.id}}">{{tag.name}}</input>
|
<option value="False" >{{_('No')}}</option>
|
||||||
</label>
|
</select>
|
||||||
{% endfor %}
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="form-group col-sm-6" id="tag">
|
||||||
|
<div><label for="include_tag">{{_('Tags')}}</label></div>
|
||||||
|
<select class="selectpicker" name="include_tag" id="include_tag" data-live-search="true" data-style="btn-primary" multiple>
|
||||||
|
{% for tag in tags %}
|
||||||
|
<option class="tags_click" value="{{tag.id}}">{{tag.name}}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group col-sm-6">
|
||||||
|
<div><label for="exclude_tag">{{_('Exclude Tags')}}</label></div>
|
||||||
|
<select class="selectpicker" name="exclude_tag" id="exclude_tag" data-live-search="true" data-style="btn-danger" multiple>
|
||||||
|
{% for tag in tags %}
|
||||||
|
<option class="tags_click" value="{{tag.id}}">{{tag.name}}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<label for="exclude_tag">{{_('Exclude Tags')}}</label>
|
<div class="row">
|
||||||
<div class="form-group">
|
<div class="form-group col-sm-6">
|
||||||
<div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
|
<div><label for="include_serie">{{_('Series')}}</label></div>
|
||||||
{% for tag in tags %}
|
<select class="selectpicker" name="include_serie" id="include_serie" data-live-search="true" data-style="btn-primary" multiple>
|
||||||
<label id="exclude_tag_{{tag.id}}" class="btn btn-danger tags_click">
|
{% for serie in series %}
|
||||||
<input type="checkbox" autocomplete="off" name="exclude_tag" id="exclude_tag" value="{{tag.id}}">{{tag.name}}</input>
|
<option value="{{serie.id}}">{{serie.name}}</option>
|
||||||
</label>
|
{% endfor %}
|
||||||
{% endfor %}
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="form-group col-sm-6">
|
||||||
<label for="include_serie">{{_('Series')}}</label>
|
<div><label for="exclude_serie">{{_('Exclude Series')}}</label></div>
|
||||||
<div class="form-group">
|
<select class="selectpicker" name="exclude_serie" id="exclude_serie" data-live-search="true" data-style="btn-danger" multiple>
|
||||||
<div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
|
{% for serie in series %}
|
||||||
{% for serie in series %}
|
<option value="{{serie.id}}">{{serie.name}}</option>
|
||||||
<label id="serie_{{serie.id}}" class="btn btn-primary serie_click">
|
{% endfor %}
|
||||||
<input type="checkbox" autocomplete="off" name="include_serie" id="include_serie" value="{{serie.id}}">{{serie.name}}</input>
|
</select>
|
||||||
</label>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<label for="exclude_serie">{{_('Exclude Series')}}</label>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
|
|
||||||
{% for serie in series %}
|
|
||||||
<label id="exclude_serie_{{serie.id}}" class="btn btn-danger serie_click">
|
|
||||||
<input type="checkbox" autocomplete="off" name="exclude_serie" id="exclude_serie" value="{{serie.id}}">{{serie.name}}</input>
|
|
||||||
</label>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if languages %}
|
{% if languages %}
|
||||||
<label for="include_language">{{_('Languages')}}</label>
|
<div class="row">
|
||||||
<div class="form-group">
|
<div class="form-group col-sm-6">
|
||||||
<div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
|
<div><label for="include_language">{{_('Languages')}}</label></div>
|
||||||
|
<select class="selectpicker" name="include_language" id="include_language" data-live-search="true" data-style="btn-primary" multiple>
|
||||||
{% for language in languages %}
|
{% for language in languages %}
|
||||||
<label id="language_{{language.id}}" class="btn btn-primary serie_click">
|
<option value="{{language.id}}">{{language.name}}</option>
|
||||||
<input type="checkbox" autocomplete="off" name="include_language" id="include_language" value="{{language.id}}">{{language.name}}</input>
|
|
||||||
</label>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<label for="exclude_language">{{_('Exclude Languages')}}</label>
|
<div class="form-group col-sm-6">
|
||||||
<div class="form-group">
|
<div><label for="exclude_language">{{_('Exclude Languages')}}</label></div>
|
||||||
<div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
|
<select class="selectpicker" name="exclude_language" id="exclude_language" data-live-search="true" data-style="btn-danger" multiple>
|
||||||
{% for language in languages %}
|
{% for language in languages %}
|
||||||
<label id="exclude_language_{{language.id}}" class="btn btn-danger language_click">
|
<option value="{{language.id}}">{{language.name}}</option>
|
||||||
<input type="checkbox" autocomplete="off" name="exclude_language" id="exclude_language" value="{{language.id}}">{{language.name}}</input>
|
|
||||||
</label>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</select>
|
||||||
</div>
|
|
||||||
{% endif%}
|
|
||||||
<label for="include_extension">{{_('Extensions')}}</label>
|
|
||||||
<div class="form-group" id="extension">
|
|
||||||
<div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
|
|
||||||
{% for extension in extensions %}
|
|
||||||
<label id="extension_{{extension.format}}" class="btn btn-primary extension_click">
|
|
||||||
<input type="checkbox" autocomplete="off" name="include_extension" id="include_extension" value="{{extension.format}}">{{extension.format}}</input>
|
|
||||||
</label>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<label for="exclude_extension">{{_('Exclude Extensions')}}</label>
|
{% endif%}
|
||||||
<div class="form-group">
|
<div class="row">
|
||||||
<div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
|
<div class="form-group col-sm-6">
|
||||||
|
<div><label for="include_extension">{{_('Extensions')}}</label></div>
|
||||||
|
<select id="include_extension" class="selectpicker" name="include_extension" id="include_extension" data-live-search="true" data-style="btn-primary" multiple>
|
||||||
{% for extension in extensions %}
|
{% for extension in extensions %}
|
||||||
<label id="exclude_extension_{{extension.format}}" class="btn btn-danger extension_click">
|
<option value="{{extension.format}}">{{extension.format}}</option>
|
||||||
<input type="checkbox" autocomplete="off" name="exclude_extension" id="exclude_extension" value="{{extension.format}}">{{extension.format}}</input>
|
{% endfor %}
|
||||||
</label>
|
</select>
|
||||||
{% endfor %}
|
</div>
|
||||||
</div>
|
<div class="form-group col-sm-6">
|
||||||
|
<div><label for="exclude_extension">{{_('Exclude Extensions')}}</label></div>
|
||||||
|
<select id="exclude_extension" class="selectpicker" name="exclude_extension" id="exclude_extension" data-live-search="true" data-style="btn-danger" multiple>
|
||||||
|
{% for extension in extensions %}
|
||||||
|
<option value="{{extension.format}}">{{extension.format}}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="form-group col-sm-6">
|
<div class="form-group col-sm-6">
|
||||||
|
@ -189,10 +189,13 @@
|
||||||
<script src="{{ url_for('static', filename='js/libs/bootstrap-rating-input.min.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/libs/bootstrap-rating-input.min.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/libs/typeahead.bundle.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/libs/typeahead.bundle.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/edit_books.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/edit_books.js') }}"></script>
|
||||||
<script>
|
<script src="{{ url_for('static', filename='js/libs/bootstrap-select.min.js')}}"></script>
|
||||||
</script>
|
{% if not g.user.locale == 'en' %}
|
||||||
|
<script src="{{ url_for('static', filename='js/libs/bootstrap-select/defaults-' + g.user.locale + '.min.js') }}" charset="UTF-8"></script>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block header %}
|
{% block header %}
|
||||||
<link href="{{ url_for('static', filename='css/libs/typeahead.css') }}" rel="stylesheet" media="screen">
|
<link href="{{ url_for('static', filename='css/libs/typeahead.css') }}" rel="stylesheet" media="screen">
|
||||||
<link href="{{ url_for('static', filename='css/libs/bootstrap-datepicker3.min.css') }}" rel="stylesheet" media="screen">
|
<link href="{{ url_for('static', filename='css/libs/bootstrap-datepicker3.min.css') }}" rel="stylesheet" media="screen">
|
||||||
|
<link href="{{ url_for('static', filename='css/libs/bootstrap-select.min.css') }}" rel="stylesheet" >
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -9,8 +9,10 @@
|
||||||
{% if g.user.is_authenticated %}
|
{% if g.user.is_authenticated %}
|
||||||
{% if (g.user.role_edit_shelfs() and shelf.is_public ) or not shelf.is_public %}
|
{% if (g.user.role_edit_shelfs() and shelf.is_public ) or not shelf.is_public %}
|
||||||
<div class="btn btn-danger" id="delete_shelf" data-value="{{ shelf.id }}">{{ _('Delete this Shelf') }}</div>
|
<div class="btn btn-danger" id="delete_shelf" data-value="{{ shelf.id }}">{{ _('Delete this Shelf') }}</div>
|
||||||
<a id="edit_shelf" href="{{ url_for('shelf.edit_shelf', shelf_id=shelf.id) }}" class="btn btn-primary">{{ _('Edit Shelf') }} </a>
|
<a id="edit_shelf" href="{{ url_for('shelf.edit_shelf', shelf_id=shelf.id) }}" class="btn btn-primary">{{ _('Edit Shelf Properties') }} </a>
|
||||||
{% if entries.__len__() %}
|
{% if entries.__len__() %}
|
||||||
|
<a id="order_shelf" href="{{ url_for('shelf.order_shelf', shelf_id=shelf.id) }}" class="btn btn-primary">{{ _('Arrange books manually') }} </a>
|
||||||
|
<button id="toggle_order_shelf" type="button" data-alt-text="{{ _('Disable Change order') }}" class="btn btn-primary">{{ _('Enable Change order') }}</button>
|
||||||
<div class="filterheader hidden-xs hidden-sm">
|
<div class="filterheader hidden-xs hidden-sm">
|
||||||
<a data-toggle="tooltip" title="{{_('Sort according to book date, newest first')}}" id="new" class="btn btn-primary disabled" href="{{url_for('shelf.show_shelf', shelf_id=shelf.id, sort_param='new')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
<a data-toggle="tooltip" title="{{_('Sort according to book date, newest first')}}" id="new" class="btn btn-primary disabled" href="{{url_for('shelf.show_shelf', shelf_id=shelf.id, sort_param='new')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||||
<a data-toggle="tooltip" title="{{_('Sort according to book date, oldest first')}}" id="old" class="btn btn-primary disabled" href="{{url_for('shelf.show_shelf', shelf_id=shelf.id, sort_param='old')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
<a data-toggle="tooltip" title="{{_('Sort according to book date, oldest first')}}" id="old" class="btn btn-primary disabled" href="{{url_for('shelf.show_shelf', shelf_id=shelf.id, sort_param='old')}}"><span class="glyphicon glyphicon-book"></span> <span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||||
|
@ -20,8 +22,6 @@
|
||||||
<a data-toggle="tooltip" title="{{_('Sort authors in reverse alphabetical order')}}" id="auth_za" class="btn btn-primary disabled" href="{{url_for('shelf.show_shelf', shelf_id=shelf.id, sort_param='authza')}}"><span class="glyphicon glyphicon-user"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
<a data-toggle="tooltip" title="{{_('Sort authors in reverse alphabetical order')}}" id="auth_za" class="btn btn-primary disabled" href="{{url_for('shelf.show_shelf', shelf_id=shelf.id, sort_param='authza')}}"><span class="glyphicon glyphicon-user"></span><span class="glyphicon glyphicon-sort-by-alphabet-alt"></span></a>
|
||||||
<a data-toggle="tooltip" title="{{_('Sort according to publishing date, newest first')}}" id="pub_new" class="btn btn-primary disabled" href="{{url_for('shelf.show_shelf', shelf_id=shelf.id, sort_param='pubnew')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
<a data-toggle="tooltip" title="{{_('Sort according to publishing date, newest first')}}" id="pub_new" class="btn btn-primary disabled" href="{{url_for('shelf.show_shelf', shelf_id=shelf.id, sort_param='pubnew')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order"></span></a>
|
||||||
<a data-toggle="tooltip" title="{{_('Sort according to publishing date, oldest first')}}" id="pub_old" class="btn btn-primary disabled" href="{{url_for('shelf.show_shelf', shelf_id=shelf.id, sort_param='pubold')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
<a data-toggle="tooltip" title="{{_('Sort according to publishing date, oldest first')}}" id="pub_old" class="btn btn-primary disabled" href="{{url_for('shelf.show_shelf', shelf_id=shelf.id, sort_param='pubold')}}"><span class="glyphicon glyphicon-calendar"></span><span class="glyphicon glyphicon-sort-by-order-alt"></span></a>
|
||||||
<a id="order_shelf" href="{{ url_for('shelf.order_shelf', shelf_id=shelf.id) }}" class="btn btn-primary disabled">{{ _('Arrange books') }} </a>
|
|
||||||
<button id="enable_order_shelf" type="button" class="btn btn-primary">{{ _('Change order') }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -31,7 +31,10 @@
|
||||||
<div class="col-sm-3 col-lg-2 col-xs-6 book">
|
<div class="col-sm-3 col-lg-2 col-xs-6 book">
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||||
|
<span class="img">
|
||||||
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
{{ book_cover_image(entry, entry.id|get_book_thumbnails(thumbnails)) }}
|
||||||
|
{% if entry.id in read_book_ids %}<span class="badge read glyphicon glyphicon-ok"></span>{% endif %}
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<button onclick="sendData('{{ url_for('shelf.order_shelf', shelf_id=shelf.id) }}')" class="btn btn-default" id="ChangeOrder">{{_('Change order')}}</button>
|
<button onclick="sendData('{{ url_for('shelf.order_shelf', shelf_id=shelf.id) }}')" class="btn btn-default" id="ChangeOrder">{{_('Save')}}</button>
|
||||||
<a href="{{ url_for('shelf.show_shelf', shelf_id=shelf.id) }}" id="shelf_back" class="btn btn-default">{{_('Back')}}</a>
|
<a href="{{ url_for('shelf.show_shelf', shelf_id=shelf.id) }}" id="shelf_back" class="btn btn-default">{{_('Back')}}</a>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -55,27 +55,14 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="btn-group" role="group" aria-label="Download, send to Kindle, reading">
|
<div class="btn-group" role="group" aria-label="Download, send to Kindle, reading">
|
||||||
{% if g.user.role_download() %}
|
{% if g.user.role_download() %}
|
||||||
{% if entry.data|length %}
|
{% if entry.data|length %}
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
{% if entry.data|length < 2 %}
|
{% for format in entry.data %}
|
||||||
|
<a href="{{ url_for('web.download_link', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}" id="btnGroupDrop{{entry.id}}{{format.format|lower}}" class="btn btn-primary" role="button">
|
||||||
{% for format in entry.data %}
|
<span class="glyphicon glyphicon-download"></span>{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
|
||||||
<a href="{{ url_for('web.download_link', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}" id="btnGroupDrop1{{format.format|lower}}" class="btn btn-primary" role="button">
|
</a>
|
||||||
<span class="glyphicon glyphicon-download"></span>{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
|
{% endfor %}
|
||||||
</a>
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
<button id="btnGroupDrop1" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
|
||||||
<span class="glyphicon glyphicon-download"></span> {{_('Download')}}
|
|
||||||
<span class="caret"></span>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
|
|
||||||
{% for format in entry.data %}
|
|
||||||
<li><a href="{{ url_for('web.download_link', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}">{{format.format}} ({{ format.uncompressed_size|filesizeformat }})</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
20
cps/ub.py
20
cps/ub.py
|
@ -476,7 +476,7 @@ def migrate_Database(session):
|
||||||
if not engine.dialect.has_table(engine.connect(), "thumbnail"):
|
if not engine.dialect.has_table(engine.connect(), "thumbnail"):
|
||||||
Thumbnail.__table__.create(bind=engine)
|
Thumbnail.__table__.create(bind=engine)
|
||||||
if not engine.dialect.has_table(engine.connect(), "registration"):
|
if not engine.dialect.has_table(engine.connect(), "registration"):
|
||||||
ReadBook.__table__.create(bind=engine)
|
Registration.__table__.create(bind=engine)
|
||||||
with engine.connect() as conn:
|
with engine.connect() as conn:
|
||||||
conn.execute("insert into registration (domain, allow) values('%.%',1)")
|
conn.execute("insert into registration (domain, allow) values('%.%',1)")
|
||||||
session.commit()
|
session.commit()
|
||||||
|
@ -525,12 +525,16 @@ def migrate_Database(session):
|
||||||
for book_shelf in session.query(BookShelf).all():
|
for book_shelf in session.query(BookShelf).all():
|
||||||
book_shelf.date_added = datetime.datetime.now()
|
book_shelf.date_added = datetime.datetime.now()
|
||||||
session.commit()
|
session.commit()
|
||||||
# Handle table exists, but no content
|
try:
|
||||||
cnt = session.query(Registration).count()
|
# Handle table exists, but no content
|
||||||
if not cnt:
|
cnt = session.query(Registration).count()
|
||||||
with engine.connect() as conn:
|
if not cnt:
|
||||||
conn.execute("insert into registration (domain, allow) values('%.%',1)")
|
with engine.connect() as conn:
|
||||||
session.commit()
|
conn.execute("insert into registration (domain, allow) values('%.%',1)")
|
||||||
|
session.commit()
|
||||||
|
except exc.OperationalError: # Database is not writeable
|
||||||
|
print('Settings database is not writeable. Exiting...')
|
||||||
|
sys.exit(2)
|
||||||
try:
|
try:
|
||||||
session.query(exists().where(BookShelf.order)).scalar()
|
session.query(exists().where(BookShelf.order)).scalar()
|
||||||
except exc.OperationalError: # Database is not compatible, some columns are missing
|
except exc.OperationalError: # Database is not compatible, some columns are missing
|
||||||
|
@ -615,7 +619,7 @@ def migrate_Database(session):
|
||||||
session.commit()
|
session.commit()
|
||||||
except exc.OperationalError:
|
except exc.OperationalError:
|
||||||
print('Settings database is not writeable. Exiting...')
|
print('Settings database is not writeable. Exiting...')
|
||||||
sys.exit(1)
|
sys.exit(2)
|
||||||
|
|
||||||
|
|
||||||
def clean_database(session):
|
def clean_database(session):
|
||||||
|
|
31
cps/web.py
31
cps/web.py
|
@ -336,8 +336,6 @@ def get_matching_tags():
|
||||||
title_input = request.args.get('book_title') or ''
|
title_input = request.args.get('book_title') or ''
|
||||||
include_tag_inputs = request.args.getlist('include_tag') or ''
|
include_tag_inputs = request.args.getlist('include_tag') or ''
|
||||||
exclude_tag_inputs = request.args.getlist('exclude_tag') or ''
|
exclude_tag_inputs = request.args.getlist('exclude_tag') or ''
|
||||||
# include_extension_inputs = request.args.getlist('include_extension') or ''
|
|
||||||
# exclude_extension_inputs = request.args.getlist('exclude_extension') or ''
|
|
||||||
q = q.filter(db.Books.authors.any(func.lower(db.Authors.name).ilike("%" + author_input + "%")),
|
q = q.filter(db.Books.authors.any(func.lower(db.Authors.name).ilike("%" + author_input + "%")),
|
||||||
func.lower(db.Books.title).ilike("%" + title_input + "%"))
|
func.lower(db.Books.title).ilike("%" + title_input + "%"))
|
||||||
if len(include_tag_inputs) > 0:
|
if len(include_tag_inputs) > 0:
|
||||||
|
@ -637,7 +635,8 @@ def render_read_books(page, are_read, as_xml=False, order=None):
|
||||||
db_filter = and_(ub.ReadBook.user_id == int(current_user.id),
|
db_filter = and_(ub.ReadBook.user_id == int(current_user.id),
|
||||||
ub.ReadBook.read_status == ub.ReadBook.STATUS_FINISHED)
|
ub.ReadBook.read_status == ub.ReadBook.STATUS_FINISHED)
|
||||||
else:
|
else:
|
||||||
db_filter = coalesce(ub.ReadBook.read_status, 0) != ub.ReadBook.STATUS_FINISHED
|
db_filter = and_(ub.ReadBook.user_id == int(current_user.id),
|
||||||
|
coalesce(ub.ReadBook.read_status, 0) != ub.ReadBook.STATUS_FINISHED)
|
||||||
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
|
||||||
db.Books,
|
db.Books,
|
||||||
db_filter,
|
db_filter,
|
||||||
|
@ -1059,6 +1058,7 @@ def render_adv_search_results(term, offset=None, order=None, limit=None):
|
||||||
rating_low = term.get("ratinghigh")
|
rating_low = term.get("ratinghigh")
|
||||||
rating_high = term.get("ratinglow")
|
rating_high = term.get("ratinglow")
|
||||||
description = term.get("comment")
|
description = term.get("comment")
|
||||||
|
read_status = term.get("read_status")
|
||||||
if author_name:
|
if author_name:
|
||||||
author_name = author_name.strip().lower().replace(',', '|')
|
author_name = author_name.strip().lower().replace(',', '|')
|
||||||
if book_title:
|
if book_title:
|
||||||
|
@ -1076,7 +1076,7 @@ def render_adv_search_results(term, offset=None, order=None, limit=None):
|
||||||
if include_tag_inputs or exclude_tag_inputs or include_series_inputs or exclude_series_inputs or \
|
if include_tag_inputs or exclude_tag_inputs or include_series_inputs or exclude_series_inputs or \
|
||||||
include_languages_inputs or exclude_languages_inputs or author_name or book_title or \
|
include_languages_inputs or exclude_languages_inputs or author_name or book_title or \
|
||||||
publisher or pub_start or pub_end or rating_low or rating_high or description or cc_present or \
|
publisher or pub_start or pub_end or rating_low or rating_high or description or cc_present or \
|
||||||
include_extension_inputs or exclude_extension_inputs:
|
include_extension_inputs or exclude_extension_inputs or read_status:
|
||||||
searchterm.extend((author_name.replace('|', ','), book_title, publisher))
|
searchterm.extend((author_name.replace('|', ','), book_title, publisher))
|
||||||
if pub_start:
|
if pub_start:
|
||||||
try:
|
try:
|
||||||
|
@ -1094,8 +1094,12 @@ def render_adv_search_results(term, offset=None, order=None, limit=None):
|
||||||
pub_start = u""
|
pub_start = u""
|
||||||
tag_names = calibre_db.session.query(db.Tags).filter(db.Tags.id.in_(include_tag_inputs)).all()
|
tag_names = calibre_db.session.query(db.Tags).filter(db.Tags.id.in_(include_tag_inputs)).all()
|
||||||
searchterm.extend(tag.name for tag in tag_names)
|
searchterm.extend(tag.name for tag in tag_names)
|
||||||
|
tag_names = calibre_db.session.query(db.Tags).filter(db.Tags.id.in_(exclude_tag_inputs)).all()
|
||||||
|
searchterm.extend(tag.name for tag in tag_names)
|
||||||
serie_names = calibre_db.session.query(db.Series).filter(db.Series.id.in_(include_series_inputs)).all()
|
serie_names = calibre_db.session.query(db.Series).filter(db.Series.id.in_(include_series_inputs)).all()
|
||||||
searchterm.extend(serie.name for serie in serie_names)
|
searchterm.extend(serie.name for serie in serie_names)
|
||||||
|
serie_names = calibre_db.session.query(db.Series).filter(db.Series.id.in_(exclude_series_inputs)).all()
|
||||||
|
searchterm.extend(serie.name for serie in serie_names)
|
||||||
language_names = calibre_db.session.query(db.Languages).\
|
language_names = calibre_db.session.query(db.Languages).\
|
||||||
filter(db.Languages.id.in_(include_languages_inputs)).all()
|
filter(db.Languages.id.in_(include_languages_inputs)).all()
|
||||||
if language_names:
|
if language_names:
|
||||||
|
@ -1105,6 +1109,8 @@ def render_adv_search_results(term, offset=None, order=None, limit=None):
|
||||||
searchterm.extend([_(u"Rating <= %(rating)s", rating=rating_high)])
|
searchterm.extend([_(u"Rating <= %(rating)s", rating=rating_high)])
|
||||||
if rating_low:
|
if rating_low:
|
||||||
searchterm.extend([_(u"Rating >= %(rating)s", rating=rating_low)])
|
searchterm.extend([_(u"Rating >= %(rating)s", rating=rating_low)])
|
||||||
|
if read_status:
|
||||||
|
searchterm.extend([_(u"Read Status = %(status)s", status=read_status)])
|
||||||
searchterm.extend(ext for ext in include_extension_inputs)
|
searchterm.extend(ext for ext in include_extension_inputs)
|
||||||
searchterm.extend(ext for ext in exclude_extension_inputs)
|
searchterm.extend(ext for ext in exclude_extension_inputs)
|
||||||
# handle custom columns
|
# handle custom columns
|
||||||
|
@ -1121,6 +1127,23 @@ def render_adv_search_results(term, offset=None, order=None, limit=None):
|
||||||
q = q.filter(db.Books.pubdate >= pub_start)
|
q = q.filter(db.Books.pubdate >= pub_start)
|
||||||
if pub_end:
|
if pub_end:
|
||||||
q = q.filter(db.Books.pubdate <= pub_end)
|
q = q.filter(db.Books.pubdate <= pub_end)
|
||||||
|
if read_status:
|
||||||
|
if config.config_read_column:
|
||||||
|
if read_status=="True":
|
||||||
|
q = q.join(db.cc_classes[config.config_read_column], isouter=True) \
|
||||||
|
.filter(db.cc_classes[config.config_read_column].value == True)
|
||||||
|
else:
|
||||||
|
q = q.join(db.cc_classes[config.config_read_column], isouter=True) \
|
||||||
|
.filter(coalesce(db.cc_classes[config.config_read_column].value, False) != True)
|
||||||
|
else:
|
||||||
|
if read_status == "True":
|
||||||
|
q = q.join(ub.ReadBook, db.Books.id==ub.ReadBook.book_id, isouter=True)\
|
||||||
|
.filter(ub.ReadBook.user_id == int(current_user.id),
|
||||||
|
ub.ReadBook.read_status == ub.ReadBook.STATUS_FINISHED)
|
||||||
|
else:
|
||||||
|
q = q.join(ub.ReadBook, db.Books.id == ub.ReadBook.book_id, isouter=True) \
|
||||||
|
.filter(ub.ReadBook.user_id == int(current_user.id),
|
||||||
|
coalesce(ub.ReadBook.read_status, 0) != ub.ReadBook.STATUS_FINISHED)
|
||||||
if publisher:
|
if publisher:
|
||||||
q = q.filter(db.Books.publishers.any(func.lower(db.Publishers.name).ilike("%" + publisher + "%")))
|
q = q.filter(db.Books.publishers.any(func.lower(db.Publishers.name).ilike("%" + publisher + "%")))
|
||||||
for tag in include_tag_inputs:
|
for tag in include_tag_inputs:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user