Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / templatetags / astakos_tags.py @ 27e51b28

History | View | Annotate | Download (10.4 kB)

1 dd5f8f4d Kostas Papadimitriou
# Copyright 2011 GRNET S.A. All rights reserved.
2 dd5f8f4d Kostas Papadimitriou
#
3 dd5f8f4d Kostas Papadimitriou
# Redistribution and use in source and binary forms, with or
4 dd5f8f4d Kostas Papadimitriou
# without modification, are permitted provided that the following
5 dd5f8f4d Kostas Papadimitriou
# conditions are met:
6 dd5f8f4d Kostas Papadimitriou
#
7 dd5f8f4d Kostas Papadimitriou
#   1. Redistributions of source code must retain the above
8 dd5f8f4d Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
9 dd5f8f4d Kostas Papadimitriou
#      disclaimer.
10 dd5f8f4d Kostas Papadimitriou
#
11 dd5f8f4d Kostas Papadimitriou
#   2. Redistributions in binary form must reproduce the above
12 dd5f8f4d Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
13 dd5f8f4d Kostas Papadimitriou
#      disclaimer in the documentation and/or other materials
14 dd5f8f4d Kostas Papadimitriou
#      provided with the distribution.
15 dd5f8f4d Kostas Papadimitriou
#
16 dd5f8f4d Kostas Papadimitriou
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 dd5f8f4d Kostas Papadimitriou
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 dd5f8f4d Kostas Papadimitriou
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 dd5f8f4d Kostas Papadimitriou
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 dd5f8f4d Kostas Papadimitriou
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 dd5f8f4d Kostas Papadimitriou
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 dd5f8f4d Kostas Papadimitriou
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 dd5f8f4d Kostas Papadimitriou
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 dd5f8f4d Kostas Papadimitriou
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 dd5f8f4d Kostas Papadimitriou
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 dd5f8f4d Kostas Papadimitriou
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 dd5f8f4d Kostas Papadimitriou
# POSSIBILITY OF SUCH DAMAGE.
28 dd5f8f4d Kostas Papadimitriou
#
29 dd5f8f4d Kostas Papadimitriou
# The views and conclusions contained in the software and
30 dd5f8f4d Kostas Papadimitriou
# documentation are those of the authors and should not be
31 dd5f8f4d Kostas Papadimitriou
# interpreted as representing official policies, either expressed
32 dd5f8f4d Kostas Papadimitriou
# or implied, of GRNET S.A.
33 dd5f8f4d Kostas Papadimitriou
34 dd5f8f4d Kostas Papadimitriou
import urllib
35 dd5f8f4d Kostas Papadimitriou
36 dd5f8f4d Kostas Papadimitriou
from inspect import getargspec
37 dd5f8f4d Kostas Papadimitriou
38 4f78c22c Sofia Papagiannaki
from django import template
39 c0b26605 Sofia Papagiannaki
from django.core.urlresolvers import resolve
40 4f78c22c Sofia Papagiannaki
from django.conf import settings
41 dd5f8f4d Kostas Papadimitriou
from django.template import TemplateSyntaxError, Variable
42 058b6ec7 Kostas Papadimitriou
from django.utils.translation import ugettext as _
43 734107ef Kostas Papadimitriou
from synnefo_branding.utils import render_to_string
44 058b6ec7 Kostas Papadimitriou
from django.template import RequestContext
45 058b6ec7 Kostas Papadimitriou
from django.core.urlresolvers import reverse
46 058b6ec7 Kostas Papadimitriou
from django.utils.safestring import mark_safe
47 4f78c22c Sofia Papagiannaki
48 4f78c22c Sofia Papagiannaki
register = template.Library()
49 4f78c22c Sofia Papagiannaki
50 4f78c22c Sofia Papagiannaki
MESSAGES_VIEWS_MAP = getattr(settings, 'ASTAKOS_MESSAGES_VIEWS_MAP', {
51 4f78c22c Sofia Papagiannaki
    'astakos.im.views.index': 'LOGIN_MESSAGES',
52 4f78c22c Sofia Papagiannaki
    'astakos.im.views.logout': 'LOGIN_MESSAGES',
53 4f78c22c Sofia Papagiannaki
    'astakos.im.views.login': 'LOGIN_MESSAGES',
54 4f78c22c Sofia Papagiannaki
    'astakos.im.views.signup': 'SIGNUP_MESSAGES',
55 4f78c22c Sofia Papagiannaki
    'astakos.im.views.edit_profile': 'PROFILE_MESSAGES',
56 4f78c22c Sofia Papagiannaki
    'astakos.im.views.change_password': 'PROFILE_MESSAGES',
57 4f78c22c Sofia Papagiannaki
    'astakos.im.views.invite': 'PROFILE_MESSAGES',
58 4f78c22c Sofia Papagiannaki
    'astakos.im.views.feedback': 'PROFILE_MESSAGES',
59 4f78c22c Sofia Papagiannaki
})
60 4f78c22c Sofia Papagiannaki
61 9a06d96f Olga Brani
62 dd5f8f4d Kostas Papadimitriou
# helper tag decorator
63 dd5f8f4d Kostas Papadimitriou
# https://github.com/djblets/djblets/blob/master/djblets/util/decorators.py#L96
64 dd5f8f4d Kostas Papadimitriou
def basictag(takes_context=False):
65 dd5f8f4d Kostas Papadimitriou
    """
66 dd5f8f4d Kostas Papadimitriou
    A decorator similar to Django's @register.simple_tag that optionally
67 dd5f8f4d Kostas Papadimitriou
    takes a context parameter. This condenses many tag implementations down
68 dd5f8f4d Kostas Papadimitriou
    to a few lines of code.
69 dd5f8f4d Kostas Papadimitriou

70 dd5f8f4d Kostas Papadimitriou
    Example:
71 dd5f8f4d Kostas Papadimitriou
        @register.tag
72 dd5f8f4d Kostas Papadimitriou
        @basictag(takes_context=True)
73 dd5f8f4d Kostas Papadimitriou
        def printuser(context):
74 dd5f8f4d Kostas Papadimitriou
            return context['user']
75 dd5f8f4d Kostas Papadimitriou
    """
76 dd5f8f4d Kostas Papadimitriou
    class BasicTagNode(template.Node):
77 dd5f8f4d Kostas Papadimitriou
        def __init__(self, take_context, tag_name, tag_func, args):
78 dd5f8f4d Kostas Papadimitriou
            self.takes_context = takes_context
79 dd5f8f4d Kostas Papadimitriou
            self.tag_name = tag_name
80 dd5f8f4d Kostas Papadimitriou
            self.tag_func = tag_func
81 dd5f8f4d Kostas Papadimitriou
            self.args = args
82 dd5f8f4d Kostas Papadimitriou
83 dd5f8f4d Kostas Papadimitriou
        def render(self, context):
84 dd5f8f4d Kostas Papadimitriou
            args = [Variable(var).resolve(context) for var in self.args]
85 dd5f8f4d Kostas Papadimitriou
86 dd5f8f4d Kostas Papadimitriou
            if self.takes_context:
87 dd5f8f4d Kostas Papadimitriou
                return self.tag_func(context, *args)
88 dd5f8f4d Kostas Papadimitriou
            else:
89 dd5f8f4d Kostas Papadimitriou
                return self.tag_func(*args)
90 dd5f8f4d Kostas Papadimitriou
91 dd5f8f4d Kostas Papadimitriou
    def basictag_func(tag_func):
92 dd5f8f4d Kostas Papadimitriou
        def _setup_tag(parser, token):
93 dd5f8f4d Kostas Papadimitriou
            bits = token.split_contents()
94 dd5f8f4d Kostas Papadimitriou
            tag_name = bits[0]
95 dd5f8f4d Kostas Papadimitriou
            del(bits[0])
96 dd5f8f4d Kostas Papadimitriou
97 dd5f8f4d Kostas Papadimitriou
            params, xx, xxx, defaults = getargspec(tag_func)
98 dd5f8f4d Kostas Papadimitriou
            max_args = len(params)
99 dd5f8f4d Kostas Papadimitriou
100 dd5f8f4d Kostas Papadimitriou
            if takes_context:
101 dd5f8f4d Kostas Papadimitriou
                if params[0] == 'context':
102 8fb8d0cf Giorgos Korfiatis
                    max_args -= 1  # Ignore context
103 dd5f8f4d Kostas Papadimitriou
                else:
