Skip to content

Commit

Permalink
Support for comment systems
Browse files Browse the repository at this point in the history
  • Loading branch information
jamadden committed Oct 9, 2017
1 parent d5d8845 commit a6ff3e0
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 14 deletions.
71 changes: 64 additions & 7 deletions src/nti/nikola_chameleon/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@
"""
Interfaces for rendering Nikola with chameleon.
The most important interface in this package for themes is
:class:`IPageKind` and its various subclasses. These function
similarly to `IBrowserLayer` in a Zope 3 application, in that they are
applied to the ``request`` variable when a template is rendered, and
more specific templates or macros can be registered for the request
based on that layer. Each request will only have one such interface
applied to it.
Similarly, the :class:`ICommentKind` (with its subclasses
:class:`ICommentKindNone` and :class:`ICommentKindAllowed` and *its*
various system types markers will be applied to the ``view`` variable).
"""
from __future__ import absolute_import
from __future__ import division
Expand All @@ -18,7 +30,6 @@ class ITemplate(interface.Interface):
def __call__(view, **kwargs):
"Called to render."


class IPost(interface.Interface):
"""
A post.
Expand Down Expand Up @@ -122,18 +133,64 @@ class IPostPage(IPost, IPageKind):

interface.taggedValue('__pagekinds__', ())

def _build(iface, result):
kinds = iface.getTaggedValue('__pagekinds__')
kinds = frozenset(kinds)
def _build(iface, result, tag='__pagekinds__', tx=lambda x: x):
__traceback_info__ = iface, tag
kinds = iface.getTaggedValue(tag)
kinds = tx(kinds)
if kinds in result and kinds: # pragma: no cover
raise ValueError("Duplicate pagkeinds", kinds, iface)
raise ValueError("Duplicate %s" % tag, kinds, iface)

if kinds not in result:
result[kinds] = iface

for sub in iface.dependents.keys():
_build(sub, result)
_build(sub, result, tag, tx)

return result

PAGEKINDS = _build(IPageKind, {})

PAGEKINDS = {}


class ICommentKind(interface.Interface):
"""
The type of comments for a given view.
"""

class ICommentKindNone(interface.Interface):
"""
No comments are allowed on this view.
"""

class ICommentKindAllowed(interface.Interface):
"""
Comments are allowed on this view.
"""

interface.taggedValue('__comment_system__', None)

class ICommentKindDisqus(ICommentKindAllowed):
"""
Use disqus comments.
"""
interface.taggedValue('__comment_system__', 'disqus')

COMMENTSYSTEMS = {}


def _cleanUp():
PAGEKINDS.clear()
PAGEKINDS.update(_build(IPageKind, {}, tx=frozenset))
COMMENTSYSTEMS.clear()
COMMENTSYSTEMS.update(_build(ICommentKindAllowed,
{}, '__comment_system__'))


_cleanUp()

try:
from zope.testing import cleanup
except ImportError:
pass
else:
cleanup.addCleanUp(_cleanUp)
8 changes: 7 additions & 1 deletion src/nti/nikola_chameleon/macro.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,11 @@ def __init__(self, context, request):
self.request = request

def traverse(self, name, ignored):
view = self.request.options['view']
templates = view.templates
return BoundMacro(self.context,
get_macro_template(self.context, None, self.request, name))
get_macro_template(self.context,
templates.new_view_for_context(self.context,
self.request),
self.request,
name))
60 changes: 56 additions & 4 deletions src/nti/nikola_chameleon/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,6 @@ def render_template_to_string(self, template, context):

# context becomes the options dict.
options = context
# self becomes view.
view = self
# The post, if given, becomes the context.
# Otherwise, it's a dummy object.
context = options.get('post')
Expand All @@ -168,8 +166,10 @@ def render_template_to_string(self, template, context):

request = Request(context, options)
# apply the "layer" to the request
pagekind = frozenset(options.get('pagekind', ()))
interface.alsoProvides(request, interfaces.PAGEKINDS[pagekind])
self._apply_request_layer(request, options)

# Apply other markers to the view
view = self.new_view_for_context(context, request)

template = component.getMultiAdapter((context, request),
ITemplate,
Expand All @@ -180,9 +180,51 @@ def render_template_to_string(self, template, context):
# zope.browserpage, assumes it's on the view object.
# chameleon/z3c.pt will use the kwargs
options['context'] = context
options['view'] = view

# When we render slides we don't get given messages.
if 'messages' not in options:
options['messages'] = self.site.MESSAGES

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

def _apply_request_layer(self, request, options):
pagekind = frozenset(options.get('pagekind', ()))
interface.alsoProvides(request, interfaces.PAGEKINDS[pagekind])

def new_view_for_context(self, context, request):
view = _View(self)
options = request.options
if not interfaces.IPost.providedBy(context):
# If it's not a post, it can't possibly have comments.
# XXX: When the context is not a post, as in when we're
# rendering an index page and we have options['posts']
# that the template will iterate over, like index.tmpl
# does, we have to traverse through the post to get a new
# view with this information before we look up the macro:
# post/@@macro/comment_link. Maybe the view isn't the best
# place to hang this? Maybe we should be traversing
# through posts here and applying this info to them? But still, that
# would require rebinding the context to the post in the same mechanism,
# so it doesn't make much difference.
interface.alsoProvides(view, interfaces.ICommentKindNone)
elif (
# comments enabled for the site?
options['site_has_comments']
# enabled for the page kind?
and options.get("enable_comments", True)
# NOT disabled for this specific post?
and not context.meta('nocomments')):
comment_system = options['comment_system']
# TODO: Make this extensible, allow plugins and themes to
# define their own comment systems.
iface = interfaces.COMMENTSYSTEMS[comment_system]
interface.alsoProvides(view, iface)
else:
# Things like galleries and pages that have comments disabled
interface.alsoProvides(view, interfaces.ICommentKindNone)
return view

def inject_directory(self, directory):
"""Injects the directory with the lowest priority in the
template search mechanism."""
Expand Down Expand Up @@ -250,3 +292,13 @@ 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)


class _View(object):
"""
The view object we pass to templates. Exists merely to hold
marker interfaces.
"""

def __init__(self, templates):
self.templates = templates
9 changes: 7 additions & 2 deletions src/nti/nikola_chameleon/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ class NikolaPageFileTemplate(ViewPageTemplateFile):
This does a few things:
1. Sets up the ``load:`` expression to work.
2. Provides a ``translate`` function based on Nikola's
2. Restores the ``import:`` and ``structure:`` expression types.
3. Provides a ``translate`` function based on Nikola's
``messages`` dictionary that will enable Chameleon's default
I18N support.
"""
Expand Down Expand Up @@ -68,6 +69,7 @@ def render(self, target_language=None, **context):

BaseTemplate.expression_types['structure'] = PageTemplateFile.expression_types['structure']
BaseTemplate.expression_types['load'] = PageTemplateFile.expression_types['load']
BaseTemplate.expression_types['import'] = PageTemplateFile.expression_types['import']
z3c.macro.zcml.ViewPageTemplateFile = NikolaPageFileTemplate
zope.browserpage.simpleviewclass.ViewPageTemplateFile = NikolaPageFileTemplate

Expand Down Expand Up @@ -117,4 +119,7 @@ def __init__(self, messages):

def __call__(self, msgid, domain=None, mapping=None, context=None,
target_language=None, default=None):
return self._messages(msgid, target_language)
try:
return self._messages(msgid, target_language)
except KeyError:
return default or msgid

0 comments on commit a6ff3e0

Please sign in to comment.