mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Start work on refactoring client app to make it fully offline-able
This commit is contained in:
parent
dd89294c62
commit
341fcfd91b
7
src/pyj/book_list/constants.pyj
Normal file
7
src/pyj/book_list/constants.pyj
Normal file
@ -0,0 +1,7 @@
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
from __python__ import hash_literals, bound_methods
|
||||
|
||||
|
||||
book_list_container_id = 'book-list-container'
|
||||
read_book_container_id = 'read-book-container'
|
@ -28,3 +28,9 @@ def get_current_query():
|
||||
def set_current_query(val):
|
||||
nonlocal current_query
|
||||
current_query = val
|
||||
|
||||
|
||||
def main_js(newval):
|
||||
if newval is not undefined:
|
||||
main_js.ans = newval
|
||||
return main_js.ans
|
||||
|
87
src/pyj/book_list/main.pyj
Normal file
87
src/pyj/book_list/main.pyj
Normal file
@ -0,0 +1,87 @@
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
from __python__ import hash_literals, bound_methods
|
||||
|
||||
import traceback
|
||||
from elementmaker import E
|
||||
from ajax import ajax
|
||||
from dom import set_css, get_widget_css
|
||||
from modals import create_modal_container, error_dialog
|
||||
from session import get_interface_data, UserSessionData, update_interface_data, get_translations
|
||||
from gettext import gettext as _, install
|
||||
from utils import parse_url_params
|
||||
|
||||
from book_list.constants import book_list_container_id, read_book_container_id
|
||||
from book_list.theme import get_color
|
||||
|
||||
|
||||
def remove_initial_progress_bar():
|
||||
p = document.getElementById('page_load_progress')
|
||||
if p:
|
||||
p.parentNode.removeChild(p)
|
||||
|
||||
def onerror(msg, script_url, line_number, column_number, error_object):
|
||||
console.log(error_object)
|
||||
try:
|
||||
fname = script_url.rpartition('/')[-1] or script_url
|
||||
msg = msg + '<br><span style="font-size:smaller">' + 'Error at {}:{}:{}'.format(fname, line_number, column_number or '') + '</span>'
|
||||
details = ''
|
||||
if error_object:
|
||||
details = traceback.format_exception(error_object).join('')
|
||||
error_dialog(_('Unhandled error'), msg, details)
|
||||
return True
|
||||
except:
|
||||
console.log('There was an error in the unhandled exception handler')
|
||||
|
||||
def init_ui():
|
||||
window.onerror = onerror
|
||||
translations = get_translations()
|
||||
if translations:
|
||||
install(translations)
|
||||
remove_initial_progress_bar()
|
||||
document.head.appendChild(E.style(get_widget_css()))
|
||||
set_css(document.body, background_color=get_color('window-background'), color=get_color('window-foreground'))
|
||||
document.body.appendChild(E.div(id='containers'))
|
||||
document.body.lastChild.appendChild(E.div(id=book_list_container_id, style='display: none'))
|
||||
document.body.lastChild.appendChild(E.div(id=read_book_container_id, style='display: none'))
|
||||
create_modal_container()
|
||||
|
||||
def on_data_loaded(end_type, xhr, ev):
|
||||
remove_initial_progress_bar()
|
||||
if end_type is 'load':
|
||||
data = JSON.parse(xhr.responseText)
|
||||
update_interface_data(data)
|
||||
if data.translations:
|
||||
get_translations(data.translations)
|
||||
init_ui()
|
||||
else:
|
||||
p = E.p(style='color:red; font-weight: bold; font-size:1.5em')
|
||||
if xhr.status is 401:
|
||||
p.innerHTML = _('You are not authorized to view this site')
|
||||
else:
|
||||
p.innerHTML = xhr.error_html
|
||||
document.body.appendChild(p)
|
||||
|
||||
def on_data_load_progress(loaded, total):
|
||||
p = document.querySelector('#page_load_progress > progress')
|
||||
p.max = total
|
||||
p.value = loaded
|
||||
|
||||
def load_interface_data():
|
||||
temp = UserSessionData(None, {}) # So that settings for anonymous users are preserved
|
||||
query = {}
|
||||
library_id = temp.get('library_id')
|
||||
if library_id:
|
||||
query.library_id = library_id
|
||||
query.sort = temp.get_library_option(library_id, 'sort')
|
||||
url_query = parse_url_params()
|
||||
for key in url_query:
|
||||
query[key] = url_query[key]
|
||||
ajax('interface-data/init', on_data_loaded, on_data_load_progress, query=query).send()
|
||||
|
||||
|
||||
def main():
|
||||
if get_interface_data().is_default:
|
||||
load_interface_data()
|
||||
else:
|
||||
init_ui()
|
@ -8,7 +8,7 @@ from gettext import gettext as _
|
||||
from utils import html_escape
|
||||
|
||||
from modals import error_dialog, warning_dialog
|
||||
from book_list.globals import get_session_data, get_boss
|
||||
from book_list.globals import get_session_data, get_boss, main_js
|
||||
from read_book.globals import messenger, iframe_id, current_book, set_current_spine_item
|
||||
from read_book.resources import load_resources
|
||||
from read_book.overlay import Overlay
|
||||
@ -193,8 +193,8 @@ class View:
|
||||
side_margin('left', margin_left), side_margin('right', margin_right)
|
||||
|
||||
def create_src_doc(self):
|
||||
iframe_script = self.ui.interface_data.main_js.replace(/is_running_in_iframe\s*=\s*false/, 'is_running_in_iframe = true')
|
||||
self.ui.interface_data.main_js = None
|
||||
iframe_script = main_js().replace(/is_running_in_iframe\s*=\s*false/, 'is_running_in_iframe = true')
|
||||
main_js(None)
|
||||
self.src_doc = self.iframe.srcdoc = LOADING_DOC.replace(
|
||||
'__BS__', _('Bootstrapping book reader...')).replace(
|
||||
'__SCRIPT__', iframe_script)
|
||||
|
@ -1,6 +1,6 @@
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPL v3 Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
from __python__ import hash_literals
|
||||
from __python__ import hash_literals, bound_methods
|
||||
|
||||
from ajax import ajax_send
|
||||
|
||||
@ -55,8 +55,6 @@ def storage_available(which):
|
||||
except:
|
||||
return False
|
||||
|
||||
session_storage = None
|
||||
|
||||
class FakeStorage:
|
||||
|
||||
def __init__(self):
|
||||
@ -74,17 +72,16 @@ class FakeStorage:
|
||||
self.data = {}
|
||||
|
||||
def get_session_storage():
|
||||
nonlocal session_storage
|
||||
if session_storage is None:
|
||||
if not get_session_storage.ans:
|
||||
if storage_available('localStorage'):
|
||||
session_storage = window.localStorage
|
||||
get_session_storage.ans = window.localStorage
|
||||
elif storage_available('sessionStorage'):
|
||||
session_storage = window.sessionStorage
|
||||
get_session_storage.ans = window.sessionStorage
|
||||
console.error('localStorage not available using sessionStorage instead')
|
||||
else:
|
||||
session_storage = FakeStorage()
|
||||
get_session_storage.ans = FakeStorage()
|
||||
console.error('sessionStorage and localStorage not available using a temp cache instead')
|
||||
return session_storage
|
||||
return get_session_storage.ans
|
||||
|
||||
class SessionData:
|
||||
|
||||
@ -130,11 +127,56 @@ class SessionData:
|
||||
self.overflow_storage = {}
|
||||
self.has_overflow = False
|
||||
|
||||
|
||||
def local_storage():
|
||||
if not local_storage.storage:
|
||||
local_storage.storage = SessionData('calibre-local-')
|
||||
return local_storage.storage
|
||||
|
||||
default_interface_data = {
|
||||
'username': None,
|
||||
'output_format': 'EPUB',
|
||||
'input_formats': {'EPUB', 'MOBI', 'AZW3'},
|
||||
'gui_pubdate_display_format': 'MMM yyyy',
|
||||
'gui_timestamp_display_format': 'dd MMM yyyy',
|
||||
'gui_last_modified_display_format': 'dd MMM yyyy',
|
||||
'use_roman_numerals_for_series_number': True,
|
||||
'allow_console_print':False,
|
||||
}
|
||||
|
||||
def get_interface_data():
|
||||
if not get_interface_data.storage:
|
||||
get_interface_data.storage = SessionData('calibre-interface-data-')
|
||||
ans = get_interface_data.storage.get('current')
|
||||
if ans:
|
||||
ans.is_default = False
|
||||
else:
|
||||
ans = {'is_default': True}
|
||||
for k in default_interface_data:
|
||||
ans[k] = default_interface_data[k]
|
||||
return ans
|
||||
|
||||
|
||||
def update_interface_data(new_data):
|
||||
data = get_interface_data()
|
||||
for k in default_interface_data:
|
||||
nval = new_data[k]
|
||||
if k is not undefined:
|
||||
data[k] = nval
|
||||
if not get_interface_data.storage:
|
||||
get_interface_data.storage = SessionData('calibre-interface-data-')
|
||||
get_interface_data.storage.set('current', data)
|
||||
|
||||
|
||||
def get_translations(newval):
|
||||
if not get_translations.storage:
|
||||
get_translations.storage = SessionData('calibre-translations-')
|
||||
if newval:
|
||||
get_translations.storage.set('current', newval)
|
||||
else:
|
||||
return get_translations.storage.get('current')
|
||||
|
||||
|
||||
class UserSessionData(SessionData):
|
||||
|
||||
def __init__(self, username, saved_data):
|
||||
|
@ -3,76 +3,25 @@
|
||||
from __python__ import hash_literals
|
||||
|
||||
import initialize # noqa: unused-import
|
||||
from ajax import ajax, set_allow_console_print
|
||||
from elementmaker import E
|
||||
from gettext import gettext as _, install
|
||||
from session import UserSessionData
|
||||
from utils import parse_url_params
|
||||
from ajax import ajax
|
||||
|
||||
from book_list.boss import Boss
|
||||
from book_list.globals import set_session_data
|
||||
from book_list.globals import main_js
|
||||
from book_list.main import main
|
||||
from read_book.iframe import init
|
||||
|
||||
def on_library_loaded(end_type, xhr, ev):
|
||||
nonlocal main_js
|
||||
p = document.getElementById('page_load_progress')
|
||||
p.parentNode.removeChild(p)
|
||||
if end_type is 'load':
|
||||
interface_data = JSON.parse(xhr.responseText)
|
||||
interface_data.main_js = main_js
|
||||
set_allow_console_print(interface_data.allow_console_print)
|
||||
main_js = None
|
||||
script = document.getElementById('main_js')
|
||||
if script:
|
||||
script.parentNode.removeChild(script) # Free up some memory
|
||||
if interface_data.translations:
|
||||
install(interface_data.translations)
|
||||
sd = UserSessionData(interface_data.username, interface_data.user_session_data)
|
||||
set_session_data(sd)
|
||||
sd.set('library_id', interface_data.library_id)
|
||||
Boss(interface_data)
|
||||
else:
|
||||
p = E.p(style='color:red; font-weight: bold; font-size:1.5em')
|
||||
if xhr.status is 401:
|
||||
p.innerHTML = _('You are not authorized to view this site')
|
||||
else:
|
||||
p.innerHTML = xhr.error_html
|
||||
document.body.appendChild(p)
|
||||
|
||||
def on_library_load_progress(loaded, total):
|
||||
p = document.querySelector('#page_load_progress > progress')
|
||||
p.max = total
|
||||
p.value = loaded
|
||||
|
||||
def load_book_list():
|
||||
temp = UserSessionData(None, {}) # So that settings for anonymous users are preserved
|
||||
query = {}
|
||||
library_id = temp.get('library_id')
|
||||
if library_id:
|
||||
query.library_id = library_id
|
||||
query.sort = temp.get_library_option(library_id, 'sort')
|
||||
url_query = parse_url_params()
|
||||
for key in url_query:
|
||||
query[key] = url_query[key]
|
||||
ajax('interface-data/init', on_library_loaded, on_library_load_progress, query=query).send()
|
||||
|
||||
def on_load():
|
||||
print('calibre loaded at:', Date().toString())
|
||||
load_book_list()
|
||||
|
||||
is_running_in_iframe = False # Changed before script is loaded in the iframe
|
||||
|
||||
if is_running_in_iframe:
|
||||
init()
|
||||
else:
|
||||
script = document.currentScript or document.scripts[0]
|
||||
main_js = script.textContent
|
||||
main_js(script.textContent)
|
||||
script.parentNode.removeChild(script) # save some memory
|
||||
script = undefined
|
||||
# We wait for all page elements to load, since this is a single page app
|
||||
# with a largely empty starting document, we can use this to preload any resources
|
||||
# we know are going to be needed immediately.
|
||||
window.addEventListener('load', on_load)
|
||||
window.addEventListener('load', main)
|
||||
|
||||
ajax('auto-reload', def(end_type, xhr, event):
|
||||
if end_type is 'load':
|
||||
|
Loading…
x
Reference in New Issue
Block a user