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