mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
IGN:Cleanup of ebook viewer code
This commit is contained in:
parent
c6853892d0
commit
ceace20197
71
resources/viewer/bookmarks.js
Normal file
71
resources/viewer/bookmarks.js
Normal 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()}});
|
||||||
|
}
|
||||||
|
|
26
resources/viewer/hyphenation.js
Normal file
26
resources/viewer/hyphenation.js
Normal 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);
|
||||||
|
}
|
||||||
|
|
62
resources/viewer/referencing.js
Normal file
62
resources/viewer/referencing.js
Normal 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()}});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -386,7 +386,7 @@ def main():
|
|||||||
{
|
{
|
||||||
'optimize' : 2,
|
'optimize' : 2,
|
||||||
'dist_dir' : 'build/py2app',
|
'dist_dir' : 'build/py2app',
|
||||||
'argv_emulation' : False,
|
'argv_emulation' : True,
|
||||||
'iconfile' : icon,
|
'iconfile' : icon,
|
||||||
'frameworks': ['libusb.dylib', 'libunrar.dylib'],
|
'frameworks': ['libusb.dylib', 'libunrar.dylib'],
|
||||||
'includes' : ['sip', 'pkg_resources', 'PyQt4.QtXml',
|
'includes' : ['sip', 'pkg_resources', 'PyQt4.QtXml',
|
||||||
|
@ -15,11 +15,12 @@ from PyQt4.QtWebKit import QWebPage, QWebView, QWebSettings
|
|||||||
from calibre.utils.config import Config, StringConfig
|
from calibre.utils.config import Config, StringConfig
|
||||||
from calibre.utils.localization import get_language
|
from calibre.utils.localization import get_language
|
||||||
from calibre.gui2.viewer.config_ui import Ui_Dialog
|
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.ptempfile import PersistentTemporaryFile
|
||||||
from calibre.constants import iswindows
|
from calibre.constants import iswindows
|
||||||
from calibre import prints, guess_type
|
from calibre import prints, guess_type
|
||||||
|
|
||||||
|
bookmarks = referencing = hyphenation = jquery = jquery_scrollTo = hyphenator = None
|
||||||
|
|
||||||
def load_builtin_fonts():
|
def load_builtin_fonts():
|
||||||
base = P('fonts/liberation/*.ttf')
|
base = P('fonts/liberation/*.ttf')
|
||||||
for f in glob.glob(base):
|
for f in glob.glob(base):
|
||||||
@ -192,15 +193,24 @@ class Document(QWebPage):
|
|||||||
self.hyphenate_default_lang = opts.hyphenate_default_lang
|
self.hyphenate_default_lang = opts.hyphenate_default_lang
|
||||||
|
|
||||||
def load_javascript_libraries(self):
|
def load_javascript_libraries(self):
|
||||||
|
global bookmarks, referencing, hyphenation, jquery, jquery_scrollTo, hyphenator
|
||||||
self.mainFrame().addToJavaScriptWindowObject("py_bridge", self)
|
self.mainFrame().addToJavaScriptWindowObject("py_bridge", self)
|
||||||
jquery = open(P('content_server/jquery.js'), 'rb').read()
|
if jquery is None:
|
||||||
jquery_scrollTo = open(P('viewer/jquery_scrollTo.js'), 'rb').read()
|
jquery = P('content_server/jquery.js', data=True)
|
||||||
hyphenator = open(P('viewer/hyphenate/Hyphenator.js'),
|
if jquery_scrollTo is None:
|
||||||
'rb').read().decode('utf-8')
|
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)
|
||||||
self.javascript(jquery_scrollTo)
|
self.javascript(jquery_scrollTo)
|
||||||
|
if bookmarks is None:
|
||||||
|
bookmarks = P('viewer/bookmarks.js', data=True)
|
||||||
self.javascript(bookmarks)
|
self.javascript(bookmarks)
|
||||||
|
if referencing is None:
|
||||||
|
referencing = P('viewer/referencing.js', data=True)
|
||||||
self.javascript(referencing)
|
self.javascript(referencing)
|
||||||
|
if hyphenation is None:
|
||||||
|
hyphenation = P('viewer/hyphenation.js', data=True)
|
||||||
self.javascript(hyphenation)
|
self.javascript(hyphenation)
|
||||||
default_lang = self.hyphenate_default_lang
|
default_lang = self.hyphenate_default_lang
|
||||||
lang = self.current_language
|
lang = self.current_language
|
||||||
@ -333,6 +343,7 @@ class Document(QWebPage):
|
|||||||
def width(self):
|
def width(self):
|
||||||
return self.mainFrame().contentsSize().width() # offsetWidth gives inaccurate results
|
return self.mainFrame().contentsSize().width() # offsetWidth gives inaccurate results
|
||||||
|
|
||||||
|
|
||||||
class EntityDeclarationProcessor(object):
|
class EntityDeclarationProcessor(object):
|
||||||
|
|
||||||
def __init__(self, html):
|
def __init__(self, html):
|
||||||
@ -508,6 +519,7 @@ class DocumentView(QWebView):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def test_line(cls, img, y):
|
def test_line(cls, img, y):
|
||||||
|
'Test if line contains pixels of exactly the same color'
|
||||||
start = img.pixel(0, y)
|
start = img.pixel(0, y)
|
||||||
for i in range(1, img.width()):
|
for i in range(1, img.width()):
|
||||||
if img.pixel(i, y) != start:
|
if img.pixel(i, y) != start:
|
||||||
@ -517,6 +529,7 @@ class DocumentView(QWebView):
|
|||||||
def find_next_blank_line(self, overlap):
|
def find_next_blank_line(self, overlap):
|
||||||
img = QImage(self.width(), overlap, QImage.Format_ARGB32)
|
img = QImage(self.width(), overlap, QImage.Format_ARGB32)
|
||||||
painter = QPainter(img)
|
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))
|
self.document.mainFrame().render(painter, QRegion(0, 0, self.width(), overlap))
|
||||||
painter.end()
|
painter.end()
|
||||||
for i in range(overlap-1, -1, -1):
|
for i in range(overlap-1, -1, -1):
|
||||||
@ -542,18 +555,20 @@ class DocumentView(QWebView):
|
|||||||
self.manager.scrolled(self.scroll_fraction)
|
self.manager.scrolled(self.scroll_fraction)
|
||||||
|
|
||||||
def next_page(self):
|
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.document.at_bottom:
|
||||||
if self.manager is not None:
|
if self.manager is not None:
|
||||||
self.manager.next_document()
|
self.manager.next_document()
|
||||||
else:
|
else:
|
||||||
opos = self.document.ypos
|
opos = self.document.ypos
|
||||||
lower_limit = opos + delta_y
|
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)
|
lower_limit = min(max_y, lower_limit)
|
||||||
if lower_limit > opos:
|
if lower_limit > opos:
|
||||||
self.document.scroll_to(self.document.xpos, lower_limit)
|
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:
|
if self.manager is not None:
|
||||||
self.manager.scrolled(self.scroll_fraction)
|
self.manager.scrolled(self.scroll_fraction)
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
'''
|
|
Loading…
x
Reference in New Issue
Block a user