# vim:fileencoding=utf-8 # License: GPL v3 Copyright: 2018, Kovid Goyal from __python__ import bound_methods, hash_literals import traceback from elementmaker import E from gettext import gettext as _ import initialize # noqa: unused-import from ajax import ajax from book_list.globals import set_session_data from book_list.theme import get_color, get_font_family from dom import get_widget_css, set_css from modals import create_modal_container, error_dialog from qt import from_python, to_python from read_book.db import new_book from read_book.globals import runtime, ui_operations from read_book.iframe import main as iframe_main from read_book.view import View from session import session_defaults from utils import encode_query_with_path from viewer.constants import FAKE_HOST, FAKE_PROTOCOL runtime.is_standalone_viewer = True runtime.FAKE_HOST = FAKE_HOST runtime.FAKE_PROTOCOL = FAKE_PROTOCOL book = None view = None def file_received(name, file_data, proceed, end_type, xhr, ev): if end_type is 'abort': return if end_type is not 'load': show_error(_('Failed to load file from book'), _( 'Could not load the file: {} with error: {}').format(name, xhr.error_html)) return if not xhr.responseType or xhr.responseType is 'text': result = xhr.responseText else if xhr.responseType is 'blob': result = xhr.response else: show_error(_('Failed to load file from book'), _( 'Could not load the file: {} unknown response type: {}').format(name, xhr.responseType)) return proceed(result, name, file_data.mimetype, book) def get_file(book, name, proceed): entry = book.manifest.files[name] xhr = ajax('book/' + name, file_received.bind(None, name, entry, proceed), ok_code=0) if entry.is_html or entry.mimetype.startswith('text/') or entry.mimetype is 'application/javascript': xhr.responseType = 'text' else: xhr.responseType = 'blob' xhr.send() def mathjax_file_received(name, proceed, end_type, xhr, ev): if end_type is 'abort': return if end_type is not 'load': show_error(_('Failed to load MathJax file'), _( 'Could not load the file: {} with error: {}').format(name, xhr.error_html)) return if not xhr.responseType or xhr.responseType is 'text': result = xhr.responseText else if xhr.responseType is 'blob' or xhr.responseType is 'json': result = xhr.response else: show_error(_('Failed to load MathJax file'), _( 'Could not load the file: {} unknown response type: {}') .format(name, xhr.responseType)) return if name is 'manifest.json': get_mathjax_files.manifest = result get_mathjax_files_stage2.files_to_get = list(Object.keys(result)) get_mathjax_files_stage2.file_data = {} get_mathjax_files_stage2(proceed) return get_mathjax_files_stage2.file_data[name] = result get_mathjax_files_stage2.files_to_get.remove(name) if not get_mathjax_files_stage2.files_to_get.length: proceed(get_mathjax_files_stage2.file_data) def get_mathjax_manifest(proceed): xhr = ajax('mathjax/manifest.json', mathjax_file_received.bind(None, 'manifest.json', proceed), ok_code=0) xhr.responseType = 'json' xhr.send() def get_mathjax_files_stage2(proceed): if not get_mathjax_files_stage2.files_to_get.length: proceed(get_mathjax_files_stage2.file_data) return for filename in get_mathjax_files_stage2.files_to_get: xhr = ajax(f'mathjax/{filename}', mathjax_file_received.bind(None, filename, proceed), ok_code=0) xhr.responseType = 'blob' xhr.send() def get_mathjax_files(proceed): if not get_mathjax_files.manifest: get_mathjax_manifest(proceed) else: get_mathjax_files_stage2(proceed) def update_url_state(replace): if view and view.currently_showing: bookpos = view.currently_showing.bookpos if bookpos: query = {'bookpos': bookpos} query = encode_query_with_path(query) window.history.pushState(None, '', query) def show_error(title, msg, details): error_dialog(title, msg, details) def manifest_received(key, initial_cfi, end_type, xhr, ev): nonlocal book if end_type is 'load': book = new_book(key, {}) data = xhr.response book.manifest = data[0] book.metadata = book.manifest.metadata = data[1] book.stored_files = {} book.is_complete = True v'delete book.manifest["metadata"]' v'delete book.manifest["last_read_positions"]' view.display_book(book, initial_cfi) else: error_dialog(_('Could not open book'), _( 'Failed to load book manifest, click "Show details" for more info'), xhr.error_html or None) class SessionData: def __init__(self, prefs): defaults = session_defaults() self.data = {k: defaults[k] if prefs[k] is undefined else prefs[k] for k in defaults} def get(self, key, defval): ans = self.data[key] if ans is undefined or ans is None: if defval is undefined: defval = None return defval return ans def set(self, key, val): if val is None: self.data[key] = session_defaults()[key] else: self.data[key] = val to_python.set_session_data(key, val) def clear(self): defaults = session_defaults() self.data = {k: defaults[k] for k in defaults} to_python.set_session_data('*', None) def create_session_data(prefs): sd = SessionData(prefs) set_session_data(sd) @from_python def create_view(prefs): nonlocal view if view is None: create_session_data(prefs) view = View(document.getElementById('view')) @from_python def show_preparing_message(msg): view.show_loading_message(msg) @from_python def start_book_load(key, initial_cfi): xhr = ajax('manifest', manifest_received.bind(None, key, initial_cfi), ok_code=0) xhr.responseType = 'json' xhr.send() def onerror(msg, script_url, line_number, column_number, error_object): if not error_object: # cross domain error return False fname = script_url.rpartition('/')[-1] or script_url msg += '
' + 'Error at {}:{}:{}'.format(fname, line_number, column_number or '') + '' details = '' console.log(error_object) details = traceback.format_exception(error_object).join('') error_dialog(_('Unhandled error'), msg, details) return True def redisplay_book(): view.redisplay_book() def reload_book(): to_python.reload_book() def forward_gesture(gesture): view.forward_gesture(gesture) def update_color_scheme(): view.update_color_scheme() def update_font_size(): view.update_font_size() if window is window.top: # main ui_operations.get_file = get_file ui_operations.get_mathjax_files = get_mathjax_files ui_operations.update_url_state = update_url_state ui_operations.show_error = show_error ui_operations.redisplay_book = redisplay_book ui_operations.reload_book = reload_book ui_operations.forward_gesture = forward_gesture ui_operations.update_color_scheme = update_color_scheme ui_operations.update_font_size = update_font_size ui_operations.toggle_toc = def(): to_python.toggle_toc() document.body.appendChild(E.div(id='view')) window.onerror = onerror create_modal_container() document.body.style.fontFamily = get_font_family() document.head.appendChild(E.style(get_widget_css())) set_css(document.body, background_color=get_color('window-background'), color=get_color('window-foreground')) else: # iframe iframe_main()