Merge branch 'master' of git://github.com/melinath/philo
[philo.git] / philo / models / pages.py
index ae64b4d..ea3bb64 100644 (file)
@@ -4,17 +4,19 @@
 
 """
 
 
 """
 
+import itertools
+
 from django.conf import settings
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes import generic
 from django.core.exceptions import ValidationError
 from django.db import models
 from django.http import HttpResponse
 from django.conf import settings
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes import generic
 from django.core.exceptions import ValidationError
 from django.db import models
 from django.http import HttpResponse
-from django.template import TemplateDoesNotExist, Context, RequestContext, Template as DjangoTemplate, add_to_builtins as register_templatetags, TextNode, VariableNode
+from django.template import TemplateDoesNotExist, Context, RequestContext, Template as DjangoTemplate, TextNode, VariableNode
 from django.template.loader_tags import BlockNode, ExtendsNode, BlockContext
 from django.utils.datastructures import SortedDict
 
 from django.template.loader_tags import BlockNode, ExtendsNode, BlockContext
 from django.utils.datastructures import SortedDict
 
-from philo.models.base import TreeModel, register_value_model
+from philo.models.base import SlugTreeEntity, register_value_model
 from philo.models.fields import TemplateField
 from philo.models.nodes import View
 from philo.signals import page_about_to_render_to_string, page_finished_rendering_to_string
 from philo.models.fields import TemplateField
 from philo.models.nodes import View
 from philo.signals import page_about_to_render_to_string, page_finished_rendering_to_string
@@ -23,11 +25,14 @@ from philo.utils import fattr
 from philo.validators import LOADED_TEMPLATE_ATTR
 
 
 from philo.validators import LOADED_TEMPLATE_ATTR
 
 
+__all__ = ('Template', 'Page', 'Contentlet', 'ContentReference')
+
+
 class LazyContainerFinder(object):
        def __init__(self, nodes, extends=False):
                self.nodes = nodes
                self.initialized = False
 class LazyContainerFinder(object):
        def __init__(self, nodes, extends=False):
                self.nodes = nodes
                self.initialized = False
-               self.contentlet_specs = set()
+               self.contentlet_specs = []
                self.contentreference_specs = SortedDict()
                self.blocks = {}
                self.block_super = False
                self.contentreference_specs = SortedDict()
                self.blocks = {}
                self.block_super = False
@@ -44,7 +49,7 @@ class LazyContainerFinder(object):
                        
                        if isinstance(node, ContainerNode):
                                if not node.references:
                        
                        if isinstance(node, ContainerNode):
                                if not node.references:
-                                       self.contentlet_specs.add(node.name)
+                                       self.contentlet_specs.append(node.name)
                                else:
                                        if node.name not in self.contentreference_specs.keys():
                                                self.contentreference_specs[node.name] = node.references
                                else:
                                        if node.name not in self.contentreference_specs.keys():
                                                self.contentreference_specs[node.name] = node.references
@@ -75,7 +80,27 @@ class LazyContainerFinder(object):
                        self.initialized = True
 
 
                        self.initialized = True
 
 
-class Template(TreeModel):
+def build_extension_tree(nodelist):
+       nodelists = []
+       extends = None
+       for node in nodelist:
+               if not isinstance(node, TextNode):
+                       if isinstance(node, ExtendsNode):
+                               extends = node
+                       break
+       
+       if extends:
+               if extends.nodelist:
+                       nodelists.append(LazyContainerFinder(extends.nodelist, extends=True))
+               loaded_template = getattr(extends, LOADED_TEMPLATE_ATTR)
+               nodelists.extend(build_extension_tree(loaded_template.nodelist))
+       else:
+               # Base case: root.
+               nodelists.append(LazyContainerFinder(nodelist))
+       return nodelists
+
+
+class Template(SlugTreeEntity):
        """Represents a database-driven django template."""
        #: The name of the template. Used for organization and debugging.
        name = models.CharField(max_length=255)
        """Represents a database-driven django template."""
        #: The name of the template. Used for organization and debugging.
        name = models.CharField(max_length=255)
