Added kwarg capability to embed tag. Adjusted reference substitution to account for...
authorStephen Burrows <stephen.r.burrows@gmail.com>
Mon, 4 Oct 2010 15:54:31 +0000 (11:54 -0400)
committerStephen Burrows <stephen.r.burrows@gmail.com>
Mon, 4 Oct 2010 15:54:31 +0000 (11:54 -0400)
contrib/penfield/embed.py
contrib/penfield/templatetags/embed.py

index ca49baa..43c08a6 100644 (file)
@@ -9,9 +9,6 @@ from philo.contrib.penfield.templatetags.embed import EmbedNode
 from philo.utils import nodelist_crawl
 
 
-embed_re = re.compile("{% embed (?P<app_label>\w+)\.(?P<model>\w+) (?P<pk>)\w+ %}")
-
-
 class Embed(models.Model):
        embedder_content_type = models.ForeignKey(ContentType, related_name="embedder_related")
        embedder_object_id = models.PositiveIntegerField()
@@ -31,14 +28,17 @@ class Embed(models.Model):
                for field in embedder._meta.fields:
                        if isinstance(field, EmbedField):
                                attr = getattr(embedder, field.attname)
-                               setattr(embedder, field.attname, attr.replace(self.get_embed_tag(), ''))
+                               setattr(embedder, field.attname, self.embed_re.sub('', attr))
                
                embedder.save()
        
-       def get_embed_tag(self):
-               """Convenience function to construct the embed tag that would create this instance."""
-               ct = self.embedded_content_type
-               return "{%% embed %s.%s %s %%}" % (ct.app_label, ct.model, self.embedded_object_id)
+       def get_embed_re(self):
+               """Convenience function to return a compiled regular expression to find embed tags that would create this instance."""
+               if not hasattr(self, '_embed_re'):
+                       ct = self.embedded_content_type
+                       self._embed_re = re.compile("{%% ?embed %s.%s %s( .*?)? ?%%}" % (ct.app_label, ct.model, self.embedded_object_id))
+               return self._embed_re
+       embed_re = property(get_embed_re)
        
        class Meta:
                app_label = 'penfield'
index 8da99af..7d1b26a 100644 (file)
@@ -8,11 +8,16 @@ register = template.Library()
 
 
 class EmbedNode(template.Node):
-       def __init__(self, content_type, varname, object_pk=None, template_name=None):
+       def __init__(self, content_type, varname, object_pk=None, template_name=None, kwargs=None):
                assert template_name is not None or object_pk is not None
                self.content_type = content_type
                self.varname = varname
                
+               kwargs = kwargs or {}
+               for k, v in kwargs.items():
+                       kwargs[k] = template.Variable(v)
+               self.kwargs = kwargs
+               
                if object_pk is not None:
                        self.object_pk = object_pk
                        try:
@@ -52,6 +57,9 @@ class EmbedNode(template.Node):
                
                context.push()
                context['embedded'] = self.instance
+               for k, v in self.kwargs.items():
+                       self.kwargs[k] = v.resolve(context)
+               context.update(self.kwargs)
                t_rendered = t.render(context)
                context.pop()
                return t_rendered
@@ -69,20 +77,17 @@ def do_embed(parser, token):
        The {% embed %} tag can be used in three ways:
        {% embed as <varname> %} :: This sets which variable will be used to track embedding template names for the current context. Default: "embed"
        {% embed <app_label>.<model_name> with <template> %} :: Sets which template will be used to render a particular model.
-       {% embed <app_label>.<model_name> <object_pk> %} :: Embeds the instance specified by the given parameters in the document with the previously-specified template.
+       {% embed <app_label>.<model_name> <object_pk> [<argname>=<value> ...]%} :: Embeds the instance specified by the given parameters in the document with the previously-specified template. Any kwargs provided will be passed into the context of the template.
        """
        args = token.split_contents()
        tag = args[0]
        
        if len(args) < 2:
                raise template.TemplateSyntaxError('"%s" template tag must have at least three arguments.' % tag)
-       elif len(args) > 4:
-               raise template.TemplateSyntaxError('"%s" template tag may have no more than four arguments.' % tag)
+       elif len(args) == 3 and args[1] == "as":
+               parser._embedNodeVarName = args[2]
+               return template.defaulttags.CommentNode()
        else:
-               if len(args) == 3 and args[1] == "as":
-                       parser._embedNodeVarName = args[2]
-                       return template.defaulttags.CommentNode()
-               
                if '.' not in args[1]:
                        raise template.TemplateSyntaxError('"%s" template tag expects the first argument to be of the form app_label.model' % tag)
                
@@ -92,13 +97,9 @@ def do_embed(parser, token):
                except ContentType.DoesNotExist:
                        raise template.TemplateSyntaxError('"%s" template tag option "references" requires an argument of the form app_label.model which refers to an installed content type (see django.contrib.contenttypes)' % tag)
                
-               if len(args) == 3:
-                       
-                       return EmbedNode(ct, object_pk=args[2], varname=getattr(parser, '_embedNodeVarName', 'embed'))
-               else:
-                       # 3 args
-                       if args[2] != "with":
-                               raise template.TemplateSyntaxError('"%s" template tag requires the second of three arguments to be "with"' % tag)
+               if args[2] == "with":
+                       if len(args) > 4:
+                               raise template.TemplateSyntaxError('"%s" template tag may have no more than four arguments.' % tag)
                        
                        if args[3][0] not in ['"', "'"] and args[3][-1] not in ['"', "'"]:
                                raise template.TemplateSyntaxError('"%s" template tag expects the template name to be in quotes.' % tag)
@@ -108,6 +109,18 @@ def do_embed(parser, token):
                        template_name = args[3].strip('"\'')
                        
                        return EmbedNode(ct, template_name=template_name, varname=getattr(parser, '_embedNodeVarName', 'embed'))
+               object_pk = args[2]
+               varname = getattr(parser, '_embedNodeVarName', 'embed')
+               
+               remaining_args = args[3:]
+               kwargs = {}
+               for arg in remaining_args:
+                       if '=' not in arg:
+                               raise template.TemplateSyntaxError("Invalid keyword argument for '%s' template tag: %s" % (tag, arg))
+                       k, v = arg.split('=')
+                       kwargs[k] = v
+               
+               return EmbedNode(ct, object_pk=object_pk, varname=varname, kwargs=kwargs)
 
 
 register.tag('embed', do_embed)
\ No newline at end of file