diff --git a/src/calibre/utils/rapydscript.py b/src/calibre/utils/rapydscript.py index a5df1cf63c..6e469151f3 100644 --- a/src/calibre/utils/rapydscript.py +++ b/src/calibre/utils/rapydscript.py @@ -17,7 +17,9 @@ from io import BytesIO from threading import Thread, local from calibre import force_unicode -from calibre.constants import __appname__, __version__, cache_dir +from calibre.constants import ( + FAKE_HOST, FAKE_PROTOCOL, __appname__, __version__, cache_dir +) from calibre.utils.filenames import atomic_rename from calibre.utils.terminal import ANSIStream from duktape import Context, JSError, to_python @@ -226,7 +228,10 @@ def compile_viewer(): rapydscript_dir = os.path.join(base, 'src', 'pyj') fname = os.path.join(rapydscript_dir, 'viewer-main.pyj') with lopen(fname, 'rb') as f: - js = compile_fast(f.read(), fname, js_version=6).replace('__SPECIAL_TITLE__', special_title, 1) + js = compile_fast(f.read(), fname, js_version=6).replace( + '__SPECIAL_TITLE__', special_title, 1).replace( + '__FAKE_PROTOCOL__', FAKE_PROTOCOL, 1).replace( + '__FAKE_HOST__', FAKE_HOST, 1) base = os.path.join(base, 'resources') atomic_write(base, 'viewer.js', js) diff --git a/src/pyj/iframe_comm.pyj b/src/pyj/iframe_comm.pyj index fb6b341760..39fcfa456d 100644 --- a/src/pyj/iframe_comm.pyj +++ b/src/pyj/iframe_comm.pyj @@ -81,13 +81,16 @@ class IframeWrapper: def create_srcdoc(self): r = /__([A-Z][A-Z_0-9]*[A-Z0-9])__/g - data = { - 'BS': self.bootstrap_text, - 'SCRIPT': iframe_js(), - 'FONT': get_font_family(), - 'ENTRY_POINT': self.entry_point, - } - self.iframe.srcdoc = LOADING_DOC.replace(r, def(match, field): return data[field];) + if self.entry_point: + data = { + 'BS': self.bootstrap_text, + 'SCRIPT': iframe_js(), + 'FONT': get_font_family(), + 'ENTRY_POINT': self.entry_point, + } + self.iframe.srcdoc = LOADING_DOC.replace(r, def(match, field): return data[field];) + else: + self.iframe.srcdoc = '
\xa0
' self.srcdoc_created = True def init(self): diff --git a/src/pyj/read_book/globals.pyj b/src/pyj/read_book/globals.pyj index e2dfcba5f1..2a59096a72 100644 --- a/src/pyj/read_book/globals.pyj +++ b/src/pyj/read_book/globals.pyj @@ -60,3 +60,16 @@ register_callback(def(): scheme = default_color_schemes[key] scheme.name = gt(scheme.name) ) + +runtime = { + 'is_standalone_viewer': False +} + + +ui_operations = { + 'get_file': None, + 'get_mathjax_files': None, + 'update_url_state': None, + 'update_last_read_time': None, + 'show_error': None, +} diff --git a/src/pyj/read_book/resources.pyj b/src/pyj/read_book/resources.pyj index 6c9e4868e0..a5f0d5cee0 100644 --- a/src/pyj/read_book/resources.pyj +++ b/src/pyj/read_book/resources.pyj @@ -6,6 +6,7 @@ from elementmaker import E from encodings import base64decode, utf8_decode from dom import clear +from read_book.globals import ui_operations JSON_XHTML_MIMETYPE = 'application/calibre+xhtml+json' @@ -19,7 +20,7 @@ def decode_url(x): def create_link_pat(book): return RegExp(book.manifest.link_uid + r'\|([^|]+)\|', 'g') -def load_resources(db, book, root_name, previous_resources, proceed): +def load_resources(book, root_name, previous_resources, proceed): ans = Object.create(None) pending_resources = v'[root_name]' link_pat = create_link_pat(book) @@ -29,7 +30,7 @@ def load_resources(db, book, root_name, previous_resources, proceed): for k in previous_resources: v'delete previous_resources[k]' if book.manifest.files[root_name].has_maths: - return load_mathjax(db, book, ans, proceed) + return load_mathjax(book, ans, proceed) return proceed(ans) name = pending_resources.shift() if ans[name]: @@ -39,7 +40,7 @@ def load_resources(db, book, root_name, previous_resources, proceed): if jstype(data[0]) is 'string': find_virtualized_resources(data[0]) return setTimeout(do_one, 0) - db.get_file(book, name, got_one) + ui_operations.get_file(book, name, got_one) def got_one(data, name, mimetype): if False and name is book.manifest.title_page_name: @@ -68,9 +69,9 @@ def load_resources(db, book, root_name, previous_resources, proceed): mathjax_data = None -def load_mathjax(db, book, resource_data, proceed): +def load_mathjax(book, resource_data, proceed): if mathjax_data is None: - db.get_mathjax_files(def(data): + ui_operations.get_mathjax_files(def(data): nonlocal mathjax_data mathjax_data = data resource_data['..mathjax-files..'] = data diff --git a/src/pyj/read_book/search.pyj b/src/pyj/read_book/search.pyj index a36957bd95..d02567e2ae 100644 --- a/src/pyj/read_book/search.pyj +++ b/src/pyj/read_book/search.pyj @@ -1,13 +1,15 @@ # vim:fileencoding=utf-8 # License: GPL v3 Copyright: 2017, Kovid Goyal -from __python__ import hash_literals, bound_methods +from __python__ import bound_methods, hash_literals +from elementmaker import E +from gettext import gettext as _ + +from book_list.theme import get_color from complete import create_search_bar from dom import add_extra_css, build_rule, svgicon from keycodes import get_key -from elementmaker import E -from gettext import gettext as _ -from book_list.theme import get_color +from read_book.globals import ui_operations from read_book.resources import text_from_serialized_html CLASS_NAME = 'book-search-container' @@ -84,7 +86,7 @@ def find_in_serialized_html(data, text): return haystack.toLowerCase().indexOf(text) > -1 -def find_in_spine(names, book, db, text, proceed): +def find_in_spine(names, book, text, proceed): text = text.toLowerCase() def got_one(data, name, mimetype): @@ -96,7 +98,7 @@ def find_in_spine(names, book, db, text, proceed): def do_one(): name = names.shift() if name: - db.get_file(book, name, got_one) + ui_operations.get_file(book, name, got_one) else: proceed(None) diff --git a/src/pyj/read_book/ui.pyj b/src/pyj/read_book/ui.pyj index ebdb8d4086..009b3e85eb 100644 --- a/src/pyj/read_book/ui.pyj +++ b/src/pyj/read_book/ui.pyj @@ -9,14 +9,13 @@ from gettext import gettext as _ from ajax import ajax from book_list.constants import read_book_container_id -from book_list.library_data import ( - current_library_id, library_data -) +from book_list.library_data import current_library_id, library_data +from book_list.router import home, push_state, read_book_mode, update_window_title from book_list.ui import show_panel -from book_list.router import update_window_title, home from dom import clear from modals import create_simple_dialog_markup, error_dialog from read_book.db import get_db +from read_book.globals import ui_operations from read_book.view import View from utils import debounce, human_readable from widgets import create_button @@ -53,9 +52,14 @@ class ReadUI: container.appendChild(E.div( id=self.display_id, style='display:none', )) - self.view = View(container.lastChild, self) + self.view = View(container.lastChild) window.addEventListener('resize', debounce(self.on_resize.bind(self), 250)) self.db = get_db(self.db_initialized.bind(self), self.show_error.bind(self)) + ui_operations.get_file = self.db.get_file + ui_operations.get_mathjax_files = self.db.get_mathjax_files + ui_operations.update_url_state = self.update_url_state.bind(self) + ui_operations.update_last_read_time = self.db.update_last_read_time + ui_operations.show_error = self.show_error.bind(self) def on_resize(self): self.view.on_resize() @@ -448,3 +452,6 @@ class ReadUI: self.view.goto_bookpos(current_query.bookpos) else: self.load_book(current_query.library_id, int(current_query.book_id), current_query.fmt, library_data.metadata[current_query.book_id]) + + def update_url_state(self, replace): + push_state(self.url_data, replace=replace, mode=read_book_mode) diff --git a/src/pyj/read_book/view.pyj b/src/pyj/read_book/view.pyj index a24e01a618..b37c2673ff 100644 --- a/src/pyj/read_book/view.pyj +++ b/src/pyj/read_book/view.pyj @@ -9,13 +9,14 @@ import read_book.iframe # noqa from ajax import ajax_send from book_list.book_details import CLASS_NAME as BD_CLASS_NAME, render_metadata from book_list.globals import get_session_data -from book_list.router import push_state, read_book_mode from book_list.theme import get_color from dom import add_extra_css, build_rule, clear, set_css, svgicon, unique_id from iframe_comm import IframeWrapper from modals import error_dialog, warning_dialog from read_book.content_popup import ContentPopupOverlay -from read_book.globals import current_book, set_current_spine_item +from read_book.globals import ( + current_book, runtime, set_current_spine_item, ui_operations +) from read_book.goto import get_next_section from read_book.overlay import Overlay from read_book.prefs.colors import resolve_color_scheme @@ -115,8 +116,7 @@ def margin_elem(sd, which, id, onclick): class View: - def __init__(self, container, ui): - self.ui = ui + def __init__(self, container): self.timers = Timers() self.loaded_resources = {} self.current_progress_frac = self.current_file_progress_frac = 0 @@ -167,7 +167,8 @@ class View: 'print': self.on_print, 'human_scroll': self.on_human_scroll, } - self.iframe_wrapper = IframeWrapper(handlers, document.getElementById(iframe_id), 'read_book.iframe', _('Bootstrapping book reader...')) + entry_point = None if runtime.is_standalone_viewer else 'read_book.iframe' + self.iframe_wrapper = IframeWrapper(handlers, document.getElementById(iframe_id), entry_point, _('Bootstrapping book reader...')) self.search_overlay = SearchOverlay(self) self.content_popup_overlay = ContentPopupOverlay(self) self.overlay = Overlay(self) @@ -245,7 +246,7 @@ class View: for items in item_groups: for i in items: names.push(spine[i]) - find_in_spine(names, self.book, self.ui.db, data.text, def(found_in): + find_in_spine(names, self.book, data.text, def(found_in): if found_in: self.show_name(found_in, initial_position={'type':'search', 'search_data':data, 'replace_history':True}) else: @@ -322,7 +323,7 @@ class View: self.show_spine_item_stage2(data) def on_iframe_error(self, data): - self.ui.show_error((data.title or _('There was an error processing the book')), data.msg, data.details) + ui_operations.show_error((data.title or _('There was an error processing the book')), data.msg, data.details) def get_color_scheme(self, apply_to_margins): ans = resolve_color_scheme() @@ -376,7 +377,8 @@ class View: self.content_popup_overlay.loaded_resources = {} self.timers.start_book(book) self.book = current_book.book = book - self.ui.db.update_last_read_time(book) + if ui_operations.update_last_read_time: + ui_operations.update_last_read_time(book) pos = {'replace_history':True} unkey = username_key(get_interface_data().username) name = book.manifest.spine[0] @@ -431,7 +433,7 @@ class View: def cb(resource_data): self.loaded_resources = resource_data done_callback(resource_data) - load_resources(self.ui.db, self.book, name, self.loaded_resources, cb) + load_resources(self.book, name, self.loaded_resources, cb) def goto_doc_boundary(self, start): name = self.book.manifest.spine[0 if start else self.book.manifest.spine.length - 1] @@ -495,13 +497,14 @@ class View: # See https://bugs.chromium.org/p/chromium/issues/detail?id=404315 return self.currently_showing.bookpos = data.cfi - push_state(self.ui.url_data, replace=data.replace_history, mode=read_book_mode) + ui_operations.update_url_state(data.replace_history) username = get_interface_data().username unkey = username_key(username) if not self.book.last_read_position: self.book.last_read_position = {} self.book.last_read_position[unkey] = data.cfi - self.ui.db.update_last_read_time(self.book) + if ui_operations.update_last_read_time: + ui_operations.update_last_read_time(self.book) lrd = {'device':get_device_uuid(), 'cfi':data.cfi, 'pos_frac':data.progress_frac} self.current_progress_frac = data.progress_frac self.current_file_progress_frac = data.file_progress_frac diff --git a/src/pyj/viewer-main.pyj b/src/pyj/viewer-main.pyj index 5d277a5e3a..df72d6fd8e 100644 --- a/src/pyj/viewer-main.pyj +++ b/src/pyj/viewer-main.pyj @@ -2,4 +2,17 @@ # License: GPL v3 Copyright: 2018, Kovid Goyal from __python__ import bound_methods, hash_literals -print('11111111111111', document.location.href) + +from elementmaker import E +from read_book.globals import runtime + +def container_div(id): + return E.div(id=id, style='margin: 0; padding: 0; display: none') + +runtime.is_standalone_viewer = True +if window is window.top: + # main + document.body.appendChild(E.iframe(srcdoc="

hello")) +else: + # iframe + pass diff --git a/src/pyj/viewer/__init__.pyj b/src/pyj/viewer/__init__.pyj new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/pyj/viewer/constants.pyj b/src/pyj/viewer/constants.pyj new file mode 100644 index 0000000000..aaabf5aefe --- /dev/null +++ b/src/pyj/viewer/constants.pyj @@ -0,0 +1,7 @@ +# vim:fileencoding=utf-8 +# License: GPL v3 Copyright: 2018, Kovid Goyal +from __python__ import bound_methods, hash_literals + + +FAKE_PROTOCOL = '__FAKE_PROTOCOL__' +FAKE_HOST = '__FAKE_HOST__'