pre .21 changes

This commit is contained in:
GRiker 2009-11-05 11:46:59 -07:00
commit 543050779c
17 changed files with 416 additions and 224 deletions

View File

@ -1,24 +1,56 @@
import re
from calibre.web.feeds.news import BasicNewsRecipe
class Cyberpresse(BasicNewsRecipe):
title = u'Cyberpresse'
__author__ = 'balok'
__author__ = 'balok and Sujata Raman'
description = 'Canadian news in French'
language = 'fr'
oldest_article = 7
max_articles_per_feed = 100
no_stylesheets = True
remove_javascript = True
html2lrf_options = ['--left-margin=0','--right-margin=0','--top-margin=0','--bottom-margin=0']
preprocess_regexps = [
(re.compile(r'<body.*?<!-- END .centerbar -->', re.IGNORECASE | re.DOTALL), lambda match : '<BODY>'),
(re.compile(r'<!-- END .entry -->.*?</body>', re.IGNORECASE | re.DOTALL), lambda match : '</BODY>'),
(re.compile(r'<strong>Agrandir.*?</strong>', re.IGNORECASE | re.DOTALL), lambda match : '<br>'),
]
encoding = 'utf-8'
feeds = [(u'Manchettes', u'http://www.cyberpresse.ca/rss/225.xml'),(u'Capitale nationale', u'http://www.cyberpresse.ca/rss/501.xml'),(u'Opinions', u'http://www.cyberpresse.ca/rss/977.xml'),(u'Insolite', u'http://www.cyberpresse.ca/rss/279.xml')]
keep_only_tags = [dict(name='div', attrs={'class':'article-page'}),
dict(name='div', attrs={'id':'articlePage'}),
]
extra_css = '''
.photodata{font-family:Arial,Helvetica,Verdana,sans-serif;color: #999999; font-size: 90%; }
h1{font-family:Georgia,Times,serif ; font-size: large; }
.amorce{font-family:Arial,Helvetica,Verdana,sans-serif; font-weight:bold;}
.article-page{font-family:Arial,Helvetica,Verdana,sans-serif; font-size: x-small;}
#articlePage{font-family:Arial,Helvetica,Verdana,sans-serif; font-size: x-small;}
.auteur{font-family:Georgia,Times,sans-serif; font-size: 90%; color:#006699 ;}
.bodyText{font-family:Arial,Helvetica,Verdana,sans-serif; font-size: x-small;}
.byLine{font-family:Arial,Helvetica,Verdana,sans-serif; font-size: 90%;}
.entry{font-family:Arial,Helvetica,Verdana,sans-serif; font-size: x-small;}
.minithumb-auteurs{font-family:Arial,Helvetica,Verdana,sans-serif; font-size: 90%; }
a{color:#003399; font-weight:bold; }
'''
remove_tags = [
dict(name='div', attrs={'class':['centerbar','colspan','share-module']}),
dict(name='p', attrs={'class':['zoom']}),
dict(name='ul', attrs={'class':['stories']}),
dict(name='h4', attrs={'class':['general-cat']}),
]
feeds = [(u'Manchettes', u'http://www.cyberpresse.ca/rss/225.xml'),
(u'Capitale nationale', u'http://www.cyberpresse.ca/rss/501.xml'),
(u'Opinions', u'http://www.cyberpresse.ca/rss/977.xml'),
(u'Insolite', u'http://www.cyberpresse.ca/rss/279.xml')
]
def postprocess_html(self, soup, first):
for tag in soup.findAll(name=['i','strong']):
tag.name = 'div'
return soup

View File

@ -16,9 +16,11 @@ class Economist(BasicNewsRecipe):
language = 'en'
__author__ = "Kovid Goyal"
description = 'Global news and current affairs from a European perspective'
oldest_article = 7.0
INDEX = 'http://www.economist.com/printedition'
description = ('Global news and current affairs from a European perspective.'
' Needs a subscription from ')+INDEX
oldest_article = 7.0
cover_url = 'http://www.economist.com/images/covers/currentcovereu_large.jpg'
remove_tags = [dict(name=['script', 'noscript', 'title'])]
remove_tags_before = dict(name=lambda tag: tag.name=='title' and tag.parent.name=='body')

View File