104 8fb8d0cf Giorgos Korfiatis
                    m = "Any tag function decorated with takes_context=True " \
105 dd5f8f4d Kostas Papadimitriou
                        "must have a first argument of 'context'"
106 8fb8d0cf Giorgos Korfiatis
                    raise TemplateSyntaxError(m)
107 dd5f8f4d Kostas Papadimitriou
108 dd5f8f4d Kostas Papadimitriou
            min_args = max_args - len(defaults or [])
109 dd5f8f4d Kostas Papadimitriou
110 dd5f8f4d Kostas Papadimitriou
            if not min_args <= len(bits) <= max_args:
111 dd5f8f4d Kostas Papadimitriou
                if min_args == max_args:
112 8fb8d0cf Giorgos Korfiatis
                    m = "%r tag takes %d arguments." % (tag_name, min_args)
113 8fb8d0cf Giorgos Korfiatis
                    raise TemplateSyntaxError(m)
114 dd5f8f4d Kostas Papadimitriou
                else:
115 8fb8d0cf Giorgos Korfiatis
                    m = "%r tag takes %d to %d arguments, got %d." % \
116 dd5f8f4d Kostas Papadimitriou
                        (tag_name, min_args, max_args, len(bits))
117 8fb8d0cf Giorgos Korfiatis
                    raise TemplateSyntaxError(m)
118 dd5f8f4d Kostas Papadimitriou
119 dd5f8f4d Kostas Papadimitriou
            return BasicTagNode(takes_context, tag_name, tag_func, bits)
120 dd5f8f4d Kostas Papadimitriou
121 dd5f8f4d Kostas Papadimitriou
        _setup_tag.__name__ = tag_func.__name__
122 dd5f8f4d Kostas Papadimitriou
        _setup_tag.__doc__ = tag_func.__doc__
123 dd5f8f4d Kostas Papadimitriou
        _setup_tag.__dict__.update(tag_func.__dict__)
124 dd5f8f4d Kostas Papadimitriou
        return _setup_tag
125 dd5f8f4d Kostas Papadimitriou
126 dd5f8f4d Kostas Papadimitriou
    return basictag_func
127 dd5f8f4d Kostas Papadimitriou
128 dd5f8f4d Kostas Papadimitriou
129 4f78c22c Sofia Papagiannaki
@register.tag(name='display_messages')
130 4f78c22c Sofia Papagiannaki
def display_messages(parser, token):
131 4f78c22c Sofia Papagiannaki
    return MessagesNode()
132 4f78c22c Sofia Papagiannaki
133 9a06d96f Olga Brani
134 4f78c22c Sofia Papagiannaki
class DummyMessage(object):
135 4f78c22c Sofia Papagiannaki
    def __init__(self, type, msg):
136 4f78c22c Sofia Papagiannaki
        self.message = msg
137 4f78c22c Sofia Papagiannaki
        self.tags = type
138 4f78c22c Sofia Papagiannaki
139 4f78c22c Sofia Papagiannaki
    def __repr__(self):
140 4f78c22c Sofia Papagiannaki
        return "%s: %s" % (self.tags, self.message)
141 4f78c22c Sofia Papagiannaki
142 9a06d96f Olga Brani
143 4f78c22c Sofia Papagiannaki
class MessagesNode(template.Node):
144 4f78c22c Sofia Papagiannaki
145 4f78c22c Sofia Papagiannaki
    def get_view_messages(self, context):
146 4f78c22c Sofia Papagiannaki
        messages = list(context['GLOBAL_MESSAGES'])
147 4f78c22c Sofia Papagiannaki
        try:
148 4f78c22c Sofia Papagiannaki
            view = resolve(context['request'].get_full_path())[0]
149 4f78c22c Sofia Papagiannaki
            view_name = "%s.%s" % (view.__module__, view.func_name)
150 4f78c22c Sofia Papagiannaki
            messages += context[MESSAGES_VIEWS_MAP.get(view_name)]
151 4f78c22c Sofia Papagiannaki
            return messages
152 4f78c22c Sofia Papagiannaki
        except Exception, e:
153 4f78c22c Sofia Papagiannaki
            return messages
154 4f78c22c Sofia Papagiannaki
155 4f78c22c Sofia Papagiannaki
    def render(self, context):
156 4f78c22c Sofia Papagiannaki
        if self not in context.render_context:
