Skip to content

Instantly share code, notes, and snippets.

@hyperking
Last active September 9, 2017 00:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hyperking/ee1c3e01ac6707de415eb332abc9f79f to your computer and use it in GitHub Desktop.
Save hyperking/ee1c3e01ac6707de415eb332abc9f79f to your computer and use it in GitHub Desktop.
Jinja Custom extension for moving block content into the footer
from flask import Flask,render_template, render_template_string
from pprint import pprint
'''HTML JINJA TEMPLATE'''
# create a new test.html file with the jinjaTemplateString below to view the issue.
jinjaTemplateString = '''
<html> <head></head> <body> <h1>Test template</h1>
{% push 'js' %} ABC {% endpush %}
{% push 'js' %} XYZ {% endpush %}
{% push 'js' %} 123 {% endpush %}
{{ pull }}<br>
</body> </html>
'''
'''custom jinja2 extension'''
from jinja2 import Markup, nodes
from jinja2.ext import Extension
from jinja2.nodes import ContextReference
class JavascriptBuilderExtension(Extension):
tags = set(['push','pull'])
def __init__(self, environment):
super(JavascriptBuilderExtension, self).__init__(environment)
self._myScope = {}
self.callstring = ""
def parse(self, parser):
"""Parse tokens """
tag = parser.stream.__next__()
ctx_ref = ContextReference()
if tag.value == "push":
args = [ctx_ref, parser.parse_expression(), nodes.Const(tag.lineno)]
body = parser.parse_statements(['name:endpush'], drop_needle=True)
callback = self.call_method('compiled', args)
else:
body = []
self.callstring = parser.parse_expression().value
callback = self.call_method('scope', [ctx_ref])
return nodes.CallBlock(callback, [], [], body).set_lineno(tag.lineno)
def scope(self, context, caller):
if self.callstring:
return str(context.vars["_myScope"].get(self.callstring) )
return str(context.vars["_myScope"])
def compiled(self, context, tagname, linenum, caller):
tagname = "{}".format(tagname, linenum)
if "_myScope" not in context.vars:
context.vars["_myScope"] = {}
if not context.vars["_myScope"].get(tagname):
context.vars["_myScope"][tagname] = ""
context.vars["_myScope"][tagname] += caller()
return "<!-- moved {} from line {} -->".format(tagname, linenum)
'''initialize Flask app'''
app = Flask(__name__)
app.config['TEMPLATES_AUTO_RELOAD'] = True
'''include custom extension to flask app'''
app.jinja_env.add_extension(JavascriptBuilderExtension)
@app.route("/")
def hello():
''' using render template string appears to work as intended'''
# return render_template_string(jinjaTemplateString, pull=pushedcontent)
# ''' using render template renders duplicate content'''
return render_template('test.html')
if __name__ == "__main__":
app.run(debug=True)
<html> <head></head> <body> <h1>Test template</h1>
{% push 'js' %} 123{% endpush %}
{% push 'js' %}xyz {% endpush %}
<h2>pull ouput bellow</h2>
{% pull 'js' %}
</body> </html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment