mirror of
				https://github.com/janeczku/calibre-web
				synced 2025-11-04 09:13:02 +00:00 
			
		
		
		
	Merged develop, fixed merged conflicts
This commit is contained in:
		
							
								
								
									
										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 . 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 .helper import check_valid_domain, send_test_mail, reset_password, generate_password_hash
 | 
			
		||||
from .gdriveutils import is_gdrive_ready, gdrive_support
 | 
			
		||||
@@ -118,7 +119,7 @@ def before_request():
 | 
			
		||||
    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()
 | 
			
		||||
    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'))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -209,7 +210,7 @@ def admin():
 | 
			
		||||
@admin_required
 | 
			
		||||
def configuration():
 | 
			
		||||
    if request.method == "POST":
 | 
			
		||||
        return _configuration_update_helper()
 | 
			
		||||
        return _configuration_update_helper(True)
 | 
			
		||||
    return _configuration_result()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -604,10 +605,11 @@ def list_restriction(res_type):
 | 
			
		||||
    return response
 | 
			
		||||
 | 
			
		||||
@admi.route("/basicconfig/pathchooser/")
 | 
			
		||||
# @unconfigured
 | 
			
		||||
@login_required
 | 
			
		||||
@unconfigured
 | 
			
		||||
def config_pathchooser():
 | 
			
		||||
    return pathchooser()
 | 
			
		||||
    if filepicker:
 | 
			
		||||
        return pathchooser()
 | 
			
		||||
    abort(403)
 | 
			
		||||
 | 
			
		||||
@admi.route("/ajax/pathchooser/")
 | 
			
		||||
@login_required
 | 
			
		||||
@@ -616,7 +618,7 @@ def ajax_pathchooser():
 | 
			
		||||
    return pathchooser()
 | 
			
		||||
 | 
			
		||||
def pathchooser():
 | 
			
		||||
    browse_for = "folder" #  if request.endpoint == "admin.pathchooser" else "file"
 | 
			
		||||
    browse_for = "folder"
 | 
			
		||||
    folder_only = request.args.get('folder', False) == "true"
 | 
			
		||||
    file_filter = request.args.get('filter', "")
 | 
			
		||||
    path = os.path.normpath(request.args.get('path', ""))
 | 
			
		||||
@@ -702,8 +704,8 @@ def pathchooser():
 | 
			
		||||
def basic_configuration():
 | 
			
		||||
    logout_user()
 | 
			
		||||
    if request.method == "POST":
 | 
			
		||||
        return _configuration_update_helper()
 | 
			
		||||
    return _configuration_result()
 | 
			
		||||
        return _configuration_update_helper(configured=filepicker)
 | 
			
		||||
    return _configuration_result(configured=filepicker)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _config_int(to_save, x, func=int):
 | 
			
		||||
@@ -858,7 +860,7 @@ def _configuration_ldap_helper(to_save, gdriveError):
 | 
			
		||||
    return reboot_required, None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _configuration_update_helper():
 | 
			
		||||
def _configuration_update_helper(configured):
 | 
			
		||||
    reboot_required = False
 | 
			
		||||
    db_change = False
 | 
			
		||||
    to_save = request.form.to_dict()
 | 
			
		||||
@@ -878,11 +880,15 @@ def _configuration_update_helper():
 | 
			
		||||
 | 
			
		||||
        reboot_required |= _config_string(to_save, "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")
 | 
			
		||||
        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")
 | 
			
		||||
        # 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:
 | 
			
		||||
            unrar_status = helper.check_unrar(config.config_rarfile_location)
 | 
			
		||||
            if unrar_status:
 | 
			
		||||
                return _configuration_result(unrar_status, gdriveError)
 | 
			
		||||
                return _configuration_result(unrar_status, gdriveError, configured)
 | 
			
		||||
    except (OperationalError, InvalidRequestError):
 | 
			
		||||
        ub.session.rollback()
 | 
			
		||||
        _configuration_result(_(u"Settings DB is not Writeable"), gdriveError)
 | 
			
		||||
        _configuration_result(_(u"Settings DB is not Writeable"), gdriveError, configured)
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        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)
 | 
			
		||||
            db_change = True
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        return _configuration_result('%s' % e, gdriveError)
 | 
			
		||||
        return _configuration_result('%s' % e, gdriveError, configured)
 | 
			
		||||
 | 
			
		||||
    if db_change:
 | 
			
		||||
        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):
 | 
			
		||||
            flash(_(u"DB is not Writeable"), category="warning")
 | 
			
		||||
 | 
			
		||||
@@ -971,10 +979,10 @@ def _configuration_update_helper():
 | 
			
		||||
    if reboot_required:
 | 
			
		||||
        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()
 | 
			
		||||
    gdrivefolders = []
 | 
			
		||||
    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,
 | 
			
		||||
                                 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,
 | 
			
		||||
                                 title=_(u"Basic Configuration"), page="config")
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,7 @@ parser.add_argument('-v', '--version', action='version', help='Shows version num
 | 
			
		||||
                    version=version_info())
 | 
			
		||||
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('-f', action='store_true', help='Enables filepicker in unconfigured mode')
 | 
			
		||||
args = parser.parse_args()
 | 
			
		||||
 | 
			
		||||
if sys.version_info < (3, 0):
 | 
			
		||||
@@ -110,3 +111,6 @@ if ipadress:
 | 
			
		||||
 | 
			
		||||
# handle and check user password argument
 | 
			
		||||
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.dispose()
 | 
			
		||||
 | 
			
		||||
        # toDo: if db changed -> delete shelfs, delete download books, delete read boks, kobo sync??
 | 
			
		||||
 | 
			
		||||
        if not config.config_calibre_dir:
 | 
			
		||||
            config.invalidate()
 | 
			
		||||
            return False
 | 
			
		||||
 
 | 
			
		||||
@@ -20,11 +20,14 @@ from flask import render_template
 | 
			
		||||
from flask_babel import gettext as _
 | 
			
		||||
from flask import g
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log = logger.create()
 | 
			
		||||
 | 
			
		||||
def get_sidebar_config(kwargs=None):
 | 
			
		||||
    kwargs = kwargs or []
 | 
			
		||||
    if 'content' in kwargs:
 | 
			
		||||
@@ -91,9 +94,23 @@ def get_sidebar_config(kwargs=None):
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
def render_title_template(*args, **kwargs):
 | 
			
		||||
    sidebar = get_sidebar_config(kwargs)
 | 
			
		||||
    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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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),
 | 
			
		||||
                                 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):
 | 
			
		||||
    shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.id == shelf_id).first()
 | 
			
		||||
 | 
			
		||||
    # check user is allowed to access shelf
 | 
			
		||||
    if shelf and check_shelf_view_permissions(shelf):
 | 
			
		||||
 | 
			
		||||
        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"
 | 
			
		||||
            pagesize = 0
 | 
			
		||||
            order = [ub.BookShelf.order.asc()]
 | 
			
		||||
        else:
 | 
			
		||||
            pagesize = sys.maxsize
 | 
			
		||||
            page = 'shelfdown.html'
 | 
			
		||||
            order = [ub.BookShelf.order.asc()]
 | 
			
		||||
 | 
			
		||||
        result, __, pagination = calibre_db.fill_indexpage(page_no, pagesize,
 | 
			
		||||
                                                            db.Books,
 | 
			
		||||
                                                            ub.BookShelf.shelf == shelf_id,
 | 
			
		||||
                                                            order,
 | 
			
		||||
                                                            [ub.BookShelf.order.asc()],
 | 
			
		||||
                                                            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
 | 
			
		||||
        wrong_entries = calibre_db.session.query(ub.BookShelf)\
 | 
			
		||||
            .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{
 | 
			
		||||
    display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cover .badge{
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    color: #fff;
 | 
			
		||||
    background-color: #cc7b19;
 | 
			
		||||
    border-radius: 0;
 | 
			
		||||
    padding: 0 8px;
 | 
			
		||||
@@ -15,3 +15,8 @@ body.serieslist.grid-view div.container-fluid>div>div.col-sm-10:before{
 | 
			
		||||
.cover{
 | 
			
		||||
    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;
 | 
			
		||||
  max-width: 100%;
 | 
			
		||||
  height: auto;
 | 
			
		||||
  max-height: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.container-fluid .discover{ margin-bottom: 50px; }
 | 
			
		||||
@@ -132,12 +133,19 @@ a, .danger,.book-remove, .editable-empty, .editable-empty:hover { color: #45b29d
 | 
			
		||||
  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;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  -webkit-box-shadow: 0 5px 8px -6px #777;
 | 
			
		||||
  -moz-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 {border-color: #000; }
 | 
			
		||||
.cover { margin-bottom: 10px; }
 | 
			
		||||
 | 
			
		||||
.cover .badge{
 | 
			
		||||
   position: absolute;
 | 
			
		||||
   top: 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;}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
    $.getJSON( getPath() + "/get_matching_tags", form, function( data ) {
 | 
			
		||||
        $(".tags_click").each(function() {
 | 
			
		||||
            if ($.inArray(parseInt($(this).children("input").first().val(), 10), data.tags) === -1 ) {
 | 
			
		||||
                if (!($(this).hasClass("active"))) {
 | 
			
		||||
                    $(this).addClass("disabled");
 | 
			
		||||
            if ($.inArray(parseInt($(this).val(), 10), data.tags) === -1) {
 | 
			
		||||
                if(!$(this).prop("selected")) {
 | 
			
		||||
                    $(this).prop("disabled", true);
 | 
			
		||||
                }
 | 
			
		||||
            } 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() {
 | 
			
		||||
        ConfirmDialog(
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,10 @@
 | 
			
		||||
    <div id="books" class="col-sm-3 col-lg-2 col-xs-6 book">
 | 
			
		||||
      <div class="cover">
 | 
			
		||||
        <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>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="meta">
 | 
			
		||||
 
 | 
			
		||||
@@ -16,12 +16,19 @@
 | 
			
		||||
    <div id="collapseOne" class="panel-collapse collapse in">
 | 
			
		||||
      <div class="panel-body">
 | 
			
		||||
       <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">
 | 
			
		||||
       {% if filepicker %}
 | 
			
		||||
        <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>
 | 
			
		||||
        </span>
 | 
			
		||||
       {% endif %}
 | 
			
		||||
      </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']  %}
 | 
			
		||||
    <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 %} >
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,10 @@
 | 
			
		||||
      <div class="cover">
 | 
			
		||||
        {% 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">
 | 
			
		||||
            <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>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
      </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="cover">
 | 
			
		||||
                      <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="badge">{{entry.count}}</span>
 | 
			
		||||
                          <span class="img">
 | 
			
		||||
                              {{ book_cover_image(entry[0], entry[0].id|get_book_thumbnails(thumbnails)) }}
 | 
			
		||||
                              <span class="badge">{{entry.count}}</span>
 | 
			
		||||
                            </span>
 | 
			
		||||
                      </a>
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <div class="meta">
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,10 @@
 | 
			
		||||
    <div class="col-sm-3 col-lg-2 col-xs-6 book" id="books_rand">
 | 
			
		||||
      <div class="cover">
 | 
			
		||||
          <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>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="meta">
 | 
			
		||||
@@ -83,7 +86,10 @@
 | 
			
		||||
    <div class="col-sm-3 col-lg-2 col-xs-6 book" id="books">
 | 
			
		||||
      <div class="cover">
 | 
			
		||||
          <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)) }}
 | 
			
		||||
              {% if entry.id in read_book_ids %}<span class="badge read glyphicon glyphicon-ok"></span>{% endif %}
 | 
			
		||||
            </span>
 | 
			
		||||
          </a>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="meta">
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,10 @@
 | 
			
		||||
      <div class="cover">
 | 
			
		||||
        {% 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">
 | 
			
		||||
               {{ 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>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
      </div>
 | 
			
		||||
 
 | 
			
		||||
@@ -31,87 +31,87 @@
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <label for="include_tag">{{_('Tags')}}</label>
 | 
			
		||||
    <div class="form-group" id="tag">
 | 
			
		||||
      <div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
 | 
			
		||||
        {% for tag in tags %}
 | 
			
		||||
          <label id="tag_{{tag.id}}" class="btn btn-primary tags_click">
 | 
			
		||||
            <input type="checkbox" autocomplete="off" name="include_tag" id="include_tag" value="{{tag.id}}">{{tag.name}}</input>
 | 
			
		||||
          </label>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
    <div class="form-group">
 | 
			
		||||
      <label for="read_status">{{_('Read Status')}}</label>
 | 
			
		||||
      <select name="read_status" id="read_status" class="form-control">
 | 
			
		||||
        <option value="" selected></option>
 | 
			
		||||
        <option value="True" >{{_('Yes')}}</option>
 | 
			
		||||
        <option value="False" >{{_('No')}}</option>
 | 
			
		||||
      </select>
 | 
			
		||||
    </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>
 | 
			
		||||
    <label for="exclude_tag">{{_('Exclude Tags')}}</label>
 | 
			
		||||
    <div class="form-group">
 | 
			
		||||
      <div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
 | 
			
		||||
        {% for tag in tags %}
 | 
			
		||||
          <label id="exclude_tag_{{tag.id}}" class="btn btn-danger tags_click">
 | 
			
		||||
            <input type="checkbox" autocomplete="off" name="exclude_tag" id="exclude_tag" value="{{tag.id}}">{{tag.name}}</input>
 | 
			
		||||
          </label>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
    <div class="row">
 | 
			
		||||
      <div class="form-group col-sm-6">
 | 
			
		||||
        <div><label for="include_serie">{{_('Series')}}</label></div>
 | 
			
		||||
        <select class="selectpicker" name="include_serie" id="include_serie" data-live-search="true" data-style="btn-primary" multiple>
 | 
			
		||||
          {% for serie in series %}
 | 
			
		||||
            <option value="{{serie.id}}">{{serie.name}}</option>
 | 
			
		||||
          {% endfor %}
 | 
			
		||||
        </select>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <label for="include_serie">{{_('Series')}}</label>
 | 
			
		||||
    <div class="form-group">
 | 
			
		||||
      <div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
 | 
			
		||||
        {% for serie in series %}
 | 
			
		||||
          <label id="serie_{{serie.id}}" class="btn btn-primary serie_click">
 | 
			
		||||
            <input type="checkbox" autocomplete="off" name="include_serie" id="include_serie" value="{{serie.id}}">{{serie.name}}</input>
 | 
			
		||||
          </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 class="form-group col-sm-6">
 | 
			
		||||
        <div><label for="exclude_serie">{{_('Exclude Series')}}</label></div>
 | 
			
		||||
        <select class="selectpicker" name="exclude_serie" id="exclude_serie" data-live-search="true" data-style="btn-danger" multiple>
 | 
			
		||||
          {% for serie in series %}
 | 
			
		||||
            <option value="{{serie.id}}">{{serie.name}}</option>
 | 
			
		||||
          {% endfor %}
 | 
			
		||||
        </select>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    {% if languages %}
 | 
			
		||||
      <label for="include_language">{{_('Languages')}}</label>
 | 
			
		||||
      <div class="form-group">
 | 
			
		||||
        <div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
 | 
			
		||||
    <div class="row">
 | 
			
		||||
      <div class="form-group col-sm-6">
 | 
			
		||||
        <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 %}
 | 
			
		||||
            <label id="language_{{language.id}}" class="btn btn-primary serie_click">
 | 
			
		||||
              <input type="checkbox" autocomplete="off" name="include_language" id="include_language" value="{{language.id}}">{{language.name}}</input>
 | 
			
		||||
            </label>
 | 
			
		||||
            <option value="{{language.id}}">{{language.name}}</option>
 | 
			
		||||
          {% endfor %}
 | 
			
		||||
        </div>
 | 
			
		||||
        </select>
 | 
			
		||||
      </div>
 | 
			
		||||
      <label for="exclude_language">{{_('Exclude Languages')}}</label>
 | 
			
		||||
      <div class="form-group">
 | 
			
		||||
        <div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
 | 
			
		||||
      <div class="form-group col-sm-6">
 | 
			
		||||
        <div><label for="exclude_language">{{_('Exclude Languages')}}</label></div>
 | 
			
		||||
        <select class="selectpicker" name="exclude_language" id="exclude_language" data-live-search="true" data-style="btn-danger" multiple>
 | 
			
		||||
          {% for language in languages %}
 | 
			
		||||
            <label id="exclude_language_{{language.id}}" class="btn btn-danger language_click">
 | 
			
		||||
              <input type="checkbox" autocomplete="off" name="exclude_language" id="exclude_language" value="{{language.id}}">{{language.name}}</input>
 | 
			
		||||
            </label>
 | 
			
		||||
            <option value="{{language.id}}">{{language.name}}</option>
 | 
			
		||||
          {% endfor %}
 | 
			
		||||
        </div>
 | 
			
		||||
      </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 %}
 | 
			
		||||
        </select>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <label for="exclude_extension">{{_('Exclude Extensions')}}</label>
 | 
			
		||||
    <div class="form-group">
 | 
			
		||||
      <div class="btn-toolbar btn-toolbar-lg" data-toggle="buttons">
 | 
			
		||||
    {% endif%}
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <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 %}
 | 
			
		||||
          <label id="exclude_extension_{{extension.format}}" class="btn btn-danger extension_click">
 | 
			
		||||
            <input type="checkbox" autocomplete="off" name="exclude_extension" id="exclude_extension" value="{{extension.format}}">{{extension.format}}</input>
 | 
			
		||||
          </label>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
      </div>
 | 
			
		||||
            <option value="{{extension.format}}">{{extension.format}}</option>
 | 
			
		||||
          {% endfor %}
 | 
			
		||||
        </select>
 | 
			
		||||
        </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 class="row">
 | 
			
		||||
        <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/typeahead.bundle.js') }}"></script>
 | 
			
		||||
<script src="{{ url_for('static', filename='js/edit_books.js') }}"></script>
 | 
			
		||||
<script>
 | 
			
		||||
</script>
 | 
			
		||||
<script src="{{ url_for('static', filename='js/libs/bootstrap-select.min.js')}}"></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 %}
 | 
			
		||||
{% block header %}
 | 
			
		||||
<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-select.min.css') }}" rel="stylesheet" >
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,8 +9,10 @@
 | 
			
		||||
  {% if g.user.is_authenticated %}
 | 
			
		||||
    {% 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>
 | 
			
		||||
      <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__() %}
 | 
			
		||||
      <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">
 | 
			
		||||
          <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>
 | 
			
		||||
@@ -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 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 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>
 | 
			
		||||
      {% endif %}
 | 
			
		||||
    {% endif %}
 | 
			
		||||
@@ -31,7 +31,10 @@
 | 
			
		||||
    <div class="col-sm-3 col-lg-2 col-xs-6 book">
 | 
			
		||||
      <div class="cover">
 | 
			
		||||
            <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)) }}
 | 
			
		||||
                {% if entry.id in read_book_ids %}<span class="badge read glyphicon glyphicon-ok"></span>{% endif %}
 | 
			
		||||
              </span>
 | 
			
		||||
            </a>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="meta">
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,7 @@
 | 
			
		||||
          </div>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
      </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>
 | 
			
		||||
  </div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
@@ -55,27 +55,14 @@
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
	  <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 %}
 | 
			
		||||
            <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="btnGroupDrop1{{format.format|lower}}" class="btn btn-primary" role="button">
 | 
			
		||||
                    <span class="glyphicon glyphicon-download"></span>{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
 | 
			
		||||
                  </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 %}
 | 
			
		||||
                {% 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">
 | 
			
		||||
                  <span class="glyphicon glyphicon-download"></span>{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
 | 
			
		||||
                </a>
 | 
			
		||||
                {% endfor %}
 | 
			
		||||
            </div>
 | 
			
		||||
            {% 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"):
 | 
			
		||||
        Thumbnail.__table__.create(bind=engine)
 | 
			
		||||
    if not engine.dialect.has_table(engine.connect(), "registration"):
 | 
			
		||||
        ReadBook.__table__.create(bind=engine)
 | 
			
		||||
        Registration.__table__.create(bind=engine)
 | 
			
		||||
        with engine.connect() as conn:
 | 
			
		||||
            conn.execute("insert into registration (domain, allow) values('%.%',1)")
 | 
			
		||||
        session.commit()
 | 
			
		||||
@@ -525,12 +525,16 @@ def migrate_Database(session):
 | 
			
		||||
        for book_shelf in session.query(BookShelf).all():
 | 
			
		||||
            book_shelf.date_added = datetime.datetime.now()
 | 
			
		||||
        session.commit()
 | 
			
		||||
    # Handle table exists, but no content
 | 
			
		||||
    cnt = session.query(Registration).count()
 | 
			
		||||
    if not cnt:
 | 
			
		||||
        with engine.connect() as conn:
 | 
			
		||||
            conn.execute("insert into registration (domain, allow) values('%.%',1)")
 | 
			
		||||
        session.commit()
 | 
			
		||||
    try:
 | 
			
		||||
        # Handle table exists, but no content
 | 
			
		||||
        cnt = session.query(Registration).count()
 | 
			
		||||
        if not cnt:
 | 
			
		||||
            with engine.connect() as conn:
 | 
			
		||||
                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:
 | 
			
		||||
        session.query(exists().where(BookShelf.order)).scalar()
 | 
			
		||||
    except exc.OperationalError:  # Database is not compatible, some columns are missing
 | 
			
		||||
@@ -615,7 +619,7 @@ def migrate_Database(session):
 | 
			
		||||
        session.commit()
 | 
			
		||||
    except exc.OperationalError:
 | 
			
		||||
        print('Settings database is not writeable. Exiting...')
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
        sys.exit(2)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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 ''
 | 
			
		||||
    include_tag_inputs = request.args.getlist('include_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 + "%")),
 | 
			
		||||
                 func.lower(db.Books.title).ilike("%" + title_input + "%"))
 | 
			
		||||
    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),
 | 
			
		||||
                             ub.ReadBook.read_status == ub.ReadBook.STATUS_FINISHED)
 | 
			
		||||
        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,
 | 
			
		||||
                                                                db.Books,
 | 
			
		||||
                                                                db_filter,
 | 
			
		||||
@@ -1059,6 +1058,7 @@ def render_adv_search_results(term, offset=None, order=None, limit=None):
 | 
			
		||||
    rating_low = term.get("ratinghigh")
 | 
			
		||||
    rating_high = term.get("ratinglow")
 | 
			
		||||
    description = term.get("comment")
 | 
			
		||||
    read_status = term.get("read_status")
 | 
			
		||||
    if author_name:
 | 
			
		||||
        author_name = author_name.strip().lower().replace(',', '|')
 | 
			
		||||
    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 \
 | 
			
		||||
            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 \
 | 
			
		||||
            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))
 | 
			
		||||
        if pub_start:
 | 
			
		||||
            try:
 | 
			
		||||
@@ -1094,8 +1094,12 @@ def render_adv_search_results(term, offset=None, order=None, limit=None):
 | 
			
		||||
                pub_start = u""
 | 
			
		||||
        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)
 | 
			
		||||
        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()
 | 
			
		||||
        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).\
 | 
			
		||||
            filter(db.Languages.id.in_(include_languages_inputs)).all()
 | 
			
		||||
        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)])
 | 
			
		||||
        if 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 exclude_extension_inputs)
 | 
			
		||||
        # 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)
 | 
			
		||||
        if 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:
 | 
			
		||||
            q = q.filter(db.Books.publishers.any(func.lower(db.Publishers.name).ilike("%" + publisher + "%")))
 | 
			
		||||
        for tag in include_tag_inputs:
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user