blob: 6af5cec31cc5365fa2bd2f266f51095484141815 [file] [log] [blame]
Armin Ronacher92f572f2007-02-26 22:17:32 +01001# -*- coding: utf-8 -*-
2"""
3 jinja.filters
4 ~~~~~~~~~~~~~
5
6 Bundled jinja filters.
7
Armin Ronacher8ebf1f92007-03-03 11:22:18 +01008 :copyright: 2007 by Armin Ronacher.
Armin Ronacher92f572f2007-02-26 22:17:32 +01009 :license: BSD, see LICENSE for more details.
10"""
Georg Brandlaf31e4d2007-04-15 00:47:37 +020011import re
Armin Ronacherfed86c12007-02-27 10:31:14 +010012from random import choice
13from urllib import urlencode, quote
Armin Ronacherae16fd02007-03-27 21:31:24 +020014from jinja.utils import urlize, escape
15from jinja.datastructure import Undefined, Markup, TemplateData
Armin Ronacher2b765132007-03-13 16:48:10 +010016from jinja.exceptions import FilterArgumentError
Armin Ronacherfed86c12007-02-27 10:31:14 +010017
18
19try:
20 _reversed = reversed
21except NameError:
22 # python2.3 compatibility hack for the do_reverse function
23 def _reversed(seq):
24 try:
25 return seq[::-1]
26 except:
27 try:
28 return list(seq)[::-1]
29 except:
30 raise TypeError('argument to _reversed must '
31 'be a sequence')
Armin Ronacher92f572f2007-02-26 22:17:32 +010032
33
34def stringfilter(f):
35 """
36 Decorator for filters that just work on unicode objects.
37 """
38 def decorator(*args):
39 def wrapped(env, context, value):
Armin Ronacher3b65b8a2007-02-27 20:21:45 +010040 nargs = list(args)
41 for idx, var in enumerate(nargs):
Armin Ronacher92f572f2007-02-26 22:17:32 +010042 if isinstance(var, str):
Armin Ronacher3b65b8a2007-02-27 20:21:45 +010043 nargs[idx] = env.to_unicode(var)
44 return f(env.to_unicode(value), *nargs)
Armin Ronacher92f572f2007-02-26 22:17:32 +010045 return wrapped
Armin Ronacher37a88512007-03-02 20:42:18 +010046 try:
47 decorator.__doc__ = f.__doc__
48 decorator.__name__ = f.__name__
49 except:
50 pass
Armin Ronacher92f572f2007-02-26 22:17:32 +010051 return decorator
52
53
54def do_replace(s, old, new, count=None):
55 """
Armin Ronacher37a88512007-03-02 20:42:18 +010056 Return a copy of the value with all occurrences of a substring
57 replaced with a new one. The first argument is the substring
58 that should be replaced, the second is the replacement string.
59 If the optional third argument ``count`` is given, only the first
60 ``count`` occurrences are replaced:
Armin Ronacher92f572f2007-02-26 22:17:32 +010061
Armin Ronacher37a88512007-03-02 20:42:18 +010062 .. sourcecode:: jinja
63
64 {{ "Hello World"|replace("Hello", "Goodbye") }}
65 -> Goodbye World
66
67 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
68 -> d'oh, d'oh, aaargh
Armin Ronacher92f572f2007-02-26 22:17:32 +010069 """
Armin Ronacher2b765132007-03-13 16:48:10 +010070 if not isinstance(old, basestring) or \
71 not isinstance(new, basestring):
Armin Ronacherae16fd02007-03-27 21:31:24 +020072 raise FilterArgumentError('the replace filter requires '
73 'string replacement arguments')
Armin Ronacher2da479f2007-04-02 10:50:18 +020074 if count is None:
75 return s.replace(old, new)
76 if not isinstance(count, (int, long)):
Armin Ronacherae16fd02007-03-27 21:31:24 +020077 raise FilterArgumentError('the count parameter of the '
78 'replace filter requires '
79 'an integer')
Armin Ronacher92f572f2007-02-26 22:17:32 +010080 return s.replace(old, new, count)
Armin Ronacher3b65b8a2007-02-27 20:21:45 +010081do_replace = stringfilter(do_replace)
Armin Ronacher92f572f2007-02-26 22:17:32 +010082
83
84def do_upper(s):
85 """
Armin Ronacher37a88512007-03-02 20:42:18 +010086 Convert a value to uppercase.
Armin Ronacher92f572f2007-02-26 22:17:32 +010087 """
88 return s.upper()
Armin Ronacher3b65b8a2007-02-27 20:21:45 +010089do_upper = stringfilter(do_upper)
Armin Ronacher92f572f2007-02-26 22:17:32 +010090
91
92def do_lower(s):
93 """
Armin Ronacher37a88512007-03-02 20:42:18 +010094 Convert a value to lowercase.
Armin Ronacher92f572f2007-02-26 22:17:32 +010095 """
96 return s.lower()
Armin Ronacher3b65b8a2007-02-27 20:21:45 +010097do_lower = stringfilter(do_lower)
Armin Ronacher92f572f2007-02-26 22:17:32 +010098
99
Armin Ronacherae16fd02007-03-27 21:31:24 +0200100def do_escape(attribute=False):
Armin Ronacher92f572f2007-02-26 22:17:32 +0100101 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100102 XML escape ``&``, ``<``, and ``>`` in a string of data. If the
103 optional parameter is `true` this filter will also convert
104 ``"`` to ``&quot;``. This filter is just used if the environment
105 was configured with disabled `auto_escape`.
Armin Ronacher92f572f2007-02-26 22:17:32 +0100106
Armin Ronacher37a88512007-03-02 20:42:18 +0100107 This method will have no effect it the value is already escaped.
Armin Ronacher92f572f2007-02-26 22:17:32 +0100108 """
Armin Ronacher1f1823c2007-04-05 19:15:11 +0200109 #: because filters are cached we can make a local alias to
110 #: speed things up a bit
111 e = escape
Armin Ronacherae16fd02007-03-27 21:31:24 +0200112 def wrapped(env, context, s):
113 if isinstance(s, TemplateData):
114 return s
115 elif hasattr(s, '__html__'):
116 return s.__html__()
Armin Ronacher1f1823c2007-04-05 19:15:11 +0200117 return e(env.to_unicode(s), attribute)
Armin Ronacherae16fd02007-03-27 21:31:24 +0200118 return wrapped
Armin Ronacher92f572f2007-02-26 22:17:32 +0100119
120
Armin Ronacher450756b2007-04-15 15:13:59 +0200121def do_xmlattr():
122 """
123 Create an SGML/XML attribute string based on the items in a dict.
124 All values that are neither `none` nor `undefined` are automatically
125 escaped:
126
127 .. sourcecode:: html
128
129 <ul{{ {'class': 'my_list', 'missing': None,
130 'id': 'list-%d'|format(variable) }}>
131 ...
132 </ul>
133
134 Results in something like this:
135
136 <ul class="my_list" id="list-42">
137 ...
138 </ul>
139
140 *New in Jinja 1.1*
141 """
142 e = escape
143 def wrapped(env, context, d):
144 if not hasattr(d, 'iteritems'):
145 raise TypeError('a dict is required')
146 result = []
147 for key, value in d.iteritems():
148 if value not in (None, Undefined):
149 result.append(u'%s="%s"' % (
150 e(env.to_unicode(key)),
151 e(env.to_unicode(value), True)
152 ))
153 return u' '.join(result)
154 return wrapped
155
156
Armin Ronacher92f572f2007-02-26 22:17:32 +0100157def do_capitalize(s):
158 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100159 Capitalize a value. The first character will be uppercase, all others
160 lowercase.
Armin Ronacher92f572f2007-02-26 22:17:32 +0100161 """
162 return s.capitalize()
Armin Ronacher3b65b8a2007-02-27 20:21:45 +0100163do_capitalize = stringfilter(do_capitalize)
Armin Ronacher92f572f2007-02-26 22:17:32 +0100164
165
166def do_title(s):
167 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100168 Return a titlecased version of the value. I.e. words will start with
169 uppercase letters, all remaining characters are lowercase.
Armin Ronacher92f572f2007-02-26 22:17:32 +0100170 """
171 return s.title()
Armin Ronacher3b65b8a2007-02-27 20:21:45 +0100172do_title = stringfilter(do_title)
Armin Ronacher92f572f2007-02-26 22:17:32 +0100173
174
Armin Ronacher2b765132007-03-13 16:48:10 +0100175def do_dictsort(case_sensitive=False, by='key'):
176 """
177 Sort a dict and yield (key, value) pairs. Because python dicts are
178 unsorted you may want to use this function to order them by either
179 key or value:
180
181 .. sourcecode:: jinja
182
183 {% for item in mydict|dictsort %}
184 sort the dict by key, case insensitive
185
186 {% for item in mydict|dicsort(true) %}
187 sort the dict by key, case sensitive
188
189 {% for item in mydict|dictsort(false, 'value') %}
190 sort the dict by key, case insensitive, sorted
191 normally and ordered by value.
192 """
193 if by == 'key':
194 pos = 0
195 elif by == 'value':
196 pos = 1
197 else:
198 raise FilterArgumentError('You can only sort by either '
199 '"key" or "value"')
200 def sort_func(value, env):
201 if isinstance(value, basestring):
202 value = env.to_unicode(value)
203 if not case_sensitive:
204 value = value.lower()
205 return value
206
207 def wrapped(env, context, value):
208 items = value.items()
209 items.sort(lambda a, b: cmp(sort_func(a[pos], env),
210 sort_func(b[pos], env)))
211 return items
212 return wrapped
213
214
Armin Ronacher37a88512007-03-02 20:42:18 +0100215def do_default(default_value=u'', boolean=False):
Armin Ronacher92f572f2007-02-26 22:17:32 +0100216 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100217 If the value is undefined it will return the passed default value,
218 otherwise the value of the variable:
Armin Ronacher92f572f2007-02-26 22:17:32 +0100219
Armin Ronacher37a88512007-03-02 20:42:18 +0100220 .. sourcecode:: jinja
221
222 {{ my_variable|default('my_variable is not defined') }}
223
224 This will output the value of ``my_variable`` if the variable was
225 defined, otherwise ``'my_variable is not defined'``. If you want
226 to use default with variables that evaluate to false you have to
227 set the second parameter to `true`:
228
229 .. sourcecode:: jinja
230
231 {{ ''|default('the string was empty', true) }}
Armin Ronacher92f572f2007-02-26 22:17:32 +0100232 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100233 def wrapped(env, context, value):
Armin Ronacherab45b842007-03-18 20:47:50 +0100234 if (boolean and not value) or value in (Undefined, None):
Armin Ronacher37a88512007-03-02 20:42:18 +0100235 return default_value
Armin Ronacherab45b842007-03-18 20:47:50 +0100236 return value
Armin Ronacher37a88512007-03-02 20:42:18 +0100237 return wrapped
Armin Ronacher92f572f2007-02-26 22:17:32 +0100238
239
240def do_join(d=u''):
241 """
Armin Ronacher92f572f2007-02-26 22:17:32 +0100242 Return a string which is the concatenation of the strings in the
Armin Ronacher37a88512007-03-02 20:42:18 +0100243 sequence. The separator between elements is an empty string per
244 default, you can define ith with the optional parameter:
245
246 .. sourcecode:: jinja
247
248 {{ [1, 2, 3]|join('|') }}
249 -> 1|2|3
250
251 {{ [1, 2, 3]|join }}
252 -> 123
Armin Ronacher92f572f2007-02-26 22:17:32 +0100253 """
254 def wrapped(env, context, value):
Armin Ronacher68c87252007-03-06 17:35:54 +0100255 return env.to_unicode(d).join([env.to_unicode(x) for x in value])
Armin Ronacher92f572f2007-02-26 22:17:32 +0100256 return wrapped
257
258
259def do_count():
260 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100261 Return the length of the value. In case if getting an integer or float
Armin Ronacher92f572f2007-02-26 22:17:32 +0100262 it will convert it into a string an return the length of the new
Armin Ronacher37a88512007-03-02 20:42:18 +0100263 string. If the object has no length it will of corse return 0.
Armin Ronacher92f572f2007-02-26 22:17:32 +0100264 """
265 def wrapped(env, context, value):
266 try:
267 if type(value) in (int, float, long):
Armin Ronacher68c87252007-03-06 17:35:54 +0100268 return len(str(value))
269 return len(value)
Armin Ronacher92f572f2007-02-26 22:17:32 +0100270 except TypeError:
271 return 0
272 return wrapped
273
274
Armin Ronacherdbc945d2007-03-05 18:03:32 +0100275def do_reverse():
Armin Ronacher92f572f2007-02-26 22:17:32 +0100276 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100277 Return a reversed list of the sequence filtered. You can use this
278 for example for reverse iteration:
Armin Ronacher92f572f2007-02-26 22:17:32 +0100279
Armin Ronacher37a88512007-03-02 20:42:18 +0100280 .. sourcecode:: jinja
281
Armin Ronacherdbc945d2007-03-05 18:03:32 +0100282 {% for item in seq|reverse %}
Armin Ronacher37a88512007-03-02 20:42:18 +0100283 {{ item|e }}
284 {% endfor %}
Armin Ronacher92f572f2007-02-26 22:17:32 +0100285 """
286 def wrapped(env, context, value):
287 try:
288 return value[::-1]
289 except:
290 l = list(value)
291 l.reverse()
292 return l
293 return wrapped
294
295
Armin Ronacherfed86c12007-02-27 10:31:14 +0100296def do_center(value, width=80):
297 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100298 Centers the value in a field of a given width.
299 """
300 return value.center(width)
301do_center = stringfilter(do_center)
302
303
Armin Ronacherfed86c12007-02-27 10:31:14 +0100304def do_first():
305 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100306 Return the frist item of a sequence.
Armin Ronacherfed86c12007-02-27 10:31:14 +0100307 """
308 def wrapped(env, context, seq):
309 try:
310 return iter(seq).next()
311 except StopIteration:
Armin Ronacher5a8e4972007-04-05 11:21:38 +0200312 if env.silent:
313 return Undefined
314 raise TemplateRuntimeError('%r is empty' % seq)
Armin Ronacherfed86c12007-02-27 10:31:14 +0100315 return wrapped
316
317
318def do_last():
319 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100320 Return the last item of a sequence.
321 """
322 def wrapped(env, context, seq):
323 try:
324 return iter(_reversed(seq)).next()
Armin Ronacher5a8e4972007-04-05 11:21:38 +0200325 except StopIteration:
326 if env.silent:
327 return Undefined
328 raise TemplateRuntimeError('%r is empty' % seq)
Armin Ronacherfed86c12007-02-27 10:31:14 +0100329 return wrapped
330
331
332def do_random():
333 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100334 Return a random item from the sequence.
335 """
336 def wrapped(env, context, seq):
337 try:
338 return choice(seq)
Armin Ronacher5a8e4972007-04-05 11:21:38 +0200339 except IndexError:
340 if env.silent:
341 return Undefined
342 raise TemplateRuntimeError('%r is empty' % seq)
Armin Ronacherfed86c12007-02-27 10:31:14 +0100343 return wrapped
344
345
346def do_urlencode():
347 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100348 urlencode a string or directory.
Armin Ronacher37a88512007-03-02 20:42:18 +0100349
350 .. sourcecode:: jinja
351
352 {{ {'foo': 'bar', 'blub': 'blah'}|urlencode }}
353 -> foo=bar&blub=blah
354
355 {{ 'Hello World' }}
356 -> Hello%20World
Armin Ronacherfed86c12007-02-27 10:31:14 +0100357 """
358 def wrapped(env, context, value):
359 if isinstance(value, dict):
360 tmp = {}
361 for key, value in value.iteritems():
362 tmp[env.to_unicode(key)] = env.to_unicode(value)
363 return urlencode(tmp)
364 else:
365 return quote(env.to_unicode(value))
366 return wrapped
367
368
369def do_jsonencode():
370 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100371 JSON dump a variable. just works if simplejson is installed.
Armin Ronacher37a88512007-03-02 20:42:18 +0100372
373 .. sourcecode:: jinja
374
375 {{ 'Hello World'|jsonencode }}
376 -> "Hello World"
Armin Ronacherfed86c12007-02-27 10:31:14 +0100377 """
378 global simplejson
379 try:
380 simplejson
381 except NameError:
382 import simplejson
383 return lambda e, c, v: simplejson.dumps(v)
384
385
Armin Ronacher2b765132007-03-13 16:48:10 +0100386def do_filesizeformat():
387 """
388 Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102
389 bytes, etc).
390 """
391 def wrapped(env, context, value):
392 # fail silently
393 try:
394 bytes = float(value)
395 except TypeError:
396 bytes = 0
397
398 if bytes < 1024:
399 return "%d Byte%s" % (bytes, bytes != 1 and 's' or '')
400 elif bytes < 1024 * 1024:
401 return "%.1f KB" % (bytes / 1024)
402 elif bytes < 1024 * 1024 * 1024:
403 return "%.1f MB" % (bytes / (1024 * 1024))
404 return "%.1f GB" % (bytes / (1024 * 1024 * 1024))
405 return wrapped
406
407
408def do_pprint():
409 """
410 Pretty print a variable. Useful for debugging.
411 """
412 def wrapped(env, context, value):
413 from pprint import pformat
414 return pformat(value)
415 return wrapped
416
417
418def do_urlize(value, trim_url_limit=None, nofollow=False):
419 """
420 Converts URLs in plain text into clickable links.
421
422 If you pass the filter an additional integer it will shorten the urls
423 to that number. Also a third argument exists that makes the urls
424 "nofollow":
425
426 .. sourcecode:: jinja
427
428 {{ mytext|urlize(40, True) }}
429 links are shortened to 40 chars and defined with rel="nofollow"
430 """
431 return urlize(value, trim_url_limit, nofollow)
432do_urlize = stringfilter(do_urlize)
433
434
435def do_indent(s, width=4, indentfirst=False):
436 """
437 {{ s|indent[ width[ indentfirst[ usetab]]] }}
438
439 Return a copy of the passed string, each line indented by
440 4 spaces. The first line is not indented. If you want to
441 change the number of spaces or indent the first line too
442 you can pass additional parameters to the filter:
443
444 .. sourcecode:: jinja
445
446 {{ mytext|indent(2, True) }}
447 indent by two spaces and indent the first line too.
448 """
449 indention = ' ' * width
450 if indentfirst:
451 return u'\n'.join([indention + line for line in s.splitlines()])
452 return s.replace('\n', '\n' + indention)
453do_indent = stringfilter(do_indent)
454
455
456def do_truncate(s, length=255, killwords=False, end='...'):
457 """
Armin Ronacher2b765132007-03-13 16:48:10 +0100458 Return a truncated copy of the string. The length is specified
459 with the first parameter which defaults to ``255``. If the second
460 parameter is ``true`` the filter will cut the text at length. Otherwise
461 it will try to save the last word. If the text was in fact
462 truncated it will append an ellipsis sign (``"..."``). If you want a
463 different ellipsis sign than ``"..."`` you can specify it using the
464 third parameter.
465
466 .. sourcecode jinja::
467
468 {{ mytext|truncate(300, false, '&raquo;') }}
469 truncate mytext to 300 chars, don't split up words, use a
470 right pointing double arrow as ellipsis sign.
471 """
472 if len(s) <= length:
473 return s
474 elif killwords:
475 return s[:length] + end
476 words = s.split(' ')
477 result = []
478 m = 0
479 for word in words:
480 m += len(word) + 1
481 if m > length:
482 break
483 result.append(word)
484 result.append(end)
485 return u' '.join(result)
486do_truncate = stringfilter(do_truncate)
487
488
489def do_wordwrap(s, pos=79, hard=False):
490 """
491 Return a copy of the string passed to the filter wrapped after
492 ``79`` characters. You can override this default using the first
493 parameter. If you set the second parameter to `true` Jinja will
494 also split words apart (usually a bad idea because it makes
495 reading hard).
496 """
497 if len(s) < pos:
498 return s
499 if hard:
500 return u'\n'.join([s[idx:idx + pos] for idx in
501 xrange(0, len(s), pos)])
502 # code from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061
503 return reduce(lambda line, word, pos=pos: u'%s%s%s' %
504 (line, u' \n'[(len(line)-line.rfind('\n') - 1 +
505 len(word.split('\n', 1)[0]) >= pos)],
506 word), s.split(' '))
507do_wordwrap = stringfilter(do_wordwrap)
508
509
510def do_wordcount(s):
511 """
512 Count the words in that string.
513 """
514 return len([x for x in s.split() if x])
515do_wordcount = stringfilter(do_wordcount)
516
517
518def do_textile(s):
519 """
520 Prase the string using textile.
521
522 requires the `PyTextile`_ library.
523
524 .. _PyTextile: http://dealmeida.net/projects/textile/
525 """
526 from textile import textile
527 return textile(s)
528do_textile = stringfilter(do_textile)
529
530
531def do_markdown(s):
532 """
533 Parse the string using markdown.
534
535 requires the `Python-markdown`_ library.
536
537 .. _Python-markdown: http://www.freewisdom.org/projects/python-markdown/
538 """
539 from markdown import markdown
540 return markdown(s)
541do_markdown = stringfilter(do_markdown)
542
543
544def do_rst(s):
545 """
546 Parse the string using the reStructuredText parser from the
547 docutils package.
548
549 requires `docutils`_.
550
551 .. _docutils: from http://docutils.sourceforge.net/
552 """
553 try:
554 from docutils.core import publish_parts
555 parts = publish_parts(source=s, writer_name='html4css1')
556 return parts['fragment']
557 except:
558 return s
559do_rst = stringfilter(do_rst)
560
561
Armin Ronacherab45b842007-03-18 20:47:50 +0100562def do_int(default=0):
Armin Ronacher2b765132007-03-13 16:48:10 +0100563 """
Armin Ronacherab45b842007-03-18 20:47:50 +0100564 Convert the value into an integer. If the
565 conversion doesn't work it will return ``0``. You can
566 override this default using the first parameter.
Armin Ronacher2b765132007-03-13 16:48:10 +0100567 """
568 def wrapped(env, context, value):
Armin Ronacherab45b842007-03-18 20:47:50 +0100569 try:
570 return int(value)
571 except (TypeError, ValueError):
572 try:
573 return int(float(value))
574 except (TypeError, ValueError):
575 return default
Armin Ronacher2b765132007-03-13 16:48:10 +0100576 return wrapped
577
578
Armin Ronacherab45b842007-03-18 20:47:50 +0100579def do_float(default=0.0):
Armin Ronacher2b765132007-03-13 16:48:10 +0100580 """
Armin Ronacherab45b842007-03-18 20:47:50 +0100581 Convert the value into a floating point number. If the
582 conversion doesn't work it will return ``0.0``. You can
583 override this default using the first parameter.
Armin Ronacher2b765132007-03-13 16:48:10 +0100584 """
585 def wrapped(env, context, value):
Armin Ronacherab45b842007-03-18 20:47:50 +0100586 try:
587 return float(value)
588 except (TypeError, ValueError):
589 return default
Armin Ronacher2b765132007-03-13 16:48:10 +0100590 return wrapped
591
592
593def do_string():
594 """
595 Convert the value into an string.
596 """
597 return lambda e, c, v: e.to_unicode(v)
598
599
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100600def do_format(*args):
601 """
602 Apply python string formatting on an object:
603
604 .. sourcecode:: jinja
605
606 {{ "%s - %s"|format("Hello?", "Foo!") }}
607 -> Hello? - Foo!
608
609 Note that you cannot use the mapping syntax (``%(name)s``)
610 like in python.
611 """
612 def wrapped(env, context, value):
613 return env.to_unicode(value) % args
614 return wrapped
615
616
Armin Ronacher566295e2007-03-19 13:19:34 +0100617def do_trim(value):
618 """
619 Strip leading and trailing whitespace.
620 """
621 return value.strip()
622do_trim = stringfilter(do_trim)
623
624
625def do_capture(name='captured', clean=False):
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100626 """
627 Store the value in a variable called ``captured`` or a variable
628 with the name provided. Useful for filter blocks:
629
630 .. sourcecode:: jinja
631
632 {% filter capture('foo') %}
Armin Ronacher566295e2007-03-19 13:19:34 +0100633 ...
634 {% endfilter %}
635 {{ foo }}
636
637 This will output "..." two times. One time from the filter block
638 and one time from the variable. If you don't want the filter to
639 output something you can use it in `clean` mode:
640
641 .. sourcecode:: jinja
642
643 {% filter capture('foo', True) %}
644 ...
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100645 {% endfilter %}
646 {{ foo }}
647 """
Armin Ronacher954153b2007-04-01 12:07:21 +0200648 if not isinstance(name, basestring):
Armin Ronacher566295e2007-03-19 13:19:34 +0100649 raise FilterArgumentError('You can only capture into variables')
Armin Ronacher0b666572007-03-18 23:15:23 +0100650 def wrapped(env, context, value):
651 context[name] = value
Armin Ronacher566295e2007-03-19 13:19:34 +0100652 if clean:
653 return Undefined
Armin Ronacher0b666572007-03-18 23:15:23 +0100654 return value
655 return wrapped
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100656
657
Georg Brandlaf31e4d2007-04-15 00:47:37 +0200658def do_striptags(value, rex=re.compile(r'<[^>]+>')):
659 """
660 Strip SGML/XML tags and replace adjacent whitespace by one space.
661
662 *new in Jinja 1.1*
663 """
664 return ' '.join(rex.sub('', value).split())
665do_striptags = stringfilter(do_striptags)
666
667
Armin Ronacherd071f952007-04-13 22:32:11 +0200668def do_slice(slices, fill_with=None):
669 """
670 Slice an iterator and return a list of lists containing
671 those items. Useful if you want to create a div containing
672 three div tags that represent columns:
673
Armin Ronacher89376072007-04-13 22:34:35 +0200674 .. sourcecode:: html+jinja
Armin Ronacherd071f952007-04-13 22:32:11 +0200675
676 <div class="columwrapper">
677 {%- for column in items|slice(3) %}
678 <ul class="column-{{ loop.index }}">
679 {%- for item in column %}
680 <li>{{ item }}</li>
681 {%- endfor %}
682 </ul>
683 {%- endfor %}
684 </div>
685
Armin Ronachereec31382007-04-14 14:50:45 +0200686 If you pass it a second argument it's used to fill missing
687 values on the last iteration.
688
689 *new in Jinja 1.1*
Armin Ronacherd071f952007-04-13 22:32:11 +0200690 """
691 def wrapped(env, context, value):
692 result = []
693 seq = list(value)
694 length = len(seq)
695 items_per_slice = length // slices
696 slices_with_extra = length % slices
697 offset = 0
698 for slice_number in xrange(slices):
699 start = offset + slice_number * items_per_slice
700 if slice_number < slices_with_extra:
701 offset += 1
702 end = offset + (slice_number + 1) * items_per_slice
703 tmp = seq[start:end]
704 if fill_with is not None and slice_number >= slices_with_extra:
705 tmp.append(fill_with)
706 result.append(tmp)
707 return result
708 return wrapped
709
710
711def do_batch(linecount, fill_with=None):
712 """
713 A filter that batches items. It works pretty much like `slice`
714 just the other way round. It returns a list of lists with the
715 given number of items. If you provide a second parameter this
716 is used to fill missing items. See this example:
717
Armin Ronacher89376072007-04-13 22:34:35 +0200718 .. sourcecode:: html+jinja
Armin Ronacherd071f952007-04-13 22:32:11 +0200719
720 <table>
721 {%- for row in items|batch(3, '&nbsp;') %}
722 <tr>
723 {%- for column in row %}
724 <tr>{{ column }}</td>
725 {%- endfor %}
726 </tr>
727 {%- endfor %}
728 </table>
729
Armin Ronachereec31382007-04-14 14:50:45 +0200730 *new in Jinja 1.1*
Armin Ronacherd071f952007-04-13 22:32:11 +0200731 """
732 def wrapped(env, context, value):
733 result = []
734 tmp = []
735 for item in value:
736 if len(tmp) == linecount:
737 result.append(tmp)
738 tmp = []
739 tmp.append(item)
740 if tmp:
741 if fill_with is not None and len(tmp) < linecount:
742 tmp += [fill_with] * (linecount - len(tmp))
743 result.append(tmp)
744 return result
745 return wrapped
746
747
Armin Ronachereec31382007-04-14 14:50:45 +0200748def do_sum():
749 """
750 Sum up the given sequence of numbers.
Armin Ronachera38b3122007-04-15 00:49:13 +0200751
752 *new in Jinja 1.1*
Armin Ronachereec31382007-04-14 14:50:45 +0200753 """
754 def wrapped(env, context, value):
755 return sum(value)
756 return wrapped
757
758
759def do_abs():
760 """
761 Return the absolute value of a number.
Armin Ronachera38b3122007-04-15 00:49:13 +0200762
763 *new in Jinja 1.1*
Armin Ronachereec31382007-04-14 14:50:45 +0200764 """
765 def wrapped(env, context, value):
766 return abs(value)
767 return wrapped
768
769
770def do_round(precision=0, method='common'):
771 """
772 Round the number to a given precision. The first
773 parameter specifies the precision (default is ``0``), the
774 second the rounding method:
775
776 - ``'common'`` rounds either up or down
777 - ``'ceil'`` always rounds up
778 - ``'floor'`` always rounds down
779
780 If you don't specify a method ``'common'`` is used.
781
782 .. sourcecode:: jinja
783
784 {{ 42.55|round }}
785 -> 43
786 {{ 42.55|round(1, 'floor') }}
787 -> 42.5
Armin Ronachera38b3122007-04-15 00:49:13 +0200788
789 *new in Jinja 1.1*
Armin Ronachereec31382007-04-14 14:50:45 +0200790 """
791 if not method in ('common', 'ceil', 'floor'):
792 raise FilterArgumentError('method must be common, ceil or floor')
793 if precision < 0:
794 raise FilterArgumentError('precision must be a postive integer '
795 'or zero.')
796 def wrapped(env, context, value):
797 if method == 'common':
798 return round(value, precision)
799 import math
800 func = getattr(math, method)
801 return func(value * 10 * precision) / (10 * precision)
802 return wrapped
803
804
Armin Ronacher92f572f2007-02-26 22:17:32 +0100805FILTERS = {
806 'replace': do_replace,
807 'upper': do_upper,
808 'lower': do_lower,
809 'escape': do_escape,
810 'e': do_escape,
Armin Ronacher450756b2007-04-15 15:13:59 +0200811 'xmlattr': do_xmlattr,
Armin Ronacher92f572f2007-02-26 22:17:32 +0100812 'capitalize': do_capitalize,
813 'title': do_title,
814 'default': do_default,
815 'join': do_join,
816 'count': do_count,
Armin Ronacher2b765132007-03-13 16:48:10 +0100817 'dictsort': do_dictsort,
Armin Ronacher68c87252007-03-06 17:35:54 +0100818 'length': do_count,
Armin Ronacherdbc945d2007-03-05 18:03:32 +0100819 'reverse': do_reverse,
Armin Ronacherfed86c12007-02-27 10:31:14 +0100820 'center': do_center,
821 'title': do_title,
822 'capitalize': do_capitalize,
823 'first': do_first,
824 'last': do_last,
825 'random': do_random,
826 'urlencode': do_urlencode,
Armin Ronacher2b765132007-03-13 16:48:10 +0100827 'jsonencode': do_jsonencode,
828 'filesizeformat': do_filesizeformat,
829 'pprint': do_pprint,
830 'indent': do_indent,
831 'truncate': do_truncate,
832 'wordwrap': do_wordwrap,
833 'wordcount': do_wordcount,
834 'textile': do_textile,
835 'markdown': do_markdown,
836 'rst': do_rst,
837 'int': do_int,
838 'float': do_float,
Tassilo Schweyer934cb712007-03-14 18:04:07 +0100839 'string': do_string,
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100840 'urlize': do_urlize,
841 'format': do_format,
Armin Ronacher566295e2007-03-19 13:19:34 +0100842 'capture': do_capture,
Armin Ronacherd071f952007-04-13 22:32:11 +0200843 'trim': do_trim,
Georg Brandlaf31e4d2007-04-15 00:47:37 +0200844 'striptags': do_striptags,
Armin Ronacherd071f952007-04-13 22:32:11 +0200845 'slice': do_slice,
Armin Ronachereec31382007-04-14 14:50:45 +0200846 'batch': do_batch,
847 'sum': do_sum,
848 'abs': do_abs,
849 'round': do_round
Armin Ronacher92f572f2007-02-26 22:17:32 +0100850}