Menu droit fonctionne pour tous les briques
[auf_savoirs_en_partage_django.git] / auf_savoirs_en_partage / savoirs / templatetags / sep.py
1 # -*- encoding: utf-8 -*-
2
3 import re
4 from django import template
5 from django.conf import settings
6 from django.template.defaultfilters import stringfilter
7 from django.utils.encoding import smart_str
8 from django.utils.safestring import mark_safe
9 from datamaster_modeles.models import Region
10 from savoirs.models import Discipline
11
12 register = template.Library()
13
14 @register.inclusion_tag('menu.html', takes_context=True)
15 def sep_menu(context, discipline_active, region_active):
16 regions = Region.objects.filter(actif=True).order_by('nom')
17 disciplines = Discipline.objects.all()
18 return dict(disciplines=disciplines, regions=regions,
19 discipline_active=discipline_active, region_active=region_active,
20 request=context['request'])
21
22 @register.inclusion_tag('menu_brique.html', takes_context=True)
23 def sep_menu_brique(context, discipline_active, region_active):
24 regions = Region.objects.filter(actif=True).order_by('nom')
25 disciplines = Discipline.objects.all()
26 return dict(disciplines=disciplines, regions=regions,
27 discipline_active=discipline_active, region_active=region_active,
28 request=context['request'])
29
30 @register.inclusion_tag('sort_link.html', takes_context=True)
31 def sort_link(context, field, label):
32 request = context['request']
33 params = request.GET.copy()
34 current_sort = params.get('tri')
35 if current_sort == field:
36 sort = field + '_desc'
37 indicator = u' (croissant)'
38 else:
39 sort = field
40 if current_sort == field + '_desc':
41 indicator = u' (décroissant)'
42 else:
43 indicator = ''
44
45 params['tri'] = sort
46 url = request.path + '?' + params.urlencode()
47 return dict(label=label, url=url, indicator=indicator)
48
49 class URLNode(template.Node):
50 def __init__(self, view_name, args, kwargs, asvar):
51 self.view_name = view_name
52 self.args = args
53 self.kwargs = kwargs
54 self.asvar = asvar
55
56 def render(self, context):
57 from django.core.urlresolvers import reverse, NoReverseMatch
58 args = [arg.resolve(context) for arg in self.args]
59 kwargs = dict([(smart_str(k,'ascii'), v.resolve(context))
60 for k, v in self.kwargs.items()])
61
62 # C'est ici que nous injectons la discipline et la région courante
63 # dans les arguments.
64 context_discipline = context.get('discipline_active')
65 if context_discipline:
66 kwargs.setdefault('discipline', context_discipline)
67 context_region = context.get('region_active')
68 if context_region:
69 kwargs.setdefault('region', context_region)
70
71 # Try to look up the URL twice: once given the view name, and again
72 # relative to what we guess is the "main" app. If they both fail,
73 # re-raise the NoReverseMatch unless we're using the
74 # {% url ... as var %} construct in which cause return nothing.
75 url = ''
76 try:
77 url = reverse(self.view_name, args=args, kwargs=kwargs, current_app=context.current_app)
78 except NoReverseMatch, e:
79 if settings.SETTINGS_MODULE:
80 project_name = settings.SETTINGS_MODULE.split('.')[0]
81 try:
82 url = reverse(project_name + '.' + self.view_name,
83 args=args, kwargs=kwargs, current_app=context.current_app)
84 except NoReverseMatch:
85 if self.asvar is None:
86 # Re-raise the original exception, not the one with
87 # the path relative to the project. This makes a
88 # better error message.
89 raise e
90 else:
91 if self.asvar is None:
92 raise e
93
94 if self.asvar:
95 context[self.asvar] = url
96 return ''
97 else:
98 return url
99
100 @register.tag
101 def sep_url(parser, token):
102 """
103 Le tag ``url`` de Django, modifié pour SEP.
104
105 Lorsque ce tag est utilisé, la discipline et la région actives sont
106 automatiquement réinjectées dans les URL construites.
107 """
108 bits = token.split_contents()
109 if len(bits) < 2:
110 raise TemplateSyntaxError("'%s' takes at least one argument"
111 " (path to a view)" % bits[0])
112 viewname = bits[1]
113 args = []
114 kwargs = {}
115 asvar = None
116
117 if len(bits) > 2:
118 bits = iter(bits[2:])
119 for bit in bits:
120 if bit == 'as':
121 asvar = bits.next()
122 break
123 else:
124 for arg in bit.split(","):
125 if '=' in arg:
126 k, v = arg.split('=', 1)
127 k = k.strip()
128 kwargs[k] = parser.compile_filter(v)
129 elif arg:
130 args.append(parser.compile_filter(arg))
131 return URLNode(viewname, args, kwargs, asvar)
132
133 DISCIPLINE_REGION_RE = re.compile(r'(/discipline/\d+)?(/region/\d+)?')
134
135 @register.filter
136 @stringfilter
137 def change_region(path, region):
138 """Modifie la région dans le chemin donné."""
139 match = DISCIPLINE_REGION_RE.match(path)
140 discipline_bit = match.group(1) or ''
141 region_bit = '/region/%d' % region if region != 'all' else ''
142 rest = path[match.end():]
143 if not rest.startswith('/recherche/'):
144 rest = '/'
145 return discipline_bit + region_bit + rest
146
147 @register.filter
148 @stringfilter
149 def change_discipline(path, discipline):
150 """Modifie la discipline dans le chemin donné."""
151 match = DISCIPLINE_REGION_RE.match(path)
152 discipline_bit = '/discipline/%d' % discipline if discipline != 'all' else ''
153 region_bit = match.group(2) or ''
154 rest = path[match.end():]
155 if not rest.startswith('/recherche/'):
156 rest = '/'
157 return discipline_bit + region_bit + rest
158
159
160 @register.filter
161 def apply(value, func):
162 """Applique une fonction arbitraire à la valeur filtrée."""
163 return func(value)
164
165 @register.filter
166 def getitem(container, key):
167 """Applique ``container[key]`` sur la valeur filtrée."""
168 return container.get(key, '')
169
170
171 # Snippet: http://djangosnippets.org/snippets/2237/
172 @register.tag
173 def query_string(parser, token):
174 """
175 Allows you too manipulate the query string of a page by adding and removing keywords.
176 If a given value is a context variable it will resolve it.
177 Based on similiar snippet by user "dnordberg".
178
179 requires you to add:
180
181 TEMPLATE_CONTEXT_PROCESSORS = (
182 'django.core.context_processors.request',
183 )
184
185 to your django settings.
186
187 Usage:
188 http://www.url.com/{% query_string "param_to_add=value, param_to_add=value" "param_to_remove, params_to_remove" %}
189
190 Example:
191 http://www.url.com/{% query_string "" "filter" %}filter={{new_filter}}
192 http://www.url.com/{% query_string "page=page_obj.number" "sort" %}
193
194 """
195 try:
196 tag_name, add_string,remove_string = token.split_contents()
197 except ValueError:
198 raise template.TemplateSyntaxError, "%r tag requires two arguments" % token.contents.split()[0]
199 if not (add_string[0] == add_string[-1] and add_string[0] in ('"', "'")) or not (remove_string[0] == remove_string[-1] and remove_string[0] in ('"', "'")):
200 raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
201
202 add = string_to_dict(add_string[1:-1])
203 remove = string_to_list(remove_string[1:-1])
204
205 return QueryStringNode(add,remove)
206
207 class QueryStringNode(template.Node):
208 def __init__(self, add,remove):
209 self.add = add
210 self.remove = remove
211
212 def render(self, context):
213 p = {}
214 for k, v in context["request"].GET.items():
215 p[k]=v
216 return get_query_string(p,self.add,self.remove,context)
217
218 def get_query_string(p, new_params, remove, context):
219 """
220 Add and remove query parameters. From `django.contrib.admin`.
221 """
222 for r in remove:
223 for k in p.keys():
224 if k.startswith(r):
225 del p[k]
226 for k, v in new_params.items():
227 if k in p and v is None:
228 del p[k]
229 elif v is not None:
230 p[k] = v
231
232 for k, v in p.items():
233 try:
234 p[k] = template.Variable(v).resolve(context)
235 except:
236 p[k]=v
237
238 return mark_safe('?' + '&amp;'.join([u'%s=%s' % (k, v) for k, v in p.items()]).replace(' ', '%20'))
239
240 # Taken from lib/utils.py
241 def string_to_dict(string):
242 kwargs = {}
243
244 if string:
245 string = str(string)
246 if ',' not in string:
247 # ensure at least one ','
248 string += ','
249 for arg in string.split(','):
250 arg = arg.strip()
251 if arg == '': continue
252 kw, val = arg.split('=', 1)
253 kwargs[kw] = val
254 return kwargs
255
256 def string_to_list(string):
257 args = []
258 if string:
259 string = str(string)
260 if ',' not in string:
261 # ensure at least one ','
262 string += ','
263 for arg in string.split(','):
264 arg = arg.strip()
265 if arg == '': continue
266 args.append(arg)
267 return args