Refactor preview panel JS into CS

This commit is contained in:
Kovid Goyal 2013-11-19 14:07:50 +05:30
parent 20e0781b80
commit b71674436e
3 changed files with 88 additions and 64 deletions

View File

@ -93,6 +93,17 @@ class CalibreUtils
return this.viewport_to_document(r.left, 0, elem.ownerDocument)[0] return this.viewport_to_document(r.left, 0, elem.ownerDocument)[0]
# }}} # }}}
abstop: (elem) -> # {{{
# The left edge of elem in document co-ords. Works in all
# circumstances, including column layout. Note that this will cause
# a relayout if the render tree is dirty. Also, because of a bug in the
# version of WebKit bundled with Qt 4.8, this does not always work, see
# https://bugs.launchpad.net/bugs/1132641 for a test case.
r = elem.getBoundingClientRect()
return this.viewport_to_document(r.top, 0, elem.ownerDocument)[0]
# }}}
if window? if window?
window.calibre_utils = new CalibreUtils() window.calibre_utils = new CalibreUtils()

View File

@ -0,0 +1,67 @@
#!/usr/bin/env coffee
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
###
Copyright 2013, Kovid Goyal <kovid at kovidgoyal.net>
Released under the GPLv3 License
###
if window?.calibre_utils
log = window.calibre_utils.log
is_hidden = (elem) ->
while elem
if (elem.style && (elem.style.visibility == 'hidden' || elem.style.display == 'none'))
return true
elem = elem.parentNode
return false
class PreviewIntegration
###
# Namespace to expose all the functions used for integration with the Tweak
# Book Preview Panel.
###
constructor: () ->
if not this instanceof arguments.callee
throw new Error('PreviewIntegration constructor called as function')
go_to_line: (lnum) ->
for node in document.querySelectorAll('[data-lnum="' + lnum + '"]')
if is_hidden(node)
continue
top = window.calibre_utils.abstop(node) - (window.innerHeight / 2)
if (top < 0)
top = 0
window.scrollTo(0, top)
return
line_numbers: () ->
found_body = false
ans = []
for node in document.getElementsByTagName('*')
if not found_body and node.tagName.toLowerCase() == "body"
found_body = true
if found_body
ans.push(node.getAttribute("data-lnum"))
return ans
find_blocks: () =>
for elem in document.body.getElementsByTagName('*')
style = window.getComputedStyle(elem)
if style.display in ['block', 'flex-box', 'box']
elem.setAttribute('data-is-block', '1')
elem.onclick = this.onclick
onload: () ->
window.document.body.addEventListener('click', window.calibre_preview_integration.onclick, true)
onclick: (event) ->
event.preventDefault()
window.py_bridge.request_sync(event.target.getAttribute("data-lnum"))
window.calibre_preview_integration = new PreviewIntegration()
window.onload = window.calibre_preview_integration.onload

View File

@ -19,7 +19,7 @@ from PyQt4.Qt import (
from PyQt4.QtWebKit import QWebView, QWebInspector, QWebPage from PyQt4.QtWebKit import QWebView, QWebInspector, QWebPage
from calibre import prints from calibre import prints
from calibre.constants import iswindows from calibre.constants import iswindows, DEBUG
from calibre.ebooks.oeb.polish.parsing import parse from calibre.ebooks.oeb.polish.parsing import parse
from calibre.ebooks.oeb.base import serialize, OEB_DOCS from calibre.ebooks.oeb.base import serialize, OEB_DOCS
from calibre.ptempfile import PersistentTemporaryDirectory from calibre.ptempfile import PersistentTemporaryDirectory
@ -220,66 +220,6 @@ class NetworkAccessManager(QNetworkAccessManager):
# }}} # }}}
JS = '''
function handle_click(event) {
event.preventDefault();
window.py_bridge.request_sync(event.target.getAttribute("data-lnum"));
}
function line_numbers() {
var elements = document.getElementsByTagName('*'), found_body = false, ans = [], node, i;
var found_body = false;
var ans = [];
for (i = 0; i < elements.length; i++) {
node = elements[i];
if (!found_body && node.tagName.toLowerCase() === "body") {
found_body = true;
}
if (found_body) {
ans.push(node.getAttribute("data-lnum"));
}
}
return ans;
}
function document_offset_top(obj) {
var curtop = 0;
if (obj.offsetParent) {
do {
curtop += obj.offsetTop;
} while (obj = obj.offsetParent);
return curtop;
}
}
function is_hidden(elem) {
var p = elem;
while (p) {
if (p.style && (p.style.visibility === 'hidden' || p.style.display === 'none'))
return true;
p = p.parentNode;
}
return false;
}
function go_to_line(lnum) {
var elements = document.querySelectorAll('[data-lnum="' + lnum + '"]');
for (var i = 0; i < elements.length; i++) {
var node = elements[i];
if (is_hidden(node)) continue;
var top = document_offset_top(node) - (window.innerHeight / 2);
if (top < 0) top = 0;
window.scrollTo(0, top);
return;
}
}
window.onload = function() {
document.body.addEventListener('click', handle_click, true);
}
'''
def uniq(vals): def uniq(vals):
''' Remove all duplicates from vals, while preserving order. ''' ''' Remove all duplicates from vals, while preserving order. '''
vals = vals or () vals = vals or ()
@ -321,10 +261,14 @@ class WebPage(QWebPage):
prints('preview js:%s:%s:'%(unicode(source_id), lineno), unicode(msg)) prints('preview js:%s:%s:'%(unicode(source_id), lineno), unicode(msg))
def init_javascript(self): def init_javascript(self):
if not hasattr(self, 'js'):
from calibre.utils.resources import compiled_coffeescript
self.js = compiled_coffeescript('ebooks.oeb.display.utils', dynamic=DEBUG)
self.js += compiled_coffeescript('ebooks.oeb.polish.preview', dynamic=DEBUG)
self._line_numbers = None self._line_numbers = None
mf = self.mainFrame() mf = self.mainFrame()
mf.addToJavaScriptWindowObject("py_bridge", self) mf.addToJavaScriptWindowObject("py_bridge", self)
mf.evaluateJavaScript(JS) mf.evaluateJavaScript(self.js)
@pyqtSlot(str) @pyqtSlot(str)
def request_sync(self, lnum): def request_sync(self, lnum):
@ -341,7 +285,8 @@ class WebPage(QWebPage):
if not ok: if not ok:
ans = None ans = None
return ans return ans
self._line_numbers = sorted(uniq(filter(lambda x:x is not None, map(atoi, self.mainFrame().evaluateJavaScript('line_numbers()').toStringList())))) self._line_numbers = sorted(uniq(filter(lambda x:x is not None, map(atoi, self.mainFrame().evaluateJavaScript(
'window.calibre_preview_integration.line_numbers()').toStringList()))))
return self._line_numbers return self._line_numbers
def go_to_line(self, lnum): def go_to_line(self, lnum):
@ -349,7 +294,8 @@ class WebPage(QWebPage):
lnum = find_le(self.line_numbers, lnum) lnum = find_le(self.line_numbers, lnum)
except ValueError: except ValueError:
return return
self.mainFrame().evaluateJavaScript('go_to_line(%d)' % lnum) self.mainFrame().evaluateJavaScript(
'window.calibre_preview_integration.go_to_line(%d)' % lnum)
class WebView(QWebView): class WebView(QWebView):