From cf5ca455314ee39b4fe334043335ac2ac798cd5b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 8 Feb 2010 11:48:15 -0700 Subject: [PATCH] E-book viewer: Make bookmark positioning (and remembering last read location) more robust. Fixes #4812 (E-book viewer not correctly remembering reading position on reopen) --- resources/viewer/bookmarks.js | 33 ++---------------- src/calibre/gui2/viewer/documentview.py | 46 +++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/resources/viewer/bookmarks.js b/resources/viewer/bookmarks.js index c6f59414ab..da3c0be946 100644 --- a/resources/viewer/bookmarks.js +++ b/resources/viewer/bookmarks.js @@ -20,37 +20,8 @@ function selector(elem) { 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); +function calculate_bookmark(y, node) { + var elem = $(node); var sel = selector(elem); var ratio = (y - elem.offset().top)/elem.height(); if (ratio > 1) { ratio = 1; } diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py index 9b911754c8..6566042755 100644 --- a/src/calibre/gui2/viewer/documentview.py +++ b/src/calibre/gui2/viewer/documentview.py @@ -5,7 +5,7 @@ __docformat__ = 'restructuredtext en' ''' ''' -import os, math, re, glob +import os, math, re, glob, sys from base64 import b64encode from PyQt4.Qt import QSize, QSizePolicy, QUrl, SIGNAL, Qt, QTimer, \ QPainter, QPalette, QBrush, QFontDatabase, QDialog, \ @@ -295,8 +295,50 @@ class Document(QWebPage): if r > 0: self.javascript('document.body.style.paddingBottom = "%dpx"'%r) + def element_ypos(self, elem): + ans, ok = elem.evaluateJavaScript('$(this).offset().top').toInt() + if not ok: + raise ValueError('No ypos found') + return ans + + def elem_outer_xml(self, elem): + return unicode(elem.toOuterXml()) + + def find_bookmark_element(self): + mf = self.mainFrame() + doc_pos = self.ypos + min_delta, min_elem = sys.maxint, None + for y in range(10, -500, -10): + for x in range(-50, 500, 10): + pos = QPoint(x, y) + result = mf.hitTestContent(pos) + if result.isNull(): continue + elem = result.enclosingBlockElement() + if elem.isNull(): continue + try: + ypos = self.element_ypos(elem) + except: + continue + delta = abs(ypos - doc_pos) + if delta < 25: + return elem + if delta < min_delta: + min_elem, min_delta = elem, delta + return min_elem + + def bookmark(self): - return self.javascript('calculate_bookmark(%d)'%(self.ypos+25), 'string') + elem = self.find_bookmark_element() + + if elem is None or self.element_ypos(elem) < 100: + print elem, self.element_ypos(elem) + bm = 'body|%f'%(float(self.ypos)/(self.height*0.7)) + else: + bm = unicode(elem.evaluateJavaScript( + 'calculate_bookmark(%d, this)'%self.ypos).toString()) + if not bm: + bm = 'body|%f'%(float(self.ypos)/(self.height*0.7)) + return bm @property def at_bottom(self):