Skip to content

Commit

Permalink
Merge pull request #6 from NextThought/issue5
Browse files Browse the repository at this point in the history
Add support for template-based shortcodes.
  • Loading branch information
jamadden committed May 24, 2018
2 parents d268276 + 335698d commit 9fa3cc3
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Expand Up @@ -18,6 +18,8 @@
pages. Together with the IRootPage this can be used to promote blog
posts to the root index.html.
- Add ``embedded_content`` to the ``@@post_text`` view.
- Initial support for template-based shortcodes. See
https://github.com/NextThought/nti.nikola_chameleon/issues/5

0.0.1a2 (2017-10-14)
====================
Expand Down
45 changes: 39 additions & 6 deletions src/nti/nikola_chameleon/plugin.py
Expand Up @@ -119,6 +119,8 @@ def __init__(self):
self._conf_context = xmlconfig.file('configure.zcml', nti.nikola_chameleon)
# A list of directories from least to most specific (or lowest to highest priority)
self._template_paths = []
# The (one) directory we check for shortcodes
self._shortcode_paths = ['shortcodes']

def set_directories(self, directories, cache_folder):
"""Sets the list of folders where templates are located and cache."""
Expand Down Expand Up @@ -185,6 +187,9 @@ def template_deps(self, template_name):
return [template.filename]


get_deps = template_deps # For shortcodes


def render_template(self, template_name, output_name, context):
"""Renders template to a file using context.
Expand Down Expand Up @@ -221,10 +226,14 @@ def render_template_to_string(self, template, context):
# Some galleries can have posts
context = _GalleryContext(options)
else:
# We only render these things once in a given run,
# so we don't bother stripping the interfaces off of it
# or using a proxy.
assert not interfaces.IPageKind.providedBy(context)
# We typically only render these things once in a
# given run, so we don't bother stripping the
# interfaces off of it or using a proxy. The exception
# is if a post uses a shortcode; then that post is
# used as the context twice: once for rendering the
# shortcode, once for rendering the page. We still don't bother
# to strip or proxy, though, because the interfaces
# should be idempotent.
interface.alsoProvides(context, interfaces.IPostPage)
# XXX: Need to look at the post's `type` and add that to the
# post https://getnikola.com/handbook.html#post-types
Expand Down Expand Up @@ -270,6 +279,7 @@ def render_template_to_string(self, template, context):
if 'messages' not in options:
options['messages'] = self.site.MESSAGES


return template(view, request=request, **options)

def _apply_request_layer(self, request, options, template):
Expand Down Expand Up @@ -326,18 +336,23 @@ def inject_directory(self, directory): # pragma: no cover (Nikola seems not to c
def _provide_templates(self):
for d in self._template_paths:
self._provide_templates_from_directory(d)
for d in self._shortcode_paths:
self._provide_shortcode_templates(d)
self._template_paths = []
self._shortcode_paths = []

def _provide_templates_from_directory(self, directory):
def __fixup_directory(self, directory):
if not isinstance(directory, str) and str is bytes:
# nikola likes to provide these as unicode on Python 2,
# which is incorrect (unless maybe on windows?)
# Ideally we'd decode using the filesystem decoding or something,
# right now we just assume the locale decodes right.
directory = directory.encode("utf-8")

directory = os.path.abspath(directory)
return os.path.abspath(directory)

def _provide_templates_from_directory(self, directory):
directory = self.__fixup_directory(directory)
seen_macros = defaultdict(set)
# Register macros for each macro found in each .macro.pt
# file. This doesn't deal with naming conflicts.
Expand Down Expand Up @@ -381,3 +396,21 @@ def _provide_templates_from_directory(self, directory):
if os.path.exists(theme_zcml):
# Let any explicit directions take precedence.
xmlconfig.file(theme_zcml, context=self._conf_context)

def _provide_shortcode_templates(self, directory):
# Nikola passes shortcode templates as the *contents* of the file,
# not the file name.
directory = self.__fixup_directory(directory)
gsm = component.getGlobalSiteManager()
for template_file in sorted(glob.glob(os.path.join(directory, "*.tmpl"))):
with open(template_file, 'r') as f:
name = f.read()
factory = TemplateFactory(template_file, 'text/html')
# Register them as template adapters for us.
# required = (view, request, context)
gsm.registerAdapter(factory,
provided=(IContentTemplate),
required=(interface.Interface,
interface.Interface,
interface.Interface),
name=name)
5 changes: 4 additions & 1 deletion src/nti/nikola_chameleon/tests/test_render.py
Expand Up @@ -84,7 +84,6 @@ def assertOutputExists(self, *path):
self._render_if_needed()
fname = os.path.join(self.testsite, 'output', *path)
if not os.path.isfile(fname):
import pdb; pdb.set_trace()
self.test.fail("No path %s" % (fname,)) # pragma: no cover
return fname

Expand Down Expand Up @@ -117,3 +116,7 @@ def test_render(self):
"pages", 'post-list-test.html')
self.layer.assertInOutput('<a href="../posts/welcome-to-nikola.html">Welcome to Nikola</a>',
"pages", 'post-list-test.html')

self.layer.assertOutputExists('posts', 'test-page.html')
self.layer.assertInOutput("<div>This came from a shortcode</div>",
'posts', 'test-page.html')
2 changes: 2 additions & 0 deletions src/nti/nikola_chameleon/tests/testsite/posts/2.rst
Expand Up @@ -25,3 +25,5 @@ Next steps:
* :doc:`See a demo of a longer text <dr-nikolas-vendetta>`

Send feedback to info@getnikola.com!

:sc:`{{% nti %}}`
@@ -0,0 +1 @@
<div>This came from a shortcode</div>

0 comments on commit 9fa3cc3

Please sign in to comment.