mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
News downloads: Fix incorrect font sizes for some text in the index pages. Fixes #1832628 [Calibre viewer freezes when opening news download converted to LRF](https://bugs.launchpad.net/calibre/+bug/1832628)
Conversion now uses a dedicated attribute data-calibre-rescale for dynamic font sizing rather than relying on class names which can get mangled by CSS flattening
This commit is contained in:
parent
7394a508e0
commit
adbd85bf33
@ -33,21 +33,6 @@ def asfloat(value, default):
|
|||||||
return float(value)
|
return float(value)
|
||||||
|
|
||||||
|
|
||||||
def dynamic_rescale_factor(node):
|
|
||||||
classes = node.get('class', '').split(' ')
|
|
||||||
classes = [x.replace('calibre_rescale_', '') for x in classes if
|
|
||||||
x.startswith('calibre_rescale_')]
|
|
||||||
if not classes:
|
|
||||||
return None
|
|
||||||
factor = 1.0
|
|
||||||
for x in classes:
|
|
||||||
try:
|
|
||||||
factor *= float(x)/100.
|
|
||||||
except ValueError:
|
|
||||||
continue
|
|
||||||
return factor
|
|
||||||
|
|
||||||
|
|
||||||
class KeyMapper(object):
|
class KeyMapper(object):
|
||||||
|
|
||||||
def __init__(self, sbase, dbase, dkey):
|
def __init__(self, sbase, dbase, dkey):
|
||||||
@ -470,8 +455,12 @@ class CSSFlattener(object):
|
|||||||
if not self.context.disable_font_rescaling and not is_drop_cap:
|
if not self.context.disable_font_rescaling and not is_drop_cap:
|
||||||
_sbase = self.sbase if self.sbase is not None else \
|
_sbase = self.sbase if self.sbase is not None else \
|
||||||
self.context.source.fbase
|
self.context.source.fbase
|
||||||
dyn_rescale = dynamic_rescale_factor(node)
|
dyn_rescale = node.attrib.pop('data-calibre-rescale', None)
|
||||||
if dyn_rescale is not None:
|
if dyn_rescale is not None:
|
||||||
|
try:
|
||||||
|
dyn_rescale = float(dyn_rescale) / 100.0
|
||||||
|
except Exception:
|
||||||
|
dyn_rescale = 1
|
||||||
fsize = self.fmap[_sbase]
|
fsize = self.fmap[_sbase]
|
||||||
fsize *= dyn_rescale
|
fsize *= dyn_rescale
|
||||||
cssdict['font-size'] = '%0.5fem'%(fsize/psize)
|
cssdict['font-size'] = '%0.5fem'%(fsize/psize)
|
||||||
@ -541,10 +530,11 @@ class CSSFlattener(object):
|
|||||||
items = sorted(iteritems(cssdict))
|
items = sorted(iteritems(cssdict))
|
||||||
css = u';\n'.join(u'%s: %s' % (key, val) for key, val in items)
|
css = u';\n'.join(u'%s: %s' % (key, val) for key, val in items)
|
||||||
classes = node.get('class', '').strip() or 'calibre'
|
classes = node.get('class', '').strip() or 'calibre'
|
||||||
|
classes_list = classes.split()
|
||||||
# lower() because otherwise if the document uses the same class
|
# lower() because otherwise if the document uses the same class
|
||||||
# name with different case, both cases will apply, leading
|
# name with different case, both cases will apply, leading
|
||||||
# to incorrect results.
|
# to incorrect results.
|
||||||
klass = ascii_text(STRIPNUM.sub('', classes.split()[0])).lower().strip().replace(' ', '_')
|
klass = ascii_text(STRIPNUM.sub('', classes_list[0])).lower().strip().replace(' ', '_')
|
||||||
if css in styles:
|
if css in styles:
|
||||||
match = styles[css]
|
match = styles[css]
|
||||||
else:
|
else:
|
||||||
|
@ -369,11 +369,11 @@ def render_jacket(mi, output_profile,
|
|||||||
# the same as for text in the main book. So text with size x em will
|
# the same as for text in the main book. So text with size x em will
|
||||||
# be rescaled to the same value in both the jacket and the main content.
|
# be rescaled to the same value in both the jacket and the main content.
|
||||||
#
|
#
|
||||||
# We cannot use calibre_rescale_100 on the body tag as that will just
|
# We cannot use data-calibre-rescale 100 on the body tag as that will just
|
||||||
# give the body tag a font size of 1em, which is useless.
|
# give the body tag a font size of 1em, which is useless.
|
||||||
for body in root.xpath('//*[local-name()="body"]'):
|
for body in root.xpath('//*[local-name()="body"]'):
|
||||||
fw = body.makeelement(XHTML('div'))
|
fw = body.makeelement(XHTML('div'))
|
||||||
fw.set('class', 'calibre_rescale_100')
|
fw.set('data-calibre-rescale', '100')
|
||||||
for child in body:
|
for child in body:
|
||||||
fw.append(child)
|
fw.append(child)
|
||||||
body.append(fw)
|
body.append(fw)
|
||||||
|
@ -16,9 +16,13 @@ from calibre import strftime, isbytestring
|
|||||||
from polyglot.builtins import unicode_type
|
from polyglot.builtins import unicode_type
|
||||||
|
|
||||||
|
|
||||||
def CLASS(*args, **kwargs): # class is a reserved word in Python
|
def attrs(*args, **kw):
|
||||||
kwargs['class'] = ' '.join(args)
|
rescale = kw.pop('rescale', None)
|
||||||
return kwargs
|
if rescale is not None:
|
||||||
|
kw['data-calibre-rescale'] = unicode_type(rescale)
|
||||||
|
if args:
|
||||||
|
kw['class'] = ' '.join(args)
|
||||||
|
return kw
|
||||||
|
|
||||||
# Regular templates
|
# Regular templates
|
||||||
|
|
||||||
@ -96,17 +100,17 @@ class IndexTemplate(Template):
|
|||||||
head.append(STYLE(style, type='text/css'))
|
head.append(STYLE(style, type='text/css'))
|
||||||
if extra_css:
|
if extra_css:
|
||||||
head.append(STYLE(extra_css, type='text/css'))
|
head.append(STYLE(extra_css, type='text/css'))
|
||||||
ul = UL(CLASS('calibre_feed_list'))
|
ul = UL(attrs('calibre_feed_list'))
|
||||||
for i, feed in enumerate(feeds):
|
for i, feed in enumerate(feeds):
|
||||||
if feed:
|
if feed:
|
||||||
li = LI(A(feed.title, CLASS('feed', 'calibre_rescale_120',
|
li = LI(A(feed.title, attrs('feed', rescale=120,
|
||||||
href='feed_%d/index.html'%i)), id='feed_%d'%i)
|
href='feed_%d/index.html'%i)), id='feed_%d'%i)
|
||||||
ul.append(li)
|
ul.append(li)
|
||||||
div = DIV(
|
div = DIV(
|
||||||
PT(IMG(src=masthead,alt="masthead"),style='text-align:center'),
|
PT(IMG(src=masthead,alt="masthead"),style='text-align:center'),
|
||||||
PT(date, style='text-align:right'),
|
PT(date, style='text-align:right'),
|
||||||
ul,
|
ul,
|
||||||
CLASS('calibre_rescale_100'))
|
attrs(rescale=100))
|
||||||
self.root = HTML(head, BODY(div))
|
self.root = HTML(head, BODY(div))
|
||||||
if self.html_lang:
|
if self.html_lang:
|
||||||
self.root.set('lang', self.html_lang)
|
self.root.set('lang', self.html_lang)
|
||||||
@ -117,7 +121,7 @@ class FeedTemplate(Template):
|
|||||||
def get_navbar(self, f, feeds, top=True):
|
def get_navbar(self, f, feeds, top=True):
|
||||||
if len(feeds) < 2:
|
if len(feeds) < 2:
|
||||||
return DIV()
|
return DIV()
|
||||||
navbar = DIV('| ', CLASS('calibre_navbar', 'calibre_rescale_70',
|
navbar = DIV('| ', attrs('calibre_navbar', rescale=70,
|
||||||
style='text-align:center'))
|
style='text-align:center'))
|
||||||
if not top:
|
if not top:
|
||||||
hr = HR()
|
hr = HR()
|
||||||
@ -153,8 +157,8 @@ class FeedTemplate(Template):
|
|||||||
|
|
||||||
div = DIV(
|
div = DIV(
|
||||||
H2(feed.title,
|
H2(feed.title,
|
||||||
CLASS('calibre_feed_title', 'calibre_rescale_160')),
|
attrs('calibre_feed_title', rescale=160)),
|
||||||
CLASS('calibre_rescale_100')
|
attrs(rescale=100)
|
||||||
)
|
)
|
||||||
body.append(div)
|
body.append(div)
|
||||||
if getattr(feed, 'image', None):
|
if getattr(feed, 'image', None):
|
||||||
@ -162,26 +166,25 @@ class FeedTemplate(Template):
|
|||||||
alt=feed.image_alt if feed.image_alt else '',
|
alt=feed.image_alt if feed.image_alt else '',
|
||||||
src=feed.image_url
|
src=feed.image_url
|
||||||
),
|
),
|
||||||
CLASS('calibre_feed_image')))
|
attrs('calibre_feed_image')))
|
||||||
if getattr(feed, 'description', None):
|
if getattr(feed, 'description', None):
|
||||||
d = DIV(clean_xml_chars(feed.description), CLASS('calibre_feed_description',
|
d = DIV(clean_xml_chars(feed.description), attrs('calibre_feed_description', rescale=80))
|
||||||
'calibre_rescale_80'))
|
|
||||||
d.append(BR())
|
d.append(BR())
|
||||||
div.append(d)
|
div.append(d)
|
||||||
ul = UL(CLASS('calibre_article_list'))
|
ul = UL(attrs('calibre_article_list'))
|
||||||
for i, article in enumerate(feed.articles):
|
for i, article in enumerate(feed.articles):
|
||||||
if not getattr(article, 'downloaded', False):
|
if not getattr(article, 'downloaded', False):
|
||||||
continue
|
continue
|
||||||
li = LI(
|
li = LI(
|
||||||
A(article.title, CLASS('article calibre_rescale_120',
|
A(article.title, attrs('article', rescale=120,
|
||||||
href=article.url)),
|
href=article.url)),
|
||||||
SPAN(article.formatted_date, CLASS('article_date')),
|
SPAN(article.formatted_date, attrs('article_date')),
|
||||||
CLASS('calibre_rescale_100', id='article_%d'%i,
|
attrs(rescale=100, id='article_%d'%i,
|
||||||
style='padding-bottom:0.5em')
|
style='padding-bottom:0.5em')
|
||||||
)
|
)
|
||||||
if article.summary:
|
if article.summary:
|
||||||
li.append(DIV(clean_xml_chars(cutoff(article.text_summary)),
|
li.append(DIV(clean_xml_chars(cutoff(article.text_summary)),
|
||||||
CLASS('article_description', 'calibre_rescale_70')))
|
attrs('article_description', rescale=70)))
|
||||||
ul.append(li)
|
ul.append(li)
|
||||||
div.append(ul)
|
div.append(ul)
|
||||||
div.append(self.get_navbar(f, feeds, top=False))
|
div.append(self.get_navbar(f, feeds, top=False))
|
||||||
@ -205,7 +208,7 @@ class NavBarTemplate(Template):
|
|||||||
prefix += '/'
|
prefix += '/'
|
||||||
align = 'center' if center else 'left'
|
align = 'center' if center else 'left'
|
||||||
|
|
||||||
navbar = DIV(CLASS('calibre_navbar', 'calibre_rescale_70',
|
navbar = DIV(attrs('calibre_navbar', rescale=70,
|
||||||
style='text-align:'+align))
|
style='text-align:'+align))
|
||||||
if bottom:
|
if bottom:
|
||||||
if not url.startswith('file://'):
|
if not url.startswith('file://'):
|
||||||
@ -260,17 +263,17 @@ class TouchscreenIndexTemplate(Template):
|
|||||||
if extra_css:
|
if extra_css:
|
||||||
head.append(STYLE(extra_css, type='text/css'))
|
head.append(STYLE(extra_css, type='text/css'))
|
||||||
|
|
||||||
toc = TABLE(CLASS('toc'),width="100%",border="0",cellpadding="3px")
|
toc = TABLE(attrs('toc'),width="100%",border="0",cellpadding="3px")
|
||||||
for i, feed in enumerate(feeds):
|
for i, feed in enumerate(feeds):
|
||||||
if feed:
|
if feed:
|
||||||
tr = TR()
|
tr = TR()
|
||||||
tr.append(TD(CLASS('calibre_rescale_120'), A(feed.title, href='feed_%d/index.html'%i)))
|
tr.append(TD(attrs(rescale=120), A(feed.title, href='feed_%d/index.html'%i)))
|
||||||
tr.append(TD('%s' % len(feed.articles), style="text-align:right"))
|
tr.append(TD('%s' % len(feed.articles), style="text-align:right"))
|
||||||
toc.append(tr)
|
toc.append(tr)
|
||||||
div = DIV(
|
div = DIV(
|
||||||
masthead_p,
|
masthead_p,
|
||||||
H3(CLASS('publish_date'),date),
|
H3(attrs('publish_date'),date),
|
||||||
DIV(CLASS('divider')),
|
DIV(attrs('divider')),
|
||||||
toc)
|
toc)
|
||||||
self.root = HTML(head, BODY(div))
|
self.root = HTML(head, BODY(div))
|
||||||
if self.html_lang:
|
if self.html_lang:
|
||||||
@ -303,28 +306,28 @@ class TouchscreenFeedTemplate(Template):
|
|||||||
feed = feeds[f]
|
feed = feeds[f]
|
||||||
|
|
||||||
# Construct the navbar
|
# Construct the navbar
|
||||||
navbar_t = TABLE(CLASS('touchscreen_navbar'))
|
navbar_t = TABLE(attrs('touchscreen_navbar'))
|
||||||
navbar_tr = TR()
|
navbar_tr = TR()
|
||||||
|
|
||||||
# Previous Section
|
# Previous Section
|
||||||
link = ''
|
link = ''
|
||||||
if f > 0:
|
if f > 0:
|
||||||
link = A(CLASS('feed_link'),
|
link = A(attrs('feed_link'),
|
||||||
trim_title(feeds[f-1].title),
|
trim_title(feeds[f-1].title),
|
||||||
href='../feed_%d/index.html' % int(f-1))
|
href='../feed_%d/index.html' % int(f-1))
|
||||||
navbar_tr.append(TD(CLASS('feed_prev'),link))
|
navbar_tr.append(TD(attrs('feed_prev'),link))
|
||||||
|
|
||||||
# Up to Sections
|
# Up to Sections
|
||||||
link = A(_('Sections'), href="../index.html")
|
link = A(_('Sections'), href="../index.html")
|
||||||
navbar_tr.append(TD(CLASS('feed_up'),link))
|
navbar_tr.append(TD(attrs('feed_up'),link))
|
||||||
|
|
||||||
# Next Section
|
# Next Section
|
||||||
link = ''
|
link = ''
|
||||||
if f < len(feeds)-1:
|
if f < len(feeds)-1:
|
||||||
link = A(CLASS('feed_link'),
|
link = A(attrs('feed_link'),
|
||||||
trim_title(feeds[f+1].title),
|
trim_title(feeds[f+1].title),
|
||||||
href='../feed_%d/index.html' % int(f+1))
|
href='../feed_%d/index.html' % int(f+1))
|
||||||
navbar_tr.append(TD(CLASS('feed_next'),link))
|
navbar_tr.append(TD(attrs('feed_next'),link))
|
||||||
navbar_t.append(navbar_tr)
|
navbar_t.append(navbar_tr)
|
||||||
top_navbar = navbar_t
|
top_navbar = navbar_t
|
||||||
bottom_navbar = copy.copy(navbar_t)
|
bottom_navbar = copy.copy(navbar_t)
|
||||||
@ -339,7 +342,7 @@ class TouchscreenFeedTemplate(Template):
|
|||||||
body = BODY()
|
body = BODY()
|
||||||
div = DIV(
|
div = DIV(
|
||||||
top_navbar,
|
top_navbar,
|
||||||
H2(feed.title, CLASS('feed_title'))
|
H2(feed.title, attrs('feed_title'))
|
||||||
)
|
)
|
||||||
body.append(div)
|
body.append(div)
|
||||||
|
|
||||||
@ -348,10 +351,9 @@ class TouchscreenFeedTemplate(Template):
|
|||||||
alt=feed.image_alt if feed.image_alt else '',
|
alt=feed.image_alt if feed.image_alt else '',
|
||||||
src=feed.image_url
|
src=feed.image_url
|
||||||
),
|
),
|
||||||
CLASS('calibre_feed_image')))
|
attrs('calibre_feed_image')))
|
||||||
if getattr(feed, 'description', None):
|
if getattr(feed, 'description', None):
|
||||||
d = DIV(clean_xml_chars(feed.description), CLASS('calibre_feed_description',
|
d = DIV(clean_xml_chars(feed.description), attrs('calibre_feed_description', rescale=80))
|
||||||
'calibre_rescale_80'))
|
|
||||||
d.append(BR())
|
d.append(BR())
|
||||||
div.append(d)
|
div.append(d)
|
||||||
|
|
||||||
@ -359,15 +361,15 @@ class TouchscreenFeedTemplate(Template):
|
|||||||
if not getattr(article, 'downloaded', False):
|
if not getattr(article, 'downloaded', False):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
div_td = DIV(CLASS('article_summary'),
|
div_td = DIV(attrs('article_summary'),
|
||||||
A(article.title, CLASS('summary_headline','calibre_rescale_120',
|
A(article.title, attrs('summary_headline',rescale=120,
|
||||||
href=article.url)))
|
href=article.url)))
|
||||||
if article.author:
|
if article.author:
|
||||||
div_td.append(DIV(article.author,
|
div_td.append(DIV(article.author,
|
||||||
CLASS('summary_byline', 'calibre_rescale_100')))
|
attrs('summary_byline', rescale=100)))
|
||||||
if article.summary:
|
if article.summary:
|
||||||
div_td.append(DIV(cutoff(article.text_summary),
|
div_td.append(DIV(cutoff(article.text_summary),
|
||||||
CLASS('summary_text', 'calibre_rescale_100')))
|
attrs('summary_text', rescale=100)))
|
||||||
div.append(div_td)
|
div.append(div_td)
|
||||||
|
|
||||||
div.append(bottom_navbar)
|
div.append(bottom_navbar)
|
||||||
@ -388,7 +390,7 @@ class TouchscreenNavBarTemplate(Template):
|
|||||||
head.append(STYLE(extra_css, type='text/css'))
|
head.append(STYLE(extra_css, type='text/css'))
|
||||||
|
|
||||||
navbar = DIV()
|
navbar = DIV()
|
||||||
navbar_t = TABLE(CLASS('touchscreen_navbar'))
|
navbar_t = TABLE(attrs('touchscreen_navbar'))
|
||||||
navbar_tr = TR()
|
navbar_tr = TR()
|
||||||
|
|
||||||
if bottom and not url.startswith('file://'):
|
if bottom and not url.startswith('file://'):
|
||||||
@ -401,25 +403,25 @@ class TouchscreenNavBarTemplate(Template):
|
|||||||
navbar.append(BR())
|
navbar.append(BR())
|
||||||
# | Previous
|
# | Previous
|
||||||
if art > 0:
|
if art > 0:
|
||||||
link = A(CLASS('article_link'),_('Previous'),href='%s../article_%d/index.html'%(prefix, art-1))
|
link = A(attrs('article_link'),_('Previous'),href='%s../article_%d/index.html'%(prefix, art-1))
|
||||||
navbar_tr.append(TD(CLASS('article_prev'),link))
|
navbar_tr.append(TD(attrs('article_prev'),link))
|
||||||
else:
|
else:
|
||||||
navbar_tr.append(TD(CLASS('article_prev'),''))
|
navbar_tr.append(TD(attrs('article_prev'),''))
|
||||||
|
|
||||||
# | Articles | Sections |
|
# | Articles | Sections |
|
||||||
link = A(CLASS('articles_link'),_('Articles'), href='%s../index.html#article_%d'%(prefix, art))
|
link = A(attrs('articles_link'),_('Articles'), href='%s../index.html#article_%d'%(prefix, art))
|
||||||
navbar_tr.append(TD(CLASS('article_articles_list'),link))
|
navbar_tr.append(TD(attrs('article_articles_list'),link))
|
||||||
|
|
||||||
link = A(CLASS('sections_link'),_('Sections'), href='%s../../index.html#feed_%d'%(prefix, feed))
|
link = A(attrs('sections_link'),_('Sections'), href='%s../../index.html#feed_%d'%(prefix, feed))
|
||||||
navbar_tr.append(TD(CLASS('article_sections_list'),link))
|
navbar_tr.append(TD(attrs('article_sections_list'),link))
|
||||||
|
|
||||||
# | Next
|
# | Next
|
||||||
next_art = 'feed_%d'%(feed+1) if art == number_of_articles_in_feed - 1 \
|
next_art = 'feed_%d'%(feed+1) if art == number_of_articles_in_feed - 1 \
|
||||||
else 'article_%d'%(art+1)
|
else 'article_%d'%(art+1)
|
||||||
up = '../..' if art == number_of_articles_in_feed - 1 else '..'
|
up = '../..' if art == number_of_articles_in_feed - 1 else '..'
|
||||||
|
|
||||||
link = A(CLASS('article_link'), _('Next'), href='%s%s/%s/index.html'%(prefix, up, next_art))
|
link = A(attrs('article_link'), _('Next'), href='%s%s/%s/index.html'%(prefix, up, next_art))
|
||||||
navbar_tr.append(TD(CLASS('article_next'),link))
|
navbar_tr.append(TD(attrs('article_next'),link))
|
||||||
navbar_t.append(navbar_tr)
|
navbar_t.append(navbar_tr)
|
||||||
navbar.append(navbar_t)
|
navbar.append(navbar_t)
|
||||||
# print "\n%s\n" % etree.tostring(navbar, pretty_print=True)
|
# print "\n%s\n" % etree.tostring(navbar, pretty_print=True)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user