Skip to content

Instantly share code, notes, and snippets.

@jlcaro
Created December 29, 2011 14:10
Show Gist options
  • Save jlcaro/1534252 to your computer and use it in GitHub Desktop.
Save jlcaro/1534252 to your computer and use it in GitHub Desktop.
A Simple first approach at a DjangoTemplate -> Handlebar converter
"""
A first approach to an implementation of a Templatetag converter between a simple Django Template to Handlebars
Wrap {% tohandlebars %} and {% endtohandlebars %} and the template tag will convert your SIMPLE Django Template to a Handlebars template
This templatetag is based in @ericflo's verbatim... probably is not the best implementation, and any feedback is welcomed!
The supported django tags are:
- {% if value %}
- {% if not value %} (is converted to Handlebar's unless)
- {% else %}
- {% for item in iter %}
- {% with value as value2 %}
- {% include "template" %} (Really great for using a simple django template and include it within a {% tohandlebars %}
- {% media_url %} For using AllButtonsPressed mediagenerator app
Sorry for the spanglish in the code! ;)
"""
from django import template
from django.template.base import TemplateSyntaxError, Lexer, TemplateDoesNotExist
from django.template.loader import find_template_loader, make_origin, template_source_loaders
from django.conf import settings
register = template.Library()
class HandlebarNode(template.Node):
def __init__(self, text):
self.text = text
def render(self, context):
return self.text
def reemplazar_with_tag_ref(contents, with_tag=None, params=[], rprevios=True):
t = contents
if with_tag is not None:
tam = len(params)
for i, param in enumerate(params):
if rprevios and tam-i > 1:
s = ('../' * (tam - i - 1))
else:
s = ''
t = t.replace('%s.' % param, s, 1)
return t
def get_template_source(name, dirs=[]):
global template_source_loaders
if template_source_loaders is None:
loaders = []
for loader_name in settings.TEMPLATE_LOADERS:
loader = find_template_loader(loader_name)
if loader is not None:
loaders.append(loader)
template_source_loaders = tuple(loaders)
for loader in template_source_loaders:
try:
source, display_name = loader.__class__().load_template_source(name, dirs)
return (source, make_origin(display_name, loader, name, dirs))
except TemplateDoesNotExist:
pass
raise TemplateDoesNotExist(name)
def get_tokens(template_string, origin):
if settings.TEMPLATE_DEBUG:
from django.template.debug import DebugLexer
lexer_class = DebugLexer
else:
lexer_class = Lexer
lexer = lexer_class(template_string, origin)
return lexer.tokenize()
def generate_tokens(template_name):
template, origin = get_template_source(template_name)
return get_tokens(template, origin)
def handle_filter(content):
bits = content.split('|')
text = bits[0]
if len(bits) > 1:
if bits[1] == 'safe':
text = "{"+text+"}"
return text
TAGS_SOPORTADOS = ['if','else','for','with','include', 'media_url']
def recorrer_template(parser, tokens, with_tag=None, handle_tags=None, params=None):
text = []
if params is None:
params = []
if handle_tags is None:
handle_tags = []
stop = False
while not stop and tokens:
token = tokens.pop(0)
content = token.contents
pre_content, post_content = '', ''
extra, with_t = None, None
rprevios = True
if content != 'endtohandlebars':
if token.token_type in (template.TOKEN_COMMENT, template.TOKEN_BLOCK, template.TOKEN_VAR):
pre_content = '{{'
post_content = '}}'
if token.token_type == template.TOKEN_VAR:
content = handle_filter(content)
elif token.token_type == template.TOKEN_COMMENT:
pre_content += '!'
elif token.token_type == template.TOKEN_BLOCK:
if token.contents[:3] == 'end':
pre_content += '/'
handle_tag = handle_tags.pop()
content = handle_tag
if with_tag is not None and with_tag in token.contents:
stop = True
else:
bits = token.contents.split(' ')
if bits[0] in TAGS_SOPORTADOS:
if bits[0] == 'media_url':
from mediagenerator.utils import media_url
pre_content, post_content = '', ''
content = media_url(bits[1].replace("'","").replace('"',''))
if bits[0] in ('include',):
if len(bits) != 2:
raise TemplateSyntaxError("'%s' takes one argument" % bits[0])
if bits[1][0] in ('"', "'") and bits[1][-1] == bits[1][0]:
template_name = bits[1][1:-1]
else:
template_name = parser.compile_filter(bits[1])
new_tokens = generate_tokens(template_name)
pre_content, content, post_content = '', '', ''
extra = recorrer_template(parser, new_tokens, with_tag=with_tag, handle_tags=handle_tags, params=params)
if bits[0] in ('if', 'for', 'with'):
pre_content += '#'
with_t = bits[0]
if bits[0] == 'if':
if bits[1] != 'not':
handle_tag = 'if'
else:
handle_tag = 'unless'
content = handle_tag + ' ' + ' '.join(bits[2:])
if bits[0] == 'with':
handle_tag = 'with'
params.append(bits[3])
content = 'with ' + bits[1]
rprevios = False
if bits[0] in 'for':
handle_tag = 'each'
params.append(bits[1])
content = 'each ' + bits[3]
rprevios = False
if with_t is not None:
handle_tags.append(handle_tag)
extra = recorrer_template(parser, tokens, with_tag=with_t, handle_tags=handle_tags, params=params)
else:
pre_content = ''
post_content = ''
content = ''
if pre_content: text.append(pre_content)
text.append(reemplazar_with_tag_ref(content, with_tag, params, rprevios))
if post_content: text.append(post_content)
if extra is not None:
text.extend(extra)
else:
stop = True
return text
@register.tag
def tohandlebars(parser, token):
text = recorrer_template(parser, parser.tokens)
return HandlebarNode(''.join(text))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment