Created
December 29, 2011 14:10
-
-
Save jlcaro/1534252 to your computer and use it in GitHub Desktop.
A Simple first approach at a DjangoTemplate -> Handlebar converter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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