157 4f78c22c Sofia Papagiannaki
            messages = list(context['messages'])
158 4f78c22c Sofia Papagiannaki
            if context['EXTRA_MESSAGES_SET']:
159 4f78c22c Sofia Papagiannaki
                view_messages = self.get_view_messages(context)
160 4f78c22c Sofia Papagiannaki
                for msg_object in view_messages:
161 4f78c22c Sofia Papagiannaki
                    messages.append(DummyMessage(msg_object[0], msg_object[1]))
162 4f78c22c Sofia Papagiannaki
163 4f78c22c Sofia Papagiannaki
            if not messages:
164 4f78c22c Sofia Papagiannaki
                return ""
165 4f78c22c Sofia Papagiannaki
166 4f78c22c Sofia Papagiannaki
            cls = messages[-1].tags
167 4f78c22c Sofia Papagiannaki
            content = '<div class="top-msg active %s">' % cls
168 4f78c22c Sofia Papagiannaki
            for msg in messages:
169 9a06d96f Olga Brani
                content += '<div class="msg %s">%s</div>' % (
170 9a06d96f Olga Brani
                    msg.tags, msg.message)
171 4f78c22c Sofia Papagiannaki
172 4f78c22c Sofia Papagiannaki
            content += '<a href="#" title="close" class="close">X</a>'
173 4f78c22c Sofia Papagiannaki
            content += '</div>'
174 4f78c22c Sofia Papagiannaki
            context.render_context[self] = content
175 4f78c22c Sofia Papagiannaki
176 4f78c22c Sofia Papagiannaki
        return context.render_context[self]
177 279d6e51 Olga Brani
178 279d6e51 Olga Brani
179 279d6e51 Olga Brani
@register.simple_tag
180 669cfe19 Olga Brani
def get_grant_value(rname, form):
181 669cfe19 Olga Brani
    grants = form.instance.grants
182 669cfe19 Olga Brani
    try:
183 8fb8d0cf Giorgos Korfiatis
        r = form.instance.projectresourcegrant_set.get(
184 8fb8d0cf Giorgos Korfiatis
            resource__name=rname).member_capacity
185 26551b92 Kostas Papadimitriou
    except Exception, e:
186 26551b92 Kostas Papadimitriou
        r = ''
187 26551b92 Kostas Papadimitriou
    return r
188 dd5f8f4d Kostas Papadimitriou
189 8fb8d0cf Giorgos Korfiatis
190 dd5f8f4d Kostas Papadimitriou
@register.tag(name="provider_login_url")
191 dd5f8f4d Kostas Papadimitriou
@basictag(takes_context=True)
192 0e79735c Kostas Papadimitriou
def provider_login_url(context, provider, from_login=False):
193 dd5f8f4d Kostas Papadimitriou
    request = context['request'].REQUEST
194 dd5f8f4d Kostas Papadimitriou
    next = request.get('next', None)
195 dd5f8f4d Kostas Papadimitriou
    code = request.get('code', None)
196 dd5f8f4d Kostas Papadimitriou
    key = request.get('key', None)
197 dd5f8f4d Kostas Papadimitriou
198 dd5f8f4d Kostas Papadimitriou
    attrs = {}
199 dd5f8f4d Kostas Papadimitriou
    if next:
200 dd5f8f4d Kostas Papadimitriou
        attrs['next'] = next
201 dd5f8f4d Kostas Papadimitriou
    if code:
202 dd5f8f4d Kostas Papadimitriou
        attrs['code'] = code
203 dd5f8f4d Kostas Papadimitriou
    if key:
204 dd5f8f4d Kostas Papadimitriou
        attrs['key'] = key
205 0e79735c Kostas Papadimitriou
    if from_login:
206 0e79735c Kostas Papadimitriou
        attrs['from_login'] = 1
207 dd5f8f4d Kostas Papadimitriou
208 9d20fe23 Kostas Papadimitriou
    url = provider.urls.get('login')
209 dd5f8f4d Kostas Papadimitriou
210 dd5f8f4d Kostas Papadimitriou
    joinchar = "?"
211 dd5f8f4d Kostas Papadimitriou
    if "?" in url:
212 dd5f8f4d Kostas Papadimitriou
        joinchar = "&"
