diff --git a/resources/viewer/bookmarks.js b/resources/viewer/bookmarks.js
new file mode 100644
index 0000000000..c6f59414ab
--- /dev/null
+++ b/resources/viewer/bookmarks.js
@@ -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()}});
+}
+
diff --git a/resources/viewer/hyphenation.js b/resources/viewer/hyphenation.js
new file mode 100644
index 0000000000..a0ba6d1f34
--- /dev/null
+++ b/resources/viewer/hyphenation.js
@@ -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);
+}
+
diff --git a/resources/viewer/referencing.js b/resources/viewer/referencing.js
new file mode 100644
index 0000000000..6de1a06be9
--- /dev/null
+++ b/resources/viewer/referencing.js
@@ -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('
')
+ 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()}});
+}
+
+
diff --git a/setup/installer/osx/freeze.py b/setup/installer/osx/freeze.py
index f30a037703..281432fcf3 100644
--- a/setup/installer/osx/freeze.py
+++ b/setup/installer/osx/freeze.py
@@ -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',
diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py
index aeaf8e2c4f..8e86604603 100644
--- a/src/calibre/gui2/viewer/documentview.py
+++ b/src/calibre/gui2/viewer/documentview.py
@@ -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)
diff --git a/src/calibre/gui2/viewer/js.py b/src/calibre/gui2/viewer/js.py
deleted file mode 100644
index 68768829bb..0000000000
--- a/src/calibre/gui2/viewer/js.py
+++ /dev/null
@@ -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('')
- 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);
-}
-'''