@ -15,8 +15,8 @@ class Guardian(BasicNewsRecipe):
__author__ = 'Seabound and Sujata Raman'
language = 'en_GB'
oldest_article = 7
max_articles_per_feed = 20
#oldest_article = 7
#max_articles_per_feed = 100
remove_javascript = True
timefmt = ' [%a, %d %b %Y]'
@ -45,26 +45,94 @@ class Guardian(BasicNewsRecipe):
feeds = [
('Front Page', 'http://www.guardian.co.uk/rss'),
('Business', 'http://www.guardian.co.uk/business/rss'),
('Sport', 'http://www.guardian.co.uk/sport/rss'),
('Culture', 'http://www.guardian.co.uk/culture/rss'),
('Money', 'http://www.guardian.co.uk/money/rss'),
('Life & Style', 'http://www.guardian.co.uk/lifeandstyle/rss'),
('Travel', 'http://www.guardian.co.uk/travel/rss'),
('Environment', 'http://www.guardian.co.uk/environment/rss'),
('Comment','http://www.guardian.co.uk/commentisfree/rss'),
]
# feeds = [
# ('Front Page', 'http://www.guardian.co.uk/rss'),
# ('Business', 'http://www.guardian.co.uk/business/rss'),
# ('Sport', 'http://www.guardian.co.uk/sport/rss'),
# ('Culture', 'http://www.guardian.co.uk/culture/rss'),
# ('Money', 'http://www.guardian.co.uk/money/rss'),
# ('Life & Style', 'http://www.guardian.co.uk/lifeandstyle/rss'),
# ('Travel', 'http://www.guardian.co.uk/travel/rss'),
# ('Environment', 'http://www.guardian.co.uk/environment/rss'),
# ('Comment','http://www.guardian.co.uk/commentisfree/rss'),
# ]
def get_article_url(self, article):
url = article.get('guid', None)
if '/video/' in url or '/flyer/' in url or '/quiz/' in url or \
'/gallery/' in url or 'ivebeenthere' in url or \
'pickthescore' in url or 'audioslideshow' in url :
url = None
return url
# def get_article_url(self, article):
# url = article.get('guid', None)
# if '/video/' in url or '/flyer/' in url or '/quiz/' in url or \
# '/gallery/' in url or 'ivebeenthere' in url or \
# 'pickthescore' in url or 'audioslideshow' in url :
# url = None
# return url
def parse_index(self):
articles = []
soup = self.index_to_soup('http://www.guardian.co.uk/theguardian')
# find cover pic
img = soup.find( 'img',attrs ={'alt':'Guardian digital edition'})
if img is not None:
self.cover_url = img['src']
# end find cover pic
for li in soup.findAll( 'li'):
if li.a and li.a.has_key('href'):
url = li.a['href']
if 'mainsection' in url:
#find the articles in the Main Section
soup = self.index_to_soup(url)
for tag in soup.findAll('h3'):
for a in tag.findAll('a'):
if a and a.has_key('href'):
url2 = a['href']
else:
url2 =''
title = self.tag_to_string(a)
#eliminate duplicates
if len(articles) == 0:
desc = 'Main Section'
date = ''
articles.append({
'title':title,
'date':date,
'url':url2,
'description':desc,
})
else:
if len(articles) > 0:
if {'title':title,'date':date,'url':url2,'description':desc} in articles:
ulrl2 = ''
#eliminate duplicates
else:
desc = 'Main Section'
date = ''
articles.append({
'title':title,
'date':date,
'url':url2,
'description':desc,
})
#find the articles in the Main Section
else:
url =''
return [('Current Issue', articles)]
def preprocess_html(self, soup):

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

@ -19,7 +19,7 @@ class NUUT2(USBMS):
supported_platforms = ['windows', 'osx', 'linux']
# Ordered list of supported formats
FORMATS = ['epub', 'pdft', 'txt']
FORMATS = ['epub', 'pdf', 'txt']
DRM_FORMATS = ['epub']
VENDOR_ID = [0x140e]

View File

@ -107,6 +107,9 @@ class FB2MLizer(object):
def get_cover_page(self):
output = u''
if 'cover' in self.oeb_book.guide:
output += '<image xlink:href="#cover.jpg" />'
self.image_hrefs[self.oeb_book.guide['cover'].href] = 'cover.jpg'
if 'titlepage' in self.oeb_book.guide:
self.log.debug('Generating cover page...')
href = self.oeb_book.guide['titlepage'].href

View File

@ -34,6 +34,7 @@ def metadata_from_formats(formats):
mi = metadata_from_filename(list(iter(formats))[0])
if not mi.authors:
mi.authors = [_('Unknown')]
return mi
def _metadata_from_formats(formats):
mi = MetaInformation(None, None)

View File

