Unverified Commit 8143bc78 authored by Ethan Lin's avatar Ethan Lin Committed by GitHub

Merge pull request #20 from janeczku/master

merge janeczku/master
parents 94762280 8923e712
helper.py ident export-subst updater.py ident export-subst
/test export-ignore /test export-ignore
cps/static/css/libs/* linguist-vendored cps/static/css/libs/* linguist-vendored
cps/static/js/libs/* linguist-vendored cps/static/js/libs/* linguist-vendored
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2016-2019 lemmsh cervinko Kennyl matthazinski OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging import logging
import uploader import uploader
import os import os
...@@ -19,6 +35,7 @@ logger = logging.getLogger("book_formats") ...@@ -19,6 +35,7 @@ logger = logging.getLogger("book_formats")
try: try:
from wand.image import Image from wand.image import Image
from wand import version as ImageVersion from wand import version as ImageVersion
from wand.exceptions import PolicyError
use_generic_pdf_cover = False use_generic_pdf_cover = False
except (ImportError, RuntimeError) as e: except (ImportError, RuntimeError) as e:
logger.warning('cannot import Image, generating pdf covers for pdf uploads will not work: %s', e) logger.warning('cannot import Image, generating pdf covers for pdf uploads will not work: %s', e)
...@@ -84,7 +101,7 @@ def default_meta(tmp_file_path, original_file_name, original_file_extension): ...@@ -84,7 +101,7 @@ def default_meta(tmp_file_path, original_file_name, original_file_extension):
def pdf_meta(tmp_file_path, original_file_name, original_file_extension): def pdf_meta(tmp_file_path, original_file_name, original_file_extension):
if use_pdf_meta: if use_pdf_meta:
pdf = PdfFileReader(open(tmp_file_path, 'rb')) pdf = PdfFileReader(open(tmp_file_path, 'rb'), strict=False)
doc_info = pdf.getDocumentInfo() doc_info = pdf.getDocumentInfo()
else: else:
doc_info = None doc_info = None
...@@ -114,12 +131,18 @@ def pdf_preview(tmp_file_path, tmp_dir): ...@@ -114,12 +131,18 @@ def pdf_preview(tmp_file_path, tmp_dir):
if use_generic_pdf_cover: if use_generic_pdf_cover:
return None return None
else: else:
cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jpg" try:
with Image(filename=tmp_file_path + "[0]", resolution=150) as img: cover_file_name = os.path.splitext(tmp_file_path)[0] + ".cover.jpg"
img.compression_quality = 88 with Image(filename=tmp_file_path + "[0]", resolution=150) as img:
img.save(filename=os.path.join(tmp_dir, cover_file_name)) img.compression_quality = 88
return cover_file_name img.save(filename=os.path.join(tmp_dir, cover_file_name))
return cover_file_name
except PolicyError as ex:
logger.warning('Pdf extraction forbidden by Imagemagick policy: %s', ex)
return None
except Exception as ex:
logger.warning('Cannot extract cover image, using default: %s', ex)
return None
def get_versions(): def get_versions():
if not use_generic_pdf_cover: if not use_generic_pdf_cover:
......
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2016-2019 jkrehm andy29485 OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Inspired by https://github.com/ChrisTM/Flask-CacheBust # Inspired by https://github.com/ChrisTM/Flask-CacheBust
# Uses query strings so CSS font files are found without having to resort to absolute URLs # Uses query strings so CSS font files are found without having to resort to absolute URLs
......
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018 OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import argparse import argparse
import os import os
import sys import sys
......
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018 OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import zipfile import zipfile
import tarfile import tarfile
import os import os
...@@ -8,21 +24,34 @@ import uploader ...@@ -8,21 +24,34 @@ import uploader
def extractCover(tmp_file_name, original_file_extension): def extractCover(tmp_file_name, original_file_extension):
cover_data = None
if original_file_extension.upper() == '.CBZ': if original_file_extension.upper() == '.CBZ':
cf = zipfile.ZipFile(tmp_file_name) cf = zipfile.ZipFile(tmp_file_name)
compressed_name = cf.namelist()[0] for name in cf.namelist():
cover_data = cf.read(compressed_name) ext = os.path.splitext(name)
if len(ext) > 1:
extension = ext[1].lower()
if extension == '.jpg':
cover_data = cf.read(name)
break
elif original_file_extension.upper() == '.CBT': elif original_file_extension.upper() == '.CBT':
cf = tarfile.TarFile(tmp_file_name) cf = tarfile.TarFile(tmp_file_name)
compressed_name = cf.getnames()[0] for name in cf.getnames():
cover_data = cf.extractfile(compressed_name).read() ext = os.path.splitext(name)
if len(ext) > 1:
extension = ext[1].lower()
if extension == '.jpg':
cover_data = cf.extractfile(name).read()
break
prefix = os.path.dirname(tmp_file_name) prefix = os.path.dirname(tmp_file_name)
if cover_data:
tmp_cover_name = prefix + '/cover' + os.path.splitext(compressed_name)[1] tmp_cover_name = prefix + '/cover' + extension
image = open(tmp_cover_name, 'wb') image = open(tmp_cover_name, 'wb')
image.write(cover_data) image.write(cover_data)
image.close() image.close()
else:
tmp_cover_name = None
return tmp_cover_name return tmp_cover_name
......
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2016-2019 Ben Bennett, OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os import os
import subprocess import subprocess
import ub import ub
......
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2012-2019 mutschler, cervinko, ok11, jkrehm, nanu-c, Wineliva,
# pjeby, elelay, idalin, Ozzieisaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from sqlalchemy import * from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import * from sqlalchemy.orm import *
...@@ -9,6 +26,7 @@ import re ...@@ -9,6 +26,7 @@ import re
import ast import ast
from ub import config from ub import config
import ub import ub
import sys
session = None session = None
cc_exceptions = ['datetime', 'comments', 'float', 'composite', 'series'] cc_exceptions = ['datetime', 'comments', 'float', 'composite', 'series']
...@@ -301,6 +319,8 @@ class Custom_Columns(Base): ...@@ -301,6 +319,8 @@ class Custom_Columns(Base):
def get_display_dict(self): def get_display_dict(self):
display_dict = ast.literal_eval(self.display) display_dict = ast.literal_eval(self.display)
if sys.version_info < (3, 0):
display_dict['enum_values'] = [x.decode('unicode_escape') for x in display_dict['enum_values']]
return display_dict return display_dict
......
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018 lemmsh, Kennyl, Kyosfonica, matthazinski
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import zipfile import zipfile
from lxml import etree from lxml import etree
import os import os
......
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018 lemmsh, cervinko, OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from lxml import etree from lxml import etree
import uploader import uploader
......
This diff is collapsed.
This diff is collapsed.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Flask License
#
# Copyright © 2010 by the Pallets team.
#
# Some rights reserved.
# Redistribution and use in source and binary forms of the software as well as
# documentation, with or without modification, are permitted provided that the
# following conditions are met:
#
# Redistributions of source code must retain the above copyright notice, this list of conditions
# and the following disclaimer.
# Redistributions in binary form must reproduce the above copyright notice, this list of conditions
# and the following disclaimer in the documentation and/or other materials provided with the distribution.
# Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# http://flask.pocoo.org/snippets/62/ # http://flask.pocoo.org/snippets/62/
try: try:
......
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2018 cervinko, janeczku, OzzieIsaacs
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class ReverseProxied(object): class ReverseProxied(object):
"""Wrap the application in this middleware and configure the """Wrap the application in this middleware and configure the
front-end server to add these headers, to let you quietly bind front-end server to add these headers, to let you quietly bind
......
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
# Copyright (C) 2012-2019 janeczku, OzzieIsaacs, andrerfcsantos, idalin
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from socket import error as SocketError from socket import error as SocketError
import sys import sys
import os import os
...@@ -20,6 +37,7 @@ except ImportError: ...@@ -20,6 +37,7 @@ except ImportError:
gevent_present = False gevent_present = False
class server: class server:
wsgiserver = None wsgiserver = None
...@@ -32,18 +50,26 @@ class server: ...@@ -32,18 +50,26 @@ class server:
def start_gevent(self): def start_gevent(self):
try: try:
ssl_args = dict() ssl_args = dict()
if web.ub.config.get_config_certfile() and web.ub.config.get_config_keyfile(): certfile_path = web.ub.config.get_config_certfile()
ssl_args = {"certfile": web.ub.config.get_config_certfile(), keyfile_path = web.ub.config.get_config_keyfile()
"keyfile": web.ub.config.get_config_keyfile()} if certfile_path and keyfile_path:
if os.path.isfile(certfile_path) and os.path.isfile(keyfile_path):
ssl_args = {"certfile": certfile_path,
"keyfile": keyfile_path}
else:
web.app.logger.info('The specified paths for the ssl certificate file and/or key file seem to be broken. Ignoring ssl. Cert path: %s | Key path: %s' % (certfile_path, keyfile_path))
if os.name == 'nt': if os.name == 'nt':
self.wsgiserver= WSGIServer(('0.0.0.0', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args) self.wsgiserver= WSGIServer(('0.0.0.0', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args)
else: else:
self.wsgiserver = WSGIServer(('', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args) self.wsgiserver = WSGIServer(('', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args)
web.py3_gevent_link = self.wsgiserver
self.wsgiserver.serve_forever() self.wsgiserver.serve_forever()
except SocketError: except SocketError:
try: try:
web.app.logger.info('Unable to listen on \'\', trying on IPv4 only...') web.app.logger.info('Unable to listen on \'\', trying on IPv4 only...')
self.wsgiserver = WSGIServer(('0.0.0.0', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args) self.wsgiserver = WSGIServer(('0.0.0.0', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args)
web.py3_gevent_link = self.wsgiserver
self.wsgiserver.serve_forever() self.wsgiserver.serve_forever()
except (OSError, SocketError) as e: except (OSError, SocketError) as e:
web.app.logger.info("Error starting server: %s" % e.strerror) web.app.logger.info("Error starting server: %s" % e.strerror)
...@@ -60,12 +86,17 @@ class server: ...@@ -60,12 +86,17 @@ class server:
self.start_gevent() self.start_gevent()
else: else:
try: try:
ssl = None
web.app.logger.info('Starting Tornado server') web.app.logger.info('Starting Tornado server')
if web.ub.config.get_config_certfile() and web.ub.config.get_config_keyfile(): certfile_path = web.ub.config.get_config_certfile()
ssl={"certfile": web.ub.config.get_config_certfile(), keyfile_path = web.ub.config.get_config_keyfile()
"keyfile": web.ub.config.get_config_keyfile()} if certfile_path and keyfile_path:
else: if os.path.isfile(certfile_path) and os.path.isfile(keyfile_path):
ssl=None ssl = {"certfile": certfile_path,
"keyfile": keyfile_path}
else:
web.app.logger.info('The specified paths for the ssl certificate file and/or key file seem to be broken. Ignoring ssl. Cert path: %s | Key path: %s' % (certfile_path, keyfile_path))
# Max Buffersize set to 200MB # Max Buffersize set to 200MB
http_server = HTTPServer(WSGIContainer(web.app), http_server = HTTPServer(WSGIContainer(web.app),
max_buffer_size = 209700000, max_buffer_size = 209700000,
...@@ -81,6 +112,9 @@ class server: ...@@ -81,6 +112,9 @@ class server:
web.helper.global_WorkerThread.stop() web.helper.global_WorkerThread.stop()
sys.exit(1) sys.exit(1)
# ToDo: Somehow caused by circular import under python3 refactor
if sys.version_info > (3, 0):
self.restart = web.py3_restart_Typ
if self.restart == True: if self.restart == True:
web.app.logger.info("Performing restart of Calibre-Web") web.app.logger.info("Performing restart of Calibre-Web")
web.helper.global_WorkerThread.stop() web.helper.global_WorkerThread.stop()
...@@ -97,16 +131,26 @@ class server: ...@@ -97,16 +131,26 @@ class server:
sys.exit(0) sys.exit(0)
def setRestartTyp(self,starttyp): def setRestartTyp(self,starttyp):
self.restart=starttyp self.restart = starttyp
# ToDo: Somehow caused by circular import under python3 refactor
web.py3_restart_Typ = starttyp
def killServer(self, signum, frame): def killServer(self, signum, frame):
self.stopServer() self.stopServer()
def stopServer(self): def stopServer(self):
if gevent_present: # ToDo: Somehow caused by circular import under python3 refactor
self.wsgiserver.close() if sys.version_info > (3, 0):
else: if not self.wsgiserver:
self.wsgiserver.add_callback(self.wsgiserver.stop) if gevent_present:
self.wsgiserver = web.py3_gevent_link
else:
self.wsgiserver = IOLoop.instance()
if self.wsgiserver:
if gevent_present:
self.wsgiserver.close()
else:
self.wsgiserver.add_callback(self.wsgiserver.stop)
@staticmethod @staticmethod
def getNameVersion(): def getNameVersion():
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -36,6 +36,11 @@ a{color: #45b29d}a:hover{color: #444;} ...@@ -36,6 +36,11 @@ a{color: #45b29d}a:hover{color: #444;}
.container-fluid .book .meta .title{font-weight:bold;font-size:15px;color:#444} .container-fluid .book .meta .title{font-weight:bold;font-size:15px;color:#444}
.container-fluid .book .meta .author{font-size:12px;color:#999} .container-fluid .book .meta .author{font-size:12px;color:#999}
.container-fluid .book .meta .rating{margin-top:5px}.rating .glyphicon-star{color:#999}.rating .glyphicon-star.good{color:#45b29d} .container-fluid .book .meta .rating{margin-top:5px}.rating .glyphicon-star{color:#999}.rating .glyphicon-star.good{color:#45b29d}
.container-fluid .author .author-hidden, .container-fluid .author .author-hidden-divider {
display: none;
}
.navbar-brand{font-family: 'Grand Hotel', cursive; font-size: 35px; color: #45b29d !important;} .navbar-brand{font-family: 'Grand Hotel', cursive; font-size: 35px; color: #45b29d !important;}
.more-stuff{margin-top: 20px; padding-top: 20px; border-top: 1px solid #ccc} .more-stuff{margin-top: 20px; padding-top: 20px; border-top: 1px solid #ccc}
.more-stuff>li{margin-bottom: 10px;} .more-stuff>li{margin-bottom: 10px;}
...@@ -52,6 +57,7 @@ span.glyphicon.glyphicon-tags {padding-right: 5px;color: #999;vertical-align: te ...@@ -52,6 +57,7 @@ span.glyphicon.glyphicon-tags {padding-right: 5px;color: #999;vertical-align: te
-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;
} }
.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;}
...@@ -103,6 +109,16 @@ input.pill:not(:checked) + label .glyphicon { ...@@ -103,6 +109,16 @@ input.pill:not(:checked) + label .glyphicon {
.tags_click, .serie_click, .language_click {margin-right: 5px;} .tags_click, .serie_click, .language_click {margin-right: 5px;}
#meta-info {
height:600px;
overflow-y:scroll;
}
.media-list {
padding-right:15px;
}
.media-body p {
text-align: justify;
}
#meta-info img { max-height: 150px; max-width: 100px; cursor: pointer; } #meta-info img { max-height: 150px; max-width: 100px; cursor: pointer; }
.padded-bottom { margin-bottom: 15px; } .padded-bottom { margin-bottom: 15px; }
...@@ -120,3 +136,7 @@ input.pill:not(:checked) + label .glyphicon { ...@@ -120,3 +136,7 @@ input.pill:not(:checked) + label .glyphicon {
.editable-cancel { margin-bottom: 0px !important; margin-left: 7px !important;} .editable-cancel { margin-bottom: 0px !important; margin-left: 7px !important;}
.editable-submit { margin-bottom: 0px !important;} .editable-submit { margin-bottom: 0px !important;}
.modal-body .comments {
max-height:300px;
overflow-y: auto;
}
@media (min-device-width: 768px) {
.upload-modal-dialog {
position: absolute;
top: 45%;
left: 50%;
transform: translate(-50%, -50%) !important;
}
}
...@@ -277,8 +277,6 @@ bitjs.archive = bitjs.archive || {}; ...@@ -277,8 +277,6 @@ bitjs.archive = bitjs.archive || {};
if (e.type === bitjs.archive.UnarchiveEvent.Type.FINISH) { if (e.type === bitjs.archive.UnarchiveEvent.Type.FINISH) {
this.worker_.terminate(); this.worker_.terminate();
} }
} else {
console.log(e);
} }
}; };
...@@ -292,15 +290,11 @@ bitjs.archive = bitjs.archive || {}; ...@@ -292,15 +290,11 @@ bitjs.archive = bitjs.archive || {};
this.worker_ = new Worker(scriptFileName); this.worker_ = new Worker(scriptFileName);
this.worker_.onerror = function(e) { this.worker_.onerror = function(e) {
console.log("Worker error: message = " + e.message);
throw e; throw e;
}; };
this.worker_.onmessage = function(e) { this.worker_.onmessage = function(e) {
if (typeof e.data === "string") { if (typeof e.data !== "string") {
// Just log any strings the workers pump our way.
console.log(e.data);
} else {
// Assume that it is an UnarchiveEvent. Some browsers preserve the 'type' // Assume that it is an UnarchiveEvent. Some browsers preserve the 'type'
// so that instanceof UnarchiveEvent returns true, but others do not. // so that instanceof UnarchiveEvent returns true, but others do not.
me.handleWorkerEvent_(e.data); me.handleWorkerEvent_(e.data);
......
This diff is collapsed.
/* This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
* Copyright (C) 2018 jkrehm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* global _ */ /* global _ */
$(function() { $(function() {
......
/* This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
* Copyright (C) 2018 idalin<dalin.lin@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* /*
* Get Metadata from Douban Books api and Google Books api * Get Metadata from Douban Books api and Google Books api
* Created by idalin<dalin.lin@gmail.com>
* Google Books api document: https://developers.google.com/books/docs/v1/using * Google Books api document: https://developers.google.com/books/docs/v1/using
* Douban Books api document: https://developers.douban.com/wiki/?title=book_v2 (Chinese Only) * Douban Books api document: https://developers.douban.com/wiki/?title=book_v2 (Chinese Only)
*/ */
......
...@@ -99,14 +99,15 @@ kthoom.setSettings = function() { ...@@ -99,14 +99,15 @@ kthoom.setSettings = function() {
}; };
var createURLFromArray = function(array, mimeType) { var createURLFromArray = function(array, mimeType) {
var offset = array.byteOffset, len = array.byteLength; var offset = array.byteOffset;
var len = array.byteLength;
var url; var url;
var blob; var blob;
if (mimeType === 'image/xml+svg') { if (mimeType === 'image/xml+svg') {
const xmlStr = new TextDecoder('utf-8').decode(array); const xmlStr = new TextDecoder('utf-8').decode(array);
return 'data:image/svg+xml;UTF-8,' + encodeURIComponent(xmlStr); return 'data:image/svg+xml;UTF-8,' + encodeURIComponent(xmlStr);
} }
// TODO: Move all this browser support testing to a common place // TODO: Move all this browser support testing to a common place
// and do it just once. // and do it just once.
...@@ -137,11 +138,13 @@ var createURLFromArray = function(array, mimeType) { ...@@ -137,11 +138,13 @@ var createURLFromArray = function(array, mimeType) {
kthoom.ImageFile = function(file) { kthoom.ImageFile = function(file) {
this.filename = file.filename; this.filename = file.filename;
var fileExtension = file.filename.split(".").pop().toLowerCase(); var fileExtension = file.filename.split(".").pop().toLowerCase();
var mimeType = fileExtension === "png" ? "image/png" : this.mimeType = fileExtension === "png" ? "image/png" :
(fileExtension === "jpg" || fileExtension === "jpeg") ? "image/jpeg" : (fileExtension === "jpg" || fileExtension === "jpeg") ? "image/jpeg" :
fileExtension === "gif" ? "image/gif" : fileExtension == 'svg' ? 'image/xml+svg' : undefined; fileExtension === "gif" ? "image/gif" : fileExtension == 'svg' ? 'image/xml+svg' : undefined;
this.dataURI = createURLFromArray(file.fileData, mimeType); if ( this.mimeType !== undefined) {
this.data = file; this.dataURI = createURLFromArray(file.fileData, this.mimeType);
this.data = file;
}
}; };
...@@ -169,34 +172,42 @@ function loadFromArrayBuffer(ab) { ...@@ -169,34 +172,42 @@ function loadFromArrayBuffer(ab) {
unarchiver.addEventListener(bitjs.archive.UnarchiveEvent.Type.PROGRESS, unarchiver.addEventListener(bitjs.archive.UnarchiveEvent.Type.PROGRESS,
function(e) { function(e) {
var percentage = e.currentBytesUnarchived / e.totalUncompressedBytesInArchive; var percentage = e.currentBytesUnarchived / e.totalUncompressedBytesInArchive;
totalImages = e.totalFilesInArchive; if (totalImages === 0) {
totalImages = e.totalFilesInArchive;
}
updateProgress(percentage *100); updateProgress(percentage *100);
lastCompletion = percentage * 100; lastCompletion = percentage * 100;
}); });
unarchiver.addEventListener(bitjs.archive.UnarchiveEvent.Type.EXTRACT, unarchiver.addEventListener(bitjs.archive.UnarchiveEvent.Type.EXTRACT,
function(e) { function(e) {
// convert DecompressedFile into a bunch of ImageFiles // convert DecompressedFile into a bunch of ImageFiles
if (e.unarchivedFile) { if (e.unarchivedFile) {
var f = e.unarchivedFile; var f = e.unarchivedFile;
// add any new pages based on the filename // add any new pages based on the filename
if (imageFilenames.indexOf(f.filename) === -1) { if (imageFilenames.indexOf(f.filename) === -1) {
imageFilenames.push(f.filename); var test = new kthoom.ImageFile(f);
imageFiles.push(new kthoom.ImageFile(f)); if ( test.mimeType !== undefined) {
// add thumbnails to the TOC list imageFilenames.push(f.filename);
$("#thumbnails").append( imageFiles.push(test);
"<li>" + // add thumbnails to the TOC list
"<a data-page='" + imageFiles.length + "'>" + $("#thumbnails").append(
"<img src='" + imageFiles[imageFiles.length - 1].dataURI + "'/>" + "<li>" +
"<span>" + imageFiles.length + "</span>" + "<a data-page='" + imageFiles.length + "'>" +
"</a>" + "<img src='" + imageFiles[imageFiles.length - 1].dataURI + "'/>" +
"</li>" "<span>" + imageFiles.length + "</span>" +
); "</a>" +
"</li>"
);
// display first page if we haven't yet
if (imageFiles.length === currentImage + 1) {
updatePage(lastCompletion);
}
}
else {
totalImages--;
}
} }
} }
// display first page if we haven't yet
if (imageFiles.length === currentImage + 1) {
updatePage(lastCompletion);
}
}); });
unarchiver.addEventListener(bitjs.archive.UnarchiveEvent.Type.FINISH, unarchiver.addEventListener(bitjs.archive.UnarchiveEvent.Type.FINISH,
function() { function() {
......
!function(a){a.fn.datepicker.dates.ja={days:["日曜","月曜","火曜","水曜","木曜","金曜","土曜"],daysShort:["日","月","火","水","木","金","土"],daysMin:["日","月","火","水","木","金","土"],months:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],monthsShort:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],today:"今日",format:"yyyy/mm/dd",titleFormat:"yyyy年mm月",clear:"クリア"}}(jQuery);
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
!function(t){var i=t(window);t.fn.visible=function(t,e,o){if(!(this.length<1)){var r=this.length>1?this.eq(0):this,n=r.get(0),f=i.width(),h=i.height(),o=o?o:"both",l=e===!0?n.offsetWidth*n.offsetHeight:!0;if("function"==typeof n.getBoundingClientRect){var g=n.getBoundingClientRect(),u=g.top>=0&&g.top<h,s=g.bottom>0&&g.bottom<=h,c=g.left>=0&&g.left<f,a=g.right>0&&g.right<=f,v=t?u||s:u&&s,b=t?c||a:c&&a;if("both"===o)return l&&v&&b;if("vertical"===o)return l&&v;if("horizontal"===o)return l&&b}else{var d=i.scrollTop(),p=d+h,w=i.scrollLeft(),m=w+f,y=r.offset(),z=y.top,B=z+r.height(),C=y.left,R=C+r.width(),j=t===!0?B:z,q=t===!0?z:B,H=t===!0?R:C,L=t===!0?C:R;if("both"===o)return!!l&&p>=q&&j>=d&&m>=L&&H>=w;if("vertical"===o)return!!l&&p>=q&&j>=d;if("horizontal"===o)return!!l&&m>=L&&H>=w}}}}(jQuery);
This diff is collapsed.
/*!
* @preserve
*
* Readmore.js jQuery plugin
* Author: @jed_foster
* Project home: http://jedfoster.github.io/Readmore.js
* Licensed under the MIT license
*
* Debounce function from http://davidwalsh.name/javascript-debounce-function
*/
!function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof exports?module.exports=t(require("jquery")):t(jQuery)}(function(t){"use strict";function e(t,e,i){var o;return function(){var n=this,a=arguments,s=function(){o=null,i||t.apply(n,a)},r=i&&!o;clearTimeout(o),o=setTimeout(s,e),r&&t.apply(n,a)}}function i(t){var e=++h;return String(null==t?"rmjs-":t)+e}function o(t){var e=t.clone().css({height:"auto",width:t.width(),maxHeight:"none",overflow:"hidden"}).insertAfter(t),i=e.outerHeight(),o=parseInt(e.css({maxHeight:""}).css("max-height").replace(/[^-\d\.]/g,""),10),n=t.data("defaultHeight");e.remove();var a=o||t.data("collapsedHeight")||n;t.data({expandedHeight:i,maxHeight:o,collapsedHeight:a}).css({maxHeight:"none"})}function n(t){if(!d[t.selector]){var e=" ";t.embedCSS&&""!==t.blockCSS&&(e+=t.selector+" + [data-readmore-toggle], "+t.selector+"[data-readmore]{"+t.blockCSS+"}"),e+=t.selector+"[data-readmore]{transition: height "+t.speed+"ms;overflow: hidden;}",function(t,e){var i=t.createElement("style");i.type="text/css",i.styleSheet?i.styleSheet.cssText=e:i.appendChild(t.createTextNode(e)),t.getElementsByTagName("head")[0].appendChild(i)}(document,e),d[t.selector]=!0}}function a(e,i){this.element=e,this.options=t.extend({},r,i),n(this.options),this._defaults=r,this._name=s,this.init(),window.addEventListener?(window.addEventListener("load",c),window.addEventListener("resize",c)):(window.attachEvent("load",c),window.attachEvent("resize",c))}var s="readmore",r={speed:100,collapsedHeight:200,heightMargin:16,moreLink:'<a href="#">Read More</a>',lessLink:'<a href="#">Close</a>',embedCSS:!0,blockCSS:"display: block; width: 100%;",startOpen:!1,blockProcessed:function(){},beforeToggle:function(){},afterToggle:function(){}},d={},h=0,c=e(function(){t("[data-readmore]").each(function(){var e=t(this),i="true"===e.attr("aria-expanded");o(e),e.css({height:e.data(i?"expandedHeight":"collapsedHeight")})})},100);a.prototype={init:function(){var e=t(this.element);e.data({defaultHeight:this.options.collapsedHeight,heightMargin:this.options.heightMargin}),o(e);var n=e.data("collapsedHeight"),a=e.data("heightMargin");if(e.outerHeight(!0)<=n+a)return this.options.blockProcessed&&"function"==typeof this.options.blockProcessed&&this.options.blockProcessed(e,!1),!0;var s=e.attr("id")||i(),r=this.options.startOpen?this.options.lessLink:this.options.moreLink;e.attr({"data-readmore":"","aria-expanded":this.options.startOpen,id:s}),e.after(t(r).on("click",function(t){return function(i){t.toggle(this,e[0],i)}}(this)).attr({"data-readmore-toggle":s,"aria-controls":s})),this.options.startOpen||e.css({height:n}),this.options.blockProcessed&&"function"==typeof this.options.blockProcessed&&this.options.blockProcessed(e,!0)},toggle:function(e,i,o){o&&o.preventDefault(),e||(e=t('[aria-controls="'+this.element.id+'"]')[0]),i||(i=this.element);var n=t(i),a="",s="",r=!1,d=n.data("collapsedHeight");n.height()<=d?(a=n.data("expandedHeight")+"px",s="lessLink",r=!0):(a=d,s="moreLink"),this.options.beforeToggle&&"function"==typeof this.options.beforeToggle&&this.options.beforeToggle(e,n,!r),n.css({height:a}),n.on("transitionend",function(i){return function(){i.options.afterToggle&&"function"==typeof i.options.afterToggle&&i.options.afterToggle(e,n,r),t(this).attr({"aria-expanded":r}).off("transitionend")}}(this)),t(e).replaceWith(t(this.options[s]).on("click",function(t){return function(e){t.toggle(this,i,e)}}(this)).attr({"data-readmore-toggle":n.attr("id"),"aria-controls":n.attr("id")}))},destroy:function(){t(this.element).each(function(){var e=t(this);e.attr({"data-readmore":null,"aria-expanded":null}).css({maxHeight:"",height:""}).next("[data-readmore-toggle]").remove(),e.removeData()})}},t.fn.readmore=function(e){var i=arguments,o=this.selector;return e=e||{},"object"==typeof e?this.each(function(){if(t.data(this,"plugin_"+s)){var i=t.data(this,"plugin_"+s);i.destroy.apply(i)}e.selector=o,t.data(this,"plugin_"+s,new a(this,e))}):"string"==typeof e&&"_"!==e[0]&&"init"!==e?this.each(function(){var o=t.data(this,"plugin_"+s);o instanceof a&&"function"==typeof o[e]&&o[e].apply(o,Array.prototype.slice.call(i,1))}):void 0}});
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
/* This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
* Copyright (C) 2012-2019 mutschler, janeczku, jkrehm, OzzieIsaacs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Generic control/related handler to show/hide fields based on a checkbox' value // Generic control/related handler to show/hide fields based on a checkbox' value
// e.g. // e.g.
// <input type="checkbox" data-control="stuff-to-show"> // <input type="checkbox" data-control="stuff-to-show">
...@@ -60,25 +77,20 @@ $(function() { ...@@ -60,25 +77,20 @@ $(function() {
layoutMode : "fitRows" layoutMode : "fitRows"
}); });
$(".load-more .row").infinitescroll({ var $loadMore = $(".load-more .row").infiniteScroll({
debug: false, debug: false,
navSelector : ".pagination",
// selector for the paged navigation (it will be hidden) // selector for the paged navigation (it will be hidden)
nextSelector : ".pagination a:last", path : ".next",
// selector for the NEXT link (to page 2) // selector for the NEXT link (to page 2)
itemSelector : ".load-more .book", append : ".load-more .book"
animate : true, //animate : true, # ToDo: Reenable function
extraScrollPx: 300 //extraScrollPx: 300
// selector for all items you'll retrieve });
}, function(data) { $loadMore.on( "append.infiniteScroll", function( event, response, path, data ) {
$(".pagination").addClass("hidden");
$(".load-more .row").isotope( "appended", $(data), null ); $(".load-more .row").isotope( "appended", $(data), null );
}); });
$("#sendbtn").click(function() {
var $this = $(this);
$this.text("Please wait...");
$this.addClass("disabled");
});
$("#restart").click(function() { $("#restart").click(function() {
$.ajax({ $.ajax({
dataType: "json", dataType: "json",
...@@ -104,15 +116,18 @@ $(function() { ...@@ -104,15 +116,18 @@ $(function() {
var $this = $(this); var $this = $(this);
var buttonText = $this.html(); var buttonText = $this.html();
$this.html("..."); $this.html("...");
$("#update_error").addClass("hidden") $("#update_error").addClass("hidden");
if ($("#message").length) {
$("#message").alert("close");
}
$.ajax({ $.ajax({
dataType: "json", dataType: "json",
url: window.location.pathname + "/../../get_update_status", url: window.location.pathname + "/../../get_update_status",
success: function success(data) { success: function success(data) {
$this.html(buttonText); $this.html(buttonText);
var cssClass = ''; var cssClass = "";
var message = '' var message = "";
if (data.success === true) { if (data.success === true) {
if (data.update === true) { if (data.update === true) {
...@@ -122,19 +137,20 @@ $(function() { ...@@ -122,19 +137,20 @@ $(function() {
.removeClass("hidden") .removeClass("hidden")
.find("span").html(data.commit); .find("span").html(data.commit);
data.history.reverse().forEach(function(entry, index) { data.history.forEach(function(entry) {
$("<tr><td>" + entry[0] + "</td><td>" + entry[1] + "</td></tr>").appendTo($("#update_table")); $("<tr><td>" + entry[0] + "</td><td>" + entry[1] + "</td></tr>").appendTo($("#update_table"));
}); });
cssClass = 'alert-warning' cssClass = "alert-warning";
} else { } else {
cssClass = 'alert-success' cssClass = "alert-success";
} }
} else { } else {
cssClass = 'alert-danger' cssClass = "alert-danger";
} }
message = '<div class="alert ' + cssClass message = "<div id=\"message\" class=\"alert " + cssClass
+ ' fade in"><a href="#" class="close" data-dismiss="alert">&times;</a>' + data.message + '</div>'; + " fade in\"><a href=\"#\" class=\"close\" data-dismiss=\"alert\">&times;</a>"
+ data.message + "</div>";
$(message).insertAfter($("#update_table")); $(message).insertAfter($("#update_table"));
} }
...@@ -163,6 +179,7 @@ $(function() { ...@@ -163,6 +179,7 @@ $(function() {
}); });
}); });
// Init all data control handlers to default
$("input[data-control]").trigger("change"); $("input[data-control]").trigger("change");
$("#bookDetailsModal") $("#bookDetailsModal")
...@@ -186,6 +203,14 @@ $(function() { ...@@ -186,6 +203,14 @@ $(function() {
}); });
$(window).resize(function() { $(window).resize(function() {
$(".discover .row").isotope("reLayout"); $(".discover .row").isotope("layout");
});
$(".author-expand").click(function() {
$(this).parent().find("a.author-name").slice($(this).data("authors-max")).toggle();
$(this).parent().find("span.author-hidden-divider").toggle();
$(this).html() === $(this).data("collapse-caption") ? $(this).html("(...)") : $(this).html($(this).data("collapse-caption"));
$(".discover .row").isotope("layout");
}); });
}); });
/* This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
* Copyright (C) 2018 jkrehm, OzzieIsaacs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* global Sortable,sortTrue */ /* global Sortable,sortTrue */
Sortable.create(sortTrue, { Sortable.create(sortTrue, {
......
/* This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
* Copyright (C) 2018 OzzieIsaacs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
$(function() { $(function() {
$("#domain_submit").click(function(event){ $("#domain_submit").click(function(event) {
event.preventDefault(); event.preventDefault();
$("#domain_add").ajaxForm(); $("#domain_add").ajaxForm();
$(this).closest("form").submit(); $(this).closest("form").submit();
...@@ -10,48 +27,49 @@ $(function() { ...@@ -10,48 +27,49 @@ $(function() {
async: true, async: true,
timeout: 900, timeout: 900,
success:function(data){ success:function(data){
$('#domain-table').bootstrapTable("load", data); $("#domain-table").bootstrapTable("load", data);
} }
}); });
}); });
$('#domain-table').bootstrapTable({ $("#domain-table").bootstrapTable({
formatNoMatches: function () { formatNoMatches: function () {
return ''; return "";
}, },
striped: false striped: false
}); });
$("#btndeletedomain").click(function() { $("#btndeletedomain").click(function() {
//get data-id attribute of the clicked element //get data-id attribute of the clicked element
var domainId = $(this).data('domainId'); var domainId = $(this).data("domainId");
$.ajax({ $.ajax({
method:"post", method:"post",
url: window.location.pathname + "/../../ajax/deletedomain", url: window.location.pathname + "/../../ajax/deletedomain",
data: {"domainid":domainId} data: {"domainid":domainId}
}); });
$('#DeleteDomain').modal('hide'); $("#DeleteDomain").modal("hide");
$.ajax({ $.ajax({
method:"get", method:"get",
url: window.location.pathname + "/../../ajax/domainlist", url: window.location.pathname + "/../../ajax/domainlist",
async: true, async: true,
timeout: 900, timeout: 900,
success:function(data){ success:function(data) {
$('#domain-table').bootstrapTable("load", data); $("#domain-table").bootstrapTable("load", data);
} }
}); });
}); });
//triggered when modal is about to be shown //triggered when modal is about to be shown
$('#DeleteDomain').on('show.bs.modal', function(e) { $("#DeleteDomain").on("show.bs.modal", function(e) {
//get data-id attribute of the clicked element and store in button //get data-id attribute of the clicked element and store in button
var domainId = $(e.relatedTarget).data('domain-id'); var domainId = $(e.relatedTarget).data("domain-id");
$(e.currentTarget).find("#btndeletedomain").data('domainId',domainId); $(e.currentTarget).find("#btndeletedomain").data("domainId", domainId);
}); });
}); });
function TableActions (value, row, index) { /*function TableActions (value, row, index) {
return [ return [
'<a class="danger remove" data-toggle="modal" data-target="#DeleteDomain" data-domain-id="'+row.id+'" title="Remove">', "<a class=\"danger remove\" data-toggle=\"modal\" data-target=\"#DeleteDomain\" data-domain-id=\"" + row.id
'<i class="glyphicon glyphicon-trash"></i>', + "\" title=\"Remove\">",
'</a>' "<i class=\"glyphicon glyphicon-trash\"></i>",
].join(''); "</a>"
} ].join("");
}*/
This diff is collapsed.
This diff is collapsed.
/*
* bootstrap-uploadprogress
* github: https://github.com/jakobadam/bootstrap-uploadprogress
*
* Copyright (c) 2015 Jakob Aarøe Dam
* Version 1.0.0
* Licensed under the MIT license.
*/
(function($) {
"use strict";
$.support.xhrFileUpload = !!(window.FileReader && window.ProgressEvent);
$.support.xhrFormData = !!window.FormData;
if (!$.support.xhrFileUpload || !$.support.xhrFormData) {
// skip decorating form
return;
}
var template = "<div class=\"modal fade\" id=\"file-progress-modal\">" +
"<div class=\"modal-dialog upload-modal-dialog\">" +
" <div class=\"modal-content\">" +
" <div class=\"modal-header\">" +
" <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>" +
" <h4 class=\"modal-title\">Uploading</h4>" +
" </div>" +
" <div class=\"modal-body\">" +
" <div class=\"modal-message\"></div>" +
" <div class=\"progress\">" +
" <div class=\"progress-bar progress-bar-striped active\" role=\"progressbar\" aria-valuenow=\"0\" aria-valuemin=\"0\"" +
" aria-valuemax=\"100\" style=\"width: 0%;min-width: 2em;\">" +
" 0%" +
" </div>" +
" </div>" +
" </div>" +
" <div class=\"modal-footer\" style=\"display:none\">" +
" <button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">Close</button>" +
" </div>" +
" </div>" +
" </div>" +
"</div>";
var UploadProgress = function(element, options) {
this.options = options;
this.$element = $(element);
};
UploadProgress.prototype = {
constructor: function() {
this.$form = this.$element;
this.$form.on("submit", $.proxy(this.submit, this));
this.$modal = $(this.options.template);
this.$modalTitle = this.$modal.find(".modal-title");
this.$modalFooter = this.$modal.find(".modal-footer");
this.$modalBar = this.$modal.find(".progress-bar");
// Translate texts
this.$modalTitle.text(this.options.modalTitle)
this.$modalFooter.children("button").text(this.options.modalFooter);
this.$modal.on("hidden.bs.modal", $.proxy(this.reset, this));
},
reset: function() {
this.$modalTitle.text(this.options.modalTitle);
this.$modalFooter.hide();
this.$modalBar.addClass("progress-bar-success");
this.$modalBar.removeClass("progress-bar-danger");
if (this.xhr) {
this.xhr.abort();
}
},
submit: function(e) {
e.preventDefault();
this.$modal.modal({
backdrop: "static",
keyboard: false
});
// We need the native XMLHttpRequest for the progress event
var xhr = new XMLHttpRequest();
this.xhr = xhr;
xhr.addEventListener("load", $.proxy(this.success, this, xhr));
xhr.addEventListener("error", $.proxy(this.error, this, xhr));
xhr.upload.addEventListener("progress", $.proxy(this.progress, this));
var form = this.$form;
xhr.open(form.attr("method"), form.attr("action"));
xhr.setRequestHeader("X-REQUESTED-WITH", "XMLHttpRequest");
var data = new FormData(form.get(0));
xhr.send(data);
},
success: function(xhr) {
if (xhr.status === 0 || xhr.status >= 400) {
// HTTP 500 ends up here!?!
return this.error(xhr);
}
this.setProgress(100);
var url;
var contentType = xhr.getResponseHeader("Content-Type");
// make it possible to return the redirect URL in
// a JSON response
if (contentType.indexOf("application/json") !== -1) {
var response = $.parseJSON(xhr.responseText);
url = response.location;
}
else{
url = this.options.redirect_url;
}
window.location.href = url;
},
// handle form error
// we replace the form with the returned one
error: function(xhr) {
this.$modalTitle.text(this.options.modalTitleFailed);
this.$modalBar.removeClass("progress-bar-success");
this.$modalBar.addClass("progress-bar-danger");
this.$modalFooter.show();
var contentType = xhr.getResponseHeader("Content-Type");
// Replace the contents of the form, with the returned html
if (xhr.status === 422) {
var newHtml = $.parseHTML(xhr.responseText);
this.replaceForm(newHtml);
this.$modal.modal("hide");
}
// Write the error response to the document.
else{
// Handle no response error
if (contentType) {
var responseText = xhr.responseText;
if (contentType.indexOf("text/plain") !== -1) {
responseText = "<pre>" + responseText + "</pre>";
}
document.write(responseText);
}
}
},
setProgress: function(percent) {
var txt = percent + "%";
if (percent === 100) {
txt = this.options.uploadedMsg;
}
this.$modalBar.attr("aria-valuenow", percent);
this.$modalBar.text(txt);
this.$modalBar.css("width", percent + "%");
},
progress: function(/*ProgressEvent*/e) {
var percent = Math.round((e.loaded / e.total) * 100);
this.setProgress(percent);
},
// replaceForm replaces the contents of the current form
// with the form in the html argument.
// We use the id of the current form to find the new form in the html
replaceForm: function(html) {
var newForm;
var formId = this.$form.attr("id");
if ( typeof formId !== "undefined") {
newForm = $(html).find("#" + formId);
} else {
newForm = $(html).find("form");
}
// add the filestyle again
newForm.find(":file").filestyle({buttonBefore: true});
this.$form.html(newForm.children());
}
};
$.fn.uploadprogress = function(options) {
return this.each(function() {
var _options = $.extend({}, $.fn.uploadprogress.defaults, options);
var fileProgress = new UploadProgress(this, _options);
fileProgress.constructor();
});
};
$.fn.uploadprogress.defaults = {
template: template,
uploadedMsg: "Upload done, processing, please wait...",
modalTitle: "Uploading",
modalFooter: "Close",
modalTitleFailed: "Upload failed"
//redirect_url: ...
// need to customize stuff? Add here, and change code accordingly.
};
})(window.jQuery);
...@@ -105,7 +105,7 @@ ...@@ -105,7 +105,7 @@
<div class="col"> <div class="col">
<h2>{{_('Administration')}}</h2> <h2>{{_('Administration')}}</h2>
<div class="btn btn-default" id="restart_database">{{_('Reconnect to Calibre DB')}}</div> <div class="btn btn-default" id="restart_database">{{_('Reconnect to Calibre DB')}}</div>
<div class="btn btn-default" id="admin_restart"data-toggle="modal" data-target="#RestartDialog">{{_('Restart Calibre-Web')}}</div> <div class="btn btn-default" id="admin_restart" data-toggle="modal" data-target="#RestartDialog">{{_('Restart Calibre-Web')}}</div>
<div class="btn btn-default" id="admin_stop" data-toggle="modal" data-target="#ShutdownDialog">{{_('Stop Calibre-Web')}}</div> <div class="btn btn-default" id="admin_stop" data-toggle="modal" data-target="#ShutdownDialog">{{_('Stop Calibre-Web')}}</div>
</div> </div>
</div> </div>
...@@ -144,7 +144,7 @@ ...@@ -144,7 +144,7 @@
<div class="modal-body text-center"> <div class="modal-body text-center">
<p>{{_('Do you really want to restart Calibre-Web?')}}</p> <p>{{_('Do you really want to restart Calibre-Web?')}}</p>
<div id="spinner" class="spinner" style="display:none;"> <div id="spinner" class="spinner" style="display:none;">
<img id="img-spinner" src="/static/css/images/loading-icon.gif"/> <img id="img-spinner" src="{{ url_for('static', filename='css/images/loading-icon.gif') }}"/>
</div> </div>
<p></p> <p></p>
<button type="button" class="btn btn-default" id="restart" >{{_('Ok')}}</button> <button type="button" class="btn btn-default" id="restart" >{{_('Ok')}}</button>
...@@ -176,7 +176,7 @@ ...@@ -176,7 +176,7 @@
</div> </div>
<div class="modal-body text-center"> <div class="modal-body text-center">
<div id="spinner2" class="spinner2" style="display:none;"> <div id="spinner2" class="spinner2" style="display:none;">
<img id="img-spinner" src="/static/css/images/loading-icon.gif"/> <img id="img-spinner2" src="{{ url_for('static', filename='css/images/loading-icon.gif') }}"/>
</div> </div>
<p></p> <p></p>
<div id="Updatecontent"></div> <div id="Updatecontent"></div>
......
This diff is collapsed.
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<div class="col-sm-3 col-lg-3 col-xs-12"> <div class="col-sm-3 col-lg-3 col-xs-12">
<div class="cover"> <div class="cover">
{% if book.has_cover %} {% if book.has_cover %}
<img src="{{ url_for('get_cover', cover_path=book.path.replace('\\','/')) }}" alt="{{ book.title }}"/> <img src="{{ url_for('get_cover', book_id=book.id) }}" alt="{{ book.title }}"/>
{% else %} {% else %}
<img src="{{ url_for('static', filename='generic_cover.jpg') }}" alt="{{ book.title }}"/> <img src="{{ url_for('static', filename='generic_cover.jpg') }}" alt="{{ book.title }}"/>
{% endif %} {% endif %}
...@@ -219,7 +219,7 @@ ...@@ -219,7 +219,7 @@
</span> </span>
</div> </div>
</form> </form>
<div>{{_('Click the cover to load metadata to the form')}}</div> <div class="text-center"><strong>{{_('Click the cover to load metadata to the form')}}</strong></div>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="text-center padded-bottom"> <div class="text-center padded-bottom">
......
This diff is collapsed.
...@@ -27,6 +27,17 @@ ...@@ -27,6 +27,17 @@
<label for="config_random_books">{{_('No. of random books to show')}}</label> <label for="config_random_books">{{_('No. of random books to show')}}</label>
<input type="number" min="1" max="30" class="form-control" name="config_random_books" id="config_random_books" value="{% if content.config_random_books != None %}{{ content.config_random_books }}{% endif %}" autocomplete="off"> <input type="number" min="1" max="30" class="form-control" name="config_random_books" id="config_random_books" value="{% if content.config_random_books != None %}{{ content.config_random_books }}{% endif %}" autocomplete="off">
</div> </div>
<div class="form-group">
<label for="config_authors_max">{{_('No. of authors to show before hiding (0=disable hiding)')}}</label>
<input type="number" min="0" max="999" class="form-control" name="config_authors_max" id="config_authors_max" value="{% if content.config_authors_max != None %}{{ content.config_authors_max }}{% endif %}" autocomplete="off">
</div>
<div class="form-group">
<label for="config_theme">{{_('Theme')}}</label>
<select name="config_theme" id="config_theme" class="form-control">
<option value="0" {% if content.config_theme == 0 %}selected{% endif %}>{{ _("Standard Theme") }}</option>
<option value="1" {% if content.config_theme == 1 %}selected{% endif %}>{{ _("caliBlur! Dark Theme") }}</option>
</select>
</div>
<div class="form-group"> <div class="form-group">
<label for="config_columns_to_ignore">{{_('Regular expression for ignoring columns')}}</label> <label for="config_columns_to_ignore">{{_('Regular expression for ignoring columns')}}</label>
<input type="text" class="form-control" name="config_columns_to_ignore" id="config_columns_to_ignore" value="{% if content.config_columns_to_ignore != None %}{{ content.config_columns_to_ignore }}{% endif %}" autocomplete="off"> <input type="text" class="form-control" name="config_columns_to_ignore" id="config_columns_to_ignore" value="{% if content.config_columns_to_ignore != None %}{{ content.config_columns_to_ignore }}{% endif %}" autocomplete="off">
......
This diff is collapsed.
This diff is collapsed.
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}"> <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
<link href="{{ url_for('static', filename='css/libs/bootstrap.min.css') }}" rel="stylesheet" media="screen"> <link href="{{ url_for('static', filename='css/libs/bootstrap.min.css') }}" rel="stylesheet" media="screen">
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" media="screen"> <link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet" media="screen">
{% if g.user.get_theme == 1 %} {% if g.current_theme == 1 %}
<link href="{{ url_for('static', filename='css/caliBlur-style.css') }}" rel="stylesheet" media="screen"> <link href="{{ url_for('static', filename='css/caliBlur.min.css') }}" rel="stylesheet" media="screen">
{% endif %} {% endif %}
</head> </head>
<body> <body>
......
This diff is collapsed.
This diff is collapsed.
{% extends "layout.html" %} {% extends "layout.html" %}
{% block body %} {% block body %}
<h1>{{title}}</h1> <h1 class="{{page}}">{{_(title)}}</h1>
<div class="container"> <div class="container">
<div class="col-xs-12 col-sm-6"> <div class="col-xs-12 col-sm-6">
{% for entry in entries %} {% for entry in entries %}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment