Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
2 changed files
with
209 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- # | ||
from __future__ import unicode_literals | ||
from datetime import date | ||
|
||
|
||
AUTHOR = u'PonyGnomeBot' | ||
SITENAME = u'Apache Infrastructure' | ||
CURRENTYEAR = date.today().year | ||
|
||
PATH = 'content' | ||
|
||
TIMEZONE = 'UTC' | ||
DEFAULT_DATE = 'fs' | ||
DEFAULT_LANG = u'en' | ||
SITEURL = 'https://infra-test.apache.org' | ||
|
||
# Save pages using full directory preservation | ||
PATH_METADATA= '.*?(pages/)?(?P<path_no_ext>.*?)\.[a-z]*$' | ||
PAGE_SAVE_AS= './{slug}.html' | ||
PAGE_URL= './{slug}.html' | ||
|
||
# Make .htaccess static | ||
STATIC_PATHS = ['pages/.htaccess'] | ||
|
||
# Standard behavior: | ||
#PAGE_SAVE_AS = './{slug}.html' | ||
|
||
#ARTICLE_SAVE_AS = 'news/{slug}.html' | ||
#ARTICLE_URL = 'news/{slug}.html' | ||
|
||
# Sort news by date, descending, latest article first | ||
ARTICLE_ORDER_BY = 'reversed-date' | ||
|
||
# Feed generation is usually not desired when developing | ||
FEED_ALL_ATOM = None | ||
CATEGORY_FEED_ATOM = None | ||
TRANSLATION_FEED_ATOM = None | ||
AUTHOR_FEED_ATOM = None | ||
AUTHOR_FEED_RSS = None | ||
|
||
# TOC Generator | ||
PLUGIN_PATHS = ['./theme/plugins'] | ||
PLUGINS = ['toc', 'pelican-gfm', 'spu'] | ||
TOC_HEADERS = r"h[1-6]" | ||
|
||
# Blogroll | ||
LINKS = (('Pelican', 'http://getpelican.com/'), | ||
('Python.org', 'http://python.org/'), | ||
('Jinja2', 'http://jinja.pocoo.org/'), | ||
('You can modify those links in your config file', '#'),) | ||
|
||
# Social widget | ||
SOCIAL = (('You can add links in your config file', '#'), | ||
('Another social link', '#'),) | ||
|
||
DEFAULT_PAGINATION = False | ||
|
||
# Uncomment following line if you want document-relative URLs when developing | ||
#RELATIVE_URLS = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
''' | ||
toc | ||
=================================== | ||
Generates Table of Contents for markdown. | ||
Only generates a ToC for the headers FOLLOWING th [TOC] tag, | ||
so you can insert it after a specific section that need not be | ||
include in the ToC. | ||
''' | ||
|
||
import logging | ||
import re | ||
|
||
from bs4 import BeautifulSoup, Comment | ||
|
||
from pelican import contents, signals | ||
from pelican.utils import slugify | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
''' | ||
https://github.com/waylan/Python-Markdown/blob/master/markdown/extensions/headerid.py | ||
''' | ||
IDCOUNT_RE = re.compile(r'^(.*)_([0-9]+)$') | ||
|
||
|
||
def unique(id, ids): | ||
""" Ensure id is unique in set of ids. Append '_1', '_2'... if not """ | ||
while id in ids or not id: | ||
m = IDCOUNT_RE.match(id) | ||
if m: | ||
id = '%s_%d' % (m.group(1), int(m.group(2)) + 1) | ||
else: | ||
id = '%s_%d' % (id, 1) | ||
ids.add(id) | ||
return id | ||
''' | ||
end | ||
''' | ||
|
||
|
||
class HtmlTreeNode(object): | ||
def __init__(self, parent, header, level, id): | ||
self.children = [] | ||
self.parent = parent | ||
self.header = header | ||
self.level = level | ||
self.id = id | ||
|
||
def add(self, new_header, ids): | ||
new_level = new_header.name | ||
new_string = new_header.string | ||
new_id = new_header.attrs.get('id') | ||
|
||
if not new_string: | ||
new_string = new_header.find_all( | ||
text=lambda t: not isinstance(t, Comment), | ||
recursive=True) | ||
new_string = "".join(new_string) | ||
|
||
if not new_id: | ||
new_id = slugify(new_string, ()) | ||
|
||
new_id = unique(new_id, ids) # make sure id is unique | ||
new_header.attrs['id'] = new_id | ||
if(self.level < new_level): | ||
new_node = HtmlTreeNode(self, new_string, new_level, new_id) | ||
self.children += [new_node] | ||
return new_node, new_header | ||
elif(self.level == new_level): | ||
new_node = HtmlTreeNode(self.parent, new_string, new_level, new_id) | ||
self.parent.children += [new_node] | ||
return new_node, new_header | ||
elif(self.level > new_level): | ||
return self.parent.add(new_header, ids) | ||
|
||
def __str__(self): | ||
ret = "" | ||
if self.parent: | ||
ret = "<a class='toc-href' href='#{0}' title='{1}'>{1}</a>".format( | ||
self.id, self.header) | ||
|
||
if self.children: | ||
ret += "<ul>{}</ul>".format('{}'*len(self.children)).format( | ||
*self.children) | ||
|
||
if self.parent: | ||
ret = "<li>{}</li>".format(ret) | ||
|
||
if not self.parent: | ||
ret = "<div id='toc' style='border-radius: 3px; border: 1px solid #999; background-color: #EEE; padding: 4px;'><h4>Table of Contents:</h4><ul>{}</ul></div>".format(ret) | ||
|
||
return ret | ||
|
||
|
||
def init_default_config(pelican): | ||
from pelican.settings import DEFAULT_CONFIG | ||
|
||
TOC_DEFAULT = { | ||
'TOC_HEADERS': '^h[1-6]', | ||
'TOC_RUN': 'true' | ||
} | ||
|
||
DEFAULT_CONFIG.setdefault('TOC', TOC_DEFAULT) | ||
if(pelican): | ||
pelican.settings.setdefault('TOC', TOC_DEFAULT) | ||
|
||
|
||
def generate_toc(content): | ||
if isinstance(content, contents.Static): | ||
return | ||
|
||
all_ids = set() | ||
title = content.metadata.get('title', 'Title') | ||
tree = node = HtmlTreeNode(None, title, 'h0', '') | ||
soup = BeautifulSoup(content._content, 'html.parser') | ||
settoc = False | ||
|
||
try: | ||
header_re = re.compile(content.metadata.get( | ||
'toc_headers', content.settings['TOC']['TOC_HEADERS'])) | ||
except re.error as e: | ||
logger.error("TOC_HEADERS '%s' is not a valid re\n%s", | ||
content.settings['TOC']['TOC_HEADERS']) | ||
raise e | ||
|
||
# Find TOC tag | ||
tocTag = soup.find('p', text = '[TOC]') | ||
if tocTag: | ||
for header in tocTag.findAllNext(header_re): | ||
settoc = True | ||
node, new_header = node.add(header, all_ids) | ||
header.replaceWith(new_header) # to get our ids back into soup | ||
|
||
if settoc: | ||
print("Generating ToC for %s" % content.slug) | ||
tree_string = '{}'.format(tree) | ||
tree_soup = BeautifulSoup(tree_string, 'html.parser') | ||
content.toc = tree_soup.decode(formatter='html') | ||
itoc = soup.find('p', text = '[TOC]') | ||
if itoc: | ||
itoc.replaceWith(tree_soup) | ||
|
||
content._content = soup.decode(formatter='html') | ||
|
||
|
||
def register(): | ||
signals.initialized.connect(init_default_config) | ||
signals.content_object_init.connect(generate_toc) |