@ -19,7 +19,7 @@ from calibre.utils.zipfile import safe_replace, ZipFile
from calibre.utils.config import DynamicConfig
from calibre.utils.logging import Log
from calibre.ebooks.epub.output import EPUBOutput
from calibre import guess_type
from calibre import guess_type, prints
TITLEPAGE = EPUBOutput.TITLEPAGE_COVER.decode('utf-8')
@ -99,29 +99,63 @@ class EbookIterator(object):
if text in open(path, 'rb').read().decode(path.encoding).lower():
return i
def find_missing_css_files(self):
for x in os.walk(os.path.dirname(self.pathtoopf)):
for f in x[-1]:
if f.endswith('.css'):
yield os.path.join(x[0], f)
def find_declared_css_files(self):
for item in self.opf.manifest:
if item.mime_type and 'css' in item.mime_type.lower():
yield item.path
def find_embedded_fonts(self):
'''
This will become unnecessary once Qt WebKit supports the @font-face rule.
'''
for item in self.opf.manifest:
if item.mime_type and 'css' in item.mime_type.lower():
css = open(item.path, 'rb').read().decode('utf-8', 'replace')
for match in re.compile(r'@font-face\s*{([^}]+)}').finditer(css):
block = match.group(1)
family = re.compile(r'font-family\s*:\s*([^;]+)').search(block)
url = re.compile(r'url\s*\([\'"]*(.+?)[\'"]*\)', re.DOTALL).search(block)
if url:
path = url.group(1).split('/')
path = os.path.join(os.path.dirname(item.path), *path)
id = QFontDatabase.addApplicationFont(path)
if id != -1:
families = [unicode(f) for f in QFontDatabase.applicationFontFamilies(id)]
if family:
family = family.group(1).strip().replace('"', '')
if family not in families:
print 'WARNING: Family aliasing not supported:', block
else:
print 'Loaded embedded font:', repr(family)
css_files = set(self.find_declared_css_files())
if not css_files:
css_files = set(self.find_missing_css_files())
bad_map = {}
font_family_pat = re.compile(r'font-family\s*:\s*([^;]+)')
for csspath in css_files:
css = open(csspath, 'rb').read().decode('utf-8', 'replace')
for match in re.compile(r'@font-face\s*{([^}]+)}').finditer(css):
block = match.group(1)
family = font_family_pat.search(block)
url = re.compile(r'url\s*\([\'"]*(.+?)[\'"]*\)', re.DOTALL).search(block)
if url:
path = url.group(1).split('/')
path = os.path.join(os.path.dirname(csspath), *path)
if not os.access(path, os.R_OK):
continue
id = QFontDatabase.addApplicationFont(path)
if id != -1:
families = [unicode(f) for f in QFontDatabase.applicationFontFamilies(id)]
if family:
family = family.group(1).strip().replace('"', '')
bad_map[family] = families[0]
if family not in families:
prints('WARNING: Family aliasing not fully supported.')
prints('\tDeclared family: %s not in actual families: %s'
% (family, families))
else:
prints('Loaded embedded font:', repr(family))
if bad_map:
def prepend_embedded_font(match):
for bad, good in bad_map.items():
if bad in match.group(1):
prints('Substituting font family: %s -> %s'%(bad, good))
return match.group().replace(bad, '"%s"'%good)
for csspath in css_files:
with open(csspath, 'r+b') as f:
css = f.read()
css = font_family_pat.sub(prepend_embedded_font, css)
f.seek(0)
f.truncate()
f.write(css)
def __enter__(self, processed=False):
self.delete_on_exit = []

View File

@ -82,13 +82,16 @@ class RBMLizer(object):
def get_cover_page(self):
output = u''
if 'cover' in self.oeb_book.guide:
if self.name_map.get(self.oeb_book.guide['cover'].href, None):
output += '<IMG SRC="%s">' % self.name_map[self.oeb_book.guide['cover'].href]
if 'titlepage' in self.oeb_book.guide:
self.log.debug('Generating cover page...')
href = self.oeb_book.guide['titlepage'].href
item = self.oeb_book.manifest.hrefs[href]
if item.spine_position is None:
stylizer = Stylizer(item.data, item.href, self.oeb_book, self.opts.output_profile)
output += self.dump_text(item.data.find(XHTML('body')), stylizer, item)
output += ''.join(self.dump_text(item.data.find(XHTML('body')), stylizer, item))
return output
def get_toc(self):
@ -152,7 +155,7 @@ class RBMLizer(object):
if tag in IMAGE_TAGS:
if elem.attrib.get('src', None):
if page.abshref(elem.attrib['src']) not in self.name_map.keys():
self.name_map[page.abshref(elem.attrib['src'])] = unique_name('%s' % len(self.image_hrefs.keys()), self.image_hrefs.keys(), self.name_map.keys())
self.name_map[page.abshref(elem.attrib['src'])] = unique_name('%s' % len(self.name_map.keys()), self.name_map.keys())
text.append('<IMG SRC="%s">' % self.name_map[page.abshref(elem.attrib['src'])])
rb_tag = tag.upper() if tag in TAGS else None

