Merge branch 'melinath'
authorJoseph Spiros <joseph.spiros@ithinksw.com>
Thu, 10 Jun 2010 08:17:25 +0000 (04:17 -0400)
committerJoseph Spiros <joseph.spiros@ithinksw.com>
Thu, 10 Jun 2010 08:18:50 +0000 (04:18 -0400)
* melinath:
  Fixing style issues and an incorrect modification of .gitignore.
  Fixed the context variable leak in the blockcontainer tag.
  Fixed a bug where the ContainerNode had a nodelist_empty=None, whereas nodelist_empty is expected to be an iterable by line 314 of models.py. Also added 'nodelist_main' to the manage.py line 314 list of subnodelist possibilities and added a child_nodelists attribute to ContainerNode for possible forward-compatibility.
  First draft of blockcontainer functionality. Tries to reuse most of the code related to the original container tag by extending it, simply interpreting the values slightly differently.
  Added documentation and help text to models.py and containers.py to hopefully improve usability.

models.py
templatetags/containers.py

index cea36c2..eb6ebc0 100644 (file)
--- a/models.py
+++ b/models.py
@@ -21,6 +21,7 @@ from django.template.loader_tags import ExtendsNode, ConstantIncludeNode, Includ
 from django.template.loader import get_template
 from django.http import Http404, HttpResponse, HttpResponseServerError, HttpResponseRedirect
 from django.core.servers.basehttp import FileWrapper
+from django.conf import settings
 
 
 def register_value_model(model):
@@ -261,7 +262,7 @@ class Redirect(Node):
                (302, 'Temporary'),
                (301, 'Permanent'),
        )
-       target = models.URLField()
+       target = models.URLField(help_text='Must be a valid, absolute URL (i.e. http://)')
        status_code = models.IntegerField(choices=STATUS_CODES, default=302, verbose_name='redirect type')
        
        def render_to_response(self, request, path=None, subpath=None):
@@ -285,8 +286,8 @@ class File(Node):
 class Template(TreeModel):
        name = models.CharField(max_length=255)
        documentation = models.TextField(null=True, blank=True)
-       mimetype = models.CharField(max_length=255, null=True, blank=True)
-       code = models.TextField()
+       mimetype = models.CharField(max_length=255, null=True, blank=True, help_text='Default: %s' % settings.DEFAULT_CONTENT_TYPE)
+       code = models.TextField(verbose_name='django template code')
        
        @property
        def origin(self):
@@ -309,7 +310,7 @@ class Template(TreeModel):
                                nodes = []
                                for node in nodelist:
                                        try:
-                                               for nodelist_name in ('nodelist', 'nodelist_loop', 'nodelist_empty', 'nodelist_true', 'nodelist_false'):
+                                               for nodelist_name in ('nodelist', 'nodelist_loop', 'nodelist_empty', 'nodelist_true', 'nodelist_false', 'nodelist_main'):
                                                        if hasattr(node, nodelist_name):
                                                                nodes.extend(nodelist_container_nodes(getattr(node, nodelist_name)))
                                                if isinstance(node, ContainerNode):
@@ -354,6 +355,11 @@ class Template(TreeModel):
 
 
 class Page(Node):
+       """
+       Represents an HTML page. The page will have a number of related Contentlets
+       depending on the template selected - but these will appear only after the
+       page has been saved with that template.
+       """
        template = models.ForeignKey(Template, related_name='pages')
        title = models.CharField(max_length=255)
        
index cc6b313..ca5e1e9 100644 (file)
@@ -9,45 +9,84 @@ register = template.Library()
 
 
 class ContainerNode(template.Node):
-       def __init__(self, name, references=None, as_var=None):
+       child_nodelists = ('nodelist_main', 'nodelist_empty',)
+       
+       def __init__(self, name, references=None, as_var=None, nodelist_main=None, nodelist_empty=None):
                self.name = name
                self.as_var = as_var
                self.references = references
+               
+               if nodelist_main is None:
+                       self.nodelist_main = template.NodeList()
+               else:
+                       self.nodelist_main = nodelist_main
+               
+               if nodelist_empty is None:
+                       self.nodelist_empty = template.NodeList()
+               else:
+                       self.nodelist_empty = nodelist_empty
+       
        def render(self, context):
                content = settings.TEMPLATE_STRING_IF_INVALID
                if 'page' in context:
-                       page = context['page']
-                       if self.references:
-                               try:
-                                       contentreference = page.contentreferences.get(name__exact=self.name, content_type=self.references)
-                                       content = contentreference.content
-                               except ObjectDoesNotExist:
-                                       pass
-                       else:
-                               try:
-                                       contentlet = page.contentlets.get(name__exact=self.name)
-                                       if contentlet.dynamic:
-                                               try:
-                                                       content = mark_safe(template.Template(contentlet.content, name=contentlet.name).render(context))
-                                               except template.TemplateSyntaxError, error:
-                                                       if settings.DEBUG:
-                                                               content = ('[Error parsing contentlet \'%s\': %s]' % self.name, error)
-                                       else:
-                                               content = contentlet.content
-                               except ObjectDoesNotExist:
-                                       pass
-               if content and self.as_var:
-                       context[self.as_var] = content
-                       return ''
+                       container_content = self.get_container_content(context['page'])
+               
+               if self.nodelist_main is None:
+                       self.nodelist_main
+                       if container_content and self.as_var:
+                               context[self.as_var] = container_content
+                               return ''
+                       return container_content
+               
+               if container_content:
+                       if self.as_var is None:
+                               self.as_var = self.name
+                       
+                       #make a new context 
+                       context.push()
+                       context[self.as_var] = container_content
+                       nodelist = template.NodeList()
+                       for node in self.nodelist_main:
+                               nodelist.append(node.render(context))
+                       context.pop()
+                       return nodelist.render(context)
+               
+               if self.nodelist_empty is not None:
+                       return self.nodelist_empty.render(context)
+               
+               return ''
+       
+       def get_container_content(self, page):
+               if self.references:
+                       try:
+                               contentreference = page.contentreferences.get(name__exact=self.name, content_type=self.references)
+                               content = contentreference.content
+                       except ObjectDoesNotExist:
+                               content = ''
+               else:
+                       try:
+                               contentlet = page.contentlets.get(name__exact=self.name)
+                               if contentlet.dynamic:
+                                       try:
+                                               content = mark_safe(template.Template(contentlet.content, name=contentlet.name).render(context))
+                                       except template.TemplateSyntaxError, error:
+                                               if settings.DEBUG:
+                                                       content = ('[Error parsing contentlet \'%s\': %s]' % self.name, error)
+                               else:
+                                       content = contentlet.content
+                       except ObjectDoesNotExist:
+                               content = ''
                return content
 
 
 def do_container(parser, token):
        """
-       {% container <name> [[references <type>] as <variable>] %}
+       {% container <name> [[references <type>] as <variable>] %} 
+       {% blockcontainer <name> [[references <type>] as <variable>] %} [ {% empty %} ] {% endblockcontainer %}
        """
        params = token.split_contents()
        if len(params) >= 2:
+               tag = params[0]
                name = params[1].strip('"')
                references = None
                as_var = None
@@ -60,19 +99,34 @@ def do_container(parser, token):
                                                app_label, model = remaining_tokens.pop(0).strip('"').split('.')
                                                references = ContentType.objects.get(app_label=app_label, model=model)
                                        except IndexError:
-                                               raise template.TemplateSyntaxError('"container" template tag option "references" requires an argument specifying a content type')
+                                               raise template.TemplateSyntaxError('"%s" template tag option "references" requires an argument specifying a content type' % tag)
                                        except ValueError:
-                                               raise template.TemplateSyntaxError('"container" template tag option "references" requires an argument of the form app_label.model (see django.contrib.contenttypes)')
+                                               raise template.TemplateSyntaxError('"%s" template tag option "references" requires an argument of the form app_label.model (see django.contrib.contenttypes)' % tag)
                                        except ObjectDoesNotExist:
-                                               raise template.TemplateSyntaxError('"container" template tag option "references" requires an argument of the form app_label.model which refers to an installed content type (see django.contrib.contenttypes)')
+                                               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)
                                elif option_token == 'as':
                                        try:
                                                as_var = remaining_tokens.pop(0)
                                        except IndexError:
-                                               raise template.TemplateSyntaxError('"container" template tag option "as" requires an argument specifying a variable name')
+                                               raise template.TemplateSyntaxError('"%s" template tag option "as" requires an argument specifying a variable name' % tag)
                        if references and not as_var:
-                               raise template.TemplateSyntaxError('"container" template tags using "references" option require additional use of the "as" option specifying a variable name')
-               return ContainerNode(name, references, as_var)
+                               raise template.TemplateSyntaxError('"%s" template tags using "references" option require additional use of the "as" option specifying a variable name' % tag)
+               if tag == 'container':
+                       return ContainerNode(name, references, as_var)
+               
+               nodelist_main = parser.parse(('empty','endblockcontainer',))
+               token = parser.next_token()
+               
+               if token.contents == 'empty':
+                       nodelist_empty = parser.parse(('endblockcontainer',))
+                       parser.delete_first_token()
+               else:
+                       nodelist_empty = None
+               return ContainerNode(name, references, as_var, nodelist_main, nodelist_empty)
+               
        else: # error
-               raise template.TemplateSyntaxError('"container" template tag provided without arguments (at least one required)')
-register.tag('container', do_container)
\ No newline at end of file
+               raise template.TemplateSyntaxError('"%s" template tag provided without arguments (at least one required)' % tag)
+
+
+register.tag('container', do_container)
+register.tag('blockcontainer', do_container)