IGN:Cleanup of ebook viewer code

This commit is contained in:
Kovid Goyal 2009-10-31 13:12:06 -06:00
parent c6853892d0
commit ceace20197
6 changed files with 183 additions and 165 deletions

View File

@ -0,0 +1,71 @@
/*
* bookmarks management
* Copyright 2008 Kovid Goyal
* License: GNU GPL v3
*/
function selector_in_parent(elem) {
var num = elem.prevAll().length;
var sel = " > *:eq("+num+") ";
return sel;
}
function selector(elem) {
var obj = elem;
var sel = "";
while (obj[0] != document) {
sel = selector_in_parent(obj) + sel;
obj = obj.parent();
}
return sel;
}
function find_closest_enclosing_block(top) {
var START = top-1000;
var STOP = top;
var matches = [];
var elem, temp;
var width = 1000;
for (y = START; y < STOP; y += 20) {
for ( x = 0; x < width; x += 20) {
elem = document.elementFromPoint(x, y);
try {
elem = $(elem);
temp = elem.offset().top
matches.push(elem);
if (Math.abs(temp - START) < 25) { y = STOP; break}
} catch(error) {}
}
}
var miny = Math.abs(matches[0].offset().top - START), min_elem = matches[0];
for (i = 1; i < matches.length; i++) {
elem = matches[i];
temp = Math.abs(elem.offset().top - START);
if ( temp < miny ) { miny = temp; min_elem = elem; }
}
return min_elem;
}
function calculate_bookmark(y) {
var elem = find_closest_enclosing_block(y);
var sel = selector(elem);
var ratio = (y - elem.offset().top)/elem.height();
if (ratio > 1) { ratio = 1; }
if (ratio < 0) { ratio = 0; }
return sel + "|" + ratio;
}
function animated_scrolling_done() {
window.py_bridge.animated_scroll_done();
}
function scroll_to_bookmark(bookmark) {
bm = bookmark.split("|");
var ratio = 0.7 * parseFloat(bm[1]);
$.scrollTo($(bm[0]), 1000,
{over:ratio, onAfter:function(){window.py_bridge.animated_scroll_done()}});
}

View File

@ -0,0 +1,26 @@
/*
* bookmarks management
* Copyright 2008 Kovid Goyal
* License: GNU GPL v3
*/
function init_hyphenate() {
window.py_bridge.init_hyphenate();
}
document.addEventListener("DOMContentLoaded", init_hyphenate, false);
function do_hyphenation(lang) {
Hyphenator.config(
{
'minwordlength' : 6,
//'hyphenchar' : '|',
'displaytogglebox' : false,
'remoteloading' : false,
'onerrorhandler' : function (e) {
window.py_bridge.debug(e);
}
});
Hyphenator.hyphenate(document.body, lang);
}

View File

@ -0,0 +1,62 @@
/*
* reference management
* Copyright 2008 Kovid Goyal
* License: GNU GPL v3
*/
var reference_old_bgcol = "transparent";
var reference_prefix = "1.";
function show_reference_panel(ref) {
panel = $("#calibre_reference_panel");
if (panel.length < 1) {
$(document.body).append('<div id="calibre_reference_panel" style="top:20px; left:20px; padding-left:30px; padding-right:30px; font:monospace normal;text-align:center; z-index:10000; background: beige; border:red ridge 2px; position:absolute;"><h5>Paragraph</h5><p style="text-indent:0pt">None</p></div>')
panel = $("#calibre_reference_panel");
}
$("> p", panel).text(ref);
panel.css({top:(window.pageYOffset+20)+"px"});
panel.fadeIn(500);
}
function toggle_reference(e) {
p = $(this);
if (e.type == "mouseenter") {
reference_old_bgcol = p.css("background-color");
p.css({backgroundColor:"beige"});
var i = 0;
var paras = $("p");
for (j = 0; j < paras.length; j++,i++) {
if (paras[j] == p[0]) break;
}
show_reference_panel(reference_prefix+(i+1) );
} else {
p.css({backgroundColor:reference_old_bgcol});
panel = $("#calibre_reference_panel").hide();
}
return false;
}
function enter_reference_mode() {
$("p").bind("mouseenter mouseleave", toggle_reference);
}
function leave_reference_mode() {
$("p").unbind("mouseenter mouseleave", toggle_reference);
}
function goto_reference(ref) {
var tokens = ref.split(".");
if (tokens.length != 2) {alert("Invalid reference: "+ref); return;}
var num = parseInt(tokens[1]);
if (isNaN(num)) {alert("Invalid reference: "+ref); return;}
num -= 1;
if (num < 0) {alert("Invalid reference: "+ref); return;}
var p = $("p");
if (num >= p.length) {alert("Reference not found: "+ref); return;}
$.scrollTo($(p[num]), 1000,
{onAfter:function(){window.py_bridge.animated_scroll_done()}});
}

