diff --git a/data/media/scrollToMark.htmlsnippet b/data/media/scrollToMark.htmlsnippet
deleted file mode 100644
index 4244414..0000000
--- a/data/media/scrollToMark.htmlsnippet
+++ /dev/null
@@ -1,3 +0,0 @@
-
\ No newline at end of file
diff --git a/uberwriter/web_view.py b/uberwriter/web_view.py
index d4bc6ae..a9dc163 100644
--- a/uberwriter/web_view.py
+++ b/uberwriter/web_view.py
@@ -14,16 +14,37 @@ class WebView(WebKit2.WebView):
Reference: https://github.com/aperezdc/webkit2gtk-python-webextension-example
"""
- GET_SCROLL_SCALE_JS = """
-e = document.documentElement;
-e.scrollHeight > e.clientHeight ? e.scrollTop / (e.scrollHeight - e.clientHeight) : -1;
-"""
-
- SET_SCROLL_SCALE_JS = """
+ SYNC_SCROLL_SCALE_JS = """
scale = {:.16f};
+write = {};
+
+// Configure MathJax.
+if (typeof hasMathJax === "undefined") {{
+ hasMathJax = typeof MathJax !== "undefined";
+ if (hasMathJax) {{
+ MathJax.Hub.Config({{ messageStyle: "none" }});
+ }}
+}}
+
+// Figure out if scrollable and rendered.
e = document.documentElement;
-e.scrollTop = (e.scrollHeight - e.clientHeight) * scale;
-"""
+canScroll = e.scrollHeight > e.clientHeight;
+wasRendered = typeof isRendered !== "undefined" && isRendered;
+isRendered = wasRendered ||
+ hasMathJax && MathJax.Hub.queue.running == 0 && MathJax.Hub.queue.pending == 0;
+
+// Write the current scroll if instructed or if it was just rendered.
+if (canScroll && (write || isRendered && !wasRendered)) {{
+ e.scrollTop = (e.scrollHeight - e.clientHeight) * scale;
+}}
+
+// Return the current scroll if scrollable and rendered, or -1.
+if (canScroll && isRendered) {{
+ e.scrollTop / (e.scrollHeight - e.clientHeight);
+}} else {{
+ -1;
+}}
+""".strip()
__gsignals__ = {
"scroll-scale-changed": (GObject.SIGNAL_RUN_LAST, None, (float,)),
@@ -38,11 +59,11 @@ e.scrollTop = (e.scrollHeight - e.clientHeight) * scale;
self.connect("destroy", self.on_destroy)
self.scroll_scale = 0.0
- self.pending_scroll_scale = None
self.state_loaded = False
self.state_load_failed = False
- self.state_discard_result = False
+ self.state_discard_read = False
+ self.state_dirty = False
self.state_waiting = False
self.timeout_id = None
@@ -51,14 +72,15 @@ e.scrollTop = (e.scrollHeight - e.clientHeight) * scale;
return self.scroll_scale
def set_scroll_scale(self, scale):
- self.pending_scroll_scale = scale
+ self.state_dirty = scale != self.scroll_scale
+ self.scroll_scale = scale
self.state_loop()
def on_load_changed(self, _web_view, event):
self.state_loaded = event >= WebKit2.LoadEvent.COMMITTED and not self.state_load_failed
self.state_load_failed = False
- self.state_discard_result = event == WebKit2.LoadEvent.STARTED and self.state_waiting
- self.pending_scroll_scale = self.scroll_scale
+ self.state_discard_read = event == WebKit2.LoadEvent.STARTED and self.state_waiting
+ self.state_dirty = True
self.state_loop()
def on_load_failed(self, _web_view, _event):
@@ -73,23 +95,16 @@ e.scrollTop = (e.scrollHeight - e.clientHeight) * scale;
self.state_loaded = False
self.state_loop()
- def read_scroll_scale(self):
+ def sync_scroll_scale(self, scroll_scale, write):
self.state_waiting = True
self.run_javascript(
- self.GET_SCROLL_SCALE_JS, None, self.finish_read_scroll_scale)
+ self.SYNC_SCROLL_SCALE_JS.format(scroll_scale, "true" if write else "false"),
+ None, self.finish_sync_scroll_scale)
- def write_scroll_scale(self, scroll_scale):
- self.run_javascript(
- self.SET_SCROLL_SCALE_JS.format(scroll_scale), None, None)
-
- def finish_read_scroll_scale(self, _web_view, result):
+ def finish_sync_scroll_scale(self, _web_view, result):
self.state_waiting = False
- if not self.state_discard_result:
- result = self.run_javascript_finish(result)
- self.state_loop(result.get_js_value().to_double())
- else:
- self.state_discard_result = False
- self.state_loop()
+ result = self.run_javascript_finish(result)
+ self.state_loop(result.get_js_value().to_double())
def state_loop(self, scroll_scale=None, delay=16): # 16ms ~ 60hz
# Remove any pending callbacks
@@ -98,18 +113,17 @@ e.scrollTop = (e.scrollHeight - e.clientHeight) * scale;
self.timeout_id = None
# Set scroll scale if specified, and the state is not dirty
- if scroll_scale not in (None, -1, self.scroll_scale):
+ if not self.state_discard_read and scroll_scale not in (None, -1, self.scroll_scale):
self.scroll_scale = scroll_scale
self.emit("scroll-scale-changed", self.scroll_scale)
+ else:
+ self.state_discard_read = False
# Handle the current state
if not self.state_loaded or self.state_load_failed or self.state_waiting:
return
- if self.pending_scroll_scale:
- self.write_scroll_scale(self.pending_scroll_scale)
- self.pending_scroll_scale = None
- self.read_scroll_scale()
- elif delay > 0:
- self.timeout_id = GLib.timeout_add(delay, self.state_loop, None, 0)
+ elif self.state_dirty or delay == 0:
+ self.sync_scroll_scale(self.scroll_scale, self.state_dirty)
+ self.state_dirty = False
else:
- self.read_scroll_scale()
+ self.timeout_id = GLib.timeout_add(delay, self.state_loop, None, 0)