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]
# }}}
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?
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 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.base import serialize, OEB_DOCS
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):
''' Remove all duplicates from vals, while preserving order. '''
vals = vals or ()
@ -321,10 +261,14 @@ class WebPage(QWebPage):
prints('preview js:%s:%s:'%(unicode(source_id), lineno), unicode(msg))
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
mf = self.mainFrame()
mf.addToJavaScriptWindowObject("py_bridge", self)
mf.evaluateJavaScript(JS)
mf.evaluateJavaScript(self.js)
@pyqtSlot(str)
def request_sync(self, lnum):
@ -341,7 +285,8 @@ class WebPage(QWebPage):
if not ok:
ans = None
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
def go_to_line(self, lnum):
@ -349,7 +294,8 @@ class WebPage(QWebPage):
lnum = find_le(self.line_numbers, lnum)
except ValueError:
return
self.mainFrame().evaluateJavaScript('go_to_line(%d)' % lnum)
self.mainFrame().evaluateJavaScript(
'window.calibre_preview_integration.go_to_line(%d)' % lnum)
class WebView(QWebView):