Implement the ability to specify font sizes relative to the rescaled base font size, via class attributes

This commit is contained in:
Kovid Goyal 2009-05-08 20:33:37 -07:00
parent 6fcfff5d68
commit 0ba01714d2
4 changed files with 96 additions and 68 deletions

View File

@ -24,6 +24,19 @@ def asfloat(value, default):
value = default 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):
@ -202,11 +215,19 @@ class CSSFlattener(object):
if 'bgcolor' in node.attrib: if 'bgcolor' in node.attrib:
cssdict['background-color'] = node.attrib['bgcolor'] cssdict['background-color'] = node.attrib['bgcolor']
del node.attrib['bgcolor'] del node.attrib['bgcolor']
if not self.context.disable_font_rescaling and \ if not self.context.disable_font_rescaling:
'font-size' in cssdict or tag == 'body': _sbase = self.sbase if self.sbase is not None else \
fsize = self.fmap[style['font-size']] self.context.source.fbase
cssdict['font-size'] = "%0.5fem" % (fsize / psize) dyn_rescale = dynamic_rescale_factor(node)
psize = fsize if dyn_rescale is not None:
fsize = self.fmap[_sbase]
fsize *= dyn_rescale
psize = fsize
cssdict['font-size'] = '%0.5fpt'%(fsize)
elif 'font-size' in cssdict or tag == 'body':
fsize = self.fmap[style['font-size']]
cssdict['font-size'] = "%0.5fem" % (fsize / psize)
psize = fsize
if cssdict: if cssdict:
if self.lineh and self.fbase and tag != 'body': if self.lineh and self.fbase and tag != 'body':
self.clean_edges(cssdict, style, psize) self.clean_edges(cssdict, style, psize)

View File

@ -25,14 +25,16 @@ class Jacket(object):
<title>%(title)s</title> <title>%(title)s</title>
</head> </head>
<body> <body>
<div style="text-align:center"> <div class="calibre_rescale_100">
<h1>%(title)s</h1> <div style="text-align:center">
<h2>%(jacket)s</h2> <h1 class="calibre_rescale_180">%(title)s</h1>
<div>%(series)s</div> <h2 class="calibre_rescale_140">%(jacket)s</h2>
<div>%(tags)s</div> <div class="calibre_rescale_100">%(series)s</div>
</div> <div class="calibre_rescale_100">%(tags)s</div>
<div style="margin-top:2em"> </div>
%(comments)s <div style="margin-top:2em" class="calibre_rescale_100">
%(comments)s
</div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -231,23 +231,23 @@ class BasicNewsRecipe(Recipe):
#: use :member:`extra_css` in your recipe to customize look and feel. #: use :member:`extra_css` in your recipe to customize look and feel.
template_css = u''' template_css = u'''
.article_date { .article_date {
font-size: x-small; color: gray; font-family: monospace; color: gray; font-family: monospace;
} }
.article_description { .article_description {
font-size: small; font-family: sans; text-indent: 0pt; font-family: sans; text-indent: 0pt;
} }
a.article { a.article {
font-weight: bold; font-size: large; font-weight: bold;
} }
a.feed { a.feed {
font-weight: bold; font-size: large; font-weight: bold;
} }
.navbar { .navbar {
font-family:monospace; font-size:8pt font-family:monospace;
} }
''' '''

View File

