diff --git a/django/template/base.py b/django/template/base.py index 7cb9807bab..9b2404cdb3 100644 --- a/django/template/base.py +++ b/django/template/base.py @@ -184,6 +184,7 @@ class Lexer(object): self.template_string = template_string self.origin = origin self.lineno = 1 + self.verbatim = False def tokenize(self): """ @@ -203,15 +204,26 @@ class Lexer(object): If in_tag is True, we are processing something that matched a tag, otherwise it should be treated as a literal string. """ - if in_tag: + if in_tag and token_string.startswith(BLOCK_TAG_START): # The [2:-2] ranges below strip off *_TAG_START and *_TAG_END. # We could do len(BLOCK_TAG_START) to be more "correct", but we've # hard-coded the 2s here for performance. And it's not like # the TAG_START values are going to change anytime, anyway. + block_content = token_string[2:-2].strip() + if self.verbatim and block_content == self.verbatim: + self.verbatim = False + if in_tag and not self.verbatim: if token_string.startswith(VARIABLE_TAG_START): token = Token(TOKEN_VAR, token_string[2:-2].strip()) elif token_string.startswith(BLOCK_TAG_START): - token = Token(TOKEN_BLOCK, token_string[2:-2].strip()) + if block_content.startswith('verbatim'): + bits = block_content.split(' ', 1) + if bits[0] == 'verbatim': + if len(bits) > 1: + self.verbatim = bits[1] + else: + self.verbatim = 'endverbatim' + token = Token(TOKEN_BLOCK, block_content) elif token_string.startswith(COMMENT_TAG_START): content = '' if token_string.find(TRANSLATOR_COMMENT_MARK): diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 1e2198fc67..3073b41049 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -6,7 +6,7 @@ from datetime import datetime from itertools import groupby, cycle as itertools_cycle from django.conf import settings -from django.template.base import (Node, NodeList, Template, Library, +from django.template.base import (Node, NodeList, Template, Context, Library, TemplateSyntaxError, VariableDoesNotExist, InvalidTemplateLibrary, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END, @@ -425,6 +425,13 @@ class URLNode(Node): else: return url +class VerbatimNode(Node): + def __init__(self, content): + self.content = content + + def render(self, context): + return self.content + class WidthRatioNode(Node): def __init__(self, val_expr, max_expr, max_width): self.val_expr = val_expr @@ -1272,6 +1279,32 @@ def url(parser, token): return URLNode(viewname, args, kwargs, asvar) +@register.tag +def verbatim(parser, token): + """ + Stops the template engine from rendering the contents of this block tag. + + Usage:: + + {% verbatim %} + {% don't process this %} + {% endverbatim %} + + You can also specify an alternate closing tag:: + + {% verbatim -- %} + ... + {% -- %} + """ + bits = token.contents.split(' ', 1) + if len(bits) > 1: + closing_tag = bits[1] + else: + closing_tag = 'endverbatim' + nodelist = parser.parse((closing_tag,)) + parser.delete_first_token() + return VerbatimNode(nodelist.render(Context())) + @register.tag def widthratio(parser, token): """ diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index 805aaf7f6f..af9004bbf1 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -1040,6 +1040,29 @@ This will follow the normal :ref:`namespaced URL resolution strategy `, including using any hints provided by the context as to the current application. +.. templatetag:: verbatim + +verbatim +^^^^^^^^ + +.. versionadded:: 1.5 + +Stops the template engine from rendering the contents of this block tag. + +A common use is to allow a Javascript template layer that collides with +Django's syntax. For example:: + + {% verbatim %} + {{if dying}}Still alive.{{/if}} + {% endverbatim %} + +You can also specify an alternate closing tag:: + + {% verbatim finished %} + The verbatim tag looks like this: + {% verbatim %}{% endverbatim %} + {% finished %} + .. templatetag:: widthratio widthratio diff --git a/docs/releases/1.5.txt b/docs/releases/1.5.txt index 696f332285..33f5003281 100644 --- a/docs/releases/1.5.txt +++ b/docs/releases/1.5.txt @@ -62,6 +62,13 @@ For one-to-one relationships, both sides can be cached. For many-to-one relationships, only the single side of the relationship can be cached. This is particularly helpful in combination with ``prefetch_related``. +``{% verbatim %}`` template tag +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To make it easier to deal with javascript templates which collide with Django's +syntax, you can now use the :ttag:`verbatim` block tag to avoid parsing the +tag's content. + Minor features ~~~~~~~~~~~~~~ diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py index 8590dd25af..957ad2b9ba 100644 --- a/tests/regressiontests/templates/tests.py +++ b/tests/regressiontests/templates/tests.py @@ -1616,6 +1616,14 @@ class Templates(unittest.TestCase): 'static-prefixtag04': ('{% load static %}{% get_media_prefix as media_prefix %}{{ media_prefix }}', {}, settings.MEDIA_URL), 'static-statictag01': ('{% load static %}{% static "admin/base.css" %}', {}, urljoin(settings.STATIC_URL, 'admin/base.css')), 'static-statictag02': ('{% load static %}{% static base_css %}', {'base_css': 'admin/base.css'}, urljoin(settings.STATIC_URL, 'admin/base.css')), + + # Verbatim template tag outputs contents without rendering. + 'verbatim-tag01': ('{% verbatim %}{{bare }}{% endverbatim %}', {}, '{{bare }}'), + 'verbatim-tag02': ('{% verbatim %}{% endif %}{% endverbatim %}', {}, '{% endif %}'), + 'verbatim-tag03': ("{% verbatim %}It's the {% verbatim %} tag{% endverbatim %}", {}, "It's the {% verbatim %} tag"), + 'verbatim-tag04': ('{% verbatim %}{% verbatim %}{% endverbatim %}{% endverbatim %}', {}, template.TemplateSyntaxError), + 'verbatim-tag05': ('{% verbatim %}{% endverbatim %}{% verbatim %}{% endverbatim %}', {}, ''), + 'verbatim-tag06': ("{% verbatim -- %}Don't {% endverbatim %} just yet{% -- %}", {}, "Don't {% endverbatim %} just yet"), } return tests