Created
January 30, 2012 20:45
-
-
Save Xion/1706583 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
from jinja2.ext import Extension | |
from jinja2.nodes import CallBlock, Output, MarkSafe | |
class CaptureExtension(Extension): | |
''' Generic capture extension, useful for providing | |
content that should go into specific places in HTML template, | |
such as the <head> tag for JavaScript includes. | |
Syntax for providing content for so-called 'dataset' (here it's "js"): | |
{% store 'foo' in 'js' %} | |
<script ... > | |
{% endstore %} | |
and for emitting it: | |
{% emit 'js' %} | |
Extension inspired heavily by http://stackoverflow.com/a/6090560/434799 , | |
but improved and refined somewhat. | |
''' | |
tags = set(['store', 'emit']) | |
def __init__(self, environment): | |
super(CaptureExtension, self).__init__(environment) | |
environment.extend(captured = {}) | |
def parse(self, parser): | |
''' Parsing function. Recognizes tags and produces | |
appropriate nodes. | |
''' | |
tag = parser.stream.next() | |
parse_method = getattr(self, '_parse_%s_tag' % tag.value) | |
return parse_method(parser, tag) | |
def _parse_store_tag(self, parser, tag): | |
''' Parses the {% store %} tag. | |
@return: A template node for the tag | |
''' | |
key = parser.parse_tuple(simplified = True, extra_end_rules = ['name:in']) | |
parser.stream.skip() # skipping 'in' | |
dataset = parser.parse_expression() | |
body = parser.parse_statements(['name:end' + tag.value], drop_needle = True) | |
node = CallBlock(self.call_method('_exec_store', [key, dataset]), [], [], body) | |
node.set_lineno(tag.lineno) # for debugging | |
return node | |
def _parse_emit_tag(self, parser, tag): | |
''' Parses the {% emit %} tag. | |
@return: A template node for the tag | |
''' | |
dataset = parser.parse_expression() | |
emit_call_node = self.call_method('_exec_emit', [dataset], lineno = tag.lineno) | |
nodes = [MarkSafe(emit_call_node)] | |
return Output(nodes) | |
def _exec_store(self, key, dataset, caller): | |
''' Executes the {% store %} command. | |
@return: Empty string (this tag does not produce output) | |
''' | |
dataset_content = self.environment.captured.setdefault(dataset, {}) | |
if key not in dataset_content: | |
dataset_content[key] = caller() | |
return "" | |
def _exec_emit(self, dataset): | |
''' Executes the {% emit %} command. | |
@return: Content of specified dataset as string | |
''' | |
dataset_content = self.environment.captured.get(dataset, {}) | |
output = "\n".join(dataset_content.itervalues()) | |
return output |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment