diff --git a/src/calibre/gui2/tweak_book/live_css.py b/src/calibre/gui2/tweak_book/live_css.py index ccaea53673..daa3d07d6d 100644 --- a/src/calibre/gui2/tweak_book/live_css.py +++ b/src/calibre/gui2/tweak_book/live_css.py @@ -5,8 +5,6 @@ from __future__ import absolute_import, division, print_function, unicode_litera __license__ = 'GPL v3' __copyright__ = '2014, Kovid Goyal ' -import json - from PyQt5.Qt import ( QWidget, QTimer, QStackedLayout, QLabel, QScrollArea, QVBoxLayout, QPainter, Qt, QPalette, QRect, QSize, QSizePolicy, pyqtSignal, @@ -382,6 +380,7 @@ class LiveCSS(QWidget): def __init__(self, preview, parent=None): QWidget.__init__(self, parent) self.preview = preview + preview.live_css_data.connect(self.got_live_css_data) self.preview_is_refreshing = False self.refresh_needed = False preview.refresh_starting.connect(self.preview_refresh_starting) @@ -417,8 +416,6 @@ class LiveCSS(QWidget): def preview_refreshed(self): self.preview_is_refreshing = False - # We must let the event loop run otherwise the webview will return - # stale data in read_data() self.refresh_needed = True self.start_update_timer() @@ -448,53 +445,46 @@ class LiveCSS(QWidget): if sourceline is None: self.clear() else: + self.preview.request_live_css_data(editor_name, sourceline, tags) + + def got_live_css_data(self, result): + maximum_specificities = {} + for node in result['nodes']: + is_ancestor = node['is_ancestor'] + for rule in node['css']: + self.process_rule(rule, is_ancestor, maximum_specificities) + for node in result['nodes']: + for rule in node['css']: + for prop in rule['properties']: + if prop.specificity < maximum_specificities[prop.name]: + prop.is_overriden = True + self.display_received_live_css_data(result) + + def display_received_live_css_data(self, data): + editor_name = data['editor_name'] + sourceline = data['sourceline'] + tags = data['tags'] + if data is None or len(data['computed_css']) < 1: + if editor_name == self.current_name and (editor_name, sourceline, tags) == self.now_showing: + # Try again in a little while in case there was a transient + # error in the web view + self.start_update_timer() + return + if self.now_showing == (None, None, None) or self.now_showing[0] != self.current_name: + self.clear() + return + # Try to refresh the data for the currently shown tag instead + # of clearing + editor_name, sourceline, tags = self.now_showing data = self.read_data(sourceline, tags) if data is None or len(data['computed_css']) < 1: - if editor_name == self.current_name and (editor_name, sourceline, tags) == self.now_showing: - # Try again in a little while in case there was a transient - # error in the web view - self.start_update_timer() - return - if self.now_showing == (None, None, None) or self.now_showing[0] != self.current_name: - self.clear() - return - # Try to refresh the data for the currently shown tag instead - # of clearing - editor_name, sourceline, tags = self.now_showing - data = self.read_data(sourceline, tags) - if data is None or len(data['computed_css']) < 1: - self.clear() - return - self.now_showing = (editor_name, sourceline, tags) - data['html_name'] = editor_name - self.box.show_data(data) - self.refresh_needed = False - self.stack.setCurrentIndex(1) - - def read_data(self, sourceline, tags): - return None # TODO: Implement this - mf = self.preview.view.page().mainFrame() - tags = [x.lower() for x in tags] - result = unicode_type(mf.evaluateJavaScript( - 'window.calibre_preview_integration.live_css(%s, %s)' % ( - json.dumps(sourceline), json.dumps(tags))) or '') - try: - result = json.loads(result) - except ValueError: - result = None - if result is not None: - maximum_specificities = {} - for node in result['nodes']: - is_ancestor = node['is_ancestor'] - for rule in node['css']: - self.process_rule(rule, is_ancestor, maximum_specificities) - for node in result['nodes']: - for rule in node['css']: - for prop in rule['properties']: - if prop.specificity < maximum_specificities[prop.name]: - prop.is_overriden = True - - return result + self.clear() + return + self.now_showing = (editor_name, sourceline, tags) + data['html_name'] = editor_name + self.box.show_data(data) + self.refresh_needed = False + self.stack.setCurrentIndex(1) def process_rule(self, rule, is_ancestor, maximum_specificities): selector = rule['selector'] diff --git a/src/calibre/gui2/tweak_book/preview.py b/src/calibre/gui2/tweak_book/preview.py index e5dca886ac..4d07824338 100644 --- a/src/calibre/gui2/tweak_book/preview.py +++ b/src/calibre/gui2/tweak_book/preview.py @@ -280,13 +280,12 @@ class PreviewBridge(Bridge): request_sync = from_js(object, object, object) request_split = from_js(object, object) + live_css_data = from_js(object) go_to_sourceline_address = to_js() go_to_anchor = to_js() set_split_mode = to_js() - - def __init__(self, parent=None): - Bridge.__init__(self, parent) + live_css = to_js() class WebPage(QWebEnginePage): @@ -423,6 +422,7 @@ class Preview(QWidget): link_clicked = pyqtSignal(object, object) refresh_starting = pyqtSignal() refreshed = pyqtSignal() + live_css_data = pyqtSignal(object) render_process_restarted = pyqtSignal() def __init__(self, parent=None): @@ -433,6 +433,7 @@ class Preview(QWidget): self.view = WebView(self) self.view._page.bridge.request_sync.connect(self.request_sync) self.view._page.bridge.request_split.connect(self.request_split) + self.view._page.bridge.live_css_data.connect(self.live_css_data) self.view._page.loadFinished.connect(self.load_finished) self.view.render_process_restarted.connect(self.render_process_restarted) self.pending_go_to_anchor = None @@ -645,6 +646,9 @@ class Preview(QWidget): else: self.stop_split() + def request_live_css_data(self, editor_name, sourceline, tags): + self.view._page.bridge.live_css(editor_name, sourceline, tags) + def apply_settings(self): s = self.view.settings() s.setFontSize(s.DefaultFontSize, tprefs['preview_base_font_size']) diff --git a/src/pyj/editor.pyj b/src/pyj/editor.pyj index adbee3c331..58b0d48562 100644 --- a/src/pyj/editor.pyj +++ b/src/pyj/editor.pyj @@ -336,19 +336,21 @@ def go_to_anchor(anchor): address = get_sourceline_address(elem) to_python.request_sync('', '', address) -def live_css(sourceline, tags): +@from_python +def live_css(editor_name, sourceline, tags): + all_properties = {} + ans = {'nodes':v'[]', 'computed_css':all_properties, 'editor_name': editor_name, 'sourceline': sourceline, 'tags': tags} target = None i = 0 for node in document.querySelectorAll(f'[data-lnum="{sourceline}"]'): tn = node.tagName.toLowerCase() if node.tagName else '' if tn is not tags[i]: - return JSON.stringify(None) + to_python.live_css_data(ans) + return i += 1 target = node if i >= tags.length: break - all_properties = {} - ans = {'nodes':v'[]', 'computed_css':all_properties} is_ancestor = False while target and target.ownerDocument: css = get_matched_css(target, is_ancestor, all_properties) @@ -362,7 +364,8 @@ def live_css(sourceline, tags): }) target = target.parentNode is_ancestor = True - return JSON.stringify(ans) + to_python.live_css_data(ans) + document.body.addEventListener('click', onclick, True) document.documentElement.appendChild(E.style(