1 from django import template
2 from django.conf import settings
3 from django.contrib.sites.models import Site
4 from django.core.urlresolvers import reverse, NoReverseMatch
5 from django.template.defaulttags import kwarg_re
6 from django.utils.encoding import smart_str
7 from philo.exceptions import ViewCanNotProvideSubpath
10 register = template.Library()
13 class NodeURLNode(template.Node):
14 def __init__(self, node, as_var, with_obj=None, view_name=None, args=None, kwargs=None):
16 self.view_name = view_name
18 # Because the following variables have already been compiled as filters if they exist, they don't need to be re-scanned as template variables.
20 self.with_obj = with_obj
24 def render(self, context):
26 node = self.node.resolve(context)
28 node = context.get('node', None)
31 return settings.TEMPLATE_STRING_IF_INVALID
33 if self.with_obj is None and self.view_name is None:
34 url = node.get_absolute_url()
36 if not node.view.accepts_subpath:
37 return settings.TEMPLATE_STRING_IF_INVALID
39 if self.with_obj is not None:
41 view_name, args, kwargs = node.view.get_reverse_params(self.with_obj.resolve(context))
42 except ViewCanNotProvideSubpath:
43 return settings.TEMPLATE_STRING_IF_INVALID
44 else: # self.view_name is not None
45 view_name = self.view_name
46 args = [arg.resolve(context) for arg in self.args]
47 kwargs = dict([(smart_str(k, 'ascii'), v.resolve(context)) for k, v in self.kwargs.items()])
51 subpath = reverse(view_name, urlconf=node.view, args=args, kwargs=kwargs)
52 except NoReverseMatch:
53 if self.as_var is None:
54 if settings.TEMPLATE_DEBUG:
56 return settings.TEMPLATE_STRING_IF_INVALID
61 url = node.get_absolute_url() + subpath
64 context[self.as_var] = url
70 @register.tag(name='node_url')
71 def do_node_url(parser, token):
73 {% node_url [for <node>] [as <var>] %}
74 {% node_url with <obj> [for <node>] [as <var>] %}
75 {% node_url <view_name> [<arg1> [<arg2> ...] ] [for <node>] [as <var>] %}
76 {% node_url <view_name> [<key1>=<value1> [<key2>=<value2> ...] ] [for <node>] [as <var>]%}
78 params = token.split_contents()
85 if len(params) >= 2 and params[-2] == 'as':
89 if len(params) >= 2 and params[-2] == 'for':
90 node = parser.compile_filter(params[-1])
93 if len(params) >= 2 and params[-2] == 'with':
94 with_obj = parser.compile_filter(params[-1])
97 if with_obj is not None:
99 raise template.TemplateSyntaxError('`%s` template tag accepts no arguments or keyword arguments if with <obj> is specified.' % tag)
100 return NodeURLNode(with_obj=with_obj, node=node, as_var=as_var)
105 view_name = params.pop(0)
107 match = kwarg_re.match(param)
109 raise TemplateSyntaxError("Malformed arguments to `%s` tag" % tag)
110 name, value = match.groups()
112 kwargs[name] = parser.compile_filter(value)
114 args.append(parser.compile_filter(value))
115 return NodeURLNode(view_name=view_name, args=args, kwargs=kwargs, node=node, as_var=as_var)
117 return NodeURLNode(node=node, as_var=as_var)
120 class NavigationNode(template.Node):
121 def __init__(self, node=None, as_var=None):
125 def render(self, context):
126 if 'request' not in context:
127 return settings.TEMPLATE_STRING_IF_INVALID
130 node = self.node.resolve(context)
132 node = context.get('node', None)
135 return settings.TEMPLATE_STRING_IF_INVALID
138 nav_root = node.attributes['navigation_root']
140 if settings.TEMPLATE_DEBUG:
142 return settings.TEMPLATE_STRING_IF_INVALID
144 # Should I get its override and check for a max depth override there?
145 navigation = nav_root.get_navigation()
148 context[self.as_var] = navigation
151 return self.compile(navigation, context['request'].path, nav_root.get_absolute_url(), nav_root.get_level(), nav_root.get_level() + 3)
153 def compile(self, navigation, active_path, root_url, current_depth, max_depth):
155 for item in navigation:
156 if item['url'] in active_path and (item['url'] != root_url or root_url == active_path):
157 compiled += "<li class='active'>"
162 compiled += "<a href='%s'>" % item['url']
164 compiled += item['title']
169 if 'children' in item and current_depth < max_depth:
170 compiled += "<ul>%s</ul>" % self.compile(item['children'], active_path, root_url, current_depth + 1, max_depth)
176 @register.tag(name='navigation')
177 def do_navigation(parser, token):
179 {% navigation [for <node>] [as <var>] %}
181 bits = token.split_contents()
187 if len(bits) >= 2 and bits[-2] == 'as':
191 if len(bits) >= 2 and bits[-2] == 'for':
192 node = parser.compile_filter(bits[-1])
196 raise template.TemplateSyntaxError('`%s` template tag expects the syntax {%% %s [for <node>] [as <var>] %}' % (tag, tag))
197 return NavigationNode(node, as_var)