Skip to content

Commit

Permalink
Allowing to write HTML fragments instead of only whole documents.
Browse files Browse the repository at this point in the history
  • Loading branch information
felixfontein committed Oct 23, 2016
1 parent 926bcc8 commit a1eb111
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 9 deletions.
2 changes: 2 additions & 0 deletions CHANGES.txt
Expand Up @@ -16,6 +16,8 @@ Features
translated (Issue #2116)
* Pass ``post`` object and ``lang`` to post compilers (Issue #2531)
* Pass ``url_type`` into template's context.
* ``render_template`` and ``generic_renderer`` can now create HTML
fragments.

New in v7.8.1
=============
Expand Down
28 changes: 19 additions & 9 deletions nikola/nikola.py
Expand Up @@ -1287,7 +1287,7 @@ def get_compiler(self, source_name):

return compiler

def render_template(self, template_name, output_name, context, url_type=None):
def render_template(self, template_name, output_name, context, url_type=None, is_fragment=False):
"""Render a template with the global context.
If ``output_name`` is None, will return a string and all URL
Expand All @@ -1298,6 +1298,9 @@ def render_template(self, template_name, output_name, context, url_type=None):
The argument ``url_type`` allows to override the ``URL_TYPE``
configuration.
If ``is_fragment`` is set to ``True``, a HTML fragment will
be rendered and not a whole HTML document.
"""
local_context = {}
local_context["template_name"] = template_name
Expand Down Expand Up @@ -1334,19 +1337,25 @@ def render_template(self, template_name, output_name, context, url_type=None):

utils.makedirs(os.path.dirname(output_name))
parser = lxml.html.HTMLParser(remove_blank_text=True)
doc = lxml.html.document_fromstring(data, parser)
self.rewrite_links(doc, src, context['lang'], url_type)
data = b'<!DOCTYPE html>\n' + lxml.html.tostring(doc, encoding='utf8', method='html', pretty_print=True)
if is_fragment:
doc = lxml.html.fragment_fromstring(data, parser)
else:
doc = lxml.html.document_fromstring(data, parser)
self.rewrite_links(doc, src, context['lang'], url_type, is_fragment=is_fragment)
if is_fragment:
data = (doc.text or '').encode('utf-8') + ''.encode('utf-8').join([lxml.html.tostring(child, encoding='utf-8', method='html') for child in doc.iterchildren()])
else:
data = b'<!DOCTYPE html>\n' + lxml.html.tostring(doc, encoding='utf8', method='html', pretty_print=True)
with open(output_name, "wb+") as post_file:
post_file.write(data)

def rewrite_links(self, doc, src, lang, url_type=None):
def rewrite_links(self, doc, src, lang, url_type=None, is_fragment=False):
"""Replace links in document to point to the right places."""
# First let lxml replace most of them
doc.rewrite_links(lambda dst: self.url_replacer(src, dst, lang, url_type), resolve_base_href=False)

# lxml ignores srcset in img and source elements, so do that by hand
objs = list(doc.xpath('(*//img|*//source)'))
objs = list(doc.xpath('({}//img|{}//source)'.format('' if is_fragment else '*')))
for obj in objs:
if 'srcset' in obj.attrib:
urls = [u.strip() for u in obj.attrib['srcset'].split(',')]
Expand Down Expand Up @@ -1997,7 +2006,7 @@ def scan_posts(self, really=False, ignore_quit=False, quiet=False):
sys.exit(1)
signal('scanned').send(self)

def generic_renderer(self, lang, output_name, template_name, filters, file_deps=None, uptodate_deps=None, context=None, context_deps_remove=None, post_deps_dict=None, url_type=None):
def generic_renderer(self, lang, output_name, template_name, filters, file_deps=None, uptodate_deps=None, context=None, context_deps_remove=None, post_deps_dict=None, url_type=None, is_fragment=False):
"""Helper function for rendering pages and post lists and other related pages.
lang is the current language.
Expand All @@ -2009,7 +2018,8 @@ def generic_renderer(self, lang, output_name, template_name, filters, file_deps=
context (optional) a dict used as a basis for the template context. The lang parameter will always be added.
context_deps_remove (optional) is a list of keys to remove from the context after using it as an uptodate dependency. This should name all keys containing non-trivial Python objects; they can be replaced by adding JSON-style dicts in post_deps_dict.
post_deps_dict (optional) is a dict merged into the copy of context which is used as an uptodate dependency.
url_type (optional) allows to override the ``URL_TYPE`` configuration
url_type (optional) allows to override the ``URL_TYPE`` configuration.
is_fragment (optional) allows to write a HTML fragment instead of a HTML document.
"""
utils.LocaleBorg().set_locale(lang)

Expand Down Expand Up @@ -2043,7 +2053,7 @@ def generic_renderer(self, lang, output_name, template_name, filters, file_deps=
'targets': [output_name],
'file_dep': file_deps,
'actions': [(self.render_template, [template_name, output_name,
context, url_type])],
context, url_type, is_fragment])],
'clean': True,
'uptodate': [config_changed(deps_dict, 'nikola.nikola.Nikola.generic_renderer')] + ([] if uptodate_deps is None else uptodate_deps)
}
Expand Down

0 comments on commit a1eb111

Please sign in to comment.