title: Insert javascript at top of including file in Jinja 2
body: <p>In Jinja2, I would like the following to work as it looks like it should, by running:</p>
  
  <pre><code>from jinja2 import Environment, FileSystemLoader
  env = Environment(loader=FileSystemLoader('.'))
  template = env.get_template('x.html')
  print template.render()
  </code></pre>
  
  <p>Essentially the objective is to coalesce all the javascript into the <code>&lt;head&gt;</code> tags by using a a <code>{% call js() %} /* some js */ {% endcall %}</code> macro.</p>
  
  <hr>
  
  <h2>x.html</h2>
  
  <pre><code>&lt;html&gt;
  &lt;head&gt;
    &lt;script type="text/javascript&gt;
    {% block head_js %}{% endblock %}
    &lt;/script&gt;
    &lt;/head&gt;
  &lt;body&gt;
    {% include "y.html" %}
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <hr>
  
  <h2> y.html</h2>
  
  <pre><code>{% macro js() -%}
      // extend head_js
      {%- block head_js -%}
      {{ super() }}
      try { {{ caller() }} } catch (e) {
         my.log.error(e.name + ": " + e.message);
      }
      {%- endblock -%}
  {%- endmacro %}
  
  Some ... &lt;div id="abc"&gt;text&lt;/div&gt; ...
  
  {% call js() %}
      // jquery parlance:
      $(function () {
          $("#abc").css("color", "red");
      });
  {% endcall %}
  </code></pre>
  
  <hr>
  
  <h2>Expected result</h2>
  
  <p>When I run X.html through jinja2, I would expect the result to be:</p>
  
  <pre><code>&lt;html&gt;
  &lt;head&gt;
    &lt;script type="text/javascript&gt;
    try { {{ $("#abc").css("color", "red"); }} } catch (e) {
         usf.log.error(e.name + ": " + e.message);
      }
    &lt;/script&gt;
    &lt;/head&gt;
  &lt;body&gt;
        Some ... &lt;div id="abc"&gt;text&lt;/div&gt; ...
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <hr>
  
  <h2>Actual result</h2>
  
  <p>The actual results are not encouraging. I get a couple types of potentially illuminating errors, e.g.:</p>
  
  <blockquote>
    <p>TypeError: macro 'js' takes no keyword argument 'caller'</p>
  </blockquote>
  
  <p>or, when I try adding another basis macro such as </p>
  
  <pre><code>{% macro js2() -%}
  {%- block head_js -%}
  //     ... something
  {%- endblock -%}
  {%- endmacro %}
  </code></pre>
  
  <p>I get the following exception</p>
  
  <blockquote>
    <p>jinja2.exceptions.TemplateAssertionError: block 'head_js' defined twice</p>
  </blockquote>
  
  <p>I feel as though I am running into a design issue regarding the precedence of the <code>block</code> tags over the <code>macro</code> tags (i.e. macros do not seem to encapsulate block tags in the way I expect).</p>
  
  <hr>
  
  <p>I suppose my questions are quite simple:</p>
  
  <ol>
  <li><p>Can Jinja2 do what I am attempting? If so, how?</p></li>
  <li><p>If not, is there another Python based templating engine that does support this sort of pattern (e.g. mako, genshi, etc.), which would work without issue in Google App Engine</p></li>
  </ol>
  
  <p>Thank you for reading - I appreciate your input.</p>
  
  <p>Brian</p>
  
  <hr>
  
  <h1> Edit: </h1>
  
  <p>I'm trying to write an extension to resolve this problem. I'm halfway there -- using the following code:</p>
  
  <pre><code>from jinja2 import nodes, Environment, FileSystemLoader
  from jinja2.ext import Extension
  
  class JavascriptBuilderExtension(Extension):
      tags = set(['js', 'js_content'])
  
      def __init__(self, environment):
          super(JavascriptBuilderExtension, self).__init__(environment)
          environment.extend(
              javascript_builder_content = [],
          )
  
      def parse(self, parser):
          """Parse tokens """
          tag = parser.stream.next()
          return getattr(self, "_%s" % str(tag))(parser, tag)
  
      def _js_content(self, parser, tag):
          """ Return the output """
          content_list = self.environment.javascript_builder_content
          node = nodes.Output(lineno=tag.lineno)
          node.nodes = []
  
          for o in content_list:
              print "\nAppending node: %s" % str(o)
              node.nodes.extend(o[0].nodes)
          print "Returning node: %s \n" % node
          return node
  
      def _js(self, parser, tag):
          body = parser.parse_statements(['name:endjs'], drop_needle=True)
          print "Adding: %s" % str(body)
          self.environment.javascript_builder_content.append(body)
          return nodes.Const('&lt;!-- Slurped Javascript --&gt;')
  
  env = Environment(
      loader      = FileSystemLoader('.'),
      extensions  = [JavascriptBuilderExtension],
      )
  </code></pre>
  
  <p>This makes it simple to add Javascript to the end of a template ... e.g.</p>
  
  <pre><code>&lt;html&gt;
  &lt;head&gt;&lt;/head&gt;
  &lt;body&gt;
      {% js %}
      some javascript {{ 3 + 5 }}
      {% endjs %}
      {% js %}
      more {{ 2 }}
      {% endjs %}
  
  &lt;script type="text/javascript"&gt;
  {% js_content %}
  &lt;/script&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>Running <code>env.get_template('x.html').render()</code> will result in some illuminating comments and the expected output of:</p>
  
  <pre><code>&lt;html&gt;
  &lt;head&gt;
    &lt;script type="text/javascript&gt;
    &lt;/script&gt;
    &lt;/head&gt;
  &lt;body&gt;
      &lt;!-- Slurped Javascript --&gt;
      &lt;!-- Slurped Javascript --&gt;
  &lt;script type="text/javascript"&gt;
      some javascript 8
      more 2
  &lt;/script&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>Of course, this isn't the same as having the script in the head, as hoped, but at least it's conveniently coalesced into one place.</p>
  
  <p>However, the solution is not complete because when you have a <code>{% include "y.html" %}</code> in there, where "y.html" includes a <code>{% js %}</code> statement, the <code>{% js_content %}</code> gets called before the include's <code>{% js %}</code> statement (i.e. <code>x.html</code> is fully parsed before <code>y.html</code> starts).</p>
  
  <p>I also need to, but have not yet, inserted constant nodes that would have the static javascript <code>try/catch</code>, which I indicated I wanted to have in there. This is not an issue.</p>
  
  <p>I'm pleased to be making progress, and I'm grateful for input.</p>
  
  <p>I've opened the related question: <a href="https://stackoverflow.com/questions/4294837/jinja2-compile-extension-after-includes">Jinja2 compile extension after includes</a></p>
  
  <hr>
  
  <h2>Edit</h2>
  
  <p>Solution</p>
  
  <pre><code>class JavascriptBuilderExtension(Extension):
      tags = set(['js'])
  
      def __init__(self, environment):
          super(JavascriptBuilderExtension, self).__init__(environment)
          environment.extend(jbc = "",)
  
      def parse(self, parser):
          """Parse tokens """
          tag = parser.stream.next()
          body = parser.parse_statements(['name:endjs'], drop_needle=True)
          return nodes.CallBlock(
              self.call_method('_jbc', [], [], None, None),
              [], [], body
          ).set_lineno(tag.lineno)
  
      def _jbc(self, caller=None):
          self.environment.jbc += "\ntry { %s } catch (e) { ; };" % caller()
          return "&lt;!-- Slurped --&gt;"
  </code></pre>
  
  <p>After completed, the environment will contain a variable <code>jbc</code> that has all the Javascript. I can insert this via, for example, <code>string.Template</code>.</p>
  
  <hr>