View File

@ -274,6 +274,7 @@ class GetMetadata(QObject):
self.emit(SIGNAL('metadata(PyQt_PyObject, PyQt_PyObject)'), id, mi)
class TableView(QTableView):
def __init__(self, parent):
QTableView.__init__(self, parent)
self.read_settings()
@ -585,8 +586,11 @@ def build_forms(srcdir, info=None):
if form.endswith('viewer%smain.ui'%os.sep):
info('\t\tPromoting WebView')
dat = dat.replace('self.view = QtWebKit.QWebView(', 'self.view = DocumentView(')
dat = dat.replace('from PyQt4 import QtWebKit', '')
if iswindows:
dat = dat.replace('self.view = QWebView(', 'self.view = DocumentView(')
dat = dat.replace('from QtWebKit.QWebView import QWebView', '')
dat += '\n\nfrom calibre.gui2.viewer.documentview import DocumentView'
dat += '\nQtWebKit'
open(compiled_form, 'wb').write(dat)

View File

@ -742,6 +742,16 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
########################## Connect to device ##############################
def save_device_view_settings(self):
model = self.location_view.model()
self.memory_view.write_settings()
for x in range(model.rowCount()):
if x > 1:
if model.location_for_row(x) == 'carda':
self.card_a_view.write_settings()
elif model.location_for_row(x) == 'cardb':
self.carb_b_view.write_settings()
def device_detected(self, connected):
'''
Called when a device is connected to the computer.
@ -757,6 +767,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.device_connected = True
self._sync_menu.enable_device_actions(True, self.device_manager.device.card_prefix())
else:
self.save_device_view_settings()
self.device_connected = False
self._sync_menu.enable_device_actions(False)
self.location_view.model().update_devices()
@ -765,7 +776,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.device_info = ' '
if self.current_view() != self.library_view:
self.status_bar.reset_info()
self.location_selected('library')
self.location_view.setCurrentIndex(self.location_view.model().index(0))
def info_read(self, job):
'''
@ -807,6 +818,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.card_b_view.set_editable(self.device_manager.device_class.CAN_SET_METADATA)
for view in (self.memory_view, self.card_a_view, self.card_b_view):
view.sortByColumn(3, Qt.DescendingOrder)
view.read_settings()
if not view.restore_column_widths():
view.resizeColumnsToContents()
view.resizeRowsToContents()
@ -1662,7 +1674,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
dynamic.set('sort_column', self.library_view.model().sorted_on)
self.library_view.write_settings()
if self.device_connected:
self.memory_view.write_settings()
self.save_device_view_settings()
def restart(self):
self.quit(restart=True)

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);
}
'''

View File

@ -108,7 +108,7 @@ will appear in the next release of |app|.
Can I use both |app| and the SONY software to manage my reader?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Yes, you can use both, provided you don not run them at the same time. That is, you should use the following sequence:
Yes, you can use both, provided you do not run them at the same time. That is, you should use the following sequence:
Connect reader->Use one of the programs->Disconnect reader. Reconnect reader->Use the other program->disconnect reader.
The underlying reason is that the Reader uses a single file to keep track
@ -122,7 +122,7 @@ other via the computers hard disk.
If you do need to reset your metadata due to problems caused by using both
at the same time, then just delete the media.xml file on the Reader using
your PC's file explorer and it'll be recreated after disconnection.
your PC's file explorer and it will be recreated after disconnection.
Can I use the collections feature of the SONY reader?
@ -149,6 +149,21 @@ How do I use |app| with my Android phone?
First install the WordPlayer e-book reading app from the Android Marketplace onto you phone. Then simply plug your phone into the computer with a USB cable. |app| should automatically detect the phone and then you can transfer books to it by clicking the Send to Device button. |app| does not have support for every single androind device out there, so if you would like to have support for your device added, follow the instructions above for getting your device supported in |app|.
Can I access my |app| books using the web browser in my Kindle or other reading device?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|app| has a *Content Server* that exports the books in |app| as a web page. You can turn it on under
Preferences->Content Server. Then just point the web browser on your device to the computer running
the Content Server and you will be able to browse your book collection. For example, if the computer running
the server has IP address 63.45.128.5, in the browser, you would type::
http://63.45.128.5:8080
Some devices, like the Kindle, do not allow you to access port 8080 (the default port on which the content
server runs. In that case, change the port in the |app| Preferences to 80. (On some operating systems,
you may not be able to run the server on a port number less than 1024 because of security settings. In
this case the simplest solution is to adjust your router to forward requests on port 80 to port 8080).
I get the error message "Failed to start content server: Port 8080 not free on '0.0.0.0'"?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~