Merge branch 'master' into assets

This commit is contained in:
Simon 2012-05-11 22:00:20 +02:00
commit d7f28d4328
12 changed files with 229 additions and 136 deletions

View file

@ -21,71 +21,76 @@ Here is a list of settings for Pelican:
Basic settings
==============
================================================ =====================================================
Setting name (default value) What does it do?
================================================ =====================================================
`AUTHOR` Default author (put your name)
`DATE_FORMATS` (``{}``) If you do manage multiple languages, you can
set the date formatting here. See "Date format and locales"
section below for details.
`DEFAULT_CATEGORY` (``'misc'``) The default category to fall back on.
`DEFAULT_DATE_FORMAT` (``'%a %d %B %Y'``) The default date format you want to use.
`DISPLAY_PAGES_ON_MENU` (``True``) Whether to display pages on the menu of the
template. Templates may or not honor this
setting.
`FALLBACK_ON_FS_DATE` (``True``) If True, Pelican will use the file system
timestamp information (mtime) if it can't get
date information from the metadata.
`JINJA_EXTENSIONS` (``[]``) A list of any Jinja2 extensions you want to use.
`DELETE_OUTPUT_DIRECTORY` (``False``) Delete the output directory as well as
the generated files.
`LOCALE` (''[#]_) Change the locale. A list of locales can be provided
here or a single string representing one locale.
When providing a list, all the locales will be tried
until one works.
`MARKUP` (``('rst', 'md')``) A list of available markup languages you want
to use. For the moment, the only available values
are `rst` and `md`.
`MD_EXTENSIONS` (``['codehilite','extra']``) A list of the extensions that the Markdown processor
will use. Refer to the extensions chapter in the
Python-Markdown documentation for a complete list of
supported extensions.
`OUTPUT_PATH` (``'output/'``) Where to output the generated files.
`PATH` (``None``) Path to look at for input files.
`PAGE_DIR` (``'pages'``) Directory to look at for pages.
`PAGE_EXCLUDES` (``()``) A list of directories to exclude when looking for pages.
`ARTICLE_DIR` (``''``) Directory to look at for articles.
`ARTICLE_EXCLUDES`: (``('pages',)``) A list of directories to exclude when looking for articles.
`PDF_GENERATOR` (``False``) Set to True if you want to have PDF versions
of your documents. You will need to install
`rst2pdf`.
`RELATIVE_URLS` (``True``) Defines whether Pelican should use relative URLs or
not.
`SITENAME` (``'A Pelican Blog'``) Your site name
`SITEURL` Base URL of your website. Not defined by default,
which means the base URL is assumed to be "/" with a
root-relative URL structure. If `SITEURL` is specified
explicitly, there should be no trailing slash at the end,
and URLs will be generated with an absolute URL structure
(including the domain). If you want to use relative URLs
instead of root-relative or absolute URLs, you should
instead use the `RELATIVE_URL` setting.
`STATIC_PATHS` (``['images']``) The static paths you want to have accessible
on the output path "static". By default,
Pelican will copy the 'images' folder to the
output folder.
`TIMEZONE` The timezone used in the date information, to
generate Atom and RSS feeds. See the "timezone"
section below for more info.
`TYPOGRIFY` (``False``) If set to true, some
additional transformations will be done on the
generated HTML, using the `Typogrify
<http://static.mintchaos.com/projects/typogrify/>`_
library
`LESS_GENERATOR` (``FALSE``) Set to True or complete path to `lessc` (if not
found in system PATH) to enable compiling less
css files. Requires installation of `less css`_.
================================================ =====================================================
===================================================================== =====================================================================
Setting name (default value) What does it do?
===================================================================== =====================================================================
`AUTHOR` Default author (put your name)
`DATE_FORMATS` (``{}``) If you do manage multiple languages, you can
set the date formatting here. See "Date format and locales"
section below for details.
`DEFAULT_CATEGORY` (``'misc'``) The default category to fall back on.
`DEFAULT_DATE_FORMAT` (``'%a %d %B %Y'``) The default date format you want to use.
`DISPLAY_PAGES_ON_MENU` (``True``) Whether to display pages on the menu of the
template. Templates may or not honor this
setting.
`FALLBACK_ON_FS_DATE` (``True``) If True, Pelican will use the file system
timestamp information (mtime) if it can't get
date information from the metadata.
`JINJA_EXTENSIONS` (``[]``) A list of any Jinja2 extensions you want to use.
`DELETE_OUTPUT_DIRECTORY` (``False``) Delete the output directory as well as
the generated files.
`LOCALE` (''[#]_) Change the locale. A list of locales can be provided
here or a single string representing one locale.
When providing a list, all the locales will be tried
until one works.
`MARKUP` (``('rst', 'md')``) A list of available markup languages you want
to use. For the moment, the only available values
are `rst` and `md`.
`MD_EXTENSIONS` (``['codehilite','extra']``) A list of the extensions that the Markdown processor
will use. Refer to the extensions chapter in the
Python-Markdown documentation for a complete list of
supported extensions.
`OUTPUT_PATH` (``'output/'``) Where to output the generated files.
`PATH` (``None``) Path to look at for input files.
`PAGE_DIR` (``'pages'``) Directory to look at for pages.
`PAGE_EXCLUDES` (``()``) A list of directories to exclude when looking for pages.
`ARTICLE_DIR` (``''``) Directory to look at for articles.
`ARTICLE_EXCLUDES`: (``('pages',)``) A list of directories to exclude when looking for articles.
`PDF_GENERATOR` (``False``) Set to True if you want to have PDF versions
of your documents. You will need to install
`rst2pdf`.
`RELATIVE_URLS` (``True``) Defines whether Pelican should use relative URLs or
not.
`SITENAME` (``'A Pelican Blog'``) Your site name
`SITEURL` Base URL of your website. Not defined by default,
which means the base URL is assumed to be "/" with a
root-relative URL structure. If `SITEURL` is specified
explicitly, there should be no trailing slash at the end,
and URLs will be generated with an absolute URL structure
(including the domain). If you want to use relative URLs
instead of root-relative or absolute URLs, you should
instead use the `RELATIVE_URL` setting.
`STATIC_PATHS` (``['images']``) The static paths you want to have accessible
on the output path "static". By default,
Pelican will copy the 'images' folder to the
output folder.
`TIMEZONE` The timezone used in the date information, to
generate Atom and RSS feeds. See the "timezone"
section below for more info.
`TYPOGRIFY` (``False``) If set to true, some
additional transformations will be done on the
generated HTML, using the `Typogrify
<http://static.mintchaos.com/projects/typogrify/>`_
library
`LESS_GENERATOR` (``FALSE``) Set to True or complete path to `lessc` (if not
found in system PATH) to enable compiling less
css files. Requires installation of `less css`_.
`DIRECT_TEMPLATES` (``('index', 'tags', 'categories', 'archives')``) List of templates that are used directly to render
content. Typically direct templates are used to generate
index pages for collections of content e.g. tags and
category index pages.
`PAGINATED_DIRECT_TEMPLATES` (``('index',)``) Provides the direct templates that should be paginated.
===================================================================== =====================================================================
.. [#] Default is the system locale.
@ -101,14 +106,15 @@ your articles in a location such as '{slug}/index.html' and link to them as
'{slug}' for clean URLs. These settings give you the flexibility to place your
articles and pages anywhere you want.
Note: If you specify a datetime directive, it will be substituted using the
input files' date metadata attribute. If the date is not specified for a
particular file, Pelican will rely on the file's mtime timestamp.
.. note::
If you specify a datetime directive, it will be substituted using the
input files' date metadata attribute. If the date is not specified for a
particular file, Pelican will rely on the file's mtime timestamp.
Check the Python datetime documentation at http://bit.ly/cNcJUC for more
information.
Also, you can use other file metadata attributes as well:
Also, you can use other file metadata attributes as well:
* slug
* date
@ -116,7 +122,7 @@ Also, you can use other file metadata attributes as well:
* author
* category
Example usage:
Example usage:
* ARTICLE_URL = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/'
* ARTICLE_SAVE_AS = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/index.html'
@ -145,9 +151,14 @@ Setting name (default value) what does it do?
`CATEGORY_SAVE_AS` ('category/{name}.html') The location to save a category.
`TAG_URL` ('tag/{name}.html') The URL to use for a tag.
`TAG_SAVE_AS` ('tag/{name}.html') The location to save the tag page.
`<DIRECT_TEMPLATE_NAME>_SAVE_AS` The location to save content generated from direct
templates. Where <DIRECT_TEMPLATE_NAME> is the
upper case template name.
================================================ =====================================================
Note: when any of `*_SAVE_AS` is set to False, files will not be created.
.. note::
When any of `*_SAVE_AS` is set to False, files will not be created.
Timezone
--------
@ -337,7 +348,7 @@ Setting name (default value) What does it do?
================================================ =====================================================
`REVERSE_ARCHIVE_ORDER` (``False``) Reverse the archives list order. (True: orders by date
in descending order, with newer articles first.)
`REVERSE_CATEGORY_ORDER` (``False``) Reverse the category order. (True: lists by reverse
`REVERSE_CATEGORY_ORDER` (``False``) Reverse the category order. (True: lists by reverse
alphabetical order; default lists alphabetically.)
================================================ =====================================================

View file

@ -163,31 +163,32 @@ class ArticlesGenerator(Generator):
writer.write_feed(items, self.context,
self.settings['TRANSLATION_FEED'] % lang)
def generate_pages(self, writer):
"""Generate the pages on the disk"""
write = partial(writer.write_file,
relative_urls=self.settings.get('RELATIVE_URLS'))
# to minimize the number of relative path stuff modification
# in writer, articles pass first
def generate_articles(self, write):
"""Generate the articles."""
article_template = self.get_template('article')
for article in chain(self.translations, self.articles):
write(article.save_as,
article_template, self.context, article=article,
category=article.category)
def generate_direct_templates(self, write):
"""Generate direct templates pages"""
PAGINATED_TEMPLATES = self.settings.get('PAGINATED_DIRECT_TEMPLATES')
for template in self.settings.get('DIRECT_TEMPLATES'):
paginated = {}
if template in PAGINATED_TEMPLATES:
paginated = {'articles': self.articles, 'dates': self.dates}
save_as = self.settings.get("%s_SAVE_AS" % template.upper(),
'%s.html' % template)
if not save_as:
continue
write('%s.html' % template, self.get_template(template),
write(save_as, self.get_template(template),
self.context, blog=True, paginated=paginated,
page_name=template)
# and subfolders after that
def generate_tags(self, write):
"""Generate Tags pages."""
tag_template = self.get_template('tag')
for tag, articles in self.tags.items():
articles.sort(key=attrgetter('date'), reverse=True)
@ -197,6 +198,8 @@ class ArticlesGenerator(Generator):
paginated={'articles': articles, 'dates': dates},
page_name=u'tag/%s' % tag)
def generate_categories(self, write):
"""Generate category pages."""
category_template = self.get_template('category')
for cat, articles in self.categories:
dates = [article for article in self.dates if article in articles]
@ -205,6 +208,8 @@ class ArticlesGenerator(Generator):
paginated={'articles': articles, 'dates': dates},
page_name=u'category/%s' % cat)
def generate_authors(self, write):
"""Generate Author pages."""
author_template = self.get_template('author')
for aut, articles in self.authors:
dates = [article for article in self.dates if article in articles]
@ -213,10 +218,30 @@ class ArticlesGenerator(Generator):
paginated={'articles': articles, 'dates': dates},
page_name=u'author/%s' % aut)
def generate_drafts(self, write):
"""Generate drafts pages."""
article_template = self.get_template('article')
for article in self.drafts:
write('drafts/%s.html' % article.slug, article_template,
self.context, article=article, category=article.category)
def generate_pages(self, writer):
"""Generate the pages on the disk"""
write = partial(writer.write_file,
relative_urls=self.settings.get('RELATIVE_URLS'))
# to minimize the number of relative path stuff modification
# in writer, articles pass first
self.generate_articles(write)
self.generate_direct_templates(write)
# and subfolders after that
self.generate_tags(write)
self.generate_categories(write)
self.generate_authors(write)
self.generate_drafts(write)
def generate_context(self):
"""change the context"""

View file

@ -174,5 +174,6 @@ def read_file(filename, fmt=None, settings=None):
if settings and settings['TYPOGRIFY']:
from typogrify import Typogrify
content = Typogrify.typogrify(content)
metadata['title'] = Typogrify.typogrify(metadata['title'])
return content, metadata

View file

@ -4,13 +4,17 @@ body {
font:1.3em/1.3 "Hoefler Text","Georgia",Georgia,serif,sans-serif;
}
.body, #banner nav, #banner nav ul, #about, #featured, #content{
width: inherit;
.post-info{
display: none;
}
#banner nav {
display: none;
-moz-border-radius: 0px;
margin-bottom: 0px;
margin-bottom: 20px;
overflow: hidden;
font-size: 1em;
background: #F5F4EF;
}
#banner nav ul{
@ -19,10 +23,11 @@ body {
#banner nav li{
float: right;
color: #000;
}
#banner nav li:first-child a {
-moz-border-radius: 0px;
#banner nav li a {
color: #000;
}
#banner h1 {

View file

@ -6,7 +6,7 @@
<dl>
{% for article in dates %}
<dt>{{ article.locale_date }}</dt>
<dd><a href="{{ article.url }}">{{ article.title }}</a></dd>
<dd><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a></dd>
{% endfor %}
</dl>
</section>

View file

@ -1,30 +1,34 @@
{% extends "base.html" %}
{% block title %}{{ article.title }}{% endblock %}
{% block content %}
<section id="content" class="body">
<article>
<header> <h1 class="entry-title"><a href="{{ pagename }}"
rel="bookmark" title="Permalink to {{ article.title }}">{{ article.title
}}</a></h1> {% include 'twitter.html' %} </header>
<div class="entry-content">
{% include 'article_infos.html' %}
{{ article.content }}
</div><!-- /.entry-content -->
{% if DISQUS_SITENAME %}
<div class="comments">
<h2>Comments !</h2>
<div id="disqus_thread"></div>
<script type="text/javascript">
var disqus_identifier = "{{ article.url }}";
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://{{ DISQUS_SITENAME }}.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
</div>
{% endif %}
{% block title %}{{ article.title|striptags }}{% endblock %}
{% block content %}
<section id="content" class="body">
<article>
<header>
<h1 class="entry-title">
<a href="{{ article.url }}" rel="bookmark"
title="Permalink to {{ article.title|striptags }}">{{ article.title}}</a></h1>
{% include 'twitter.html' %}
</header>
</article>
<div class="entry-content">
{% include 'article_infos.html' %}
{{ article.content }}
</div><!-- /.entry-content -->
{% if DISQUS_SITENAME %}
<div class="comments">
<h2>Comments !</h2>
<div id="disqus_thread"></div>
<script type="text/javascript">
var disqus_identifier = "{{ article.url }}";
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://{{ DISQUS_SITENAME }}.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
</div>
{% endif %}
</article>
</section>
{% endblock %}

View file

@ -2,7 +2,7 @@
{% block content %}
<ul>
{% for category, articles in categories %}
<li><a href="{{ category.url }}">{{ category }}</a></li>
<li><a href="{{ SITEURL }}/{{ category.url }}">{{ category }}</a></li>
{% endfor %}
</ul>
{% endblock %}

View file

@ -5,7 +5,7 @@
<dl>
{% for article in dates %}
<dt>{{ article.locale_date }}</dt>
<dd><a href="{{ article.url }}">{{ article.title }}</a></dd>
<dd><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a></dd>
{% endfor %}
</dl>
{% endblock %}

View file

@ -1,19 +1,23 @@
{% extends "base.html" %}
{% block content %}
<section id="content" class="body">
<header> <h2 class="entry-title"><a href="{{ pagename }}" rel="bookmark" title="Permalink to {{ article.title}}">{{ article.title }}</a></h2> </header>
<footer class="post-info">
<abbr class="published" title="{{ article.date.isoformat() }}">
{{ article.locale_date }}
</abbr>
{% if article.author %}
<address class="vcard author">
By <a class="url fn" href="{{ SITEURL }}/{{ article.author.url }}">{{ article.author }}</a>
</address>
{% endif %}
</footer><!-- /.post-info -->
<div class="entry-content">
{{ article.content }}
</div><!-- /.entry-content -->
{% block content %}
<section id="content" class="body">
<header>
<h2 class="entry-title">
<a href="{{ article.url }}" rel="bookmark"
title="Permalink to {{ article.title|striptags }}">{{ article.title }}</a></h2>
</header>
<footer class="post-info">
<abbr class="published" title="{{ article.date.isoformat() }}">
{{ article.locale_date }}
</abbr>
{% if article.author %}
<address class="vcard author">
By <a class="url fn" href="{{ SITEURL }}/{{ article.author.url }}">{{ article.author }}</a>
</address>
{% endif %}
</footer><!-- /.post-info -->
<div class="entry-content">
{{ article.content }}
</div><!-- /.entry-content -->
</section>
{% endblock %}

View file

@ -8,6 +8,7 @@ import logging
from codecs import open as _open
from datetime import datetime
from itertools import groupby
from jinja2 import Markup
from operator import attrgetter
logger = logging.getLogger(__name__)
@ -44,6 +45,7 @@ def slugify(value):
Took from django sources.
"""
value = Markup(value).striptags()
if type(value) == unicode:
import unicodedata
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')

View file

@ -8,8 +8,8 @@ import logging
from codecs import open
from functools import partial
from feedgenerator import Atom1Feed, Rss201rev2Feed
from jinja2 import Markup
from pelican.paginator import Paginator
from pelican.utils import get_relative_path, set_date_tzinfo
@ -25,8 +25,9 @@ class Writer(object):
def _create_new_feed(self, feed_type, context):
feed_class = Rss201rev2Feed if feed_type == 'rss' else Atom1Feed
sitename = Markup(context['SITENAME']).striptags()
feed = feed_class(
title=context['SITENAME'],
title=sitename,
link=(self.site_url + '/'),
feed_url=self.feed_url,
description=context.get('SITESUBTITLE', ''))
@ -34,8 +35,9 @@ class Writer(object):
def _add_item_to_the_feed(self, feed, item):
title = Markup(item.title).striptags()
feed.add_item(
title=item.title,
title=title,
link='%s/%s' % (self.site_url, item.url),
unique_id='tag:%s,%s:%s' % (self.site_url.replace('http://', ''),
item.date.date(), item.url),

View file

@ -54,6 +54,45 @@ class TestArticlesGenerator(unittest.TestCase):
categories, ['Default', 'TestCategory', 'Yeah', 'test',
'yeah'])
def test_direct_templates_save_as_default(self):
settings = _DEFAULT_CONFIG.copy()
settings['DIRECT_TEMPLATES'] = ['archives']
generator = ArticlesGenerator(settings.copy(), settings, None,
_DEFAULT_CONFIG['THEME'], None,
_DEFAULT_CONFIG['MARKUP'])
write = MagicMock()
generator.generate_direct_templates(write)
write.assert_called_with("archives.html",
generator.get_template("archives"), settings,
blog=True, paginated={}, page_name='archives')
def test_direct_templates_save_as_modified(self):
settings = _DEFAULT_CONFIG.copy()
settings['DIRECT_TEMPLATES'] = ['archives']
settings['ARCHIVES_SAVE_AS'] = 'archives/index.html'
generator = ArticlesGenerator(settings, settings, None,
_DEFAULT_CONFIG['THEME'], None,
_DEFAULT_CONFIG['MARKUP'])
write = MagicMock()
generator.generate_direct_templates(write)
write.assert_called_with("archives/index.html",
generator.get_template("archives"), settings,
blog=True, paginated={}, page_name='archives')
def test_direct_templates_save_as_false(self):
settings = _DEFAULT_CONFIG.copy()
settings['DIRECT_TEMPLATES'] = ['archives']
settings['ARCHIVES_SAVE_AS'] = 'archives/index.html'
generator = ArticlesGenerator(settings, settings, None,
_DEFAULT_CONFIG['THEME'], None,
_DEFAULT_CONFIG['MARKUP'])
write = MagicMock()
generator.generate_direct_templates(write)
write.assert_called_count == 0
class TestLessCSSGenerator(unittest.TestCase):
@ -79,7 +118,7 @@ class TestLessCSSGenerator(unittest.TestCase):
with temporary_folder() as temp_content:
with temporary_folder() as temp_output:
generator = LessCSSGenerator(None, settings, temp_content,
_DEFAULT_CONFIG['THEME'], temp_output, None)
_DEFAULT_CONFIG['THEME'], temp_output, None)
# create a dummy less file
less_dir = os.path.join(temp_content, 'static', 'css')