View File

@ -386,7 +386,7 @@ def main():
{
'optimize' : 2,
'dist_dir' : 'build/py2app',
'argv_emulation' : False,
'argv_emulation' : True,
'iconfile' : icon,
'frameworks': ['libusb.dylib', 'libunrar.dylib'],
'includes' : ['sip', 'pkg_resources', 'PyQt4.QtXml',

View File

@ -15,11 +15,12 @@ from PyQt4.QtWebKit import QWebPage, QWebView, QWebSettings
from calibre.utils.config import Config, StringConfig
from calibre.utils.localization import get_language
from calibre.gui2.viewer.config_ui import Ui_Dialog
from calibre.gui2.viewer.js import bookmarks, referencing, hyphenation
from calibre.ptempfile import PersistentTemporaryFile
from calibre.constants import iswindows
from calibre import prints, guess_type
bookmarks = referencing = hyphenation = jquery = jquery_scrollTo = hyphenator = None
def load_builtin_fonts():
base = P('fonts/liberation/*.ttf')
for f in glob.glob(base):
@ -192,15 +193,24 @@ class Document(QWebPage):
self.hyphenate_default_lang = opts.hyphenate_default_lang
def load_javascript_libraries(self):
global bookmarks, referencing, hyphenation, jquery, jquery_scrollTo, hyphenator
self.mainFrame().addToJavaScriptWindowObject("py_bridge", self)
jquery = open(P('content_server/jquery.js'), 'rb').read()
jquery_scrollTo = open(P('viewer/jquery_scrollTo.js'), 'rb').read()
hyphenator = open(P('viewer/hyphenate/Hyphenator.js'),
'rb').read().decode('utf-8')
if jquery is None:
jquery = P('content_server/jquery.js', data=True)
if jquery_scrollTo is None:
jquery_scrollTo = P('viewer/jquery_scrollTo.js', data=True)
if hyphenator is None:
hyphenator = P('viewer/hyphenate/Hyphenator.js', data=True).decode('utf-8')
self.javascript(jquery)
self.javascript(jquery_scrollTo)
if bookmarks is None:
bookmarks = P('viewer/bookmarks.js', data=True)
self.javascript(bookmarks)
if referencing is None:
referencing = P('viewer/referencing.js', data=True)
self.javascript(referencing)
if hyphenation is None:
hyphenation = P('viewer/hyphenation.js', data=True)
self.javascript(hyphenation)
default_lang = self.hyphenate_default_lang
lang = self.current_language
@ -333,6 +343,7 @@ class Document(QWebPage):
def width(self):
return self.mainFrame().contentsSize().width() # offsetWidth gives inaccurate results
class EntityDeclarationProcessor(object):
def __init__(self, html):
@ -508,6 +519,7 @@ class DocumentView(QWebView):
@classmethod
def test_line(cls, img, y):
'Test if line contains pixels of exactly the same color'
start = img.pixel(0, y)
for i in range(1, img.width()):
if img.pixel(i, y) != start:
@ -517,6 +529,7 @@ class DocumentView(QWebView):
def find_next_blank_line(self, overlap):
img = QImage(self.width(), overlap, QImage.Format_ARGB32)
painter = QPainter(img)
# Render a region of width x overlap pixels atthe bottom of the current viewport
self.document.mainFrame().render(painter, QRegion(0, 0, self.width(), overlap))
painter.end()
for i in range(overlap-1, -1, -1):
@ -542,18 +555,20 @@ class DocumentView(QWebView):
self.manager.scrolled(self.scroll_fraction)
def next_page(self):
delta_y = self.document.window_height - 25
window_height = self.document.window_height
delta_y = window_height - 25
if self.document.at_bottom:
if self.manager is not None:
self.manager.next_document()
else:
opos = self.document.ypos
lower_limit = opos + delta_y
max_y = self.document.height - self.document.window_height
max_y = self.document.height - window_height
lower_limit = min(max_y, lower_limit)
if lower_limit > opos:
self.document.scroll_to(self.document.xpos, lower_limit)
self.find_next_blank_line( self.height() - (self.document.ypos-opos) )
actually_scrolled = self.document.ypos - opos
self.find_next_blank_line(window_height - actually_scrolled)
if self.manager is not None:
self.manager.scrolled(self.scroll_fraction)

View File

@ -1,156 +0,0 @@
bookmarks = '''
function selector_in_parent(elem) {
var num = elem.prevAll().length;
var sel = " > *:eq("+num+") ";
return sel;
}
function selector(elem) {
var obj = elem;
var sel = "";
while (obj[0] != document) {
sel = selector_in_parent(obj) + sel;
obj = obj.parent();
}
return sel;
}
function find_closest_enclosing_block(top) {
var START = top-1000;
var STOP = top;
var matches = [];
var elem, temp;
var width = 1000;
for (y = START; y < STOP; y += 20) {
for ( x = 0; x < width; x += 20) {
elem = document.elementFromPoint(x, y);
try {
elem = $(elem);
temp = elem.offset().top
matches.push(elem);
if (Math.abs(temp - START) < 25) { y = STOP; break}
} catch(error) {}
}
}
var miny = Math.abs(matches[0].offset().top - START), min_elem = matches[0];
for (i = 1; i < matches.length; i++) {
elem = matches[i];
temp = Math.abs(elem.offset().top - START);
if ( temp < miny ) { miny = temp; min_elem = elem; }
}
return min_elem;
}
function calculate_bookmark(y) {
var elem = find_closest_enclosing_block(y);
var sel = selector(elem);
var ratio = (y - elem.offset().top)/elem.height();
if (ratio > 1) { ratio = 1; }
if (ratio < 0) { ratio = 0; }
return sel + "|" + ratio;
}
function animated_scrolling_done() {
window.py_bridge.animated_scroll_done();
}
function scroll_to_bookmark(bookmark) {
bm = bookmark.split("|");
var ratio = 0.7 * parseFloat(bm[1]);
$.scrollTo($(bm[0]), 1000,
{over:ratio, onAfter:function(){window.py_bridge.animated_scroll_done()}});
}
'''
referencing = '''
var reference_old_bgcol = "transparent";
var reference_prefix = "1.";
function show_reference_panel(ref) {
panel = $("#calibre_reference_panel");
if (panel.length < 1) {
$(document.body).append('<div id="calibre_reference_panel" style="top:20px; left:20px; padding-left:30px; padding-right:30px; font:monospace normal;text-align:center; z-index:10000; background: beige; border:red ridge 2px; position:absolute;"><h5>Paragraph</h5><p style="text-indent:0pt">None</p></div>')
panel = $("#calibre_reference_panel");
}
$("> p", panel).text(ref);
panel.css({top:(window.pageYOffset+20)+"px"});
panel.fadeIn(500);
}
function toggle_reference(e) {
p = $(this);
if (e.type == "mouseenter") {
reference_old_bgcol = p.css("background-color");
p.css({backgroundColor:"beige"});
var i = 0;
var paras = $("p");
for (j = 0; j < paras.length; j++,i++) {
if (paras[j] == p[0]) break;
}
show_reference_panel(reference_prefix+(i+1) );
} else {
p.css({backgroundColor:reference_old_bgcol});
panel = $("#calibre_reference_panel").hide();
}
return false;
}
function enter_reference_mode() {
$("p").bind("mouseenter mouseleave", toggle_reference);
}
function leave_reference_mode() {
$("p").unbind("mouseenter mouseleave", toggle_reference);
}
function goto_reference(ref) {
var tokens = ref.split(".");
if (tokens.length != 2) {alert("Invalid reference: "+ref); return;}
var num = parseInt(tokens[1]);
if (isNaN(num)) {alert("Invalid reference: "+ref); return;}
num -= 1;
if (num < 0) {alert("Invalid reference: "+ref); return;}
var p = $("p");
if (num >= p.length) {alert("Reference not found: "+ref); return;}
$.scrollTo($(p[num]), 1000,
{onAfter:function(){window.py_bridge.animated_scroll_done()}});
}
'''
test = '''
$(document.body).click(function(e) {
bm = calculate_bookmark(e.pageY);
scroll_to_bookmark(bm);
});
$(document).ready(enter_reference_mode);
'''
hyphenation = '''
function init_hyphenate() {
window.py_bridge.init_hyphenate();
}
document.addEventListener("DOMContentLoaded", init_hyphenate, false);
function do_hyphenation(lang) {
Hyphenator.config(
{
'minwordlength' : 6,
//'hyphenchar' : '|',
'displaytogglebox' : false,
'remoteloading' : false,
'onerrorhandler' : function (e) {
window.py_bridge.debug(e);
}
});
Hyphenator.hyphenate(document.body, lang);
}
'''