@ -7,7 +7,7 @@ from calibre import preferred_encoding, strftime
class Template(MarkupTemplate): class Template(MarkupTemplate):
def generate(self, *args, **kwargs): def generate(self, *args, **kwargs):
if not kwargs.has_key('style'): if not kwargs.has_key('style'):
kwargs['style'] = '' kwargs['style'] = ''
@ -17,20 +17,20 @@ class Template(MarkupTemplate):
for arg in args: for arg in args:
if isinstance(arg, basestring) and not isinstance(arg, unicode): if isinstance(arg, basestring) and not isinstance(arg, unicode):
arg = unicode(arg, 'utf-8', 'replace') arg = unicode(arg, 'utf-8', 'replace')
return MarkupTemplate.generate(self, *args, **kwargs) return MarkupTemplate.generate(self, *args, **kwargs)
class NavBarTemplate(Template): class NavBarTemplate(Template):
def __init__(self): def __init__(self):
Template.__init__(self, u'''\ Template.__init__(self, u'''\
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" <html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en" xml:lang="en"
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/" xmlns:py="http://genshi.edgewall.org/"
> >
<head> <head>
<style py:if="extra_css" type="text/css"> <style py:if="extra_css" type="text/css">
@ -38,7 +38,7 @@ class NavBarTemplate(Template):
</style> </style>
</head> </head>
<body> <body>
<div class="navbar" style="text-align:${'center' if center else 'left'};"> <div class="navbar calibre_rescale_70" style="text-align:${'center' if center else 'left'};">
<hr py:if="bottom" /> <hr py:if="bottom" />
<p py:if="bottom" style="text-align:left"> <p py:if="bottom" style="text-align:left">
This article was downloaded by <b>${__appname__}</b> from <a href="${url}">${url}</a> This article was downloaded by <b>${__appname__}</b> from <a href="${url}">${url}</a>
@ -50,7 +50,7 @@ class NavBarTemplate(Template):
<py:if test="art == num - 1 and not bottom"> <py:if test="art == num - 1 and not bottom">
| <a href="${prefix}../../feed_${str(feed+1)}/index.html">Next</a> | <a href="${prefix}../../feed_${str(feed+1)}/index.html">Next</a>
</py:if> </py:if>
| <a href="${prefix}../index.html#article_${str(art)}">Section menu</a> | <a href="${prefix}../index.html#article_${str(art)}">Section menu</a>
<py:if test="two_levels"> <py:if test="two_levels">
| <a href="${prefix}../../index.html#feed_${str(feed)}">Main menu</a> | <a href="${prefix}../../index.html#feed_${str(feed)}">Main menu</a>
</py:if> </py:if>
@ -64,29 +64,29 @@ class NavBarTemplate(Template):
</html> </html>
''') ''')
def generate(self, bottom, feed, art, number_of_articles_in_feed, def generate(self, bottom, feed, art, number_of_articles_in_feed,
two_levels, url, __appname__, prefix='', center=True, two_levels, url, __appname__, prefix='', center=True,
extra_css=None): extra_css=None):
if prefix and not prefix.endswith('/'): if prefix and not prefix.endswith('/'):
prefix += '/' prefix += '/'
return Template.generate(self, bottom=bottom, art=art, feed=feed, return Template.generate(self, bottom=bottom, art=art, feed=feed,
num=number_of_articles_in_feed, num=number_of_articles_in_feed,
two_levels=two_levels, url=url, two_levels=two_levels, url=url,
__appname__=__appname__, prefix=prefix, __appname__=__appname__, prefix=prefix,
center=center, extra_css=extra_css) center=center, extra_css=extra_css)
class IndexTemplate(Template): class IndexTemplate(Template):
def __init__(self): def __init__(self):
Template.__init__(self, u'''\ Template.__init__(self, u'''\
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" <html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en" xml:lang="en"
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/" xmlns:py="http://genshi.edgewall.org/"
> >
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
@ -99,15 +99,17 @@ class IndexTemplate(Template):
</style> </style>
</head> </head>
<body> <body>
<h1 class="calibre_recipe_title">${title}</h1> <div class="calibre_rescale_100">
<p style="text-align:right">${date}</p> <h1 class="calibre_recipe_title calibre_rescale_180">${title}</h1>
<ul class="calibre_feed_list"> <p style="text-align:right">${date}</p>
<py:for each="i, feed in enumerate(feeds)"> <ul class="calibre_feed_list">
<li py:if="feed" id="feed_${str(i)}"> <py:for each="i, feed in enumerate(feeds)">
<a class="feed" href="${'feed_%d/index.html'%i}">${feed.title}</a> <li py:if="feed" id="feed_${str(i)}">
</li> <a class="feed calibre_rescale_120" href="${'feed_%d/index.html'%i}">${feed.title}</a>
</py:for> </li>
</ul> </py:for>
</ul>
</div>
</body> </body>
</html> </html>
''') ''')
@ -118,19 +120,19 @@ class IndexTemplate(Template):
date = strftime(datefmt) date = strftime(datefmt)
return Template.generate(self, title=title, date=date, feeds=feeds, return Template.generate(self, title=title, date=date, feeds=feeds,
extra_css=extra_css) extra_css=extra_css)
class FeedTemplate(Template): class FeedTemplate(Template):
def __init__(self): def __init__(self):
Template.__init__(self, u'''\ Template.__init__(self, u'''\
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" <html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en" xml:lang="en"
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/" xmlns:py="http://genshi.edgewall.org/"
> >
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
@ -143,61 +145,64 @@ class FeedTemplate(Template):
</style> </style>
</head> </head>
<body style="page-break-before:always"> <body style="page-break-before:always">
<h2 class="calibre_feed_title">${feed.title}</h2> <div class="calibre_rescale_100">
<h2 class="calibre_feed_title calibre_rescale_160">${feed.title}</h2>
<py:if test="getattr(feed, 'image', None)"> <py:if test="getattr(feed, 'image', None)">
<div class="calibre_feed_image"> <div class="calibre_feed_image">
<img alt="${feed.image_alt}" src="${feed.image_url}" /> <img alt="${feed.image_alt}" src="${feed.image_url}" />
</div> </div>
</py:if> </py:if>
<div class="calibre_feed_description" py:if="getattr(feed, 'description', None)"> <div class="calibre_feed_description calibre_rescale_80" py:if="getattr(feed, 'description', None)">
${feed.description}<br /> ${feed.description}<br />
</div> </div>
<ul class="calibre_article_list"> <ul class="calibre_article_list">
<py:for each="i, article in enumerate(feed.articles)"> <py:for each="i, article in enumerate(feed.articles)">
<li id="${'article_%d'%i}" py:if="getattr(article, 'downloaded', False)" style="padding-bottom:0.5em"> <li id="${'article_%d'%i}" py:if="getattr(article, 'downloaded',
<a class="article" href="${article.url}">${article.title}</a> False)" style="padding-bottom:0.5em" class="calibre_rescale_100">
<a class="article calibre_rescale_120" href="${article.url}">${article.title}</a>
<span class="article_date">${article.localtime.strftime(" [%a, %d %b %H:%M]")}</span> <span class="article_date">${article.localtime.strftime(" [%a, %d %b %H:%M]")}</span>
<div class="article_decription" py:if="article.summary"> <div class="article_decription calibre_rescale_70" py:if="article.summary">
${Markup(cutoff(article.text_summary))} ${Markup(cutoff(article.text_summary))}
</div> </div>
</li> </li>
</py:for> </py:for>
</ul> </ul>
<div class="navbar" style="text-align:center; font-family:monospace; font-size:8pt"> <div class="navbar calibre_rescale_70">
| <a href="../index.html">Up one level</a> | | <a href="../index.html">Up one level</a> |
</div> </div>
</div>
</body> </body>
</html> </html>
''') ''')
def generate(self, feed, cutoff, extra_css=None): def generate(self, feed, cutoff, extra_css=None):
return Template.generate(self, feed=feed, cutoff=cutoff, return Template.generate(self, feed=feed, cutoff=cutoff,
extra_css=extra_css) extra_css=extra_css)
class EmbeddedContent(Template): class EmbeddedContent(Template):
def __init__(self): def __init__(self):
Template.__init__(self, u'''\ Template.__init__(self, u'''\
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" <html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en" xml:lang="en"
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/" xmlns:py="http://genshi.edgewall.org/"
> >
<head> <head>
<title>${article.title}</title> <title>${article.title}</title>
</head> </head>
<body> <body>
<h2>${article.title}</h2> <h2>${article.title}</h2>
<div> <div>
${Markup(article.content if len(article.content if article.content else '') > len(article.summary if article.summary else '') else article.summary)} ${Markup(article.content if len(article.content if article.content else '') > len(article.summary if article.summary else '') else article.summary)}
</div> </div>
</body> </body>
</html> </html>
''') ''')
def generate(self, article): def generate(self, article):
return Template.generate(self, article=article) return Template.generate(self, article=article)