From 09717b15c4b0f2d648889dda830a2388d655a2d1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 24 Jan 2017 07:03:00 +0530 Subject: [PATCH] Load the db early during initialization --- src/pyj/book_list/globals.pyj | 12 +++++ src/pyj/book_list/main.pyj | 17 ++++++- src/pyj/book_list/router.pyj | 15 +++++- src/pyj/read_book/db.pyj | 93 ++++++++++++++++++++++------------- src/pyj/read_book/ui.pyj | 23 +++++---- src/pyj/read_book/view.pyj | 7 +-- 6 files changed, 120 insertions(+), 47 deletions(-) diff --git a/src/pyj/book_list/globals.pyj b/src/pyj/book_list/globals.pyj index 7f01cb3795..b21d79b246 100644 --- a/src/pyj/book_list/globals.pyj +++ b/src/pyj/book_list/globals.pyj @@ -21,3 +21,15 @@ def get_current_query(newval): if newval: get_current_query.ans = newval return get_current_query.ans + + +def get_db(db): + if db: + get_db.db = db + return get_db.db + + +def get_translations(val): + if val: + get_translations.ans = val + return get_translations.ans diff --git a/src/pyj/book_list/main.pyj b/src/pyj/book_list/main.pyj index 2b9010a7f3..26c49c94f8 100644 --- a/src/pyj/book_list/main.pyj +++ b/src/pyj/book_list/main.pyj @@ -14,8 +14,10 @@ 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 -from book_list.router import update_window_title, set_default_mode_handler, apply_url +from book_list.router import update_window_title, set_default_mode_handler, apply_url, set_mode_handler +from book_list.globals import get_db, set_session_data from book_list.ui import apply_url_state as book_list_mode_handler +from read_book.ui import ReadUI # Register the various panels import book_list.home # noqa: unused-import @@ -39,13 +41,17 @@ def onerror(msg, script_url, line_number, column_number, error_object): except: console.log('There was an error in the unhandled exception handler') +read_ui = None + def init_ui(): + nonlocal read_ui install_event_filters() set_default_mode_handler(book_list_mode_handler) window.onerror = onerror translations = get_translations() if translations: install(translations) + get_translations(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')) @@ -54,6 +60,9 @@ def init_ui(): document.body.lastChild.appendChild(E.div(id=read_book_container_id, style='display: none')) create_modal_container() update_window_title() + read_ui = ReadUI() + get_db(read_ui.db) + set_mode_handler('read_book', read_ui.apply_url_state.bind(read_ui)) apply_url() def on_data_loaded(end_type, xhr, ev): @@ -61,6 +70,9 @@ def on_data_loaded(end_type, xhr, ev): if end_type is 'load': data = JSON.parse(xhr.responseText) update_interface_data(data) + interface_data = get_interface_data() + sd = UserSessionData(interface_data.username, interface_data.user_session_data) + set_session_data(sd) if data.translations: get_translations(data.translations) init_ui() @@ -94,4 +106,7 @@ def main(): if get_interface_data().is_default: load_interface_data() else: + interface_data = get_interface_data() + sd = UserSessionData(interface_data.username, interface_data.user_session_data) + set_session_data(sd) init_ui() diff --git a/src/pyj/book_list/router.pyj b/src/pyj/book_list/router.pyj index 2db757e1f6..9ec7d3ae6e 100644 --- a/src/pyj/book_list/router.pyj +++ b/src/pyj/book_list/router.pyj @@ -8,6 +8,7 @@ from utils import parse_url_params mode_handlers = {} default_mode_handler = None +read_book_mode = 'read_book' def set_mode_handler(mode, handler): @@ -24,8 +25,13 @@ def update_window_title(subtitle, title='calibre', sep=' :: '): document.title = title + extra +def is_reading_book(): + cq = get_current_query + return cq and cq.mode is read_book_mode + + def apply_mode(mode): - divid = read_book_container_id if (mode or get_current_query().mode) is 'read_book' else book_list_container_id + divid = read_book_container_id if is_reading_book() else book_list_container_id for div in document.getElementById(divid).parentNode.childNodes: div.style.display = 'block' if div.id is divid else 'none' @@ -37,3 +43,10 @@ def apply_url(): apply_mode() handler = mode_handlers[data.mode] or default_mode_handler handler(data) + + +def push_state(query, replace=False, mode='book_list'): + query = {k:query[k] for k in query} + if mode is not 'book_list': + query.mode = mode + # TODO: Implement this (see push_state in boos.pyj) diff --git a/src/pyj/read_book/db.pyj b/src/pyj/read_book/db.pyj index cbf379e68c..267ab99400 100644 --- a/src/pyj/read_book/db.pyj +++ b/src/pyj/read_book/db.pyj @@ -1,9 +1,12 @@ # vim:fileencoding=utf-8 # License: GPL v3 Copyright: 2016, Kovid Goyal -from __python__ import hash_literals +from __python__ import hash_literals, bound_methods from gettext import gettext as _ from encodings import base64encode, base64decode +from modals import error_dialog + +from book_list.router import is_reading_book def upgrade_schema(idb, old_version, new_version): print('upgrade_schema:', old_version, new_version) @@ -31,13 +34,59 @@ DB_VERSION = 2 class DB: - def __init__(self, idb, ui, supports_blobs): - self.interface_data = ui.interface_data + def __init__(self, callback, show_read_book_error): + self.initialized = False + self.initialize_error_msg = None + self.callback = callback + self.show_read_book_error = show_read_book_error + self.initialize_stage1() + + def show_error(self, title, msg, det_msg): + if is_reading_book(): + self.show_read_book_error(title, msg, det_msg) + else: + error_dialog(title, msg, det_msg) + + def initialize_stage1(self): + if not window.indexedDB: + self.initialize_error_msg = _('Your browser does not support IndexedDB. Cannot read books. Consider using a modern browser, such as Firefox, Chrome or Edge.') + self.initialized = True + self.callback() + return + + request = window.indexedDB.open(DB_NAME, DB_VERSION) + + request.onupgradeneeded = def(event): + upgrade_schema(event.target.result, event.oldVersion, event.newVersion) + + request.onblocked = def(event): + self.initialize_error_msg = _('Please close all other browser tabs with calibre open') + self.initialized = True + self.callback() + + request.onerror = def(event): + self.initialize_error_msg = _('You must allow calibre to use IndexedDB storage in your browser to read books') + self.initialized = True + self.callback() + + request.onsuccess = def(event): + blob = Blob(['test'], {'type':"text/plain"}) + idb = event.target.result + try: + req = idb.transaction(['files'], 'readwrite').objectStore('files').put(blob, ':-test-blob-:') + except Exception: + self.initialize_stage2(idb, False) + req.onsuccess = def(event): + self.initialize_stage2(idb, True) + req.onerror = def(event): + self.initialize_stage2(idb, False) + + def initialize_stage2(self, idb, supports_blobs): self.idb = idb self.supports_blobs = supports_blobs + self.initialized = True if not supports_blobs: - print('IndexedDB does not support Blob storage, using base64 encoding instead') - self.show_error = ui.show_error.bind(ui) + print('WARNING: browser does not support blob storage, calibre falling back to base64 encoding') idb.onerror = def(event): self.display_error(None, event) @@ -48,8 +97,9 @@ class DB: idb.onversionchange = def(event): idb.close() - ui.show_error(_('Database upgraded!'), _( + self.show_error(_('Database upgraded!'), _( 'A newer version of calibre is available, please click the reload button in your browser.')) + self.callback() def display_error(self, msg, event): if event.already_displayed_by_calibre: @@ -225,31 +275,8 @@ class DB: books.delete(book.key) next_step() -def create_db(ui, interface_data): - if not window.indexedDB: - return ui.db_initialized(_('Your browser does not support IndexedDB. Cannot read books. Consider using a modern browser, such as Firefox, Chrome or Edge.')) - request = window.indexedDB.open(DB_NAME, DB_VERSION) - - request.onupgradeneeded = def(event): - upgrade_schema(event.target.result, event.oldVersion, event.newVersion) - - request.onblocked = def(event): - alert(_('Please close all other tabs with a calibre book open')) - - request.onerror = def(event): - ui.db_initialized(_('You must allow calibre to use IndexedDB storage in your browser to read books')) - - request.onsuccess = def(event): - blob = Blob(['test'], {'type':"text/plain"}) - idb = event.target.result - try: - req = idb.transaction(['files'], 'readwrite').objectStore('files').put(blob, ':-test-blob-:') - except Exception: - print('WARNING: browser does not support blob storage, calibre falling back to base64 encoding') - return ui.db_initialized(DB(idb, ui, False)) - req.onsuccess = def(event): - ui.db_initialized(DB(idb, ui, True)) - req.onerror = def(event): - print('WARNING: browser does not support blob storage, calibre falling back to base64 encoding') - ui.db_initialized(DB(idb, ui, False)) +def get_db(callback, show_read_book_error): + if not get_db.ans: + get_db.ans = DB(callback) + return get_db.ans diff --git a/src/pyj/read_book/ui.pyj b/src/pyj/read_book/ui.pyj index 205e1e27f2..6975acac3a 100644 --- a/src/pyj/read_book/ui.pyj +++ b/src/pyj/read_book/ui.pyj @@ -10,8 +10,9 @@ from gettext import gettext as _ from modals import error_dialog from utils import human_readable, debounce +from book_list.constants import read_book_container_id +from read_book.db import get_db from book_list.router import update_window_title -from read_book.db import create_db from read_book.view import View RENDER_VERSION = __RENDER_VERSION__ @@ -19,19 +20,17 @@ MATHJAX_VERSION = "__MATHJAX_VERSION__" class ReadUI: - def __init__(self, interface_data, container): - self.interface_data = interface_data - self.db = None + def __init__(self): self.current_metadata = {'title': _('Unknown book')} self.current_book_id = None self.manifest_xhr = None - create_db(self, interface_data) self.pending_load = None self.downloads_in_progress = [] self.progress_id = 'book-load-progress' self.display_id = 'book-iframe-container' self.error_id = 'book-global-error-container' self.stacked_widgets = [self.progress_id, self.display_id, self.error_id] + container = document.getElementById(read_book_container_id) container.appendChild(E.div( id=self.progress_id, style='display:none; text-align: center', @@ -51,6 +50,7 @@ class ReadUI: )) self.view = View(container.lastChild, self) window.addEventListener('resize', debounce(self.on_resize.bind(self), 250)) + self.db = get_db(self.db_initialized.bind(self), self.show_error.bind(self)) def on_resize(self): self.view.on_resize() @@ -99,7 +99,7 @@ class ReadUI: def load_book(self, book_id, fmt, metadata, force_reload): self.base_url_data = {'book_id':book_id, 'fmt':fmt} - if self.db is None: + if not self.db.initialized: self.pending_load = [book_id, fmt, metadata, force_reload] return self.start_load(book_id, fmt, metadata, force_reload) @@ -126,11 +126,13 @@ class ReadUI: ans.bookpos = bookpos return ans - def db_initialized(self, db): - self.db = db + def db_initialized(self): if self.pending_load is not None: pl, self.pending_load = self.pending_load, None - self.start_load(*pl) + if self.db.initialize_error_msg: + self.show_error(_('Failed to initialize IndexedDB'), self.db.initialize_error_msg) + else: + self.start_load(*pl) def start_load(self, book_id, fmt, metadata, force_reload): self.current_book_id = book_id @@ -402,3 +404,6 @@ class ReadUI: def display_book_stage2(self, book): self.show_stack(self.display_id) self.view.display_book(book) + + def apply_url_state(self, current_query): + pass diff --git a/src/pyj/read_book/view.pyj b/src/pyj/read_book/view.pyj index 992852ece4..f846a2b82c 100644 --- a/src/pyj/read_book/view.pyj +++ b/src/pyj/read_book/view.pyj @@ -8,7 +8,8 @@ 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, main_js +from book_list.globals import get_session_data, main_js, get_translations +from book_list.router import push_state, read_book_mode 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 @@ -228,7 +229,7 @@ class View: def on_iframe_ready(self, data): messenger.reset() - self.send_message('initialize', secret=messenger.secret, translations=self.ui.interface_data.translations) + self.send_message('initialize', secret=messenger.secret, translations=get_translations()) self.iframe_ready = True if self.pending_load: data = self.pending_load @@ -354,7 +355,7 @@ class View: def on_update_cfi(self, data): self.currently_showing.bookpos = data.cfi - get_boss().push_state(replace=data.replace_history) + push_state(self.url_data, replace=data.replace_history, mode=read_book_mode) unkey = username_key(self.ui.interface_data.username) if not self.book.last_read_position: self.book.last_read_position = {}