213 dd5f8f4d Kostas Papadimitriou
214 9d20fe23 Kostas Papadimitriou
    return "%s%s%s" % (url, joinchar, urllib.urlencode(attrs))
215 dd5f8f4d Kostas Papadimitriou
216 058b6ec7 Kostas Papadimitriou
217 058b6ec7 Kostas Papadimitriou
EXTRA_CONTENT_MAP = {
218 058b6ec7 Kostas Papadimitriou
    'confirm_text': '<textarea name="reason"></textarea>'
219 058b6ec7 Kostas Papadimitriou
}
220 058b6ec7 Kostas Papadimitriou
221 058b6ec7 Kostas Papadimitriou
CONFIRM_LINK_PROMPT_MAP = {
222 058b6ec7 Kostas Papadimitriou
    'project_modification_cancel': _('Are you sure you want to dismiss this '
223 058b6ec7 Kostas Papadimitriou
                                     'project ?'),
224 058b6ec7 Kostas Papadimitriou
    'project_app_cancel': _('Are you sure you want to cancel this project ?'),
225 058b6ec7 Kostas Papadimitriou
    'project_app_approve': _('Are you sure you want to approve this '
226 058b6ec7 Kostas Papadimitriou
                             'project ?'),
227 058b6ec7 Kostas Papadimitriou
    'project_app_deny': _('Are you sure you want to deny this project ? '
228 058b6ec7 Kostas Papadimitriou
                          '<br /><br />You '
229 058b6ec7 Kostas Papadimitriou
                          'may optionally provide denial reason in the '
230 44f2d10d Kostas Papadimitriou
                          'following field: <br /><br /><textarea '
231 44f2d10d Kostas Papadimitriou
                          'class="deny_reason" name="reason"></textarea>'),
232 058b6ec7 Kostas Papadimitriou
    'project_app_dismiss': _('Are you sure you want to dismiss this '
233 058b6ec7 Kostas Papadimitriou
                             'project ?'),
234 44f2d10d Kostas Papadimitriou
    'project_join': _('Are you sure you want to join this project ?'),
235 44f2d10d Kostas Papadimitriou
    'project_leave': _('Are you sure you want to leave from the project ?'),
236 058b6ec7 Kostas Papadimitriou
}
237 058b6ec7 Kostas Papadimitriou
238 058b6ec7 Kostas Papadimitriou
239 058b6ec7 Kostas Papadimitriou
@register.tag(name="confirm_link")
240 058b6ec7 Kostas Papadimitriou
@basictag(takes_context=True)
241 058b6ec7 Kostas Papadimitriou
def confirm_link(context, title, prompt='', url=None, urlarg=None,
242 058b6ec7 Kostas Papadimitriou
                 extracontent='',
243 058b6ec7 Kostas Papadimitriou
                 confirm_prompt=None,
244 058b6ec7 Kostas Papadimitriou
                 inline=True,
245 c2b1d833 Olga Brani
                 cls='',
246 058b6ec7 Kostas Papadimitriou
                 template="im/table_rich_link_column.html"):
247 058b6ec7 Kostas Papadimitriou
248 058b6ec7 Kostas Papadimitriou
    urlargs = None
249 058b6ec7 Kostas Papadimitriou
    if urlarg:
250 b4a8228e Kostas Papadimitriou
        if isinstance(urlarg, basestring) and "," in urlarg:
251 b4a8228e Kostas Papadimitriou
            args = urlarg.split(",")
252 b4a8228e Kostas Papadimitriou
            for index, arg in enumerate(args):
253 b4a8228e Kostas Papadimitriou
                if context.get(arg, None) is not None:
254 b4a8228e Kostas Papadimitriou
                    args[index] = context.get(arg)
255 b4a8228e Kostas Papadimitriou
            urlargs = args
256 b4a8228e Kostas Papadimitriou
        else:
257 b4a8228e Kostas Papadimitriou
            urlargs = (urlarg,)
258 058b6ec7 Kostas Papadimitriou
259 058b6ec7 Kostas Papadimitriou
    if CONFIRM_LINK_PROMPT_MAP.get(prompt, None):
260 058b6ec7 Kostas Papadimitriou
        prompt = mark_safe(CONFIRM_LINK_PROMPT_MAP.get(prompt))
261 058b6ec7 Kostas Papadimitriou
262 c2b1d833 Olga Brani
    if url:
263 c2b1d833 Olga Brani
        url = reverse(url, args=urlargs)
264 c2b1d833 Olga Brani
    else:
265 c2b1d833 Olga Brani
        url = None
266 c2b1d833 Olga Brani
267 058b6ec7 Kostas Papadimitriou
    title = _(title)
268 058b6ec7 Kostas Papadimitriou
    tpl_context = RequestContext(context.get('request'))
269 058b6ec7 Kostas Papadimitriou
    tpl_context.update({
270 058b6ec7 Kostas Papadimitriou
        'col': {
271 058b6ec7 Kostas Papadimitriou
            'method': 'POST',
272 058b6ec7 Kostas Papadimitriou
            'cancel_prompt': 'CANCEL',
273 058b6ec7 Kostas Papadimitriou
            'confirm_prompt': confirm_prompt or title
274 058b6ec7 Kostas Papadimitriou
        },
275 058b6ec7 Kostas Papadimitriou
        'inline': inline,
276 058b6ec7 Kostas Papadimitriou
        'url': url,
277 058b6ec7 Kostas Papadimitriou
        'action': title,
278 c2b1d833 Olga Brani
        'cls': cls,
279 058b6ec7 Kostas Papadimitriou
        'prompt': prompt,
280 058b6ec7 Kostas Papadimitriou
        'extra_form_content': EXTRA_CONTENT_MAP.get(extracontent, ''),
281 058b6ec7 Kostas Papadimitriou
        'confirm': True
282 058b6ec7 Kostas Papadimitriou
    })
283 058b6ec7 Kostas Papadimitriou
284 058b6ec7 Kostas Papadimitriou
    content = render_to_string(template, tpl_context)
285 058b6ec7 Kostas Papadimitriou
    return content
286 058b6ec7 Kostas Papadimitriou
287 3f3dc4b7 Olga Brani
288 460b907d Kostas Papadimitriou
@register.simple_tag
289 3f3dc4b7 Olga Brani
def substract(arg1, arg2):
290 460b907d Kostas Papadimitriou
    return arg1 - arg2
291 460b907d Kostas Papadimitriou
292 460b907d Kostas Papadimitriou
293 4e03ba30 Kostas Papadimitriou
class VerbatimNode(template.Node):
294 4e03ba30 Kostas Papadimitriou
295 4e03ba30 Kostas Papadimitriou
    def __init__(self, text):
296 4e03ba30 Kostas Papadimitriou
        self.text = text
297 4e03ba30 Kostas Papadimitriou
298 4e03ba30 Kostas Papadimitriou
    def render(self, context):
299 4e03ba30 Kostas Papadimitriou
        return self.text
300 4e03ba30 Kostas Papadimitriou
301 4e03ba30 Kostas Papadimitriou
302 4e03ba30 Kostas Papadimitriou
@register.tag
303 4e03ba30 Kostas Papadimitriou
def verbatim(parser, token):
304 4e03ba30 Kostas Papadimitriou
    text = []
305 4e03ba30 Kostas Papadimitriou
    while 1:
306 4e03ba30 Kostas Papadimitriou
        token = parser.tokens.pop(0)
307 4e03ba30 Kostas Papadimitriou
        if token.contents == 'endverbatim':
308 4e03ba30 Kostas Papadimitriou
            break
309 4e03ba30 Kostas Papadimitriou
        if token.token_type == template.TOKEN_VAR:
310 4e03ba30 Kostas Papadimitriou
            text.append('{{')
311 4e03ba30 Kostas Papadimitriou
        elif token.token_type == template.TOKEN_BLOCK:
312 4e03ba30 Kostas Papadimitriou
            text.append('{%')
313 4e03ba30 Kostas Papadimitriou
        text.append(token.contents)
314 4e03ba30 Kostas Papadimitriou
        if token.token_type == template.TOKEN_VAR:
315 4e03ba30 Kostas Papadimitriou
            text.append('}}')
316 4e03ba30 Kostas Papadimitriou
        elif token.token_type == template.TOKEN_BLOCK:
317 4e03ba30 Kostas Papadimitriou
            text.append('%}')
318 4e03ba30 Kostas Papadimitriou
    return VerbatimNode(''.join(text))