@@ -94,35 +119,16 @@ class Template(TreeModel):
                """
                template = DjangoTemplate(self.code)
                
                """
                template = DjangoTemplate(self.code)
                
-               def build_extension_tree(nodelist):
-                       nodelists = []
-                       extends = None
-                       for node in nodelist:
-                               if not isinstance(node, TextNode):
-                                       if isinstance(node, ExtendsNode):
-                                               extends = node
-                                       break
-                       
-                       if extends:
-                               if extends.nodelist:
-                                       nodelists.append(LazyContainerFinder(extends.nodelist, extends=True))
-                               loaded_template = getattr(extends, LOADED_TEMPLATE_ATTR)
-                               nodelists.extend(build_extension_tree(loaded_template.nodelist))
-                       else:
-                               # Base case: root.
-                               nodelists.append(LazyContainerFinder(nodelist))
-                       return nodelists
-               
                # Build a tree of the templates we're using, placing the root template first.
                # Build a tree of the templates we're using, placing the root template first.
-               levels = build_extension_tree(template.nodelist)[::-1]
+               levels = build_extension_tree(template.nodelist)
                
                
-               contentlet_specs = set()
+               contentlet_specs = []
                contentreference_specs = SortedDict()
                blocks = {}
                
                contentreference_specs = SortedDict()
                blocks = {}
                
-               for level in levels:
+               for level in reversed(levels):
                        level.initialize()
                        level.initialize()
-                       contentlet_specs |= level.contentlet_specs
+                       contentlet_specs.extend(itertools.ifilter(lambda x: x not in contentlet_specs, level.contentlet_specs))
                        contentreference_specs.update(level.contentreference_specs)
                        for name, block in level.blocks.items():
                                if block.block_super:
                        contentreference_specs.update(level.contentreference_specs)
                        for name, block in level.blocks.items():
                                if block.block_super:
@@ -133,7 +139,7 @@ class Template(TreeModel):
                for block_list in blocks.values():
                        for block in block_list:
                                block.initialize()
                for block_list in blocks.values():
                        for block in block_list:
                                block.initialize()
-                               contentlet_specs |= block.contentlet_specs
+                               contentlet_specs.extend(itertools.ifilter(lambda x: x not in contentlet_specs, block.contentlet_specs))
                                contentreference_specs.update(block.contentreference_specs)
                
                return contentlet_specs, contentreference_specs
                                contentreference_specs.update(block.contentreference_specs)
                
                return contentlet_specs, contentreference_specs
@@ -142,7 +148,7 @@ class Template(TreeModel):
                """Returns the value of the :attr:`name` field."""
                return self.name
        
                """Returns the value of the :attr:`name` field."""
                return self.name
        
-       class Meta:
+       class Meta(SlugTreeEntity.Meta):
                app_label = 'philo'
 
 
                app_label = 'philo'
 
 
@@ -170,6 +176,8 @@ class Page(View):
                """
                In addition to rendering as an :class:`HttpResponse`, a :class:`Page` can also render as a string. This means, for example, that :class:`Page`\ s can be used to render emails or other non-HTML content with the same :ttag:`container`-based functionality as is used for HTML.
                
                """
                In addition to rendering as an :class:`HttpResponse`, a :class:`Page` can also render as a string. This means, for example, that :class:`Page`\ s can be used to render emails or other non-HTML content with the same :ttag:`container`-based functionality as is used for HTML.
                
+               The :class:`Page` will add itself to the context as ``page`` and its :attr:`~.Entity.attributes` as ``attributes``. If a request is provided, then :class:`request.node <.Node>` will also be added to the context as ``node`` and ``attributes`` will be set to the result of calling :meth:`~.View.attributes_with_node` with that :class:`.Node`.
+               
                """
                context = {}
                context.update(extra_context or {})
                """
                context = {}
                context.update(extra_context or {})
@@ -258,8 +266,5 @@ class ContentReference(models.Model):
                app_label = 'philo'
 
 
                app_label = 'philo'
 
 
-register_templatetags('philo.templatetags.containers')
-
-
 register_value_model(Template)
 register_value_model(Page)
\ No newline at end of file
 register_value_model(Template)
 register_value_model(Page)
\ No newline at end of file